diff options
-rw-r--r-- | arch/powerpc/kernel/eeh_pe.c | 157 |
1 files changed, 144 insertions, 13 deletions
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 55943fcdaeb8..016588a6f5ed 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/delay.h> | ||
25 | #include <linux/export.h> | 26 | #include <linux/export.h> |
26 | #include <linux/gfp.h> | 27 | #include <linux/gfp.h> |
27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
@@ -567,30 +568,132 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state) | |||
567 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); | 568 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); |
568 | } | 569 | } |
569 | 570 | ||
570 | /** | 571 | /* |
571 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device | 572 | * Some PCI bridges (e.g. PLX bridges) have primary/secondary |
572 | * @data: EEH device | 573 | * buses assigned explicitly by firmware, and we probably have |
573 | * @flag: Unused | 574 | * lost that after reset. So we have to delay the check until |
575 | * the PCI-CFG registers have been restored for the parent | ||
576 | * bridge. | ||
574 | * | 577 | * |
575 | * Loads the PCI configuration space base address registers, | 578 | * Don't use normal PCI-CFG accessors, which probably has been |
576 | * the expansion ROM base address, the latency timer, and etc. | 579 | * blocked on normal path during the stage. So we need utilize |
577 | * from the saved values in the device node. | 580 | * eeh operations, which is always permitted. |
578 | */ | 581 | */ |
579 | static void *eeh_restore_one_device_bars(void *data, void *flag) | 582 | static void eeh_bridge_check_link(struct pci_dev *pdev, |
583 | struct device_node *dn) | ||
584 | { | ||
585 | int cap; | ||
586 | uint32_t val; | ||
587 | int timeout = 0; | ||
588 | |||
589 | /* | ||
590 | * We only check root port and downstream ports of | ||
591 | * PCIe switches | ||
592 | */ | ||
593 | if (!pci_is_pcie(pdev) || | ||
594 | (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && | ||
595 | pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)) | ||
596 | return; | ||
597 | |||
598 | pr_debug("%s: Check PCIe link for %s ...\n", | ||
599 | __func__, pci_name(pdev)); | ||
600 | |||
601 | /* Check slot status */ | ||
602 | cap = pdev->pcie_cap; | ||
603 | eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val); | ||
604 | if (!(val & PCI_EXP_SLTSTA_PDS)) { | ||
605 | pr_debug(" No card in the slot (0x%04x) !\n", val); | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | /* Check power status if we have the capability */ | ||
610 | eeh_ops->read_config(dn, cap + PCI_EXP_SLTCAP, 2, &val); | ||
611 | if (val & PCI_EXP_SLTCAP_PCP) { | ||
612 | eeh_ops->read_config(dn, cap + PCI_EXP_SLTCTL, 2, &val); | ||
613 | if (val & PCI_EXP_SLTCTL_PCC) { | ||
614 | pr_debug(" In power-off state, power it on ...\n"); | ||
615 | val &= ~(PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PIC); | ||
616 | val |= (0x0100 & PCI_EXP_SLTCTL_PIC); | ||
617 | eeh_ops->write_config(dn, cap + PCI_EXP_SLTCTL, 2, val); | ||
618 | msleep(2 * 1000); | ||
619 | } | ||
620 | } | ||
621 | |||
622 | /* Enable link */ | ||
623 | eeh_ops->read_config(dn, cap + PCI_EXP_LNKCTL, 2, &val); | ||
624 | val &= ~PCI_EXP_LNKCTL_LD; | ||
625 | eeh_ops->write_config(dn, cap + PCI_EXP_LNKCTL, 2, val); | ||
626 | |||
627 | /* Check link */ | ||
628 | eeh_ops->read_config(dn, cap + PCI_EXP_LNKCAP, 4, &val); | ||
629 | if (!(val & PCI_EXP_LNKCAP_DLLLARC)) { | ||
630 | pr_debug(" No link reporting capability (0x%08x) \n", val); | ||
631 | msleep(1000); | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | /* Wait the link is up until timeout (5s) */ | ||
636 | timeout = 0; | ||
637 | while (timeout < 5000) { | ||
638 | msleep(20); | ||
639 | timeout += 20; | ||
640 | |||
641 | eeh_ops->read_config(dn, cap + PCI_EXP_LNKSTA, 2, &val); | ||
642 | if (val & PCI_EXP_LNKSTA_DLLLA) | ||
643 | break; | ||
644 | } | ||
645 | |||
646 | if (val & PCI_EXP_LNKSTA_DLLLA) | ||
647 | pr_debug(" Link up (%s)\n", | ||
648 | (val & PCI_EXP_LNKSTA_CLS_2_5GB) ? "2.5GB" : "5GB"); | ||
649 | else | ||
650 | pr_debug(" Link not ready (0x%04x)\n", val); | ||
651 | } | ||
652 | |||
653 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
654 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | ||
655 | |||
656 | static void eeh_restore_bridge_bars(struct pci_dev *pdev, | ||
657 | struct eeh_dev *edev, | ||
658 | struct device_node *dn) | ||
659 | { | ||
660 | int i; | ||
661 | |||
662 | /* | ||
663 | * Device BARs: 0x10 - 0x18 | ||
664 | * Bus numbers and windows: 0x18 - 0x30 | ||
665 | */ | ||
666 | for (i = 4; i < 13; i++) | ||
667 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); | ||
668 | /* Rom: 0x38 */ | ||
669 | eeh_ops->write_config(dn, 14*4, 4, edev->config_space[14]); | ||
670 | |||
671 | /* Cache line & Latency timer: 0xC 0xD */ | ||
672 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, | ||
673 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | ||
674 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, | ||
675 | SAVED_BYTE(PCI_LATENCY_TIMER)); | ||
676 | /* Max latency, min grant, interrupt ping and line: 0x3C */ | ||
677 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); | ||
678 | |||
679 | /* PCI Command: 0x4 */ | ||
680 | eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]); | ||
681 | |||
682 | /* Check the PCIe link is ready */ | ||
683 | eeh_bridge_check_link(pdev, dn); | ||
684 | } | ||
685 | |||
686 | static void eeh_restore_device_bars(struct eeh_dev *edev, | ||
687 | struct device_node *dn) | ||
580 | { | 688 | { |
581 | int i; | 689 | int i; |
582 | u32 cmd; | 690 | u32 cmd; |
583 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
584 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
585 | 691 | ||
586 | for (i = 4; i < 10; i++) | 692 | for (i = 4; i < 10; i++) |
587 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); | 693 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); |
588 | /* 12 == Expansion ROM Address */ | 694 | /* 12 == Expansion ROM Address */ |
589 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); | 695 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); |
590 | 696 | ||
591 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
592 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | ||
593 | |||
594 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, | 697 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, |
595 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | 698 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); |
596 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, | 699 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, |
@@ -613,6 +716,34 @@ static void *eeh_restore_one_device_bars(void *data, void *flag) | |||
613 | else | 716 | else |
614 | cmd &= ~PCI_COMMAND_SERR; | 717 | cmd &= ~PCI_COMMAND_SERR; |
615 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); | 718 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); |
719 | } | ||
720 | |||
721 | /** | ||
722 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device | ||
723 | * @data: EEH device | ||
724 | * @flag: Unused | ||
725 | * | ||
726 | * Loads the PCI configuration space base address registers, | ||
727 | * the expansion ROM base address, the latency timer, and etc. | ||
728 | * from the saved values in the device node. | ||
729 | */ | ||
730 | static void *eeh_restore_one_device_bars(void *data, void *flag) | ||
731 | { | ||
732 | struct pci_dev *pdev = NULL; | ||
733 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
734 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
735 | |||
736 | /* Trace the PCI bridge */ | ||
737 | if (eeh_probe_mode_dev()) { | ||
738 | pdev = eeh_dev_to_pci_dev(edev); | ||
739 | if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) | ||
740 | pdev = NULL; | ||
741 | } | ||
742 | |||
743 | if (pdev) | ||
744 | eeh_restore_bridge_bars(pdev, edev, dn); | ||
745 | else | ||
746 | eeh_restore_device_bars(edev, dn); | ||
616 | 747 | ||
617 | return NULL; | 748 | return NULL; |
618 | } | 749 | } |