Skip to content

Commit

Permalink
Merge branch 'pci/yinghai-for-pci-root-bus-hotplug' into next
Browse files Browse the repository at this point in the history
* 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()
  • Loading branch information
Bjorn Helgaas committed Nov 9, 2012
2 parents 13a8468 + f426cef commit fa20f6f
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 22 deletions.
21 changes: 20 additions & 1 deletion drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,30 +644,49 @@ 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;
}

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);
Expand Down
22 changes: 22 additions & 0 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
36 changes: 36 additions & 0 deletions drivers/pci/remove.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
22 changes: 1 addition & 21 deletions drivers/pci/setup-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1550,25 +1550,12 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
}
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 ||
Expand All @@ -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
3 changes: 3 additions & 0 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 *),
Expand Down

0 comments on commit fa20f6f

Please sign in to comment.