Merge branch 'pci/yinghai-for-pci-root-bus-hotplug' into next

* pci/yinghai-for-pci-root-bus-hotplug:
  PCI/ACPI: Remove acpi_root_driver in reverse order
  PCI/ACPI: Delete host bridge _PRT during hot remove path
  PCI/ACPI: Make acpi_pci_root_remove() stop/remove pci root bus
  PCI: Add pci_stop_and_remove_root_bus()
  PCI/ACPI: Assign unassigned resource for hot-added root bus
  PCI: Move out pci_enable_bridges out of assign_unsigned_bus_res
  PCI: Move pci_rescan_bus() back to probe.c
  PCI: Separate out pci_assign_unassigned_bus_resources()
This commit is contained in:
Bjorn Helgaas 2012-11-09 10:00:02 -07:00
commit fa20f6f240
5 changed files with 82 additions and 22 deletions

View file

@ -644,12 +644,19 @@ static int acpi_pci_root_start(struct acpi_device *device)
struct acpi_pci_root *root = acpi_driver_data(device);
struct acpi_pci_driver *driver;
if (system_state != SYSTEM_BOOTING)
pci_assign_unassigned_bus_resources(root->bus);
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(driver, &acpi_pci_drivers, node)
if (driver->add)
driver->add(root);
mutex_unlock(&acpi_pci_root_lock);
/* need to after hot-added ioapic is registered */
if (system_state != SYSTEM_BOOTING)
pci_enable_bridges(root->bus);
pci_bus_add_devices(root->bus);
return 0;
@ -657,17 +664,29 @@ static int acpi_pci_root_start(struct acpi_device *device)
static int acpi_pci_root_remove(struct acpi_device *device, int type)
{
acpi_status status;
acpi_handle handle;
struct acpi_pci_root *root = acpi_driver_data(device);
struct acpi_pci_driver *driver;
pci_stop_root_bus(root->bus);
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(driver, &acpi_pci_drivers, node)
list_for_each_entry_reverse(driver, &acpi_pci_drivers, node)
if (driver->remove)
driver->remove(root);
mutex_unlock(&acpi_pci_root_lock);
device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device);
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status))
acpi_pci_irq_del_prt(root->bus);
pci_remove_root_bus(root->bus);
mutex_lock(&acpi_pci_root_lock);
list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock);
kfree(root);

View file

@ -1890,6 +1890,28 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
return max;
}
/**
* pci_rescan_bus - scan a PCI bus for devices.
* @bus: PCI bus to scan
*
* Scan a PCI bus and child buses for new devices, adds them,
* and enables them.
*
* Returns the max number of subordinate bus discovered.
*/
unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
{
unsigned int max;
max = pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
return max;
}
EXPORT_SYMBOL_GPL(pci_rescan_bus);
EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bridge);

View file

@ -111,3 +111,39 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
pci_remove_bus_device(dev);
}
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
void pci_stop_root_bus(struct pci_bus *bus)
{
struct pci_dev *child, *tmp;
struct pci_host_bridge *host_bridge;
if (!pci_is_root_bus(bus))
return;
host_bridge = to_pci_host_bridge(bus->bridge);
list_for_each_entry_safe_reverse(child, tmp,
&bus->devices, bus_list)
pci_stop_bus_device(child);
/* stop the host bridge */
device_del(&host_bridge->dev);
}
void pci_remove_root_bus(struct pci_bus *bus)
{
struct pci_dev *child, *tmp;
struct pci_host_bridge *host_bridge;
if (!pci_is_root_bus(bus))
return;
host_bridge = to_pci_host_bridge(bus->bridge);
list_for_each_entry_safe(child, tmp,
&bus->devices, bus_list)
pci_remove_bus_device(child);
pci_remove_bus(bus);
host_bridge->bus = NULL;
/* remove the host bridge */
put_device(&host_bridge->dev);
}

View file

@ -1550,25 +1550,12 @@ enable_all:
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
#ifdef CONFIG_HOTPLUG
/**
* pci_rescan_bus - scan a PCI bus for devices.
* @bus: PCI bus to scan
*
* Scan a PCI bus and child buses for new devices, adds them,
* and enables them.
*
* Returns the max number of subordinate bus discovered.
*/
unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
{
unsigned int max;
struct pci_dev *dev;
LIST_HEAD(add_list); /* list of resources that
want additional resources */
max = pci_scan_child_bus(bus);
down_read(&pci_bus_sem);
list_for_each_entry(dev, &bus->devices, bus_list)
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
@ -1579,11 +1566,4 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
up_read(&pci_bus_sem);
__pci_bus_assign_resources(bus, &add_list, NULL);
BUG_ON(!list_empty(&add_list));
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
return max;
}
EXPORT_SYMBOL_GPL(pci_rescan_bus);
#endif

View file

@ -712,6 +712,8 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
extern void pci_remove_bus(struct pci_bus *b);
extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
void pci_stop_root_bus(struct pci_bus *bus);
void pci_remove_root_bus(struct pci_bus *bus);
void pci_setup_cardbus(struct pci_bus *bus);
extern void pci_sort_breadthfirst(void);
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
@ -958,6 +960,7 @@ void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),