summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2017-01-11 11:50:08 +1100
committerMichael Ellerman <mpe@ellerman.id.au>2017-02-15 20:02:43 +1100
commit454593e54cac126a0f49d4b65f90a5e518c51404 (patch)
treefad75e4dfb75619ec384dafc0968919e830c266b /drivers
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')
-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)
if (sts & PCI_EXP_SLTSTA_DLLSC) {
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
- } else if (sts & PCI_EXP_SLTSTA_PDC) {
+ } else if (!(php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) &&
+ (sts & PCI_EXP_SLTSTA_PDC)) {
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
if (ret) {
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)
static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
{
struct pci_dev *pdev = php_slot->pdev;
+ u32 broken_pdc = 0;
u16 sts, ctrl;
int ret;
@@ -779,9 +781,18 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
return;
}
+ /* Check PDC (Presence Detection Change) is broken or not */
+ ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
+ &broken_pdc);
+ if (!ret && broken_pdc)
+ php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
+
/* Clear pending interrupts */
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
- sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+ if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
+ sts |= PCI_EXP_SLTSTA_DLLSC;
+ else
+ sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
/* Request the interrupt */
@@ -795,9 +806,15 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
/* Enable the interrupts */
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
- ctrl |= (PCI_EXP_SLTCTL_HPIE |
- PCI_EXP_SLTCTL_PDCE |
- PCI_EXP_SLTCTL_DLLSCE);
+ if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
+ ctrl &= ~PCI_EXP_SLTCTL_PDCE;
+ ctrl |= (PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ } else {
+ ctrl |= (PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ }
pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
/* The interrupt is initialized successfully when @irq is valid */