diff options
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b2255736ac81..51f56ef4ab6f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -749,6 +749,37 @@ static void pcie_disable_notification(struct controller *ctrl) ctrl_warn(ctrl, "Cannot disable software notification\n"); } +/* + * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary + * bus reset of the bridge, but if the slot supports surprise removal we need + * to disable presence detection around the bus reset and clear any spurious + * events after. + */ +int pciehp_reset_slot(struct slot *slot, int probe) +{ + struct controller *ctrl = slot->ctrl; + + if (probe) + return 0; + + if (HP_SUPR_RM(ctrl)) { + pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE); + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); + } + + pci_reset_bridge_secondary_bus(ctrl->pcie->port); + + if (HP_SUPR_RM(ctrl)) { + pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDC); + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE); + if (pciehp_poll_mode) + int_poll_timeout(ctrl->poll_timer.data); + } + + return 0; +} + int pcie_init_notification(struct controller *ctrl) { if (pciehp_request_irq(ctrl)) |