]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge branch 'pci/jiang-subdrivers' into next
authorBjorn Helgaas <bhelgaas@google.com>
Tue, 16 Apr 2013 16:37:22 +0000 (10:37 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 16 Apr 2013 16:37:22 +0000 (10:37 -0600)
* pci/jiang-subdrivers:
  PCI/ACPI: Remove support of ACPI PCI subdrivers
  PCI: acpiphp: Protect acpiphp data structures from concurrent updates
  PCI: acpiphp: Use normal list to simplify implementation
  PCI: acpiphp: Do not use ACPI PCI subdriver mechanism
  PCI: acpiphp: Convert acpiphp to be builtin only, not modular
  PCI/ACPI: Handle PCI slot devices when creating/destroying PCI buses
  x86/PCI: Implement pcibios_{add|remove}_bus() hooks
  ia64/PCI: Implement pcibios_{add|remove}_bus() hooks
  PCI/ACPI: Prepare stub functions to handle ACPI PCI (hotplug) slots
  PCI: Add pcibios hooks for adding and removing PCI buses
  PCI: acpiphp: Replace local macros with standard ACPI macros
  PCI: acpiphp: Remove all functions even if function 0 doesn't exist
  PCI: acpiphp: Use list_for_each_entry_safe() in acpiphp_sanitize_bus()
  PCI: Clean up usages of pci_bus->is_added
  PCI: When removing bus, always remove legacy files & unregister

16 files changed:
arch/ia64/pci/pci.c
arch/x86/pci/common.c
drivers/acpi/pci_root.c
drivers/acpi/pci_slot.c
drivers/acpi/scan.c
drivers/pci/bus.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/pci-acpi.c
drivers/pci/probe.c
drivers/pci/remove.c
include/linux/acpi.h
include/linux/pci-acpi.h
include/linux/pci.h

index 60532ab2734684eafc036e5a5bc88194b7bae142..de1474ff0bc59fb26d2822c6793da608bb3194fb 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -458,6 +459,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
        platform_pci_fixup_bus(b);
 }
 
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 void pcibios_set_master (struct pci_dev *dev)
 {
        /* No special bus mastering setup handling */
index 901177d75ff5e36663b3083ba7f7eb77ab4a86c8..305c68b8d53825fbda7f635de0ae4c1af43fe03b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/sched.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -170,6 +171,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
                pcibios_fixup_device_resources(dev);
 }
 
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 /*
  * Only use DMI information to set this if nothing was passed
  * on the kernel command line (which was parsed earlier).
index 0ac546d5e53f5b0f079792c71419dd07001fe892..b80e06e0b2d9af965ee453901fb13370e6eda3ca 100644 (file)
@@ -65,44 +65,12 @@ static struct acpi_scan_handler pci_root_handler = {
        .detach = acpi_pci_root_remove,
 };
 
-/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
+/* Lock to protect both acpi_pci_roots lists */
 static DEFINE_MUTEX(acpi_pci_root_lock);
 static LIST_HEAD(acpi_pci_roots);
-static LIST_HEAD(acpi_pci_drivers);
 
 static DEFINE_MUTEX(osc_lock);
 
-int acpi_pci_register_driver(struct acpi_pci_driver *driver)
-{
-       int n = 0;
-       struct acpi_pci_root *root;
-
-       mutex_lock(&acpi_pci_root_lock);
-       list_add_tail(&driver->node, &acpi_pci_drivers);
-       if (driver->add)
-               list_for_each_entry(root, &acpi_pci_roots, node) {
-                       driver->add(root);
-                       n++;
-               }
-       mutex_unlock(&acpi_pci_root_lock);
-
-       return n;
-}
-EXPORT_SYMBOL(acpi_pci_register_driver);
-
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
-{
-       struct acpi_pci_root *root;
-
-       mutex_lock(&acpi_pci_root_lock);
-       list_del(&driver->node);
-       if (driver->remove)
-               list_for_each_entry(root, &acpi_pci_roots, node)
-                       driver->remove(root);
-       mutex_unlock(&acpi_pci_root_lock);
-}
-EXPORT_SYMBOL(acpi_pci_unregister_driver);
-
 /**
  * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
  * @handle - the ACPI CA node in question.
@@ -413,7 +381,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
        acpi_status status;
        int result;
        struct acpi_pci_root *root;
-       struct acpi_pci_driver *driver;
        u32 flags, base_flags;
        bool is_osc_granted = false;
 
@@ -573,12 +540,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
                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);
@@ -599,16 +560,9 @@ end:
 static void acpi_pci_root_remove(struct acpi_device *device)
 {
        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_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);
 
index cd1434eb1de8d806e28f794ff2e1d55d69020989..033d1179bdb56bb0937e067cb907b9f4272f282d 100644 (file)
@@ -9,6 +9,9 @@
  *  Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P.
  *     Alex Chiang <achiang@hp.com>
  *
+ *  Copyright (C) 2013 Huawei Tech. Co., Ltd.
+ *     Jiang Liu <jiang.liu@huawei.com>
+ *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
  *  version 2, as published by the Free Software Foundation.
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
 #include <linux/dmi.h>
 
 static bool debug;
@@ -61,20 +63,12 @@ ACPI_MODULE_NAME("pci_slot");
 #define SLOT_NAME_SIZE 21              /* Inspired by #define in acpiphp.h */
 
 struct acpi_pci_slot {
-       acpi_handle root_handle;        /* handle of the root bridge */
        struct pci_slot *pci_slot;      /* corresponding pci_slot */
        struct list_head list;          /* node in the list of slots */
 };
 
-static int acpi_pci_slot_add(struct acpi_pci_root *root);
-static void acpi_pci_slot_remove(struct acpi_pci_root *root);
-
 static LIST_HEAD(slot_list);
 static DEFINE_MUTEX(slot_list_lock);
-static struct acpi_pci_driver acpi_pci_slot_driver = {
-       .add = acpi_pci_slot_add,
-       .remove = acpi_pci_slot_remove,
-};
 
 static int
 check_slot(acpi_handle handle, unsigned long long *sun)
@@ -113,21 +107,8 @@ out:
        return device;
 }
 
-struct callback_args {
-       acpi_walk_callback      user_function;  /* only for walk_p2p_bridge */
-       struct pci_bus          *pci_bus;
-       acpi_handle             root_handle;
-};
-
 /*
- * register_slot
- *
- * Called once for each SxFy object in the namespace. Don't worry about
- * calling pci_create_slot multiple times for the same pci_bus:device,
- * since each subsequent call simply bumps the refcount on the pci_slot.
- *
- * The number of calls to pci_destroy_slot from unregister_slot is
- * symmetrical.
+ * Check whether handle has an associated slot and create PCI slot if it has.
  */
 static acpi_status
 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -137,13 +118,22 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        char name[SLOT_NAME_SIZE];
        struct acpi_pci_slot *slot;
        struct pci_slot *pci_slot;
-       struct callback_args *parent_context = context;
-       struct pci_bus *pci_bus = parent_context->pci_bus;
+       struct pci_bus *pci_bus = context;
 
        device = check_slot(handle, &sun);
        if (device < 0)
                return AE_OK;
 
+       /*
+        * There may be multiple PCI functions associated with the same slot.
+        * Check whether PCI slot has already been created for this PCI device.
+        */
+       list_for_each_entry(slot, &slot_list, list) {
+               pci_slot = slot->pci_slot;
+               if (pci_slot->bus == pci_bus && pci_slot->number == device)
+                       return AE_OK;
+       }
+
        slot = kmalloc(sizeof(*slot), GFP_KERNEL);
        if (!slot) {
                err("%s: cannot allocate memory\n", __func__);
@@ -158,12 +148,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
        }
 
-       slot->root_handle = parent_context->root_handle;
        slot->pci_slot = pci_slot;
-       INIT_LIST_HEAD(&slot->list);
-       mutex_lock(&slot_list_lock);
        list_add(&slot->list, &slot_list);
-       mutex_unlock(&slot_list_lock);
 
        get_device(&pci_bus->dev);
 
@@ -173,131 +159,24 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-/*
- * walk_p2p_bridge - discover and walk p2p bridges
- * @handle: points to an acpi_pci_root
- * @context: p2p_bridge_context pointer
- *
- * Note that when we call ourselves recursively, we pass a different
- * value of pci_bus in the child_context.
- */
-static acpi_status
-walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       int device, function;
-       unsigned long long adr;
-       acpi_status status;
-       acpi_handle dummy_handle;
-       acpi_walk_callback user_function;
-
-       struct pci_dev *dev;
-       struct pci_bus *pci_bus;
-       struct callback_args child_context;
-       struct callback_args *parent_context = context;
-
-       pci_bus = parent_context->pci_bus;
-       user_function = parent_context->user_function;
-
-       status = acpi_get_handle(handle, "_ADR", &dummy_handle);
-       if (ACPI_FAILURE(status))
-               return AE_OK;
-
-       status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-       if (ACPI_FAILURE(status))
-               return AE_OK;
-
-       device = (adr >> 16) & 0xffff;
-       function = adr & 0xffff;
-
-       dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
-       if (!dev || !dev->subordinate)
-               goto out;
-
-       child_context.pci_bus = dev->subordinate;
-       child_context.user_function = user_function;
-       child_context.root_handle = parent_context->root_handle;
-
-       dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    user_function, NULL, &child_context, NULL);
-       if (ACPI_FAILURE(status))
-               goto out;
-
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    walk_p2p_bridge, NULL, &child_context, NULL);
-out:
-       pci_dev_put(dev);
-       return AE_OK;
-}
-
-/*
- * walk_root_bridge - generic root bridge walker
- * @root: poiner of an acpi_pci_root
- * @user_function: user callback for slot objects
- *
- * Call user_function for all objects underneath this root bridge.
- * Walk p2p bridges underneath us and call user_function on those too.
- */
-static int
-walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
-{
-       acpi_status status;
-       acpi_handle handle = root->device->handle;
-       struct pci_bus *pci_bus = root->bus;
-       struct callback_args context;
-
-       context.pci_bus = pci_bus;
-       context.user_function = user_function;
-       context.root_handle = handle;
-
-       dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    user_function, NULL, &context, NULL);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    walk_p2p_bridge, NULL, &context, NULL);
-       if (ACPI_FAILURE(status))
-               err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
-
-       return status;
-}
-
-/*
- * acpi_pci_slot_add
- * @handle: points to an acpi_pci_root
- */
-static int
-acpi_pci_slot_add(struct acpi_pci_root *root)
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
 {
-       acpi_status status;
-
-       status = walk_root_bridge(root, register_slot);
-       if (ACPI_FAILURE(status))
-               err("%s: register_slot failure - %d\n", __func__, status);
-
-       return status;
+       mutex_lock(&slot_list_lock);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                           register_slot, NULL, bus, NULL);
+       mutex_unlock(&slot_list_lock);
 }
 
-/*
- * acpi_pci_slot_remove
- * @handle: points to an acpi_pci_root
- */
-static void
-acpi_pci_slot_remove(struct acpi_pci_root *root)
+void acpi_pci_slot_remove(struct pci_bus *bus)
 {
        struct acpi_pci_slot *slot, *tmp;
-       struct pci_bus *pbus;
-       acpi_handle handle = root->device->handle;
 
        mutex_lock(&slot_list_lock);
        list_for_each_entry_safe(slot, tmp, &slot_list, list) {
-               if (slot->root_handle == handle) {
+               if (slot->pci_slot->bus == bus) {
                        list_del(&slot->list);
-                       pbus = slot->pci_slot->bus;
                        pci_destroy_slot(slot->pci_slot);
-                       put_device(&pbus->dev);
+                       put_device(&bus->dev);
                        kfree(slot);
                }
        }
@@ -332,5 +211,4 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
 void __init acpi_pci_slot_init(void)
 {
        dmi_check_system(acpi_pci_slot_dmi_table);
-       acpi_pci_register_driver(&acpi_pci_slot_driver);
 }
index 5e7e991717d76f97981fcff3d0a221879b47fcea..f54d1985e59465a049af9cffd76d8f7f38a20e4a 100644 (file)
@@ -1790,7 +1790,6 @@ int __init acpi_scan_init(void)
        acpi_platform_init();
        acpi_csrt_init();
        acpi_container_init();
-       acpi_pci_slot_init();
 
        mutex_lock(&acpi_scan_lock);
        /*
index 8647dc6f52d0cfab432826a1261118c487d29bad..bdc1e8bf7e608381e610eeabeebc33fc1369e5af 100644 (file)
@@ -206,16 +206,9 @@ void pci_bus_add_devices(const struct pci_bus *bus)
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                BUG_ON(!dev->is_added);
-
                child = dev->subordinate;
-
-               if (!child)
-                       continue;
-               pci_bus_add_devices(child);
-
-               if (child->is_added)
-                       continue;
-               child->is_added = 1;
+               if (child)
+                       pci_bus_add_devices(child);
        }
 }
 
index 13e9e63a72665ab22ee431fdcd22392a2fb68c77..9fcb87f353d44cec965301af6799fd8b950d8794 100644 (file)
@@ -52,15 +52,12 @@ config HOTPLUG_PCI_IBM
          When in doubt, say N.
 
 config HOTPLUG_PCI_ACPI
-       tristate "ACPI PCI Hotplug driver"
-       depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
+       bool "ACPI PCI Hotplug driver"
+       depends on HOTPLUG_PCI=y && ((!ACPI_DOCK && ACPI) || (ACPI_DOCK))
        help
          Say Y here if you have a system that supports PCI Hotplug using
          ACPI.
 
-         To compile this driver as a module, choose M here: the
-         module will be called acpiphp.
-
          When in doubt, say N.
 
 config HOTPLUG_PCI_ACPI_IBM
index b70ac00a117e1eaa3c65939cd64555982a482f7a..6a319f42b30cad54994f8cfd92d73654fb6d2fe0 100644 (file)
@@ -73,8 +73,9 @@ static inline const char *slot_name(struct slot *slot)
  */
 struct acpiphp_bridge {
        struct list_head list;
+       struct list_head slots;
+       struct kref ref;
        acpi_handle handle;
-       struct acpiphp_slot *slots;
 
        /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
        struct acpiphp_func *func;
@@ -97,7 +98,7 @@ struct acpiphp_bridge {
  * PCI slot information for each *physical* PCI slot
  */
 struct acpiphp_slot {
-       struct acpiphp_slot *next;
+       struct list_head node;
        struct acpiphp_bridge *bridge;  /* parent */
        struct list_head funcs;         /* one slot may have different
                                           objects (i.e. for each function) */
@@ -119,7 +120,6 @@ struct acpiphp_slot {
  */
 struct acpiphp_func {
        struct acpiphp_slot *slot;      /* parent */
-       struct acpiphp_bridge *bridge;  /* Ejectable PCI-to-PCI bridge */
 
        struct list_head sibling;
        struct notifier_block nb;
@@ -146,10 +146,6 @@ struct acpiphp_attention_info
 #define ACPI_PCI_HOST_HID              "PNP0A03"
 
 /* ACPI _STA method value (ignore bit 4; battery present) */
-#define ACPI_STA_PRESENT               (0x00000001)
-#define ACPI_STA_ENABLED               (0x00000002)
-#define ACPI_STA_SHOW_IN_UI            (0x00000004)
-#define ACPI_STA_FUNCTIONING           (0x00000008)
 #define ACPI_STA_ALL                   (0x0000000f)
 
 /* bridge flags */
@@ -180,8 +176,6 @@ extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
 extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
-extern int acpiphp_glue_init (void);
-extern void acpiphp_glue_exit (void);
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
 extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
@@ -194,5 +188,6 @@ extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
 
 /* variables */
 extern bool acpiphp_debug;
+extern bool acpiphp_disabled;
 
 #endif /* _ACPIPHP_H */
index c2fd3095701f5a8bd3f91c56f7b7a8e51913d182..ca8127950fcd49397027370d82937246204a0e9b 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/pci_hotplug.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -48,6 +49,7 @@
 #define SLOT_NAME_SIZE  21              /* {_SUN} */
 
 bool acpiphp_debug;
+bool acpiphp_disabled;
 
 /* local variables */
 static struct acpiphp_attention_info *attention_info;
@@ -60,7 +62,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(disable, "disable acpiphp driver");
 module_param_named(debug, acpiphp_debug, bool, 0644);
+module_param_named(disable, acpiphp_disabled, bool, 0444);
 
 /* export the attention callback registration methods */
 EXPORT_SYMBOL_GPL(acpiphp_register_attention);
@@ -351,27 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
 }
 
 
-static int __init acpiphp_init(void)
+void __init acpiphp_init(void)
 {
-       info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
-       if (acpi_pci_disabled)
-               return 0;
-
-       /* read all the ACPI info from the system */
-       /* initialize internal data structure etc. */
-       return acpiphp_glue_init();
-}
-
-
-static void __exit acpiphp_exit(void)
-{
-       if (acpi_pci_disabled)
-               return;
-
-       /* deallocate internal data structures etc. */
-       acpiphp_glue_exit();
+       info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
+               acpiphp_disabled ? ", disabled by user; please report a bug"
+                                : "");
 }
-
-module_init(acpiphp_init);
-module_exit(acpiphp_exit);
index 270fdbadc19c93e97b62db8049a1542a748b1223..96fed19c6d90358833e37d1e9f55b1899b2d11b8 100644 (file)
@@ -54,6 +54,7 @@
 #include "acpiphp.h"
 
 static LIST_HEAD(bridge_list);
+static DEFINE_MUTEX(bridge_mutex);
 
 #define MY_NAME "acpiphp_glue"
 
@@ -61,6 +62,7 @@ static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
 static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void free_bridge(struct kref *kref);
 
 /* callback routine to check for the existence of a pci dock device */
 static acpi_status
@@ -76,6 +78,39 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 }
 
+static inline void get_bridge(struct acpiphp_bridge *bridge)
+{
+       kref_get(&bridge->ref);
+}
+
+static inline void put_bridge(struct acpiphp_bridge *bridge)
+{
+       kref_put(&bridge->ref, free_bridge);
+}
+
+static void free_bridge(struct kref *kref)
+{
+       struct acpiphp_bridge *bridge;
+       struct acpiphp_slot *slot, *next;
+       struct acpiphp_func *func, *tmp;
+
+       bridge = container_of(kref, struct acpiphp_bridge, ref);
+
+       list_for_each_entry_safe(slot, next, &bridge->slots, node) {
+               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+                       kfree(func);
+               }
+               kfree(slot);
+       }
+
+       /* Release reference acquired by acpiphp_bridge_handle_to_function() */
+       if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
+               put_bridge(bridge->func->slot->bridge);
+       put_device(&bridge->pci_bus->dev);
+       pci_dev_put(bridge->pci_dev);
+       kfree(bridge);
+}
+
 /*
  * the _DCK method can do funny things... and sometimes not
  * hah-hah funny.
@@ -154,9 +189,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        acpi_handle tmp;
        acpi_status status = AE_OK;
        unsigned long long adr, sun;
-       int device, function, retval;
+       int device, function, retval, found = 0;
        struct pci_bus *pbus = bridge->pci_bus;
        struct pci_dev *pdev;
+       u32 val;
 
        if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
                return AE_OK;
@@ -170,7 +206,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
-       pdev = pbus->self;
+       pdev = bridge->pci_dev;
        if (pdev && device_is_managed_by_native_pciehp(pdev))
                return AE_OK;
 
@@ -178,7 +214,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        if (!newfunc)
                return AE_NO_MEMORY;
 
-       INIT_LIST_HEAD(&newfunc->sibling);
        newfunc->handle = handle;
        newfunc->function = function;
 
@@ -207,14 +242,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 
        /* search for objects that share the same slot */
-       for (slot = bridge->slots; slot; slot = slot->next)
+       list_for_each_entry(slot, &bridge->slots, node)
                if (slot->device == device) {
                        if (slot->sun != sun)
                                warn("sibling found, but _SUN doesn't match!\n");
+                       found = 1;
                        break;
                }
 
-       if (!slot) {
+       if (!found) {
                slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
                if (!slot) {
                        kfree(newfunc);
@@ -227,9 +263,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                INIT_LIST_HEAD(&slot->funcs);
                mutex_init(&slot->crit_sect);
 
-               slot->next = bridge->slots;
-               bridge->slots = slot;
-
+               mutex_lock(&bridge_mutex);
+               list_add_tail(&slot->node, &bridge->slots);
+               mutex_unlock(&bridge_mutex);
                bridge->nr_slots++;
 
                dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
@@ -247,13 +283,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 
        newfunc->slot = slot;
+       mutex_lock(&bridge_mutex);
        list_add_tail(&newfunc->sibling, &slot->funcs);
+       mutex_unlock(&bridge_mutex);
 
-       pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
-       if (pdev) {
+       if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
+                                      &val, 60*1000))
                slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
-               pci_dev_put(pdev);
-       }
 
        if (is_dock_device(handle)) {
                /* we don't want to call this device's _EJ0
@@ -290,7 +326,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 
  err_exit:
        bridge->nr_slots--;
-       bridge->slots = slot->next;
+       mutex_lock(&bridge_mutex);
+       list_del(&slot->node);
+       mutex_unlock(&bridge_mutex);
        kfree(slot);
        kfree(newfunc);
 
@@ -315,13 +353,17 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
        acpi_status status;
 
        /* must be added to the list prior to calling register_slot */
+       mutex_lock(&bridge_mutex);
        list_add(&bridge->list, &bridge_list);
+       mutex_unlock(&bridge_mutex);
 
        /* register all slot objects under this bridge */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
                                     register_slot, NULL, bridge, NULL);
        if (ACPI_FAILURE(status)) {
+               mutex_lock(&bridge_mutex);
                list_del(&bridge->list);
+               mutex_unlock(&bridge_mutex);
                return;
        }
 
@@ -351,178 +393,46 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle
 {
        struct acpiphp_bridge *bridge;
        struct acpiphp_slot *slot;
-       struct acpiphp_func *func;
+       struct acpiphp_func *func = NULL;
 
+       mutex_lock(&bridge_mutex);
        list_for_each_entry(bridge, &bridge_list, list) {
-               for (slot = bridge->slots; slot; slot = slot->next) {
+               list_for_each_entry(slot, &bridge->slots, node) {
                        list_for_each_entry(func, &slot->funcs, sibling) {
-                               if (func->handle == handle)
+                               if (func->handle == handle) {
+                                       get_bridge(func->slot->bridge);
+                                       mutex_unlock(&bridge_mutex);
                                        return func;
+                               }
                        }
                }
        }
+       mutex_unlock(&bridge_mutex);
 
        return NULL;
 }
 
 
-static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
-{
-       acpi_handle dummy_handle;
-       struct acpiphp_func *func;
-
-       if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
-                                       "_EJ0", &dummy_handle))) {
-               bridge->flags |= BRIDGE_HAS_EJ0;
-
-               dbg("found ejectable p2p bridge\n");
-
-               /* make link between PCI bridge and PCI function */
-               func = acpiphp_bridge_handle_to_function(bridge->handle);
-               if (!func)
-                       return;
-               bridge->func = func;
-               func->bridge = bridge;
-       }
-}
-
-
-/* allocate and initialize host bridge data structure */
-static void add_host_bridge(struct acpi_pci_root *root)
-{
-       struct acpiphp_bridge *bridge;
-       acpi_handle handle = root->device->handle;
-
-       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-       if (bridge == NULL)
-               return;
-
-       bridge->handle = handle;
-
-       bridge->pci_bus = root->bus;
-
-       init_bridge_misc(bridge);
-}
-
-
-/* allocate and initialize PCI-to-PCI bridge data structure */
-static void add_p2p_bridge(acpi_handle *handle)
-{
-       struct acpiphp_bridge *bridge;
-
-       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-       if (bridge == NULL) {
-               err("out of memory\n");
-               return;
-       }
-
-       bridge->handle = handle;
-       config_p2p_bridge_flags(bridge);
-
-       bridge->pci_dev = acpi_get_pci_dev(handle);
-       bridge->pci_bus = bridge->pci_dev->subordinate;
-       if (!bridge->pci_bus) {
-               err("This is not a PCI-to-PCI bridge!\n");
-               goto err;
-       }
-
-       /*
-        * Grab a ref to the subordinate PCI bus in case the bus is
-        * removed via PCI core logical hotplug. The ref pins the bus
-        * (which we access during module unload).
-        */
-       get_device(&bridge->pci_bus->dev);
-
-       init_bridge_misc(bridge);
-       return;
- err:
-       pci_dev_put(bridge->pci_dev);
-       kfree(bridge);
-       return;
-}
-
-
-/* callback routine to find P2P bridges */
-static acpi_status
-find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       acpi_status status;
-       struct pci_dev *dev;
-
-       dev = acpi_get_pci_dev(handle);
-       if (!dev || !dev->subordinate)
-               goto out;
-
-       /* check if this bridge has ejectable slots */
-       if ((detect_ejectable_slots(handle) > 0)) {
-               dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
-               add_p2p_bridge(handle);
-       }
-
-       /* search P2P bridges under this p2p bridge */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    find_p2p_bridge, NULL, NULL, NULL);
-       if (ACPI_FAILURE(status))
-               warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
- out:
-       pci_dev_put(dev);
-       return AE_OK;
-}
-
-
-/* find hot-pluggable slots, and then find P2P bridge */
-static int add_bridge(struct acpi_pci_root *root)
-{
-       acpi_status status;
-       unsigned long long tmp;
-       acpi_handle dummy_handle;
-       acpi_handle handle = root->device->handle;
-
-       /* if the bridge doesn't have _STA, we assume it is always there */
-       status = acpi_get_handle(handle, "_STA", &dummy_handle);
-       if (ACPI_SUCCESS(status)) {
-               status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-               if (ACPI_FAILURE(status)) {
-                       dbg("%s: _STA evaluation failure\n", __func__);
-                       return 0;
-               }
-               if ((tmp & ACPI_STA_FUNCTIONING) == 0)
-                       /* don't register this object */
-                       return 0;
-       }
-
-       /* check if this bridge has ejectable slots */
-       if (detect_ejectable_slots(handle) > 0) {
-               dbg("found PCI host-bus bridge with hot-pluggable slots\n");
-               add_host_bridge(root);
-       }
-
-       /* search P2P bridges under this host bridge */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    find_p2p_bridge, NULL, NULL, NULL);
-
-       if (ACPI_FAILURE(status))
-               warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
-       return 0;
-}
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
        struct acpiphp_bridge *bridge;
 
+       mutex_lock(&bridge_mutex);
        list_for_each_entry(bridge, &bridge_list, list)
-               if (bridge->handle == handle)
+               if (bridge->handle == handle) {
+                       get_bridge(bridge);
+                       mutex_unlock(&bridge_mutex);
                        return bridge;
+               }
+       mutex_unlock(&bridge_mutex);
 
        return NULL;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)
 {
-       struct acpiphp_slot *slot, *next;
-       struct acpiphp_func *func, *tmp;
+       struct acpiphp_slot *slot;
+       struct acpiphp_func *func;
        acpi_status status;
        acpi_handle handle = bridge->handle;
 
@@ -543,10 +453,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                        err("failed to install interrupt notify handler\n");
        }
 
-       slot = bridge->slots;
-       while (slot) {
-               next = slot->next;
-               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+       list_for_each_entry(slot, &bridge->slots, node) {
+               list_for_each_entry(func, &slot->funcs, sibling) {
                        if (is_dock_device(func->handle)) {
                                unregister_hotplug_dock_device(func->handle);
                                unregister_dock_notifier(&func->nb);
@@ -558,63 +466,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                                if (ACPI_FAILURE(status))
                                        err("failed to remove notify handler\n");
                        }
-                       list_del(&func->sibling);
-                       kfree(func);
                }
                acpiphp_unregister_hotplug_slot(slot);
-               list_del(&slot->funcs);
-               kfree(slot);
-               slot = next;
        }
 
-       /*
-        * Only P2P bridges have a pci_dev
-        */
-       if (bridge->pci_dev)
-               put_device(&bridge->pci_bus->dev);
-
-       pci_dev_put(bridge->pci_dev);
+       mutex_lock(&bridge_mutex);
        list_del(&bridge->list);
-       kfree(bridge);
-}
-
-static acpi_status
-cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       struct acpiphp_bridge *bridge;
-
-       /* cleanup p2p bridges under this P2P bridge
-          in a depth-first manner */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                               cleanup_p2p_bridge, NULL, NULL, NULL);
-
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge)
-               cleanup_bridge(bridge);
-
-       return AE_OK;
-}
-
-static void remove_bridge(struct acpi_pci_root *root)
-{
-       struct acpiphp_bridge *bridge;
-       acpi_handle handle = root->device->handle;
-
-       /* cleanup p2p bridges under this host bridge
-          in a depth-first manner */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-                               (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL);
-
-       /*
-        * On root bridges with hotplug slots directly underneath (ie,
-        * no p2p bridge between), we call cleanup_bridge(). 
-        *
-        * The else clause cleans up root bridges that either had no
-        * hotplug slots at all, or had a p2p bridge underneath.
-        */
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge)
-               cleanup_bridge(bridge);
+       mutex_unlock(&bridge_mutex);
 }
 
 static int power_on_slot(struct acpiphp_slot *slot)
@@ -798,6 +656,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
                }
        }
 }
+
 /**
  * enable_device - enable, configure a slot
  * @slot: slot to be enabled
@@ -810,9 +669,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        struct pci_dev *dev;
        struct pci_bus *bus = slot->bridge->pci_bus;
        struct acpiphp_func *func;
-       int retval = 0;
        int num, max, pass;
-       acpi_status status;
 
        if (slot->flags & SLOT_ENABLED)
                goto err_exit;
@@ -867,23 +724,11 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                        slot->flags &= (~SLOT_ENABLED);
                        continue;
                }
-
-               if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
-                   dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
-                       pci_dev_put(dev);
-                       continue;
-               }
-
-               status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
-               if (ACPI_FAILURE(status))
-                       warn("find_p2p_bridge failed (error code = 0x%x)\n",
-                               status);
-               pci_dev_put(dev);
        }
 
 
  err_exit:
-       return retval;
+       return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
@@ -912,23 +757,6 @@ static int disable_device(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
        struct pci_dev *pdev;
-       struct pci_bus *bus = slot->bridge->pci_bus;
-
-       /* The slot will be enabled when func 0 is added, so check
-          func 0 before disable the 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) {
-                       /* cleanup p2p bridges under this P2P bridge */
-                       cleanup_p2p_bridge(func->bridge->handle,
-                                               (u32)1, NULL, NULL);
-                       func->bridge = NULL;
-               }
-       }
 
        /*
         * enable_device() enumerates all functions in this device via
@@ -947,7 +775,6 @@ static int disable_device(struct acpiphp_slot *slot)
 
        slot->flags &= (~SLOT_ENABLED);
 
-err_exit:
        return 0;
 }
 
@@ -1037,7 +864,7 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 
        enabled = disabled = 0;
 
-       for (slot = bridge->slots; slot; slot = slot->next) {
+       list_for_each_entry(slot, &bridge->slots, node) {
                unsigned int status = get_slot_status(slot);
                if (slot->flags & SLOT_ENABLED) {
                        if (status == ACPI_STA_ALL)
@@ -1082,11 +909,11 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus)
  */
 static void acpiphp_sanitize_bus(struct pci_bus *bus)
 {
-       struct pci_dev *dev;
+       struct pci_dev *dev, *tmp;
        int i;
        unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
 
-       list_for_each_entry(dev, &bus->devices, bus_list) {
+       list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
                for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
                        struct resource *res = &dev->resource[i];
                        if ((res->flags & type_mask) && !res->start &&
@@ -1118,6 +945,7 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
                dbg("%s: re-enumerating slots under %s\n",
                        __func__, objname);
                acpiphp_check_bridge(bridge);
+               put_bridge(bridge);
        }
        return AE_OK ;
 }
@@ -1195,6 +1023,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
+       put_bridge(bridge);
 }
 
 /**
@@ -1208,6 +1037,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
                                        void *context)
 {
+       struct acpiphp_bridge *bridge = context;
+
        /*
         * Currently the code adds all hotplug events to the kacpid_wq
         * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1216,6 +1047,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
         * For now just re-add this work to the kacpi_hotplug_wq so we
         * don't deadlock on hotplug actions.
         */
+       get_bridge(bridge);
        alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
 }
 
@@ -1270,6 +1102,7 @@ static void _handle_hotplug_event_func(struct work_struct *work)
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_func */
+       put_bridge(func->slot->bridge);
 }
 
 /**
@@ -1283,6 +1116,8 @@ static void _handle_hotplug_event_func(struct work_struct *work)
 static void handle_hotplug_event_func(acpi_handle handle, u32 type,
                                      void *context)
 {
+       struct acpiphp_func *func = context;
+
        /*
         * Currently the code adds all hotplug events to the kacpid_wq
         * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1291,33 +1126,69 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
         * For now just re-add this work to the kacpi_hotplug_wq so we
         * don't deadlock on hotplug actions.
         */
+       get_bridge(func->slot->bridge);
        alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
 }
 
-static struct acpi_pci_driver acpi_pci_hp_driver = {
-       .add =          add_bridge,
-       .remove =       remove_bridge,
-};
-
-/**
- * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+/*
+ * Create hotplug slots for the PCI bus.
+ * It should always return 0 to avoid skipping following notifiers.
  */
-int __init acpiphp_glue_init(void)
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
 {
-       acpi_pci_register_driver(&acpi_pci_hp_driver);
+       acpi_handle dummy_handle;
+       struct acpiphp_bridge *bridge;
 
-       return 0;
-}
+       if (acpiphp_disabled)
+               return;
 
+       if (detect_ejectable_slots(handle) <= 0)
+               return;
 
-/**
- * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
- *
- * This function frees all data allocated in acpiphp_glue_init().
- */
-void  acpiphp_glue_exit(void)
+       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+       if (bridge == NULL) {
+               err("out of memory\n");
+               return;
+       }
+
+       INIT_LIST_HEAD(&bridge->slots);
+       kref_init(&bridge->ref);
+       bridge->handle = handle;
+       bridge->pci_dev = pci_dev_get(bus->self);
+       bridge->pci_bus = bus;
+
+       /*
+        * Grab a ref to the subordinate PCI bus in case the bus is
+        * removed via PCI core logical hotplug. The ref pins the bus
+        * (which we access during module unload).
+        */
+       get_device(&bus->dev);
+
+       if (!pci_is_root_bus(bridge->pci_bus) &&
+           ACPI_SUCCESS(acpi_get_handle(bridge->handle,
+                                       "_EJ0", &dummy_handle))) {
+               dbg("found ejectable p2p bridge\n");
+               bridge->flags |= BRIDGE_HAS_EJ0;
+               bridge->func = acpiphp_bridge_handle_to_function(handle);
+       }
+
+       init_bridge_misc(bridge);
+}
+
+/* Destroy hotplug slots associated with the PCI bus */
+void acpiphp_remove_slots(struct pci_bus *bus)
 {
-       acpi_pci_unregister_driver(&acpi_pci_hp_driver);
+       struct acpiphp_bridge *bridge, *tmp;
+
+       if (acpiphp_disabled)
+               return;
+
+       list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+               if (bridge->pci_bus == bus) {
+                       cleanup_bridge(bridge);
+                       put_bridge(bridge);
+                       break;
+               }
 }
 
 /**
@@ -1396,7 +1267,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 
        sta = get_slot_status(slot);
 
-       return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
+       return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
 }
 
 
index dee5dddaa292a04ad2200c005ad59b959ed5ad7e..d927933dcf44afebd52b4a3d94eef1f90b788563 100644 (file)
@@ -287,6 +287,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
        .run_wake = acpi_pci_run_wake,
 };
 
+void acpi_pci_add_bus(struct pci_bus *bus)
+{
+       acpi_handle handle = NULL;
+
+       if (bus->bridge)
+               handle = ACPI_HANDLE(bus->bridge);
+       if (acpi_pci_disabled || handle == NULL)
+               return;
+
+       acpi_pci_slot_enumerate(bus, handle);
+       acpiphp_enumerate_slots(bus, handle);
+}
+
+void acpi_pci_remove_bus(struct pci_bus *bus)
+{
+       /*
+        * bus->bridge->acpi_node.handle has already been reset to NULL
+        * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
+        */
+       if (acpi_pci_disabled)
+               return;
+
+       acpiphp_remove_slots(bus);
+       acpi_pci_slot_remove(bus);
+}
+
 /* ACPI bus type */
 static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
 {
@@ -361,7 +387,11 @@ static int __init acpi_pci_init(void)
        ret = register_acpi_bus_type(&acpi_pci_bus);
        if (ret)
                return 0;
+
        pci_set_platform_pm(&acpi_pci_platform_pm);
+       acpi_pci_slot_init();
+       acpiphp_init();
+
        return 0;
 }
 arch_initcall(acpi_pci_init);
index b494066ef32f5f08e3f5d4f4b3d88acf9257d710..43ece5d41d36ca428068ef8b09f01f5956f10a25 100644 (file)
@@ -673,6 +673,8 @@ add_dev:
        ret = device_register(&child->dev);
        WARN_ON(ret < 0);
 
+       pcibios_add_bus(child);
+
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(child);
 
@@ -1627,8 +1629,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
        if (!bus->is_added) {
                dev_dbg(&bus->dev, "fixups for bus\n");
                pcibios_fixup_bus(bus);
-               if (pci_is_root_bus(bus))
-                       bus->is_added = 1;
+               bus->is_added = 1;
        }
 
        for (pass=0; pass < 2; pass++)
@@ -1661,6 +1662,14 @@ int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
        return 0;
 }
 
+void __weak pcibios_add_bus(struct pci_bus *bus)
+{
+}
+
+void __weak pcibios_remove_bus(struct pci_bus *bus)
+{
+}
+
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
@@ -1715,6 +1724,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        if (error)
                goto class_dev_reg_err;
 
+       pcibios_add_bus(b);
+
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(b);
 
index cc875e6ed159f1edb890946a96e78917bb6fe2c5..8fc54b7327bc02b59af4a6455bcf43bdaf597252 100644 (file)
@@ -50,10 +50,8 @@ void pci_remove_bus(struct pci_bus *bus)
        list_del(&bus->node);
        pci_bus_release_busn_res(bus);
        up_write(&pci_bus_sem);
-       if (!bus->is_added)
-               return;
-
        pci_remove_legacy_files(bus);
+       pcibios_remove_bus(bus);
        device_unregister(&bus->dev);
 }
 EXPORT_SYMBOL(pci_remove_bus);
index bcbdd7484e581404d54be807c034fced32ba45c2..03053aca5b326c07d56f0022336fc9fc49927653 100644 (file)
@@ -152,15 +152,6 @@ void acpi_penalize_isa_irq(int irq, int active);
 
 void acpi_pci_irq_disable (struct pci_dev *dev);
 
-struct acpi_pci_driver {
-       struct list_head node;
-       int (*add)(struct acpi_pci_root *root);
-       void (*remove)(struct acpi_pci_root *root);
-};
-
-int acpi_pci_register_driver(struct acpi_pci_driver *driver);
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
-
 extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
 extern int ec_transaction(u8 command,
index 9a22b5efb384a5247e57319222ba05f883fed25a..81b31613eb252b3a46052d2375e333affc91c77f 100644 (file)
@@ -41,8 +41,37 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 
        return DEVICE_ACPI_HANDLE(dev);
 }
+
+void acpi_pci_add_bus(struct pci_bus *bus);
+void acpi_pci_remove_bus(struct pci_bus *bus);
+
+#ifdef CONFIG_ACPI_PCI_SLOT
+void acpi_pci_slot_init(void);
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_remove(struct pci_bus *bus);
+#else
+static inline void acpi_pci_slot_init(void) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
+                                          acpi_handle handle) { }
+static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
 #endif
 
+#ifdef CONFIG_HOTPLUG_PCI_ACPI
+void acpiphp_init(void);
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_remove_slots(struct pci_bus *bus);
+#else
+static inline void acpiphp_init(void) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
+                                          acpi_handle handle) { }
+static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
+#endif
+
+#else  /* CONFIG_ACPI */
+static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
+static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+#endif /* CONFIG_ACPI */
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
index bcd976976c3e607a976a6ad6a17bb7e4d9855f9c..4a6ee631a0c5fab531a90435f35fcd775f21f2d0 100644 (file)
@@ -693,6 +693,8 @@ extern struct list_head pci_root_buses;     /* list of all known PCI buses */
 extern int no_pci_devices(void);
 
 void pcibios_resource_survey_bus(struct pci_bus *bus);
+void pcibios_add_bus(struct pci_bus *bus);
+void pcibios_remove_bus(struct pci_bus *bus);
 void pcibios_fixup_bus(struct pci_bus *);
 int __must_check pcibios_enable_device(struct pci_dev *, int mask);
 /* Architecture specific versions may override this (weak) */