1 /*
2 * eeh.c
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 /* Change Activity:
21 * 2001/10/27 : engebret : Created.
22 * End Change Activity
23 */
24
25 #include <linux/init.h>
26 #include <linux/pci.h>
27 #include <linux/proc_fs.h>
28 #include <linux/bootmem.h>
29 #include <asm/paca.h>
30 #include <asm/processor.h>
31 #include <asm/naca.h>
32 #include <asm/io.h>
33 #include <asm/machdep.h>
34 #include "pci.h"
35
36 #define BUID_HI(buid) ((buid) >> 32)
37 #define BUID_LO(buid) ((buid) & 0xffffffff)
38 #define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
39
40 unsigned long eeh_total_mmio_ffs;
41 unsigned long eeh_false_positives;
42 /* RTAS tokens */
43 static int ibm_set_eeh_option;
44 static int ibm_set_slot_reset;
45 static int ibm_read_slot_reset_state;
46
47 static int eeh_implemented;
48 #define EEH_MAX_OPTS 4096
49 static char *eeh_opts;
50 static int eeh_opts_last;
51
52 pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va); /* from htab.c */
53 static int eeh_check_opts_config(struct device_node *dn,
54 int class_code, int vendor_id, int device_id,
55 int default_state);
56
eeh_token_to_phys(unsigned long token)57 unsigned long eeh_token_to_phys(unsigned long token)
58 {
59 if (REGION_ID(token) == EEH_REGION_ID) {
60 unsigned long vaddr = IO_TOKEN_TO_ADDR(token);
61 pte_t *ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
62 unsigned long pa = pte_pagenr(*ptep) << PAGE_SHIFT;
63 return pa | (vaddr & (PAGE_SIZE-1));
64 } else
65 return token;
66 }
67
68 /* Check for an eeh failure at the given token address.
69 * The given value has been read and it should be 1's (0xff, 0xffff or
70 * 0xffffffff).
71 *
72 * Probe to determine if an error actually occurred. If not return val.
73 * Otherwise panic.
74 */
eeh_check_failure(void * token,unsigned long val)75 unsigned long eeh_check_failure(void *token, unsigned long val)
76 {
77 unsigned long addr;
78 struct pci_dev *dev;
79 struct device_node *dn;
80 unsigned long ret, rets[2];
81
82 /* IO BAR access could get us here...or if we manually force EEH
83 * operation on even if the hardware won't support it.
84 */
85 if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
86 return val;
87
88 /* Finding the phys addr + pci device is quite expensive.
89 * However, the RTAS call is MUCH slower.... :(
90 */
91 addr = eeh_token_to_phys((unsigned long)token);
92 dev = pci_find_dev_by_addr(addr);
93 if (!dev) {
94 printk("EEH: no pci dev found for addr=0x%lx\n", addr);
95 return val;
96 }
97 dn = pci_device_to_OF_node(dev);
98 if (!dn) {
99 printk("EEH: no pci dn found for addr=0x%lx\n", addr);
100 return val;
101 }
102
103 /* Access to IO BARs might get this far and still not want checking. */
104 if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
105 return val;
106
107
108 /* Now test for an EEH failure. This is VERY expensive.
109 * Note that the eeh_config_addr may be a parent device
110 * in the case of a device behind a bridge, or it may be
111 * function zero of a multi-function device.
112 * In any case they must share a common PHB.
113 */
114 if (dn->eeh_config_addr) {
115 ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
116 dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
117 if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
118 unsigned char slot_err_buf[RTAS_ERROR_LOG_MAX];
119 unsigned long slot_err_ret;
120
121 memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX);
122 slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"),
123 8, 1, dn->eeh_config_addr,
124 BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid),
125 NULL, 0, __pa(slot_err_buf), RTAS_ERROR_LOG_MAX,
126 2 /* Permanent Error */);
127 if (slot_err_ret == 0)
128 log_error(slot_err_buf, ERR_TYPE_RTAS_LOG, 1 /* Fatal */);
129
130 panic("EEH: MMIO failure (%ld) on device:\n %s %s\n",
131 rets[0], dev->slot_name, dev->name);
132 }
133 }
134 eeh_false_positives++;
135 return val; /* good case */
136
137 }
138
139 struct eeh_early_enable_info {
140 unsigned int buid_hi;
141 unsigned int buid_lo;
142 int adapters_enabled;
143 };
144
145
146 /* Enable/disable eeh for the given device node. */
early_set_eeh(struct device_node * dn,struct eeh_early_enable_info * info,int enable)147 static void *early_set_eeh(struct device_node *dn, struct eeh_early_enable_info *info, int enable)
148 {
149 long ret;
150 char *status = get_property(dn, "status", 0);
151 u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
152 u32 *vendor_id =(u32 *) get_property(dn, "vendor-id", 0);
153 u32 *device_id = (u32 *)get_property(dn, "device-id", 0);
154 u32 *regs;
155
156 if (status && strcmp(status, "ok") != 0)
157 return NULL; /* ignore devices with bad status */
158
159 /* Weed out PHBs or other bad nodes. */
160 if (!class_code || !vendor_id || !device_id)
161 return NULL;
162
163 /* Ignore known PHBs and EADs bridges */
164 if (*vendor_id == PCI_VENDOR_ID_IBM &&
165 (*device_id == 0x0102 || *device_id == 0x008b ||
166 *device_id == 0x0188 || *device_id == 0x0302))
167 return NULL;
168
169 /* Now decide if we are going to "Disable" EEH checking
170 * for this device. We still run with the EEH hardware active,
171 * but we won't be checking for ff's. This means a driver
172 * could return bad data (very bad!), an interrupt handler could
173 * hang waiting on status bits that won't change, etc.
174 * But there are a few cases like display devices that make sense.
175 */
176
177 if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, enable)) {
178 if (enable) {
179 printk(KERN_INFO "EEH: %s user requested to run without EEH.\n", dn->full_name);
180 enable = 0;
181 }
182 #if 0
183 /* Turn off EEH automatically for graphics ...
184 * but we don't want to do this, not really. .... */
185 } else if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) {
186 printk(KERN_INFO "EEH: %s DISPLAY automatically set to run without EEH.\n", dn->full_name);
187 enable = 0;
188 #endif
189 }
190
191 if (!enable)
192 dn->eeh_mode = EEH_MODE_NOCHECK;
193
194 /* This device may already have an EEH parent. */
195 if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
196 /* Parent supports EEH. */
197 dn->eeh_mode |= EEH_MODE_SUPPORTED;
198
199 /* Recurse to parent to set EEH, since we are probably
200 * a non-eeh supporting pci bridge chip on some card.
201 * But recurse only if our eeh setting is to be different.
202 */
203 if ((enable && (EEH_MODE_NOCHECK == dn->eeh_mode)) ||
204 (!enable && (EEH_MODE_NOCHECK != dn->eeh_mode)))
205 {
206 early_set_eeh (dn->parent, info, enable);
207 }
208 dn->eeh_config_addr = dn->parent->eeh_config_addr;
209 return NULL;
210 }
211
212 /* Ok..see if this device supports EEH. */
213 regs = (u32 *)get_property(dn, "reg", 0);
214 if (regs) {
215 /* First register entry is addr (00BBSS00) */
216 /* Try to enable/disable eeh */
217 ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
218 regs[0], info->buid_hi, info->buid_lo,
219 enable ? EEH_ENABLE : EEH_DISABLE);
220 if (ret == 0) {
221 info->adapters_enabled++;
222 dn->eeh_mode |= EEH_MODE_SUPPORTED;
223 dn->eeh_config_addr = regs[0];
224 } else {
225 printk(KERN_INFO "EEH: %s failed to %s ret=%ld\n", dn->full_name, enable ? "enable" : "disable", ret);
226 }
227 }
228 return NULL;
229 }
230
231 /* Enable eeh for the given device node. */
early_enable_eeh(struct device_node * dn,void * data)232 static void *early_enable_eeh(struct device_node *dn, void *data)
233 {
234 struct eeh_early_enable_info *info = data;
235 /* Set enable to 1, i.e. we will do checking */
236 return early_set_eeh (dn, info, 1);
237 }
238
239 /*
240 * Initialize eeh by trying to enable it for all of the adapters in the system.
241 * As a side effect we can determine here if eeh is supported at all.
242 * Note that we leave EEH on so failed config cycles won't cause a machine
243 * check. If a user turns off EEH for a particular adapter they are really
244 * telling Linux to ignore errors.
245 *
246 * We should probably distinguish between "ignore errors" and "turn EEH off"
247 * but for now disabling EEH for adapters is mostly to work around drivers that
248 * directly access mmio space (without using the macros).
249 *
250 * The eeh-force-off/on option does literally what it says, so if Linux must
251 * avoid enabling EEH this must be done.
252 */
eeh_init(void)253 void eeh_init(void)
254 {
255 struct device_node *phb;
256 struct eeh_early_enable_info info;
257
258 extern char cmd_line[]; /* Very early cmd line parse. Cheap, but works. */
259 char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
260 char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
261
262 ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
263 ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
264 ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
265
266 /* Allow user to force eeh mode on or off -- even if the hardware
267 * doesn't exist. This allows driver writers to at least test use
268 * of I/O macros even if we can't actually test for EEH failure.
269 */
270 if (eeh_force_on > eeh_force_off)
271 eeh_implemented = 1;
272 else if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
273 return;
274
275 if (eeh_force_off > eeh_force_on) {
276 /* User is forcing EEH off. Be noisy if it is implemented. */
277 if (eeh_implemented)
278 printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
279 eeh_implemented = 0;
280 return;
281 }
282
283
284 /* Enable EEH for all adapters. Note that eeh requires buid's */
285 info.adapters_enabled = 0;
286 for (phb = find_devices("pci"); phb; phb = phb->next) {
287 int len;
288 int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
289 if (!buid_vals)
290 continue;
291 if (len == sizeof(int)) {
292 info.buid_lo = buid_vals[0];
293 info.buid_hi = 0;
294 } else if (len == sizeof(int)*2) {
295 info.buid_hi = buid_vals[0];
296 info.buid_lo = buid_vals[1];
297 } else {
298 printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
299 continue;
300 }
301 traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
302 }
303 if (info.adapters_enabled) {
304 printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
305 eeh_implemented = 1;
306 }
307 }
308
309
eeh_set_option(struct pci_dev * dev,int option)310 int eeh_set_option(struct pci_dev *dev, int option)
311 {
312 struct device_node *dn = pci_device_to_OF_node(dev);
313 struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
314
315 if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
316 return -2;
317
318 return rtas_call(ibm_set_eeh_option, 4, 1, NULL,
319 CONFIG_ADDR(dn->busno, dn->devfn),
320 BUID_HI(phb->buid), BUID_LO(phb->buid), option);
321 }
322
323
324 /* If EEH is implemented, find the PCI device using given phys addr
325 * and check to see if eeh failure checking is disabled.
326 * Remap the addr (trivially) to the EEH region if not.
327 * For addresses not known to PCI the vaddr is simply returned unchanged.
328 */
eeh_ioremap(unsigned long addr,void * vaddr)329 void *eeh_ioremap(unsigned long addr, void *vaddr)
330 {
331 struct pci_dev *dev;
332 struct device_node *dn;
333
334 if (!eeh_implemented)
335 return vaddr;
336 dev = pci_find_dev_by_addr(addr);
337 if (!dev)
338 return vaddr;
339 dn = pci_device_to_OF_node(dev);
340 if (!dn)
341 return vaddr;
342 if (dn->eeh_mode & EEH_MODE_NOCHECK)
343 return vaddr;
344
345 return (void *)IO_ADDR_TO_TOKEN(vaddr);
346 }
347
eeh_proc_falsepositive_read(char * page,char ** start,off_t off,int count,int * eof,void * data)348 static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
349 int count, int *eof, void *data)
350 {
351 int len;
352 len = sprintf(page, "eeh_false_positives=%ld\n"
353 "eeh_total_mmio_ffs=%ld\n",
354 eeh_false_positives, eeh_total_mmio_ffs);
355 return len;
356 }
357
358 /* Implementation of /proc/ppc64/eeh
359 * For now it is one file showing false positives.
360 */
eeh_init_proc(void)361 static int __init eeh_init_proc(void)
362 {
363 struct proc_dir_entry *ent = create_proc_entry("ppc64/eeh", S_IRUGO, 0);
364 if (ent) {
365 ent->nlink = 1;
366 ent->data = NULL;
367 ent->read_proc = (void *)eeh_proc_falsepositive_read;
368 }
369 return 0;
370 }
371
372 /*
373 * Test if "dev" should be configured on or off.
374 * This processes the options literally from left to right.
375 * This lets the user specify stupid combinations of options,
376 * but at least the result should be very predictable.
377 */
eeh_check_opts_config(struct device_node * dn,int class_code,int vendor_id,int device_id,int default_state)378 static int eeh_check_opts_config(struct device_node *dn,
379 int class_code, int vendor_id, int device_id,
380 int default_state)
381 {
382 char devname[32], classname[32];
383 char *strs[8], *s;
384 int nstrs, i;
385 int ret = default_state;
386
387 /* Build list of strings to match */
388 nstrs = 0;
389 s = (char *)get_property(dn, "ibm,loc-code", 0);
390 if (s)
391 strs[nstrs++] = s;
392 sprintf(devname, "dev%04x:%04x", vendor_id, device_id);
393 strs[nstrs++] = devname;
394 sprintf(classname, "class%04x", class_code);
395 strs[nstrs++] = classname;
396 strs[nstrs++] = ""; /* yes, this matches the empty string */
397
398 /* Now see if any string matches the eeh_opts list.
399 * The eeh_opts list entries start with + or -.
400 */
401 for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) {
402 for (i = 0; i < nstrs; i++) {
403 if (strcasecmp(strs[i], s+1) == 0) {
404 ret = (strs[i][0] == '+') ? 1 : 0;
405 }
406 }
407 }
408 return ret;
409 }
410
411 /* Handle kernel eeh-on & eeh-off cmd line options for eeh.
412 *
413 * We support:
414 * eeh-off=loc1,loc2,loc3...
415 *
416 * and this option can be repeated so
417 * eeh-off=loc1,loc2 eeh-off=loc3
418 * is the same as eeh-off=loc1,loc2,loc3
419 *
420 * loc is an IBM location code that can be found in a manual or
421 * via openfirmware (or the Hardware Management Console).
422 *
423 * We also support these additional "loc" values:
424 *
425 * dev#:# vendor:device id in hex (e.g. dev1022:2000)
426 * class# class id in hex (e.g. class0200)
427 *
428 * If no location code is specified all devices are assumed
429 * so eeh-off means eeh by default is off.
430 */
431
432 /* This is implemented as a null separated list of strings.
433 * Each string looks like this: "+X" or "-X"
434 * where X is a loc code, vendor:device, class (as shown above)
435 * or empty which is used to indicate all.
436 *
437 * We interpret this option string list so that it will literally
438 * behave left-to-right even if some combinations don't make sense.
439 */
440
eeh_parm(char * str,int state)441 static int __init eeh_parm(char *str, int state)
442 {
443 char *s, *cur, *curend;
444 if (!eeh_opts) {
445 eeh_opts = alloc_bootmem(EEH_MAX_OPTS);
446 eeh_opts[eeh_opts_last++] = '+'; /* default */
447 eeh_opts[eeh_opts_last++] = '\0';
448 }
449 if (*str == '\0') {
450 eeh_opts[eeh_opts_last++] = state ? '+' : '-';
451 eeh_opts[eeh_opts_last++] = '\0';
452 return 1;
453 }
454 if (*str == '=')
455 str++;
456 for (s = str; s && *s != '\0'; s = curend) {
457 cur = s;
458 while (*cur == ',')
459 cur++; /* ignore empties. Don't treat as "all-on" or "all-off" */
460 curend = strchr(cur, ',');
461 if (!curend)
462 curend = cur + strlen(cur);
463 if (*cur) {
464 int curlen = curend-cur;
465 if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
466 printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
467 return 1;
468 }
469 eeh_opts[eeh_opts_last++] = state ? '+' : '-';
470 strncpy(eeh_opts+eeh_opts_last, cur, curlen);
471 eeh_opts_last += curlen;
472 eeh_opts[eeh_opts_last++] = '\0';
473 }
474 }
475 return 1;
476 }
477
eehoff_parm(char * str)478 static int __init eehoff_parm(char *str)
479 {
480 return eeh_parm(str, 0);
481 }
482
eehon_parm(char * str)483 static int __init eehon_parm(char *str)
484 {
485 return eeh_parm(str, 1);
486 }
487
488 __initcall(eeh_init_proc);
489 __setup("eeh-off", eehoff_parm);
490 __setup("eeh-on", eehon_parm);
491