diff options
author | David S. Miller <davem@davemloft.net> | 2008-09-10 06:52:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-09-11 02:11:58 -0400 |
commit | e6e003720fd7123482f77dcec19e930d272937fe (patch) | |
tree | 4b08ce49ffc264b7c2e8ae9a7c4650e9f4eff63b /arch/sparc64/kernel/pci_sabre.c | |
parent | 1c03a55cdf309d0939e881b313abbe7e9a67d95e (diff) |
sparc64: Commonize large portions of PSYCHO error handling.
The IOMMU and streaming cache error interrogation is moved here
as well as the PCI error interrupt handler.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_sabre.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sabre.c | 223 |
1 files changed, 5 insertions, 218 deletions
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index ae11d67388e1..f8089aa84f64 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c | |||
@@ -210,95 +210,6 @@ | |||
210 | static int hummingbird_p; | 210 | static int hummingbird_p; |
211 | static struct pci_bus *sabre_root_bus; | 211 | static struct pci_bus *sabre_root_bus; |
212 | 212 | ||
213 | /* SABRE error handling support. */ | ||
214 | static void sabre_check_iommu_error(struct pci_pbm_info *pbm, | ||
215 | unsigned long afsr, | ||
216 | unsigned long afar) | ||
217 | { | ||
218 | struct iommu *iommu = pbm->iommu; | ||
219 | unsigned long iommu_tag[16]; | ||
220 | unsigned long iommu_data[16]; | ||
221 | unsigned long flags; | ||
222 | u64 control; | ||
223 | int i; | ||
224 | |||
225 | spin_lock_irqsave(&iommu->lock, flags); | ||
226 | control = sabre_read(iommu->iommu_control); | ||
227 | if (control & SABRE_IOMMUCTRL_ERR) { | ||
228 | char *type_string; | ||
229 | |||
230 | /* Clear the error encountered bit. | ||
231 | * NOTE: On Sabre this is write 1 to clear, | ||
232 | * which is different from Psycho. | ||
233 | */ | ||
234 | sabre_write(iommu->iommu_control, control); | ||
235 | switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) { | ||
236 | case 1: | ||
237 | type_string = "Invalid Error"; | ||
238 | break; | ||
239 | case 3: | ||
240 | type_string = "ECC Error"; | ||
241 | break; | ||
242 | default: | ||
243 | type_string = "Unknown"; | ||
244 | break; | ||
245 | }; | ||
246 | printk("%s: IOMMU Error, type[%s]\n", | ||
247 | pbm->name, type_string); | ||
248 | |||
249 | /* Enter diagnostic mode and probe for error'd | ||
250 | * entries in the IOTLB. | ||
251 | */ | ||
252 | control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR); | ||
253 | sabre_write(iommu->iommu_control, | ||
254 | (control | SABRE_IOMMUCTRL_DENAB)); | ||
255 | for (i = 0; i < 16; i++) { | ||
256 | unsigned long base = pbm->controller_regs; | ||
257 | |||
258 | iommu_tag[i] = | ||
259 | sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL)); | ||
260 | iommu_data[i] = | ||
261 | sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL)); | ||
262 | sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0); | ||
263 | sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0); | ||
264 | } | ||
265 | sabre_write(iommu->iommu_control, control); | ||
266 | |||
267 | for (i = 0; i < 16; i++) { | ||
268 | unsigned long tag, data; | ||
269 | |||
270 | tag = iommu_tag[i]; | ||
271 | if (!(tag & SABRE_IOMMUTAG_ERR)) | ||
272 | continue; | ||
273 | |||
274 | data = iommu_data[i]; | ||
275 | switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) { | ||
276 | case 1: | ||
277 | type_string = "Invalid Error"; | ||
278 | break; | ||
279 | case 3: | ||
280 | type_string = "ECC Error"; | ||
281 | break; | ||
282 | default: | ||
283 | type_string = "Unknown"; | ||
284 | break; | ||
285 | }; | ||
286 | printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", | ||
287 | pbm->name, i, tag, type_string, | ||
288 | ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), | ||
289 | ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), | ||
290 | ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT)); | ||
291 | printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n", | ||
292 | pbm->name, i, data, | ||
293 | ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), | ||
294 | ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), | ||
295 | ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), | ||
296 | ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT)); | ||
297 | } | ||
298 | } | ||
299 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
300 | } | ||
301 | |||
302 | static irqreturn_t sabre_ue_intr(int irq, void *dev_id) | 213 | static irqreturn_t sabre_ue_intr(int irq, void *dev_id) |
303 | { | 214 | { |
304 | struct pci_pbm_info *pbm = dev_id; | 215 | struct pci_pbm_info *pbm = dev_id; |
@@ -354,7 +265,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id) | |||
354 | printk("]\n"); | 265 | printk("]\n"); |
355 | 266 | ||
356 | /* Interrogate IOMMU for error status. */ | 267 | /* Interrogate IOMMU for error status. */ |
357 | sabre_check_iommu_error(pbm, afsr, afar); | 268 | psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); |
358 | 269 | ||
359 | return IRQ_HANDLED; | 270 | return IRQ_HANDLED; |
360 | } | 271 | } |
@@ -415,133 +326,6 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id) | |||
415 | return IRQ_HANDLED; | 326 | return IRQ_HANDLED; |
416 | } | 327 | } |
417 | 328 | ||
418 | static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm) | ||
419 | { | ||
420 | unsigned long csr_reg, csr, csr_error_bits; | ||
421 | irqreturn_t ret = IRQ_NONE; | ||
422 | u16 stat; | ||
423 | |||
424 | csr_reg = pbm->controller_regs + SABRE_PCICTRL; | ||
425 | csr = sabre_read(csr_reg); | ||
426 | csr_error_bits = | ||
427 | csr & SABRE_PCICTRL_SERR; | ||
428 | if (csr_error_bits) { | ||
429 | /* Clear the errors. */ | ||
430 | sabre_write(csr_reg, csr); | ||
431 | |||
432 | /* Log 'em. */ | ||
433 | if (csr_error_bits & SABRE_PCICTRL_SERR) | ||
434 | printk("%s: PCI SERR signal asserted.\n", | ||
435 | pbm->name); | ||
436 | ret = IRQ_HANDLED; | ||
437 | } | ||
438 | pci_bus_read_config_word(sabre_root_bus, 0, | ||
439 | PCI_STATUS, &stat); | ||
440 | if (stat & (PCI_STATUS_PARITY | | ||
441 | PCI_STATUS_SIG_TARGET_ABORT | | ||
442 | PCI_STATUS_REC_TARGET_ABORT | | ||
443 | PCI_STATUS_REC_MASTER_ABORT | | ||
444 | PCI_STATUS_SIG_SYSTEM_ERROR)) { | ||
445 | printk("%s: PCI bus error, PCI_STATUS[%04x]\n", | ||
446 | pbm->name, stat); | ||
447 | pci_bus_write_config_word(sabre_root_bus, 0, | ||
448 | PCI_STATUS, 0xffff); | ||
449 | ret = IRQ_HANDLED; | ||
450 | } | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) | ||
455 | { | ||
456 | struct pci_pbm_info *pbm = dev_id; | ||
457 | unsigned long afsr_reg, afar_reg; | ||
458 | unsigned long afsr, afar, error_bits; | ||
459 | int reported; | ||
460 | |||
461 | afsr_reg = pbm->controller_regs + SABRE_PIOAFSR; | ||
462 | afar_reg = pbm->controller_regs + SABRE_PIOAFAR; | ||
463 | |||
464 | /* Latch error status. */ | ||
465 | afar = sabre_read(afar_reg); | ||
466 | afsr = sabre_read(afsr_reg); | ||
467 | |||
468 | /* Clear primary/secondary error status bits. */ | ||
469 | error_bits = afsr & | ||
470 | (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA | | ||
471 | SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR | | ||
472 | SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA | | ||
473 | SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR); | ||
474 | if (!error_bits) | ||
475 | return sabre_pcierr_intr_other(pbm); | ||
476 | sabre_write(afsr_reg, error_bits); | ||
477 | |||
478 | /* Log the error. */ | ||
479 | printk("%s: PCI Error, primary error type[%s]\n", | ||
480 | pbm->name, | ||
481 | (((error_bits & SABRE_PIOAFSR_PMA) ? | ||
482 | "Master Abort" : | ||
483 | ((error_bits & SABRE_PIOAFSR_PTA) ? | ||
484 | "Target Abort" : | ||
485 | ((error_bits & SABRE_PIOAFSR_PRTRY) ? | ||
486 | "Excessive Retries" : | ||
487 | ((error_bits & SABRE_PIOAFSR_PPERR) ? | ||
488 | "Parity Error" : "???")))))); | ||
489 | printk("%s: bytemask[%04lx] was_block(%d)\n", | ||
490 | pbm->name, | ||
491 | (afsr & SABRE_PIOAFSR_BMSK) >> 32UL, | ||
492 | (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0); | ||
493 | printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar); | ||
494 | printk("%s: PCI Secondary errors [", pbm->name); | ||
495 | reported = 0; | ||
496 | if (afsr & SABRE_PIOAFSR_SMA) { | ||
497 | reported++; | ||
498 | printk("(Master Abort)"); | ||
499 | } | ||
500 | if (afsr & SABRE_PIOAFSR_STA) { | ||
501 | reported++; | ||
502 | printk("(Target Abort)"); | ||
503 | } | ||
504 | if (afsr & SABRE_PIOAFSR_SRTRY) { | ||
505 | reported++; | ||
506 | printk("(Excessive Retries)"); | ||
507 | } | ||
508 | if (afsr & SABRE_PIOAFSR_SPERR) { | ||
509 | reported++; | ||
510 | printk("(Parity Error)"); | ||
511 | } | ||
512 | if (!reported) | ||
513 | printk("(none)"); | ||
514 | printk("]\n"); | ||
515 | |||
516 | /* For the error types shown, scan both PCI buses for devices | ||
517 | * which have logged that error type. | ||
518 | */ | ||
519 | |||
520 | /* If we see a Target Abort, this could be the result of an | ||
521 | * IOMMU translation error of some sort. It is extremely | ||
522 | * useful to log this information as usually it indicates | ||
523 | * a bug in the IOMMU support code or a PCI device driver. | ||
524 | */ | ||
525 | if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { | ||
526 | sabre_check_iommu_error(pbm, afsr, afar); | ||
527 | pci_scan_for_target_abort(pbm, pbm->pci_bus); | ||
528 | } | ||
529 | if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) | ||
530 | pci_scan_for_master_abort(pbm, pbm->pci_bus); | ||
531 | |||
532 | /* For excessive retries, SABRE/PBM will abort the device | ||
533 | * and there is no way to specifically check for excessive | ||
534 | * retries in the config space status registers. So what | ||
535 | * we hope is that we'll catch it via the master/target | ||
536 | * abort events. | ||
537 | */ | ||
538 | |||
539 | if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) | ||
540 | pci_scan_for_parity_error(pbm, pbm->pci_bus); | ||
541 | |||
542 | return IRQ_HANDLED; | ||
543 | } | ||
544 | |||
545 | static void sabre_register_error_handlers(struct pci_pbm_info *pbm) | 329 | static void sabre_register_error_handlers(struct pci_pbm_info *pbm) |
546 | { | 330 | { |
547 | struct device_node *dp = pbm->op->node; | 331 | struct device_node *dp = pbm->op->node; |
@@ -588,7 +372,7 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm) | |||
588 | if (err) | 372 | if (err) |
589 | printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n", | 373 | printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n", |
590 | pbm->name, err); | 374 | pbm->name, err); |
591 | err = request_irq(op->irqs[0], sabre_pcierr_intr, 0, | 375 | err = request_irq(op->irqs[0], psycho_pcierr_intr, 0, |
592 | "SABRE_PCIERR", pbm); | 376 | "SABRE_PCIERR", pbm); |
593 | if (err) | 377 | if (err) |
594 | printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n", | 378 | printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n", |
@@ -679,6 +463,9 @@ static void __init sabre_pbm_init(struct pci_pbm_info *pbm, | |||
679 | struct of_device *op) | 463 | struct of_device *op) |
680 | { | 464 | { |
681 | psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); | 465 | psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); |
466 | pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR; | ||
467 | pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR; | ||
468 | pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL; | ||
682 | sabre_scan_bus(pbm, &op->dev); | 469 | sabre_scan_bus(pbm, &op->dev); |
683 | } | 470 | } |
684 | 471 | ||