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, type) \
86 ((val) == (type)~0 && ++eeh_total_mmio_ffs)
87 #define EEH_POSSIBLE_ERROR(addr, vaddr, val, type) \
88 (EEH_POSSIBLE_IO_ERROR(val, type) && (vaddr) != (addr))
89
90 /*
91 * MMIO read/write operations with EEH support.
92 *
93 * addr: 64b token of the form 0xA0PPBBDDyyyyyyyy
94 * 0xA0 : Unmapped MMIO region
95 * PP : PHB index (starting at zero)
96 * BB : PCI Bus number under given PHB
97 * DD : PCI devfn under given bus
98 * yyyyyyyy : Virtual address offset
99 *
100 * An actual virtual address is produced from this token
101 * by masking into the form:
102 * 0xE0000000yyyyyyyy
103 */
eeh_readb(void * addr)104 static inline u8 eeh_readb(void *addr) {
105 volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
106 u8 val = in_8(vaddr);
107 if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u8))
108 return eeh_check_failure(addr, val);
109 return val;
110 }
eeh_writeb(u8 val,void * addr)111 static inline void eeh_writeb(u8 val, void *addr) {
112 volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
113 out_8(vaddr, val);
114 }
eeh_readw(void * addr)115 static inline u16 eeh_readw(void *addr) {
116 volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
117 u16 val = in_le16(vaddr);
118 if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
119 return eeh_check_failure(addr, val);
120 return val;
121 }
eeh_writew(u16 val,void * addr)122 static inline void eeh_writew(u16 val, void *addr) {
123 volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
124 out_le16(vaddr, val);
125 }
eeh_raw_readw(void * addr)126 static inline u16 eeh_raw_readw(void *addr) {
127 volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
128 u16 val = in_be16(vaddr);
129 if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
130 return eeh_check_failure(addr, val);
131 return val;
132 }
eeh_raw_writew(u16 val,void * addr)133 static inline void eeh_raw_writew(u16 val, void *addr) {
134 volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
135 out_be16(vaddr, val);
136 }
eeh_readl(void * addr)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 }
eeh_writel(u32 val,void * addr)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 }
eeh_raw_readl(void * addr)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 }
eeh_raw_writel(u32 val,void * addr)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
eeh_memset_io(void * addr,int c,unsigned long n)160 static inline void eeh_memset_io(void *addr, int c, unsigned long n) {
161 void *vaddr = (void *)IO_TOKEN_TO_ADDR(addr);
162 memset(vaddr, c, n);
163 }
eeh_memcpy_fromio(void * dest,void * src,unsigned long n)164 static inline void eeh_memcpy_fromio(void *dest, void *src, unsigned long n) {
165 void *vsrc = (void *)IO_TOKEN_TO_ADDR(src);
166 memcpy(dest, vsrc, n);
167 /* look for ffff's here at dest[n] */
168 }
eeh_memcpy_toio(void * dest,void * src,unsigned long n)169 static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
170 void *vdest = (void *)IO_TOKEN_TO_ADDR(dest);
171 memcpy(vdest, src, n);
172 }
173
174 /* The I/O macros must handle ISA ports as well as PCI I/O bars.
175 * ISA does not implement EEH and ISA may not exist in the system.
176 * For PCI we check for EEH failures.
177 */
178 #define _IO_IS_ISA(port) ((port) < 0x10000)
179 #define _IO_HAS_ISA_BUS (isa_io_base != 0)
180
eeh_inb(unsigned long port)181 static inline u8 eeh_inb(unsigned long port) {
182 u8 val;
183 if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
184 return ~0;
185 val = in_8((u8 *)(port+pci_io_base));
186 if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u8))
187 return eeh_check_failure((void*)(port+pci_io_base), val);
188 return val;
189 }
190
eeh_outb(u8 val,unsigned long port)191 static inline void eeh_outb(u8 val, unsigned long port) {
192 if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
193 return out_8((u8 *)(port+pci_io_base), val);
194 }
195
eeh_inw(unsigned long port)196 static inline u16 eeh_inw(unsigned long port) {
197 u16 val;
198 if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
199 return ~0;
200 val = in_le16((u16 *)(port+pci_io_base));
201 if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u16))
202 return eeh_check_failure((void*)(port+pci_io_base), val);
203 return val;
204 }
205
eeh_outw(u16 val,unsigned long port)206 static inline void eeh_outw(u16 val, unsigned long port) {
207 if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
208 return out_le16((u16 *)(port+pci_io_base), val);
209 }
210
eeh_inl(unsigned long port)211 static inline u32 eeh_inl(unsigned long port) {
212 u32 val;
213 if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
214 return ~0;
215 val = in_le32((u32 *)(port+pci_io_base));
216 if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u32))
217 return eeh_check_failure((void*)(port+pci_io_base), val);
218 return val;
219 }
220
eeh_outl(u32 val,unsigned long port)221 static inline void eeh_outl(u32 val, unsigned long port) {
222 if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
223 return out_le32((u32 *)(port+pci_io_base), val);
224 }
225
226 #endif /* _EEH_H */
227