File: /usr/src/linux/include/asm-ia64/io.h
1 #ifndef _ASM_IA64_IO_H
2 #define _ASM_IA64_IO_H
3
4 /*
5 * This file contains the definitions for the emulated IO instructions
6 * inb/inw/inl/outb/outw/outl and the "string versions" of the same
7 * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
8 * versions of the single-IO instructions (inb_p/inw_p/..).
9 *
10 * This file is not meant to be obfuscating: it's just complicated to
11 * (a) handle it all in a way that makes gcc able to optimize it as
12 * well as possible and (b) trying to avoid writing the same thing
13 * over and over again with slight variations and possibly making a
14 * mistake somewhere.
15 *
16 * Copyright (C) 1998-2001 Hewlett-Packard Co
17 * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
18 * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
19 * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
20 */
21
22 /* We don't use IO slowdowns on the ia64, but.. */
23 #define __SLOW_DOWN_IO do { } while (0)
24 #define SLOW_DOWN_IO do { } while (0)
25
26 #define __IA64_UNCACHED_OFFSET 0xc000000000000000 /* region 6 */
27
28 #define IO_SPACE_LIMIT 0xffff
29
30 # ifdef __KERNEL__
31
32 #include <asm/machvec.h>
33 #include <asm/page.h>
34 #include <asm/system.h>
35
36 /*
37 * Change virtual addresses to physical addresses and vv.
38 */
39 static inline unsigned long
40 virt_to_phys (volatile void *address)
41 {
42 return (unsigned long) address - PAGE_OFFSET;
43 }
44
45 static inline void*
46 phys_to_virt(unsigned long address)
47 {
48 return (void *) (address + PAGE_OFFSET);
49 }
50
51 /*
52 * The following two macros are deprecated and scheduled for removal.
53 * Please use the PCI-DMA interface defined in <asm/pci.h> instead.
54 */
55 #define bus_to_virt phys_to_virt
56 #define virt_to_bus virt_to_phys
57
58 # endif /* KERNEL */
59
60 /*
61 * Memory fence w/accept. This should never be used in code that is
62 * not IA-64 specific.
63 */
64 #define __ia64_mf_a() __asm__ __volatile__ ("mf.a" ::: "memory")
65
66 static inline const unsigned long
67 __ia64_get_io_port_base (void)
68 {
69 extern unsigned long ia64_iobase;
70
71 return ia64_iobase;
72 }
73
74 static inline void*
75 __ia64_mk_io_addr (unsigned long port)
76 {
77 const unsigned long io_base = __ia64_get_io_port_base();
78 unsigned long addr;
79
80 addr = io_base | ((port >> 2) << 12) | (port & 0xfff);
81 return (void *) addr;
82 }
83
84 /*
85 * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure
86 * that the access has completed before executing other I/O accesses. Since we're doing
87 * the accesses through an uncachable (UC) translation, the CPU will execute them in
88 * program order. However, we still need to tell the compiler not to shuffle them around
89 * during optimization, which is why we use "volatile" pointers.
90 */
91
92 static inline unsigned int
93 __ia64_inb (unsigned long port)
94 {
95 volatile unsigned char *addr = __ia64_mk_io_addr(port);
96 unsigned char ret;
97
98 ret = *addr;
99 __ia64_mf_a();
100 return ret;
101 }
102
103 static inline unsigned int
104 __ia64_inw (unsigned long port)
105 {
106 volatile unsigned short *addr = __ia64_mk_io_addr(port);
107 unsigned short ret;
108
109 ret = *addr;
110 __ia64_mf_a();
111 return ret;
112 }
113
114 static inline unsigned int
115 __ia64_inl (unsigned long port)
116 {
117 volatile unsigned int *addr = __ia64_mk_io_addr(port);
118 unsigned int ret;
119
120 ret = *addr;
121 __ia64_mf_a();
122 return ret;
123 }
124
125 static inline void
126 __ia64_outb (unsigned char val, unsigned long port)
127 {
128 volatile unsigned char *addr = __ia64_mk_io_addr(port);
129
130 *addr = val;
131 __ia64_mf_a();
132 }
133
134 static inline void
135 __ia64_outw (unsigned short val, unsigned long port)
136 {
137 volatile unsigned short *addr = __ia64_mk_io_addr(port);
138
139 *addr = val;
140 __ia64_mf_a();
141 }
142
143 static inline void
144 __ia64_outl (unsigned int val, unsigned long port)
145 {
146 volatile unsigned int *addr = __ia64_mk_io_addr(port);
147
148 *addr = val;
149 __ia64_mf_a();
150 }
151
152 static inline void
153 __insb (unsigned long port, void *dst, unsigned long count)
154 {
155 unsigned char *dp = dst;
156
157 if (platform_inb == __ia64_inb) {
158 volatile unsigned char *addr = __ia64_mk_io_addr(port);
159
160 __ia64_mf_a();
161 while (count--)
162 *dp++ = *addr;
163 __ia64_mf_a();
164 } else
165 while (count--)
166 *dp++ = platform_inb(port);
167 return;
168 }
169
170 static inline void
171 __insw (unsigned long port, void *dst, unsigned long count)
172 {
173 unsigned short *dp = dst;
174
175 if (platform_inw == __ia64_inw) {
176 volatile unsigned short *addr = __ia64_mk_io_addr(port);
177
178 __ia64_mf_a();
179 while (count--)
180 *dp++ = *addr;
181 __ia64_mf_a();
182 } else
183 while (count--)
184 *dp++ = platform_inw(port);
185 return;
186 }
187
188 static inline void
189 __insl (unsigned long port, void *dst, unsigned long count)
190 {
191 unsigned int *dp = dst;
192
193 if (platform_inl == __ia64_inl) {
194 volatile unsigned int *addr = __ia64_mk_io_addr(port);
195
196 __ia64_mf_a();
197 while (count--)
198 *dp++ = *addr;
199 __ia64_mf_a();
200 } else
201 while (count--)
202 *dp++ = platform_inl(port);
203 return;
204 }
205
206 static inline void
207 __outsb (unsigned long port, const void *src, unsigned long count)
208 {
209 const unsigned char *sp = src;
210
211 if (platform_outb == __ia64_outb) {
212 volatile unsigned char *addr = __ia64_mk_io_addr(port);
213
214 while (count--)
215 *addr = *sp++;
216 __ia64_mf_a();
217 } else
218 while (count--)
219 platform_outb(*sp++, port);
220 return;
221 }
222
223 static inline void
224 __outsw (unsigned long port, const void *src, unsigned long count)
225 {
226 const unsigned short *sp = src;
227
228 if (platform_outw == __ia64_outw) {
229 volatile unsigned short *addr = __ia64_mk_io_addr(port);
230
231 while (count--)
232 *addr = *sp++;
233 __ia64_mf_a();
234 } else
235 while (count--)
236 platform_outw(*sp++, port);
237 return;
238 }
239
240 static inline void
241 __outsl (unsigned long port, void *src, unsigned long count)
242 {
243 const unsigned int *sp = src;
244
245 if (platform_outl == __ia64_outl) {
246 volatile unsigned int *addr = __ia64_mk_io_addr(port);
247
248 while (count--)
249 *addr = *sp++;
250 __ia64_mf_a();
251 } else
252 while (count--)
253 platform_outl(*sp++, port);
254 return;
255 }
256
257 /*
258 * Unfortunately, some platforms are broken and do not follow the
259 * IA-64 architecture specification regarding legacy I/O support.
260 * Thus, we have to make these operations platform dependent...
261 */
262 #define __inb platform_inb
263 #define __inw platform_inw
264 #define __inl platform_inl
265 #define __outb platform_outb
266 #define __outw platform_outw
267 #define __outl platform_outl
268
269 #define inb __inb
270 #define inw __inw
271 #define inl __inl
272 #define insb __insb
273 #define insw __insw
274 #define insl __insl
275 #define outb __outb
276 #define outw __outw
277 #define outl __outl
278 #define outsb __outsb
279 #define outsw __outsw
280 #define outsl __outsl
281
282 /*
283 * The address passed to these functions are ioremap()ped already.
284 */
285 static inline unsigned char
286 __readb (void *addr)
287 {
288 return *(volatile unsigned char *)addr;
289 }
290
291 static inline unsigned short
292 __readw (void *addr)
293 {
294 return *(volatile unsigned short *)addr;
295 }
296
297 static inline unsigned int
298 __readl (void *addr)
299 {
300 return *(volatile unsigned int *) addr;
301 }
302
303 static inline unsigned long
304 __readq (void *addr)
305 {
306 return *(volatile unsigned long *) addr;
307 }
308
309 static inline void
310 __writeb (unsigned char val, void *addr)
311 {
312 *(volatile unsigned char *) addr = val;
313 }
314
315 static inline void
316 __writew (unsigned short val, void *addr)
317 {
318 *(volatile unsigned short *) addr = val;
319 }
320
321 static inline void
322 __writel (unsigned int val, void *addr)
323 {
324 *(volatile unsigned int *) addr = val;
325 }
326
327 static inline void
328 __writeq (unsigned long val, void *addr)
329 {
330 *(volatile unsigned long *) addr = val;
331 }
332
333 #define readb(a) __readb((void *)(a))
334 #define readw(a) __readw((void *)(a))
335 #define readl(a) __readl((void *)(a))
336 #define readq(a) __readq((void *)(a))
337 #define __raw_readb readb
338 #define __raw_readw readw
339 #define __raw_readl readl
340 #define __raw_readq readq
341 #define writeb(v,a) __writeb((v), (void *) (a))
342 #define writew(v,a) __writew((v), (void *) (a))
343 #define writel(v,a) __writel((v), (void *) (a))
344 #define writeq(v,a) __writeq((v), (void *) (a))
345 #define __raw_writeb writeb
346 #define __raw_writew writew
347 #define __raw_writel writel
348 #define __raw_writeq writeq
349
350 #ifndef inb_p
351 # define inb_p inb
352 #endif
353 #ifndef inw_p
354 # define inw_p inw
355 #endif
356 #ifndef inl_p
357 # define inl_p inl
358 #endif
359
360 #ifndef outb_p
361 # define outb_p outb
362 #endif
363 #ifndef outw_p
364 # define outw_p outw
365 #endif
366 #ifndef outl_p
367 # define outl_p outl
368 #endif
369
370 /*
371 * An "address" in IO memory space is not clearly either an integer or a pointer. We will
372 * accept both, thus the casts.
373 *
374 * On ia-64, we access the physical I/O memory space through the uncached kernel region.
375 */
376 static inline void *
377 ioremap (unsigned long offset, unsigned long size)
378 {
379 return (void *) (__IA64_UNCACHED_OFFSET | (offset));
380 }
381
382 static inline void
383 iounmap (void *addr)
384 {
385 }
386
387 #define ioremap_nocache(o,s) ioremap(o,s)
388
389 # ifdef __KERNEL__
390
391 /*
392 * String version of IO memory access ops:
393 */
394 extern void __ia64_memcpy_fromio (void *, unsigned long, long);
395 extern void __ia64_memcpy_toio (unsigned long, void *, long);
396 extern void __ia64_memset_c_io (unsigned long, unsigned long, long);
397
398 #define memcpy_fromio(to,from,len) \
399 __ia64_memcpy_fromio((to),(unsigned long)(from),(len))
400 #define memcpy_toio(to,from,len) \
401 __ia64_memcpy_toio((unsigned long)(to),(from),(len))
402 #define memset_io(addr,c,len) \
403 __ia64_memset_c_io((unsigned long)(addr),0x0101010101010101UL*(u8)(c),(len))
404
405 # endif /* __KERNEL__ */
406 #endif /* _ASM_IA64_IO_H */
407