This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / include / asm-ppc64 / eeh.h
1 /* 
2  * eeh.h
3  * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  */
19
20 #ifndef _PPC64_EEH_H
21 #define _PPC64_EEH_H
22
23 #include <linux/string.h>
24 #include <linux/init.h>
25
26 struct pci_dev;
27 struct device_node;
28
29 /* I/O addresses are converted to EEH "tokens" such that a driver will cause
30  * a bad page fault if the address is used directly (i.e. these addresses are
31  * never actually mapped.  Translation between IO <-> EEH region is 1 to 1.
32  */
33 #define IO_TOKEN_TO_ADDR(token) \
34         (((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
35         (IO_REGION_ID << REGION_SHIFT))
36
37 #define IO_ADDR_TO_TOKEN(addr) \
38         (((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
39         (EEH_REGION_ID << REGION_SHIFT))
40
41 /* Values for eeh_mode bits in device_node */
42 #define EEH_MODE_SUPPORTED      (1<<0)
43 #define EEH_MODE_NOCHECK        (1<<1)
44
45 extern void __init eeh_init(void);
46 unsigned long eeh_check_failure(void *token, unsigned long val);
47 void *eeh_ioremap(unsigned long addr, void *vaddr);
48 void __init pci_addr_cache_build(void);
49
50 /**
51  * eeh_add_device_early
52  * eeh_add_device_late
53  *
54  * Perform eeh initialization for devices added after boot.
55  * Call eeh_add_device_early before doing any i/o to the
56  * device (including config space i/o).  Call eeh_add_device_late
57  * to finish the eeh setup for this device.
58  */
59 struct device_node;
60 void eeh_add_device_early(struct device_node *);
61 void eeh_add_device_late(struct pci_dev *);
62
63 /**
64  * eeh_remove_device - undo EEH setup for the indicated pci device
65  * @dev: pci device to be removed
66  *
67  * This routine should be when a device is removed from a running
68  * system (e.g. by hotplug or dlpar).
69  */
70 void eeh_remove_device(struct pci_dev *);
71
72 #define EEH_DISABLE             0
73 #define EEH_ENABLE              1
74 #define EEH_RELEASE_LOADSTORE   2
75 #define EEH_RELEASE_DMA         3
76 int eeh_set_option(struct pci_dev *dev, int options);
77
78 /*
79  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
80  *
81  * Order this macro for performance.
82  * If EEH is off for a device and it is a memory BAR, ioremap will
83  * map it to the IOREGION.  In this case addr == vaddr and since these
84  * should be in registers we compare them first.  Next we check for
85  * ff's which indicates a (very) possible failure.
86  *
87  * If this macro yields TRUE, the caller relays to eeh_check_failure()
88  * which does further tests out of line.
89  */
90 #define EEH_POSSIBLE_IO_ERROR(val, type)        ((val) == (type)~0)
91
92 /* The vaddr will equal the addr if EEH checking is disabled for
93  * this device.  This is because eeh_ioremap() will not have
94  * remapped to 0xA0, and thus both vaddr and addr will be 0xE0...
95  */
96 #define EEH_POSSIBLE_ERROR(addr, vaddr, val, type) \
97                 ((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val, type))
98
99 /* 
100  * MMIO read/write operations with EEH support.
101  */
102 static inline u8 eeh_readb(void *addr) {
103         volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
104         u8 val = in_8(vaddr);
105         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u8))
106                 return eeh_check_failure(addr, val);
107         return val;
108 }
109 static inline void eeh_writeb(u8 val, void *addr) {
110         volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
111         out_8(vaddr, val);
112 }
113
114 static inline u16 eeh_readw(void *addr) {
115         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
116         u16 val = in_le16(vaddr);
117         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
118                 return eeh_check_failure(addr, val);
119         return val;
120 }
121 static inline void eeh_writew(u16 val, void *addr) {
122         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
123         out_le16(vaddr, val);
124 }
125 static inline u16 eeh_raw_readw(void *addr) {
126         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
127         u16 val = in_be16(vaddr);
128         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
129                 return eeh_check_failure(addr, val);
130         return val;
131 }
132 static inline void eeh_raw_writew(u16 val, void *addr) {
133         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
134         out_be16(vaddr, val);
135 }
136
137 static inline u32 eeh_readl(void *addr) {
138         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
139         u32 val = in_le32(vaddr);
140         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u32))
141                 return eeh_check_failure(addr, val);
142         return val;
143 }
144 static inline void eeh_writel(u32 val, void *addr) {
145         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
146         out_le32(vaddr, val);
147 }
148 static inline u32 eeh_raw_readl(void *addr) {
149         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
150         u32 val = in_be32(vaddr);
151         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u32))
152                 return eeh_check_failure(addr, val);
153         return val;
154 }
155 static inline void eeh_raw_writel(u32 val, void *addr) {
156         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
157         out_be32(vaddr, val);
158 }
159
160 static inline u64 eeh_readq(void *addr) {
161         volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
162         u64 val = in_le64(vaddr);
163         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u64))
164                 return eeh_check_failure(addr, val);
165         return val;
166 }
167 static inline void eeh_writeq(u64 val, void *addr) {
168         volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
169         out_le64(vaddr, val);
170 }
171 static inline u64 eeh_raw_readq(void *addr) {
172         volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
173         u64 val = in_be64(vaddr);
174         if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u64))
175                 return eeh_check_failure(addr, val);
176         return val;
177 }
178 static inline void eeh_raw_writeq(u64 val, void *addr) {
179         volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
180         out_be64(vaddr, val);
181 }
182
183 static inline void eeh_memset_io(void *addr, int c, unsigned long n) {
184         void *vaddr = (void *)IO_TOKEN_TO_ADDR(addr);
185         memset(vaddr, c, n);
186 }
187 static inline void eeh_memcpy_fromio(void *dest, void *src, unsigned long n) {
188         void *vsrc = (void *)IO_TOKEN_TO_ADDR(src);
189         memcpy(dest, vsrc, n);
190         /* Look for ffff's here at dest[n].  Assume that at least 4 bytes
191          * were copied. Check all four bytes.
192          */
193         if ((n >= 4) &&
194                 (EEH_POSSIBLE_ERROR(src, vsrc, (*((u32 *) dest+n-4)), u32))) {
195                 eeh_check_failure(src, (*((u32 *) dest+n-4)));
196         }
197 }
198
199 static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
200         void *vdest = (void *)IO_TOKEN_TO_ADDR(dest);
201         memcpy(vdest, src, n);
202 }
203
204 #define MAX_ISA_PORT 0x10000
205 extern unsigned long io_page_mask;
206 #define _IO_IS_VALID(port) ((port) >= MAX_ISA_PORT || (1 << (port>>PAGE_SHIFT)) & io_page_mask)
207
208 static inline u8 eeh_inb(unsigned long port) {
209         u8 val;
210         if (!_IO_IS_VALID(port))
211                 return ~0;
212         val = in_8((u8 *)(port+pci_io_base));
213         if (EEH_POSSIBLE_IO_ERROR(val, u8))
214                 return eeh_check_failure((void*)(port), val);
215         return val;
216 }
217
218 static inline void eeh_outb(u8 val, unsigned long port) {
219         if (_IO_IS_VALID(port))
220                 out_8((u8 *)(port+pci_io_base), val);
221 }
222
223 static inline u16 eeh_inw(unsigned long port) {
224         u16 val;
225         if (!_IO_IS_VALID(port))
226                 return ~0;
227         val = in_le16((u16 *)(port+pci_io_base));
228         if (EEH_POSSIBLE_IO_ERROR(val, u16))
229                 return eeh_check_failure((void*)(port), val);
230         return val;
231 }
232
233 static inline void eeh_outw(u16 val, unsigned long port) {
234         if (_IO_IS_VALID(port))
235                 out_le16((u16 *)(port+pci_io_base), val);
236 }
237
238 static inline u32 eeh_inl(unsigned long port) {
239         u32 val;
240         if (!_IO_IS_VALID(port))
241                 return ~0;
242         val = in_le32((u32 *)(port+pci_io_base));
243         if (EEH_POSSIBLE_IO_ERROR(val, u32))
244                 return eeh_check_failure((void*)(port), val);
245         return val;
246 }
247
248 static inline void eeh_outl(u32 val, unsigned long port) {
249         if (_IO_IS_VALID(port))
250                 out_le32((u32 *)(port+pci_io_base), val);
251 }
252
253 /* in-string eeh macros */
254 static inline void eeh_insb(unsigned long port, void * buf, int ns) {
255         _insb((u8 *)(port+pci_io_base), buf, ns);
256         if (EEH_POSSIBLE_IO_ERROR((*(((u8*)buf)+ns-1)), u8))
257                 eeh_check_failure((void*)(port), *(u8*)buf);
258 }
259
260 static inline void eeh_insw_ns(unsigned long port, void * buf, int ns) {
261         _insw_ns((u16 *)(port+pci_io_base), buf, ns);
262         if (EEH_POSSIBLE_IO_ERROR((*(((u16*)buf)+ns-1)), u16))
263                 eeh_check_failure((void*)(port), *(u16*)buf);
264 }
265
266 static inline void eeh_insl_ns(unsigned long port, void * buf, int nl) {
267         _insl_ns((u32 *)(port+pci_io_base), buf, nl);
268         if (EEH_POSSIBLE_IO_ERROR((*(((u32*)buf)+nl-1)), u32))
269                 eeh_check_failure((void*)(port), *(u32*)buf);
270 }
271
272 #endif /* _PPC64_EEH_H */