diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 96 |
1 files changed, 73 insertions, 23 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 32eaddfa5470..84bc8f7e17ef 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -449,7 +449,11 @@ EXPORT_SYMBOL(eeh_check_failure); | |||
449 | /* ------------------------------------------------------------- */ | 449 | /* ------------------------------------------------------------- */ |
450 | /* The code below deals with error recovery */ | 450 | /* The code below deals with error recovery */ |
451 | 451 | ||
452 | /** Return negative value if a permanent error, else return | 452 | /** |
453 | * eeh_slot_availability - returns error status of slot | ||
454 | * @pdn pci device node | ||
455 | * | ||
456 | * Return negative value if a permanent error, else return | ||
453 | * a number of milliseconds to wait until the PCI slot is | 457 | * a number of milliseconds to wait until the PCI slot is |
454 | * ready to be used. | 458 | * ready to be used. |
455 | */ | 459 | */ |
@@ -474,11 +478,42 @@ eeh_slot_availability(struct pci_dn *pdn) | |||
474 | 478 | ||
475 | printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n", | 479 | printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n", |
476 | rc, rets[0], rets[1], rets[2]); | 480 | rc, rets[0], rets[1], rets[2]); |
477 | return -1; | 481 | return -2; |
482 | } | ||
483 | |||
484 | /** | ||
485 | * rtas_pci_enable - enable MMIO or DMA transfers for this slot | ||
486 | * @pdn pci device node | ||
487 | */ | ||
488 | |||
489 | int | ||
490 | rtas_pci_enable(struct pci_dn *pdn, int function) | ||
491 | { | ||
492 | int config_addr; | ||
493 | int rc; | ||
494 | |||
495 | /* Use PE configuration address, if present */ | ||
496 | config_addr = pdn->eeh_config_addr; | ||
497 | if (pdn->eeh_pe_config_addr) | ||
498 | config_addr = pdn->eeh_pe_config_addr; | ||
499 | |||
500 | rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | ||
501 | config_addr, | ||
502 | BUID_HI(pdn->phb->buid), | ||
503 | BUID_LO(pdn->phb->buid), | ||
504 | function); | ||
505 | |||
506 | if (rc) | ||
507 | printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n", | ||
508 | function, rc, pdn->node->full_name); | ||
509 | |||
510 | return rc; | ||
478 | } | 511 | } |
479 | 512 | ||
480 | /** rtas_pci_slot_reset raises/lowers the pci #RST line | 513 | /** |
481 | * state: 1/0 to raise/lower the #RST | 514 | * rtas_pci_slot_reset - raises/lowers the pci #RST line |
515 | * @pdn pci device node | ||
516 | * @state: 1/0 to raise/lower the #RST | ||
482 | * | 517 | * |
483 | * Clear the EEH-frozen condition on a slot. This routine | 518 | * Clear the EEH-frozen condition on a slot. This routine |
484 | * asserts the PCI #RST line if the 'state' argument is '1', | 519 | * asserts the PCI #RST line if the 'state' argument is '1', |
@@ -511,24 +546,21 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) | |||
511 | BUID_HI(pdn->phb->buid), | 546 | BUID_HI(pdn->phb->buid), |
512 | BUID_LO(pdn->phb->buid), | 547 | BUID_LO(pdn->phb->buid), |
513 | state); | 548 | state); |
514 | if (rc) { | 549 | if (rc) |
515 | printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n", | 550 | printk (KERN_WARNING "EEH: Unable to reset the failed slot," |
551 | " (%d) #RST=%d dn=%s\n", | ||
516 | rc, state, pdn->node->full_name); | 552 | rc, state, pdn->node->full_name); |
517 | return; | ||
518 | } | ||
519 | } | 553 | } |
520 | 554 | ||
521 | /** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 555 | /** |
522 | * dn -- device node to be reset. | 556 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second |
557 | * @pdn: pci device node to be reset. | ||
523 | * | 558 | * |
524 | * Return 0 if success, else a non-zero value. | 559 | * Return 0 if success, else a non-zero value. |
525 | */ | 560 | */ |
526 | 561 | ||
527 | int | 562 | static void __rtas_set_slot_reset(struct pci_dn *pdn) |
528 | rtas_set_slot_reset(struct pci_dn *pdn) | ||
529 | { | 563 | { |
530 | int i, rc; | ||
531 | |||
532 | rtas_pci_slot_reset (pdn, 1); | 564 | rtas_pci_slot_reset (pdn, 1); |
533 | 565 | ||
534 | /* The PCI bus requires that the reset be held high for at least | 566 | /* The PCI bus requires that the reset be held high for at least |
@@ -549,17 +581,33 @@ rtas_set_slot_reset(struct pci_dn *pdn) | |||
549 | * up traffic. */ | 581 | * up traffic. */ |
550 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 | 582 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 |
551 | msleep (PCI_BUS_SETTLE_TIME_MSEC); | 583 | msleep (PCI_BUS_SETTLE_TIME_MSEC); |
584 | } | ||
585 | |||
586 | int rtas_set_slot_reset(struct pci_dn *pdn) | ||
587 | { | ||
588 | int i, rc; | ||
589 | |||
590 | __rtas_set_slot_reset(pdn); | ||
552 | 591 | ||
553 | /* Now double check with the firmware to make sure the device is | 592 | /* Now double check with the firmware to make sure the device is |
554 | * ready to be used; if not, wait for recovery. */ | 593 | * ready to be used; if not, wait for recovery. */ |
555 | for (i=0; i<10; i++) { | 594 | for (i=0; i<10; i++) { |
556 | rc = eeh_slot_availability (pdn); | 595 | rc = eeh_slot_availability (pdn); |
557 | if (rc < 0) | ||
558 | printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n", rc, pdn->node->full_name); | ||
559 | if (rc == 0) | 596 | if (rc == 0) |
560 | return 0; | 597 | return 0; |
561 | if (rc < 0) | 598 | |
599 | if (rc == -2) { | ||
600 | printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n", | ||
601 | i, pdn->node->full_name); | ||
602 | __rtas_set_slot_reset(pdn); | ||
603 | continue; | ||
604 | } | ||
605 | |||
606 | if (rc < 0) { | ||
607 | printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", | ||
608 | pdn->node->full_name); | ||
562 | return -1; | 609 | return -1; |
610 | } | ||
563 | 611 | ||
564 | msleep (rc+100); | 612 | msleep (rc+100); |
565 | } | 613 | } |
@@ -582,6 +630,8 @@ rtas_set_slot_reset(struct pci_dn *pdn) | |||
582 | 630 | ||
583 | /** | 631 | /** |
584 | * __restore_bars - Restore the Base Address Registers | 632 | * __restore_bars - Restore the Base Address Registers |
633 | * @pdn: pci device node | ||
634 | * | ||
585 | * Loads the PCI configuration space base address registers, | 635 | * Loads the PCI configuration space base address registers, |
586 | * the expansion ROM base address, the latency timer, and etc. | 636 | * the expansion ROM base address, the latency timer, and etc. |
587 | * from the saved values in the device node. | 637 | * from the saved values in the device node. |
@@ -691,11 +741,11 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
691 | { | 741 | { |
692 | struct eeh_early_enable_info *info = data; | 742 | struct eeh_early_enable_info *info = data; |
693 | int ret; | 743 | int ret; |
694 | char *status = get_property(dn, "status", NULL); | 744 | const char *status = get_property(dn, "status", NULL); |
695 | u32 *class_code = (u32 *)get_property(dn, "class-code", NULL); | 745 | const u32 *class_code = get_property(dn, "class-code", NULL); |
696 | u32 *vendor_id = (u32 *)get_property(dn, "vendor-id", NULL); | 746 | const u32 *vendor_id = get_property(dn, "vendor-id", NULL); |
697 | u32 *device_id = (u32 *)get_property(dn, "device-id", NULL); | 747 | const u32 *device_id = get_property(dn, "device-id", NULL); |
698 | u32 *regs; | 748 | const u32 *regs; |
699 | int enable; | 749 | int enable; |
700 | struct pci_dn *pdn = PCI_DN(dn); | 750 | struct pci_dn *pdn = PCI_DN(dn); |
701 | 751 | ||
@@ -737,7 +787,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
737 | 787 | ||
738 | /* Ok... see if this device supports EEH. Some do, some don't, | 788 | /* Ok... see if this device supports EEH. Some do, some don't, |
739 | * and the only way to find out is to check each and every one. */ | 789 | * and the only way to find out is to check each and every one. */ |
740 | regs = (u32 *)get_property(dn, "reg", NULL); | 790 | regs = get_property(dn, "reg", NULL); |
741 | if (regs) { | 791 | if (regs) { |
742 | /* First register entry is addr (00BBSS00) */ | 792 | /* First register entry is addr (00BBSS00) */ |
743 | /* Try to enable eeh */ | 793 | /* Try to enable eeh */ |