cleanup
[linux-2.4.21-pre4.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 /* Start Change Log
21  * 2001/10/27 : engebret : Created.
22  * End Change Log 
23  */
24
25 #ifndef _EEH_H
26 #define _EEH_H
27
28 struct pci_dev;
29
30 /* I/O addresses are converted to EEH "tokens" such that a driver will cause
31  * a bad page fault if the address is used directly (i.e. these addresses are
32  * never actually mapped.  Translation between IO <-> EEH region is 1 to 1.
33  */
34 #define IO_TOKEN_TO_ADDR(token) (((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
35                                 (IO_REGION_ID << REGION_SHIFT))
36 #define IO_ADDR_TO_TOKEN(addr) (((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
37                                 (EEH_REGION_ID << REGION_SHIFT))
38
39 /* Values for eeh_mode bits in device_node */
40 #define EEH_MODE_SUPPORTED      (1<<0)
41 #define EEH_MODE_NOCHECK        (1<<1)
42
43 /* This is for profiling only */
44 extern unsigned long eeh_total_mmio_ffs;
45
46 void eeh_init(void);
47 int eeh_get_state(unsigned long ea);
48 unsigned long eeh_check_failure(void *token, unsigned long val);
49 void *eeh_ioremap(unsigned long addr, void *vaddr);
50
51 #define EEH_DISABLE             0
52 #define EEH_ENABLE              1
53 #define EEH_RELEASE_LOADSTORE   2
54 #define EEH_RELEASE_DMA         3
55 int eeh_set_option(struct pci_dev *dev, int options);
56
57 /* Given a PCI device check if eeh should be configured or not.
58  * This may look at firmware properties and/or kernel cmdline options.
59  */
60 int is_eeh_configured(struct pci_dev *dev);
61
62 /* Translate a (possible) eeh token to a physical addr.
63  * If "token" is not an eeh token it is simply returned under
64  * the assumption that it is already a physical addr.
65  */
66 unsigned long eeh_token_to_phys(unsigned long token);
67
68 extern void *memcpy(void *, const void *, unsigned long);
69 extern void *memset(void *,int, unsigned long);
70
71 /* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
72  *
73  * Order this macro for performance.
74  * If EEH is off for a device and it is a memory BAR, ioremap will
75  * map it to the IOREGION.  In this case addr == vaddr and since these
76  * should be in registers we compare them first.  Next we check for
77  * ff's which indicates a (very) possible failure.
78  *
79  * If this macro yields TRUE, the caller relays to eeh_check_failure()
80  * which does further tests out of line.
81  */
82 /* #define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0) */
83 /* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val) */
84 /* This version is rearranged to collect some profiling data */
85 #define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0 && ++eeh_total_mmio_ffs)
86 #define EEH_POSSIBLE_ERROR(addr, vaddr, val) (EEH_POSSIBLE_IO_ERROR(val) && (vaddr) != (addr))
87
88 /* 
89  * MMIO read/write operations with EEH support.
90  *
91  * addr: 64b token of the form 0xA0PPBBDDyyyyyyyy
92  *       0xA0     : Unmapped MMIO region
93  *       PP       : PHB index (starting at zero)
94  *       BB       : PCI Bus number under given PHB
95  *       DD       : PCI devfn under given bus
96  *       yyyyyyyy : Virtual address offset
97  * 
98  * An actual virtual address is produced from this token
99  * by masking into the form:
100  *   0xE0000000yyyyyyyy
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))
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 static inline u16 eeh_readw(void *addr) {
114         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
115         u16 val = in_le16(vaddr);
116         if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
117                 return eeh_check_failure(addr, val);
118         return val;
119 }
120 static inline void eeh_writew(u16 val, void *addr) {
121         volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
122         out_le16(vaddr, val);
123 }
124 static inline u32 eeh_readl(void *addr) {
125         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
126         u32 val = in_le32(vaddr);
127         if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
128                 return eeh_check_failure(addr, val);
129         return val;
130 }
131 static inline void eeh_writel(u32 val, void *addr) {
132         volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
133         out_le32(vaddr, val);
134 }
135
136 static inline void eeh_memset_io(void *addr, int c, unsigned long n) {
137         void *vaddr = (void *)IO_TOKEN_TO_ADDR(addr);
138         memset(vaddr, c, n);
139 }
140 static inline void eeh_memcpy_fromio(void *dest, void *src, unsigned long n) {
141         void *vsrc = (void *)IO_TOKEN_TO_ADDR(src);
142         memcpy(dest, vsrc, n);
143         /* look for ffff's here at dest[n] */
144 }
145 static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
146         void *vdest = (void *)IO_TOKEN_TO_ADDR(dest);
147         memcpy(vdest, src, n);
148 }
149
150 /* The I/O macros must handle ISA ports as well as PCI I/O bars.
151  * ISA does not implement EEH and ISA may not exist in the system.
152  * For PCI we check for EEH failures.
153  */
154 #define _IO_IS_ISA(port) ((port) < 0x10000)
155 #define _IO_HAS_ISA_BUS (isa_io_base != 0)
156
157 static inline u8 eeh_inb(unsigned long port) {
158         u8 val;
159         if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
160                 return ~0;
161         val = in_8((u8 *)(port+pci_io_base));
162         if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
163                 return eeh_check_failure((void*)(port+pci_io_base), val);
164         return val;
165 }
166
167 static inline void eeh_outb(u8 val, unsigned long port) {
168         if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
169                 return out_8((u8 *)(port+pci_io_base), val);
170 }
171
172 static inline u16 eeh_inw(unsigned long port) {
173         u16 val;
174         if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
175                 return ~0;
176         val = in_le16((u16 *)(port+pci_io_base));
177         if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
178                 return eeh_check_failure((void*)(port+pci_io_base), val);
179         return val;
180 }
181
182 static inline void eeh_outw(u16 val, unsigned long port) {
183         if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
184                 return out_le16((u16 *)(port+pci_io_base), val);
185 }
186
187 static inline u32 eeh_inl(unsigned long port) {
188         u32 val;
189         if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
190                 return ~0;
191         val = in_le32((u32 *)(port+pci_io_base));
192         if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
193                 return eeh_check_failure((void*)(port+pci_io_base), val);
194         return val;
195 }
196
197 static inline void eeh_outl(u32 val, unsigned long port) {
198         if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
199                 return out_le32((u32 *)(port+pci_io_base), val);
200 }
201
202 #endif /* _EEH_H */