aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pnv_php.c
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2017-01-10 19:50:08 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2017-02-15 04:02:43 -0500
commit454593e54cac126a0f49d4b65f90a5e518c51404 (patch)
treefad75e4dfb75619ec384dafc0968919e830c266b /drivers/pci/hotplug/pnv_php.c
parentd0c424971f70501ec0a0364117b9934db039c9cc (diff)
drivers/pci/hotplug: Mask PDC interrupt if required
We're supporting surprise hotplug on PCI slots behind root port or PCIe switch downstream ports, which don't claim the capability in hardware register (offset: PCIe cap + PCI_EXP_SLTCAP). PEX8718 is one of the examples. For those PCI slots, the PDC (Presence Detection Change) event isn't reliable and the underly (skiboot) firmware has best judgement. This masks the PDC event when skiboot requests by "ibm,slot-broken-pdc" property in PCI slot's device-tree node. Reported-by: Hank Chang <hankmax0000@gmail.com> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Tested-by: Willie Liauw <williel@supermicro.com.tw> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/pci/hotplug/pnv_php.c')
-rw-r--r--drivers/pci/hotplug/pnv_php.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index 41304b313512..63cd9f354b79 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -717,7 +717,8 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data)
717 if (sts & PCI_EXP_SLTSTA_DLLSC) { 717 if (sts & PCI_EXP_SLTSTA_DLLSC) {
718 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts); 718 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
719 added = !!(lsts & PCI_EXP_LNKSTA_DLLLA); 719 added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
720 } else if (sts & PCI_EXP_SLTSTA_PDC) { 720 } else if (!(php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) &&
721 (sts & PCI_EXP_SLTSTA_PDC)) {
721 ret = pnv_pci_get_presence_state(php_slot->id, &presence); 722 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
722 if (ret) { 723 if (ret) {
723 dev_warn(&pdev->dev, "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n", 724 dev_warn(&pdev->dev, "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n",
@@ -768,6 +769,7 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data)
768static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq) 769static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
769{ 770{
770 struct pci_dev *pdev = php_slot->pdev; 771 struct pci_dev *pdev = php_slot->pdev;
772 u32 broken_pdc = 0;
771 u16 sts, ctrl; 773 u16 sts, ctrl;
772 int ret; 774 int ret;
773 775
@@ -779,9 +781,18 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
779 return; 781 return;
780 } 782 }
781 783
784 /* Check PDC (Presence Detection Change) is broken or not */
785 ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
786 &broken_pdc);
787 if (!ret && broken_pdc)
788 php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
789
782 /* Clear pending interrupts */ 790 /* Clear pending interrupts */
783 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts); 791 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
784 sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); 792 if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
793 sts |= PCI_EXP_SLTSTA_DLLSC;
794 else
795 sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
785 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts); 796 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
786 797
787 /* Request the interrupt */ 798 /* Request the interrupt */
@@ -795,9 +806,15 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
795 806
796 /* Enable the interrupts */ 807 /* Enable the interrupts */
797 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl); 808 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
798 ctrl |= (PCI_EXP_SLTCTL_HPIE | 809 if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
799 PCI_EXP_SLTCTL_PDCE | 810 ctrl &= ~PCI_EXP_SLTCTL_PDCE;
800 PCI_EXP_SLTCTL_DLLSCE); 811 ctrl |= (PCI_EXP_SLTCTL_HPIE |
812 PCI_EXP_SLTCTL_DLLSCE);
813 } else {
814 ctrl |= (PCI_EXP_SLTCTL_HPIE |
815 PCI_EXP_SLTCTL_PDCE |
816 PCI_EXP_SLTCTL_DLLSCE);
817 }
801 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl); 818 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
802 819
803 /* The interrupt is initialized successfully when @irq is valid */ 820 /* The interrupt is initialized successfully when @irq is valid */