summaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpiphp_glue.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-24 16:17:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-24 16:17:07 -0700
commit6dd53aa4563a2c69e80a24d2cc68d484b5ea2891 (patch)
tree0cca9f65984b524527910960d972fc6ef85fac88 /drivers/pci/hotplug/acpiphp_glue.c
parentf14121ab35912e3d2e57ac9a4ce1f9d4b7baeffb (diff)
parent63b96f7baeba71966c723912c3f8f0274577f877 (diff)
Merge tag 'for-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI changes from Bjorn Helgaas: "Host bridge hotplug: - Add MMCONFIG support for hot-added host bridges (Jiang Liu) Device hotplug: - Move fixups from __init to __devinit (Sebastian Andrzej Siewior) - Call FINAL fixups for hot-added devices, too (Myron Stowe) - Factor out generic code for P2P bridge hot-add (Yinghai Lu) - Remove all functions in a slot, not just those with _EJx (Amos Kong) Dynamic resource management: - Track bus number allocation (struct resource tree per domain) (Yinghai Lu) - Make P2P bridge 1K I/O windows work with resource reassignment (Bjorn Helgaas, Yinghai Lu) - Disable decoding while updating 64-bit BARs (Bjorn Helgaas) Power management: - Add PCIe runtime D3cold support (Huang Ying) Virtualization: - Add VFIO infrastructure (ACS, DMA source ID quirks) (Alex Williamson) - Add quirks for devices with broken INTx masking (Jan Kiszka) Miscellaneous: - Fix some PCI Express capability version issues (Myron Stowe) - Factor out some arch code with a weak, generic, pcibios_setup() (Myron Stowe)" * tag 'for-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (122 commits) PCI: hotplug: ensure a consistent return value in error case PCI: fix undefined reference to 'pci_fixup_final_inited' PCI: build resource code for M68K architecture PCI: pciehp: remove unused pciehp_get_max_lnk_width(), pciehp_get_cur_lnk_width() PCI: reorder __pci_assign_resource() (no change) PCI: fix truncation of resource size to 32 bits PCI: acpiphp: merge acpiphp_debug and debug PCI: acpiphp: remove unused res_lock sparc/PCI: replace pci_cfg_fake_ranges() with pci_read_bridge_bases() PCI: call final fixups hot-added devices PCI: move final fixups from __init to __devinit x86/PCI: move final fixups from __init to __devinit MIPS/PCI: move final fixups from __init to __devinit PCI: support sizing P2P bridge I/O windows with 1K granularity PCI: reimplement P2P bridge 1K I/O windows (Intel P64H2) PCI: disable MEM decoding while updating 64-bit MEM BARs PCI: leave MEM and IO decoding disabled during 64-bit BAR sizing, too PCI: never discard enable/suspend/resume_early/resume fixups PCI: release temporary reference in __nv_msi_ht_cap_quirk() PCI: restructure 'pci_do_fixups()' ...
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c67
1 files changed, 46 insertions, 21 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 806c44fa645..ad6fd669549 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -100,11 +100,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
PCI_PRIMARY_BUS,
&buses);
- if (((buses >> 8) & 0xff) != bus->secondary) {
+ if (((buses >> 8) & 0xff) != bus->busn_res.start) {
buses = (buses & 0xff000000)
| ((unsigned int)(bus->primary) << 0)
- | ((unsigned int)(bus->secondary) << 8)
- | ((unsigned int)(bus->subordinate) << 16);
+ | ((unsigned int)(bus->busn_res.start) << 8)
+ | ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
return NOTIFY_OK;
@@ -132,6 +132,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
+ status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+ if (ACPI_FAILURE(status)) {
+ warn("can't evaluate _ADR (%#x)\n", status);
+ return AE_OK;
+ }
+
+ device = (adr >> 16) & 0xffff;
+ function = adr & 0xffff;
+
pdev = pbus->self;
if (pdev && pci_is_pcie(pdev)) {
tmp = acpi_find_root_bridge_handle(pdev);
@@ -144,10 +153,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
}
}
- acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
- device = (adr >> 16) & 0xffff;
- function = adr & 0xffff;
-
newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
if (!newfunc)
return AE_NO_MEMORY;
@@ -391,8 +396,6 @@ static void add_host_bridge(acpi_handle *handle)
bridge->pci_bus = root->bus;
- spin_lock_init(&bridge->res_lock);
-
init_bridge_misc(bridge);
}
@@ -425,7 +428,6 @@ static void add_p2p_bridge(acpi_handle *handle)
* (which we access during module unload).
*/
get_device(&bridge->pci_bus->dev);
- spin_lock_init(&bridge->res_lock);
init_bridge_misc(bridge);
return;
@@ -692,7 +694,7 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
* bus->subordinate value because it could have
* padding in it.
*/
- max = bus->secondary;
+ max = bus->busn_res.start;
list_for_each(tmp, &bus->children) {
n = pci_bus_max_busnr(pci_bus_b(tmp));
@@ -878,6 +880,24 @@ static void disable_bridges(struct pci_bus *bus)
}
}
+/* return first device in slot, acquiring a reference on it */
+static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
+{
+ struct pci_bus *bus = slot->bridge->pci_bus;
+ struct pci_dev *dev;
+ struct pci_dev *ret = NULL;
+
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->device) {
+ ret = pci_dev_get(dev);
+ break;
+ }
+ up_read(&pci_bus_sem);
+
+ return ret;
+}
+
/**
* disable_device - disable a slot
* @slot: ACPI PHP slot
@@ -893,6 +913,7 @@ static int disable_device(struct acpiphp_slot *slot)
pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
if (!pdev)
goto err_exit;
+ pci_dev_put(pdev);
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->bridge) {
@@ -901,18 +922,22 @@ static int disable_device(struct acpiphp_slot *slot)
(u32)1, NULL, NULL);
func->bridge = NULL;
}
+ }
- pdev = pci_get_slot(slot->bridge->pci_bus,
- PCI_DEVFN(slot->device, func->function));
- if (pdev) {
- pci_stop_bus_device(pdev);
- if (pdev->subordinate) {
- disable_bridges(pdev->subordinate);
- pci_disable_device(pdev);
- }
- __pci_remove_bus_device(pdev);
- pci_dev_put(pdev);
+ /*
+ * enable_device() enumerates all functions in this device via
+ * pci_scan_slot(), whether they have associated ACPI hotplug
+ * methods (_EJ0, etc.) or not. Therefore, we remove all functions
+ * here.
+ */
+ while ((pdev = dev_in_slot(slot))) {
+ pci_stop_bus_device(pdev);
+ if (pdev->subordinate) {
+ disable_bridges(pdev->subordinate);
+ pci_disable_device(pdev);
}
+ __pci_remove_bus_device(pdev);
+ pci_dev_put(pdev);
}
list_for_each_entry(func, &slot->funcs, sibling) {