--- drivers/pci/hotplug/pciehp_hpc.c | 19 +++++++++++++++++++ drivers/pci/hotplug/pciehp_pci.c | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) Index: linux-2.6/drivers/pci/hotplug/pciehp_pci.c =================================================================== --- linux-2.6.orig/drivers/pci/hotplug/pciehp_pci.c +++ linux-2.6/drivers/pci/hotplug/pciehp_pci.c @@ -81,7 +81,7 @@ int pciehp_configure_device(struct slot pci_dev_put(dev); } - pci_bus_add_devices(parent); + pci_bus_add_single_device(bridge); return 0; } @@ -96,6 +96,10 @@ int pciehp_unconfigure_device(struct slo u16 command; struct controller *ctrl = p_slot->ctrl; + /* Someone removed the bus already */ + if (!parent) + return 0; + ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n", __func__, pci_domain_nr(parent), parent->number); ret = pciehp_get_adapter_status(p_slot, &presence); Index: linux-2.6/drivers/pci/hotplug/pciehp_hpc.c =================================================================== --- linux-2.6.orig/drivers/pci/hotplug/pciehp_hpc.c +++ linux-2.6/drivers/pci/hotplug/pciehp_hpc.c @@ -283,6 +283,21 @@ static void pcie_wait_link_not_active(st __pcie_wait_link_active(ctrl, false); } + +static bool pci_hp_check_subordinate(struct pci_dev *dev) +{ + if (dev->subordinate) + return true; + + /* someone remove it already, get it back */ + if (pci_hp_add_bridge(dev)) + return false; + + pci_stop_and_remove_behind_bridge(dev); + + return true; +} + static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) { u32 l; @@ -327,6 +342,10 @@ int pciehp_check_link_status(struct cont /* wait 100ms before read pci conf, and try in 1s */ msleep(100); + + if (!pci_hp_check_subordinate(ctrl->pcie->port)) + return -1; + found = pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0));