vserver 1.9.5.x5
[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/config.h>
24 #include <linux/init.h>
25 #include <linux/list.h>
26 #include <linux/string.h>
27
28 struct pci_dev;
29 struct device_node;
30 struct device_node;
31 struct notifier_block;
32
33 #ifdef CONFIG_EEH
34
35 /* Values for eeh_mode bits in device_node */
36 #define EEH_MODE_SUPPORTED      (1<<0)
37 #define EEH_MODE_NOCHECK        (1<<1)
38 #define EEH_MODE_ISOLATED       (1<<2)
39
40 void __init eeh_init(void);
41 unsigned long eeh_check_failure(const volatile void __iomem *token,
42                                 unsigned long val);
43 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev);
44 void __init pci_addr_cache_build(void);
45
46 /**
47  * eeh_add_device_early
48  * eeh_add_device_late
49  *
50  * Perform eeh initialization for devices added after boot.
51  * Call eeh_add_device_early before doing any i/o to the
52  * device (including config space i/o).  Call eeh_add_device_late
53  * to finish the eeh setup for this device.
54  */
55 void eeh_add_device_early(struct device_node *);
56 void eeh_add_device_late(struct pci_dev *);
57
58 /**
59  * eeh_remove_device - undo EEH setup for the indicated pci device
60  * @dev: pci device to be removed
61  *
62  * This routine should be when a device is removed from a running
63  * system (e.g. by hotplug or dlpar).
64  */
65 void eeh_remove_device(struct pci_dev *);
66
67 #define EEH_DISABLE             0
68 #define EEH_ENABLE              1
69 #define EEH_RELEASE_LOADSTORE   2
70 #define EEH_RELEASE_DMA         3
71
72 /**
73  * Notifier event flags.
74  */
75 #define EEH_NOTIFY_FREEZE  1
76
77 /** EEH event -- structure holding pci slot data that describes
78  *  a change in the isolation status of a PCI slot.  A pointer
79  *  to this struct is passed as the data pointer in a notify callback.
80  */
81 struct eeh_event {
82         struct list_head     list;
83         struct pci_dev       *dev;
84         struct device_node   *dn;
85         int                  reset_state;
86 };
87
88 /** Register to find out about EEH events. */
89 int eeh_register_notifier(struct notifier_block *nb);
90 int eeh_unregister_notifier(struct notifier_block *nb);
91
92 /**
93  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
94  *
95  * If this macro yields TRUE, the caller relays to eeh_check_failure()
96  * which does further tests out of line.
97  */
98 #define EEH_POSSIBLE_ERROR(val, type)   ((val) == (type)~0)
99
100 /*
101  * Reads from a device which has been isolated by EEH will return
102  * all 1s.  This macro gives an all-1s value of the given size (in
103  * bytes: 1, 2, or 4) for comparing with the result of a read.
104  */
105 #define EEH_IO_ERROR_VALUE(size)        (~0U >> ((4 - (size)) * 8))
106
107 #else
108 #define eeh_init()
109 #define eeh_check_failure(token, val) (val)
110 #define eeh_dn_check_failure(dn, dev) (0)
111 #define pci_addr_cache_build()
112 #define eeh_add_device_early(dn)
113 #define eeh_add_device_late(dev)
114 #define eeh_remove_device(dev)
115 #define EEH_POSSIBLE_ERROR(val, type) (0)
116 #define EEH_IO_ERROR_VALUE(size) (-1UL)
117 #endif
118
119 /* 
120  * MMIO read/write operations with EEH support.
121  */
122 static inline u8 eeh_readb(const volatile void __iomem *addr)
123 {
124         u8 val = in_8(addr);
125         if (EEH_POSSIBLE_ERROR(val, u8))
126                 return eeh_check_failure(addr, val);
127         return val;
128 }
129 static inline void eeh_writeb(u8 val, volatile void __iomem *addr)
130 {
131         out_8(addr, val);
132 }
133
134 static inline u16 eeh_readw(const volatile void __iomem *addr)
135 {
136         u16 val = in_le16(addr);
137         if (EEH_POSSIBLE_ERROR(val, u16))
138                 return eeh_check_failure(addr, val);
139         return val;
140 }
141 static inline void eeh_writew(u16 val, volatile void __iomem *addr)
142 {
143         out_le16(addr, val);
144 }
145 static inline u16 eeh_raw_readw(const volatile void __iomem *addr)
146 {
147         u16 val = in_be16(addr);
148         if (EEH_POSSIBLE_ERROR(val, u16))
149                 return eeh_check_failure(addr, val);
150         return val;
151 }
152 static inline void eeh_raw_writew(u16 val, volatile void __iomem *addr) {
153         volatile u16 __iomem *vaddr = (volatile u16 __iomem *) addr;
154         out_be16(vaddr, val);
155 }
156
157 static inline u32 eeh_readl(const volatile void __iomem *addr)
158 {
159         u32 val = in_le32(addr);
160         if (EEH_POSSIBLE_ERROR(val, u32))
161                 return eeh_check_failure(addr, val);
162         return val;
163 }
164 static inline void eeh_writel(u32 val, volatile void __iomem *addr)
165 {
166         out_le32(addr, val);
167 }
168 static inline u32 eeh_raw_readl(const volatile void __iomem *addr)
169 {
170         u32 val = in_be32(addr);
171         if (EEH_POSSIBLE_ERROR(val, u32))
172                 return eeh_check_failure(addr, val);
173         return val;
174 }
175 static inline void eeh_raw_writel(u32 val, volatile void __iomem *addr)
176 {
177         out_be32(addr, val);
178 }
179
180 static inline u64 eeh_readq(const volatile void __iomem *addr)
181 {
182         u64 val = in_le64(addr);
183         if (EEH_POSSIBLE_ERROR(val, u64))
184                 return eeh_check_failure(addr, val);
185         return val;
186 }
187 static inline void eeh_writeq(u64 val, volatile void __iomem *addr)
188 {
189         out_le64(addr, val);
190 }
191 static inline u64 eeh_raw_readq(const volatile void __iomem *addr)
192 {
193         u64 val = in_be64(addr);
194         if (EEH_POSSIBLE_ERROR(val, u64))
195                 return eeh_check_failure(addr, val);
196         return val;
197 }
198 static inline void eeh_raw_writeq(u64 val, volatile void __iomem *addr)
199 {
200         out_be64(addr, val);
201 }
202
203 #define EEH_CHECK_ALIGN(v,a) \
204         ((((unsigned long)(v)) & ((a) - 1)) == 0)
205
206 static inline void eeh_memset_io(volatile void __iomem *addr, int c,
207                                  unsigned long n)
208 {
209         u32 lc = c;
210         lc |= lc << 8;
211         lc |= lc << 16;
212
213         while(n && !EEH_CHECK_ALIGN(addr, 4)) {
214                 *((volatile u8 *)addr) = c;
215                 addr = (void *)((unsigned long)addr + 1);
216                 n--;
217         }
218         while(n >= 4) {
219                 *((volatile u32 *)addr) = lc;
220                 addr = (void *)((unsigned long)addr + 4);
221                 n -= 4;
222         }
223         while(n) {
224                 *((volatile u8 *)addr) = c;
225                 addr = (void *)((unsigned long)addr + 1);
226                 n--;
227         }
228         __asm__ __volatile__ ("sync" : : : "memory");
229 }
230 static inline void eeh_memcpy_fromio(void *dest, const volatile void __iomem *src,
231                                      unsigned long n)
232 {
233         void *vsrc = (void __force *) src;
234         void *destsave = dest;
235         unsigned long nsave = n;
236
237         while(n && (!EEH_CHECK_ALIGN(vsrc, 4) || !EEH_CHECK_ALIGN(dest, 4))) {
238                 *((u8 *)dest) = *((volatile u8 *)vsrc);
239                 __asm__ __volatile__ ("eieio" : : : "memory");
240                 vsrc = (void *)((unsigned long)vsrc + 1);
241                 dest = (void *)((unsigned long)dest + 1);                       
242                 n--;
243         }
244         while(n > 4) {
245                 *((u32 *)dest) = *((volatile u32 *)vsrc);
246                 __asm__ __volatile__ ("eieio" : : : "memory");
247                 vsrc = (void *)((unsigned long)vsrc + 4);
248                 dest = (void *)((unsigned long)dest + 4);                       
249                 n -= 4;
250         }
251         while(n) {
252                 *((u8 *)dest) = *((volatile u8 *)vsrc);
253                 __asm__ __volatile__ ("eieio" : : : "memory");
254                 vsrc = (void *)((unsigned long)vsrc + 1);
255                 dest = (void *)((unsigned long)dest + 1);                       
256                 n--;
257         }
258         __asm__ __volatile__ ("sync" : : : "memory");
259
260         /* Look for ffff's here at dest[n].  Assume that at least 4 bytes
261          * were copied. Check all four bytes.
262          */
263         if ((nsave >= 4) &&
264                 (EEH_POSSIBLE_ERROR((*((u32 *) destsave+nsave-4)), u32))) {
265                 eeh_check_failure(src, (*((u32 *) destsave+nsave-4)));
266         }
267 }
268
269 static inline void eeh_memcpy_toio(volatile void __iomem *dest, const void *src,
270                                    unsigned long n)
271 {
272         void *vdest = (void __force *) dest;
273
274         while(n && (!EEH_CHECK_ALIGN(vdest, 4) || !EEH_CHECK_ALIGN(src, 4))) {
275                 *((volatile u8 *)vdest) = *((u8 *)src);
276                 src = (void *)((unsigned long)src + 1);
277                 vdest = (void *)((unsigned long)vdest + 1);                     
278                 n--;
279         }
280         while(n > 4) {
281                 *((volatile u32 *)vdest) = *((volatile u32 *)src);
282                 src = (void *)((unsigned long)src + 4);
283                 vdest = (void *)((unsigned long)vdest + 4);                     
284                 n-=4;
285         }
286         while(n) {
287                 *((volatile u8 *)vdest) = *((u8 *)src);
288                 src = (void *)((unsigned long)src + 1);
289                 vdest = (void *)((unsigned long)vdest + 1);                     
290                 n--;
291         }
292         __asm__ __volatile__ ("sync" : : : "memory");
293 }
294
295 #undef EEH_CHECK_ALIGN
296
297 static inline u8 eeh_inb(unsigned long port)
298 {
299         u8 val;
300         if (!_IO_IS_VALID(port))
301                 return ~0;
302         val = in_8((u8 __iomem *)(port+pci_io_base));
303         if (EEH_POSSIBLE_ERROR(val, u8))
304                 return eeh_check_failure((void __iomem *)(port), val);
305         return val;
306 }
307
308 static inline void eeh_outb(u8 val, unsigned long port)
309 {
310         if (_IO_IS_VALID(port))
311                 out_8((u8 __iomem *)(port+pci_io_base), val);
312 }
313
314 static inline u16 eeh_inw(unsigned long port)
315 {
316         u16 val;
317         if (!_IO_IS_VALID(port))
318                 return ~0;
319         val = in_le16((u16 __iomem *)(port+pci_io_base));
320         if (EEH_POSSIBLE_ERROR(val, u16))
321                 return eeh_check_failure((void __iomem *)(port), val);
322         return val;
323 }
324
325 static inline void eeh_outw(u16 val, unsigned long port)
326 {
327         if (_IO_IS_VALID(port))
328                 out_le16((u16 __iomem *)(port+pci_io_base), val);
329 }
330
331 static inline u32 eeh_inl(unsigned long port)
332 {
333         u32 val;
334         if (!_IO_IS_VALID(port))
335                 return ~0;
336         val = in_le32((u32 __iomem *)(port+pci_io_base));
337         if (EEH_POSSIBLE_ERROR(val, u32))
338                 return eeh_check_failure((void __iomem *)(port), val);
339         return val;
340 }
341
342 static inline void eeh_outl(u32 val, unsigned long port)
343 {
344         if (_IO_IS_VALID(port))
345                 out_le32((u32 __iomem *)(port+pci_io_base), val);
346 }
347
348 /* in-string eeh macros */
349 static inline void eeh_insb(unsigned long port, void * buf, int ns)
350 {
351         _insb((u8 __iomem *)(port+pci_io_base), buf, ns);
352         if (EEH_POSSIBLE_ERROR((*(((u8*)buf)+ns-1)), u8))
353                 eeh_check_failure((void __iomem *)(port), *(u8*)buf);
354 }
355
356 static inline void eeh_insw_ns(unsigned long port, void * buf, int ns)
357 {
358         _insw_ns((u16 __iomem *)(port+pci_io_base), buf, ns);
359         if (EEH_POSSIBLE_ERROR((*(((u16*)buf)+ns-1)), u16))
360                 eeh_check_failure((void __iomem *)(port), *(u16*)buf);
361 }
362
363 static inline void eeh_insl_ns(unsigned long port, void * buf, int nl)
364 {
365         _insl_ns((u32 __iomem *)(port+pci_io_base), buf, nl);
366         if (EEH_POSSIBLE_ERROR((*(((u32*)buf)+nl-1)), u32))
367                 eeh_check_failure((void __iomem *)(port), *(u32*)buf);
368 }
369
370 #endif /* _PPC64_EEH_H */