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