diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-11-09 12:00:02 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-11-09 12:00:02 -0500 |
commit | fa20f6f240e127bc914ca980a4b10c723c55fec9 (patch) | |
tree | 1a8267f53240b763a9d555a410341c3d7e432721 | |
parent | 13a84687092f47a6d67b1b17940eb3127ae888b3 (diff) | |
parent | f426cef3bc58806284e0fee55d29262b10279f9c (diff) |
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()
-rw-r--r-- | drivers/acpi/pci_root.c | 21 | ||||
-rw-r--r-- | drivers/pci/probe.c | 22 | ||||
-rw-r--r-- | drivers/pci/remove.c | 36 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 22 | ||||
-rw-r--r-- | include/linux/pci.h | 3 |
5 files changed, 82 insertions, 22 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index bce469c0b48a..012f40d1d75d 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -644,12 +644,19 @@ static int acpi_pci_root_start(struct acpi_device *device) | |||
644 | struct acpi_pci_root *root = acpi_driver_data(device); | 644 | struct acpi_pci_root *root = acpi_driver_data(device); |
645 | struct acpi_pci_driver *driver; | 645 | struct acpi_pci_driver *driver; |
646 | 646 | ||
647 | if (system_state != SYSTEM_BOOTING) | ||
648 | pci_assign_unassigned_bus_resources(root->bus); | ||
649 | |||
647 | mutex_lock(&acpi_pci_root_lock); | 650 | mutex_lock(&acpi_pci_root_lock); |
648 | list_for_each_entry(driver, &acpi_pci_drivers, node) | 651 | list_for_each_entry(driver, &acpi_pci_drivers, node) |
649 | if (driver->add) | 652 | if (driver->add) |
650 | driver->add(root); | 653 | driver->add(root); |
651 | mutex_unlock(&acpi_pci_root_lock); | 654 | mutex_unlock(&acpi_pci_root_lock); |
652 | 655 | ||
656 | /* need to after hot-added ioapic is registered */ | ||
657 | if (system_state != SYSTEM_BOOTING) | ||
658 | pci_enable_bridges(root->bus); | ||
659 | |||
653 | pci_bus_add_devices(root->bus); | 660 | pci_bus_add_devices(root->bus); |
654 | 661 | ||
655 | return 0; | 662 | return 0; |
@@ -657,17 +664,29 @@ static int acpi_pci_root_start(struct acpi_device *device) | |||
657 | 664 | ||
658 | static int acpi_pci_root_remove(struct acpi_device *device, int type) | 665 | static int acpi_pci_root_remove(struct acpi_device *device, int type) |
659 | { | 666 | { |
667 | acpi_status status; | ||
668 | acpi_handle handle; | ||
660 | struct acpi_pci_root *root = acpi_driver_data(device); | 669 | struct acpi_pci_root *root = acpi_driver_data(device); |
661 | struct acpi_pci_driver *driver; | 670 | struct acpi_pci_driver *driver; |
662 | 671 | ||
672 | pci_stop_root_bus(root->bus); | ||
673 | |||
663 | mutex_lock(&acpi_pci_root_lock); | 674 | mutex_lock(&acpi_pci_root_lock); |
664 | list_for_each_entry(driver, &acpi_pci_drivers, node) | 675 | list_for_each_entry_reverse(driver, &acpi_pci_drivers, node) |
665 | if (driver->remove) | 676 | if (driver->remove) |
666 | driver->remove(root); | 677 | driver->remove(root); |
678 | mutex_unlock(&acpi_pci_root_lock); | ||
667 | 679 | ||
668 | device_set_run_wake(root->bus->bridge, false); | 680 | device_set_run_wake(root->bus->bridge, false); |
669 | pci_acpi_remove_bus_pm_notifier(device); | 681 | pci_acpi_remove_bus_pm_notifier(device); |
670 | 682 | ||
683 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); | ||
684 | if (ACPI_SUCCESS(status)) | ||
685 | acpi_pci_irq_del_prt(root->bus); | ||
686 | |||
687 | pci_remove_root_bus(root->bus); | ||
688 | |||
689 | mutex_lock(&acpi_pci_root_lock); | ||
671 | list_del(&root->node); | 690 | list_del(&root->node); |
672 | mutex_unlock(&acpi_pci_root_lock); | 691 | mutex_unlock(&acpi_pci_root_lock); |
673 | kfree(root); | 692 | kfree(root); |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ec909afa90b6..59cf1ba34936 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1890,6 +1890,28 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) | |||
1890 | return max; | 1890 | return max; |
1891 | } | 1891 | } |
1892 | 1892 | ||
1893 | /** | ||
1894 | * pci_rescan_bus - scan a PCI bus for devices. | ||
1895 | * @bus: PCI bus to scan | ||
1896 | * | ||
1897 | * Scan a PCI bus and child buses for new devices, adds them, | ||
1898 | * and enables them. | ||
1899 | * | ||
1900 | * Returns the max number of subordinate bus discovered. | ||
1901 | */ | ||
1902 | unsigned int __ref pci_rescan_bus(struct pci_bus *bus) | ||
1903 | { | ||
1904 | unsigned int max; | ||
1905 | |||
1906 | max = pci_scan_child_bus(bus); | ||
1907 | pci_assign_unassigned_bus_resources(bus); | ||
1908 | pci_enable_bridges(bus); | ||
1909 | pci_bus_add_devices(bus); | ||
1910 | |||
1911 | return max; | ||
1912 | } | ||
1913 | EXPORT_SYMBOL_GPL(pci_rescan_bus); | ||
1914 | |||
1893 | EXPORT_SYMBOL(pci_add_new_bus); | 1915 | EXPORT_SYMBOL(pci_add_new_bus); |
1894 | EXPORT_SYMBOL(pci_scan_slot); | 1916 | EXPORT_SYMBOL(pci_scan_slot); |
1895 | EXPORT_SYMBOL(pci_scan_bridge); | 1917 | EXPORT_SYMBOL(pci_scan_bridge); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 513972f3ed13..7c0fd9252e6f 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -111,3 +111,39 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev) | |||
111 | pci_remove_bus_device(dev); | 111 | pci_remove_bus_device(dev); |
112 | } | 112 | } |
113 | EXPORT_SYMBOL(pci_stop_and_remove_bus_device); | 113 | EXPORT_SYMBOL(pci_stop_and_remove_bus_device); |
114 | |||
115 | void pci_stop_root_bus(struct pci_bus *bus) | ||
116 | { | ||
117 | struct pci_dev *child, *tmp; | ||
118 | struct pci_host_bridge *host_bridge; | ||
119 | |||
120 | if (!pci_is_root_bus(bus)) | ||
121 | return; | ||
122 | |||
123 | host_bridge = to_pci_host_bridge(bus->bridge); | ||
124 | list_for_each_entry_safe_reverse(child, tmp, | ||
125 | &bus->devices, bus_list) | ||
126 | pci_stop_bus_device(child); | ||
127 | |||
128 | /* stop the host bridge */ | ||
129 | device_del(&host_bridge->dev); | ||
130 | } | ||
131 | |||
132 | void pci_remove_root_bus(struct pci_bus *bus) | ||
133 | { | ||
134 | struct pci_dev *child, *tmp; | ||
135 | struct pci_host_bridge *host_bridge; | ||
136 | |||
137 | if (!pci_is_root_bus(bus)) | ||
138 | return; | ||
139 | |||
140 | host_bridge = to_pci_host_bridge(bus->bridge); | ||
141 | list_for_each_entry_safe(child, tmp, | ||
142 | &bus->devices, bus_list) | ||
143 | pci_remove_bus_device(child); | ||
144 | pci_remove_bus(bus); | ||
145 | host_bridge->bus = NULL; | ||
146 | |||
147 | /* remove the host bridge */ | ||
148 | put_device(&host_bridge->dev); | ||
149 | } | ||
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 1e808ca338f8..6d3591d57ea0 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -1550,25 +1550,12 @@ enable_all: | |||
1550 | } | 1550 | } |
1551 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | 1551 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); |
1552 | 1552 | ||
1553 | #ifdef CONFIG_HOTPLUG | 1553 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus) |
1554 | /** | ||
1555 | * pci_rescan_bus - scan a PCI bus for devices. | ||
1556 | * @bus: PCI bus to scan | ||
1557 | * | ||
1558 | * Scan a PCI bus and child buses for new devices, adds them, | ||
1559 | * and enables them. | ||
1560 | * | ||
1561 | * Returns the max number of subordinate bus discovered. | ||
1562 | */ | ||
1563 | unsigned int __ref pci_rescan_bus(struct pci_bus *bus) | ||
1564 | { | 1554 | { |
1565 | unsigned int max; | ||
1566 | struct pci_dev *dev; | 1555 | struct pci_dev *dev; |
1567 | LIST_HEAD(add_list); /* list of resources that | 1556 | LIST_HEAD(add_list); /* list of resources that |
1568 | want additional resources */ | 1557 | want additional resources */ |
1569 | 1558 | ||
1570 | max = pci_scan_child_bus(bus); | ||
1571 | |||
1572 | down_read(&pci_bus_sem); | 1559 | down_read(&pci_bus_sem); |
1573 | list_for_each_entry(dev, &bus->devices, bus_list) | 1560 | list_for_each_entry(dev, &bus->devices, bus_list) |
1574 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 1561 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
@@ -1579,11 +1566,4 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) | |||
1579 | up_read(&pci_bus_sem); | 1566 | up_read(&pci_bus_sem); |
1580 | __pci_bus_assign_resources(bus, &add_list, NULL); | 1567 | __pci_bus_assign_resources(bus, &add_list, NULL); |
1581 | BUG_ON(!list_empty(&add_list)); | 1568 | BUG_ON(!list_empty(&add_list)); |
1582 | |||
1583 | pci_enable_bridges(bus); | ||
1584 | pci_bus_add_devices(bus); | ||
1585 | |||
1586 | return max; | ||
1587 | } | 1569 | } |
1588 | EXPORT_SYMBOL_GPL(pci_rescan_bus); | ||
1589 | #endif | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index ee2179546c63..786094254d57 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -712,6 +712,8 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev); | |||
712 | extern void pci_dev_put(struct pci_dev *dev); | 712 | extern void pci_dev_put(struct pci_dev *dev); |
713 | extern void pci_remove_bus(struct pci_bus *b); | 713 | extern void pci_remove_bus(struct pci_bus *b); |
714 | extern void pci_stop_and_remove_bus_device(struct pci_dev *dev); | 714 | extern void pci_stop_and_remove_bus_device(struct pci_dev *dev); |
715 | void pci_stop_root_bus(struct pci_bus *bus); | ||
716 | void pci_remove_root_bus(struct pci_bus *bus); | ||
715 | void pci_setup_cardbus(struct pci_bus *bus); | 717 | void pci_setup_cardbus(struct pci_bus *bus); |
716 | extern void pci_sort_breadthfirst(void); | 718 | extern void pci_sort_breadthfirst(void); |
717 | #define dev_is_pci(d) ((d)->bus == &pci_bus_type) | 719 | #define dev_is_pci(d) ((d)->bus == &pci_bus_type) |
@@ -958,6 +960,7 @@ void pci_bus_size_bridges(struct pci_bus *bus); | |||
958 | int pci_claim_resource(struct pci_dev *, int); | 960 | int pci_claim_resource(struct pci_dev *, int); |
959 | void pci_assign_unassigned_resources(void); | 961 | void pci_assign_unassigned_resources(void); |
960 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); | 962 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); |
963 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus); | ||
961 | void pdev_enable_device(struct pci_dev *); | 964 | void pdev_enable_device(struct pci_dev *); |
962 | int pci_enable_resources(struct pci_dev *, int mask); | 965 | int pci_enable_resources(struct pci_dev *, int mask); |
963 | void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), | 966 | void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), |