Merge master.kernel.org:/home/rmk/linux-2.6-arm
[safe/jmp/linux-2.6] / drivers / pci / hotplug / acpiphp_glue.c
index 2a83e6b..803d9dd 100644 (file)
@@ -26,7 +26,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Send feedback to <t-kochi@bq.jp.nec.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
  *
  */
 
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
+#include <linux/pci_hotplug.h>
+#include <linux/pci-acpi.h>
 #include <linux/mutex.h>
 
 #include "../pci.h"
-#include "pci_hotplug.h"
 #include "acpiphp.h"
 
 static LIST_HEAD(bridge_list);
+static LIST_HEAD(ioapic_list);
+static DEFINE_SPINLOCK(ioapic_list_lock);
 
 #define MY_NAME "acpiphp_glue"
 
 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(acpi_handle handle, struct pci_bus *bus);
+static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
 
-
-/*
- * initialization & terminatation routines
- */
-
-/**
- * is_ejectable - determine if a slot is ejectable
- * @handle: handle to acpi namespace
- *
- * Ejectable slot should satisfy at least these conditions:
- *
- *  1. has _ADR method
- *  2. has _EJ0 method
- *
- * optionally
- *
- *  1. has _STA method
- *  2. has _PS0 method
- *  3. has _PS3 method
- *  4. ..
- *
- */
-static int is_ejectable(acpi_handle handle)
-{
-       acpi_status status;
-       acpi_handle tmp;
-
-       status = acpi_get_handle(handle, "_ADR", &tmp);
-       if (ACPI_FAILURE(status)) {
-               return 0;
-       }
-
-       status = acpi_get_handle(handle, "_EJ0", &tmp);
-       if (ACPI_FAILURE(status)) {
-               return 0;
-       }
-
-       return 1;
-}
-
-
-/* callback routine to check the existence of ejectable slots */
+/* callback routine to check for the existence of a pci dock device */
 static acpi_status
-is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int *count = (int *)context;
 
-       if (is_ejectable(handle)) {
+       if (is_dock_device(handle)) {
                (*count)++;
-               /* only one ejectable slot is enough */
                return AE_CTRL_TERMINATE;
        } else {
                return AE_OK;
        }
 }
 
+/*
+ * the _DCK method can do funny things... and sometimes not
+ * hah-hah funny.
+ *
+ * TBD - figure out a way to only call fixups for
+ * systems that require them.
+ */
+static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
+       void *v)
+{
+       struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
+       struct pci_bus *bus = func->slot->bridge->pci_bus;
+       u32 buses;
+
+       if (!bus->self)
+               return  NOTIFY_OK;
+
+       /* fixup bad _DCK function that rewrites
+        * secondary bridge on slot
+        */
+       pci_read_config_dword(bus->self,
+                       PCI_PRIMARY_BUS,
+                       &buses);
+
+       if (((buses >> 8) & 0xff) != bus->secondary) {
+               buses = (buses & 0xff000000)
+                       | ((unsigned int)(bus->primary)     <<  0)
+                       | ((unsigned int)(bus->secondary)   <<  8)
+                       | ((unsigned int)(bus->subordinate) << 16);
+               pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
+       }
+       return NOTIFY_OK;
+}
+
+
+static struct acpi_dock_ops acpiphp_dock_ops = {
+       .handler = handle_hotplug_event_func,
+};
 
 /* callback routine to register each ACPI PCI slot object */
 static acpi_status
@@ -124,22 +123,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
        struct acpiphp_slot *slot;
        struct acpiphp_func *newfunc;
-       struct dependent_device *dd;
        acpi_handle tmp;
        acpi_status status = AE_OK;
-       unsigned long adr, sun;
+       unsigned long long adr, sun;
        int device, function, retval;
+       struct pci_bus *pbus = bridge->pci_bus;
 
-       status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-
-       if (ACPI_FAILURE(status))
-               return AE_OK;
-
-       status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-       if (ACPI_FAILURE(status) && !(is_dependent_device(handle)))
+       if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
                return AE_OK;
 
+       acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
@@ -150,7 +143,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        INIT_LIST_HEAD(&newfunc->sibling);
        newfunc->handle = handle;
        newfunc->function = function;
-       if (ACPI_SUCCESS(status))
+
+       if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
                newfunc->flags = FUNC_HAS_EJ0;
 
        if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
@@ -162,22 +156,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
                newfunc->flags |= FUNC_HAS_PS3;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) {
+       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
                newfunc->flags |= FUNC_HAS_DCK;
-               /* add to devices dependent on dock station,
-                * because this may actually be the dock bridge
-                */
-               dd = alloc_dependent_device(handle);
-                if (!dd)
-                        err("Can't allocate memory for "
-                               "new dependent device!\n");
-               else
-                       add_dependent_device(dd);
-       }
 
        status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-       if (ACPI_FAILURE(status))
-               sun = -1;
+       if (ACPI_FAILURE(status)) {
+               /*
+                * use the count of the number of slots we've found
+                * for the number of the slot
+                */
+               sun = bridge->nr_slots+1;
+       }
 
        /* search for objects that share the same slot */
        for (slot = bridge->slots; slot; slot = slot->next)
@@ -205,12 +194,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 
                bridge->nr_slots++;
 
-               dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n",
-                               slot->sun, pci_domain_nr(bridge->pci_bus),
-                               bridge->pci_bus->number, slot->device);
+               dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
+                   slot->sun, pci_domain_nr(pbus), pbus->number, device);
                retval = acpiphp_register_hotplug_slot(slot);
                if (retval) {
-                       warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval);
+                       if (retval == -EBUSY)
+                               warn("Slot %llu already registered by another "
+                                       "hotplug driver\n", slot->sun);
+                       else
+                               warn("acpiphp_register_hotplug_slot failed "
+                                       "(err code = 0x%x)\n", retval);
                        goto err_exit;
                }
        }
@@ -219,26 +212,28 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        list_add_tail(&newfunc->sibling, &slot->funcs);
 
        /* associate corresponding pci_dev */
-       newfunc->pci_dev = pci_get_slot(bridge->pci_bus,
-                                        PCI_DEVFN(device, function));
+       newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
        if (newfunc->pci_dev) {
                slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
        }
 
-       /* if this is a device dependent on a dock station,
-        * associate the acpiphp_func to the dependent_device
-        * struct.
-        */
-       if ((dd = get_dependent_device(handle))) {
-               newfunc->flags |= FUNC_IS_DD;
-               /*
-                * we don't want any devices which is dependent
-                * on the dock to have it's _EJ0 method executed.
-                * because we need to run _DCK first.
+       if (is_dock_device(handle)) {
+               /* we don't want to call this device's _EJ0
+                * because we want the dock notify handler
+                * to call it after it calls _DCK
                 */
                newfunc->flags &= ~FUNC_HAS_EJ0;
-               dd->func = newfunc;
-               add_pci_dependent_device(dd);
+               if (register_hotplug_dock_device(handle,
+                       &acpiphp_dock_ops, newfunc))
+                       dbg("failed to register dock device\n");
+
+               /* we need to be notified when dock events happen
+                * outside of the hotplug operation, since we may
+                * need to do fixups before we can hotplug.
+                */
+               newfunc->nb.notifier_call = post_dock_fixups;
+               if (register_dock_notifier(&newfunc->nb))
+                       dbg("failed to register a dock notifier");
        }
 
        /* install notify handler */
@@ -266,18 +261,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 
 
 /* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle *bridge_handle)
+static int detect_ejectable_slots(struct pci_bus *pbus)
 {
-       acpi_status status;
-       int count;
-
-       count = 0;
-
-       /* only check slots defined directly below bridge object */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
-                                    is_ejectable_slot, (void *)&count, NULL);
-
-       return count;
+       int found = acpi_pci_detect_ejectable(pbus);
+       if (!found) {
+               acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus);
+               if (!bridge_handle)
+                       return 0;
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
+                                   is_pci_dock_device, (void *)&found, NULL);
+       }
+       return found;
 }
 
 
@@ -286,13 +280,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
 {
        acpi_status status;
 
-       status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp);
-       if (ACPI_FAILURE(status)) {
+       status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp);
+       if (ACPI_FAILURE(status) ||
+           !bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) {
                /* use default numbers */
-               bridge->hpp.cache_line_size = 0x10;
-               bridge->hpp.latency_timer = 0x40;
-               bridge->hpp.enable_serr = 0;
-               bridge->hpp.enable_perr = 0;
+               printk(KERN_WARNING
+                      "%s: Could not get hotplug parameters. Use defaults\n",
+                      __func__);
+               bridge->hpp.t0 = &bridge->hpp.type0_data;
+               bridge->hpp.t0->revision = 0;
+               bridge->hpp.t0->cache_line_size = 0x10;
+               bridge->hpp.t0->latency_timer = 0x40;
+               bridge->hpp.t0->enable_serr = 0;
+               bridge->hpp.t0->enable_perr = 0;
        }
 }
 
@@ -457,7 +457,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        acpi_status status;
        acpi_handle dummy_handle;
-       unsigned long tmp;
+       unsigned long long tmp;
        int device, function;
        struct pci_dev *dev;
        struct pci_bus *pci_bus = context;
@@ -468,7 +468,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
        if (ACPI_FAILURE(status)) {
-               dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
+               dbg("%s: _ADR evaluation failure\n", __func__);
                return AE_OK;
        }
 
@@ -481,8 +481,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
                goto out;
 
        /* check if this bridge has ejectable slots */
-       if ((detect_ejectable_slots(handle) > 0) ||
-               (detect_dependent_devices(handle) > 0)) {
+       if ((detect_ejectable_slots(dev->subordinate) > 0)) {
                dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
                add_p2p_bridge(handle, dev);
        }
@@ -503,7 +502,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 static int add_bridge(acpi_handle handle)
 {
        acpi_status status;
-       unsigned long tmp;
+       unsigned long long tmp;
        int seg, bus;
        acpi_handle dummy_handle;
        struct pci_bus *pci_bus;
@@ -513,7 +512,7 @@ static int add_bridge(acpi_handle handle)
        if (ACPI_SUCCESS(status)) {
                status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
                if (ACPI_FAILURE(status)) {
-                       dbg("%s: _STA evaluation failure\n", __FUNCTION__);
+                       dbg("%s: _STA evaluation failure\n", __func__);
                        return 0;
                }
                if ((tmp & ACPI_STA_FUNCTIONING) == 0)
@@ -543,7 +542,7 @@ static int add_bridge(acpi_handle handle)
        }
 
        /* check if this bridge has ejectable slots */
-       if (detect_ejectable_slots(handle) > 0) {
+       if (detect_ejectable_slots(pci_bus) > 0) {
                dbg("found PCI host-bus bridge with hot-pluggable slots\n");
                add_host_bridge(handle, pci_bus);
        }
@@ -599,6 +598,10 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                list_for_each_safe (list, tmp, &slot->funcs) {
                        struct acpiphp_func *func;
                        func = list_entry(list, struct acpiphp_func, sibling);
+                       if (is_dock_device(func->handle)) {
+                               unregister_hotplug_dock_device(func->handle);
+                               unregister_dock_notifier(&func->nb);
+                       }
                        if (!(func->flags & FUNC_HAS_DCK)) {
                                status = acpi_remove_notify_handler(func->handle,
                                                ACPI_SYSTEM_NOTIFY,
@@ -631,9 +634,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
        acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
                                cleanup_p2p_bridge, NULL, NULL);
 
-       if (!(bridge = acpiphp_handle_to_bridge(handle)))
-               return AE_OK;
-       cleanup_bridge(bridge);
+       bridge = acpiphp_handle_to_bridge(handle);
+       if (bridge)
+               cleanup_bridge(bridge);
+
        return AE_OK;
 }
 
@@ -646,9 +650,19 @@ static void remove_bridge(acpi_handle handle)
        acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
                                (u32)1, cleanup_p2p_bridge, NULL, NULL);
 
+       /*
+        * On root bridges with hotplug slots directly underneath (ie,
+        * no p2p bridge inbetween), 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);
+       else
+               acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                          handle_hotplug_event_bridge);
 }
 
 static struct pci_dev * get_apic_pci_info(acpi_handle handle)
@@ -682,7 +696,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
 {
        acpi_status status;
        int result = -1;
-       unsigned long gsb;
+       unsigned long long gsb;
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *obj;
        void *table;
@@ -702,13 +716,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
                goto out;
 
        table = obj->buffer.pointer;
-       switch (((acpi_table_entry_header *)table)->type) {
-       case ACPI_MADT_IOSAPIC:
-               *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+       switch (((struct acpi_subtable_header *)table)->type) {
+       case ACPI_MADT_TYPE_IO_SAPIC:
+               *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
                result = 0;
                break;
-       case ACPI_MADT_IOAPIC:
-               *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+       case ACPI_MADT_TYPE_IO_APIC:
+               *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
                result = 0;
                break;
        default:
@@ -723,11 +737,12 @@ static acpi_status
 ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        acpi_status status;
-       unsigned long sta;
+       unsigned long long sta;
        acpi_handle tmp;
        struct pci_dev *pdev;
        u32 gsi_base;
        u64 phys_addr;
+       struct acpiphp_ioapic *ioapic;
 
        /* Evaluate _STA if present */
        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
@@ -742,41 +757,107 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
        if (get_gsi_base(handle, &gsi_base))
                return AE_OK;
 
+       ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
+       if (!ioapic)
+               return AE_NO_MEMORY;
+
        pdev = get_apic_pci_info(handle);
        if (!pdev)
-               return AE_OK;
+               goto exit_kfree;
 
-       if (pci_enable_device(pdev)) {
-               pci_dev_put(pdev);
-               return AE_OK;
-       }
+       if (pci_enable_device(pdev))
+               goto exit_pci_dev_put;
 
        pci_set_master(pdev);
 
-       if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
-               pci_disable_device(pdev);
-               pci_dev_put(pdev);
-               return AE_OK;
-       }
+       if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
+               goto exit_pci_disable_device;
 
        phys_addr = pci_resource_start(pdev, 0);
-       if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
-               pci_release_region(pdev, 0);
-               pci_disable_device(pdev);
-               pci_dev_put(pdev);
+       if (acpi_register_ioapic(handle, phys_addr, gsi_base))
+               goto exit_pci_release_region;
+
+       ioapic->gsi_base = gsi_base;
+       ioapic->dev = pdev;
+       spin_lock(&ioapic_list_lock);
+       list_add_tail(&ioapic->list, &ioapic_list);
+       spin_unlock(&ioapic_list_lock);
+
+       return AE_OK;
+
+ exit_pci_release_region:
+       pci_release_region(pdev, 0);
+ exit_pci_disable_device:
+       pci_disable_device(pdev);
+ exit_pci_dev_put:
+       pci_dev_put(pdev);
+ exit_kfree:
+       kfree(ioapic);
+
+       return AE_OK;
+}
+
+static acpi_status
+ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       acpi_status status;
+       unsigned long long sta;
+       acpi_handle tmp;
+       u32 gsi_base;
+       struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
+
+       /* Evaluate _STA if present */
+       status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+       if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
+               return AE_CTRL_DEPTH;
+
+       /* Scan only PCI bus scope */
+       status = acpi_get_handle(handle, "_HID", &tmp);
+       if (ACPI_SUCCESS(status))
+               return AE_CTRL_DEPTH;
+
+       if (get_gsi_base(handle, &gsi_base))
                return AE_OK;
+
+       acpi_unregister_ioapic(handle, gsi_base);
+
+       spin_lock(&ioapic_list_lock);
+       list_for_each_entry_safe(pos, n, &ioapic_list, list) {
+               if (pos->gsi_base != gsi_base)
+                       continue;
+               ioapic = pos;
+               list_del(&ioapic->list);
+               break;
        }
+       spin_unlock(&ioapic_list_lock);
+
+       if (!ioapic)
+               return AE_OK;
+
+       pci_release_region(ioapic->dev, 0);
+       pci_disable_device(ioapic->dev);
+       pci_dev_put(ioapic->dev);
+       kfree(ioapic);
 
        return AE_OK;
 }
 
 static int acpiphp_configure_ioapics(acpi_handle handle)
 {
+       ioapic_add(handle, 0, NULL, NULL);
        acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
                            ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
        return 0;
 }
 
+static int acpiphp_unconfigure_ioapics(acpi_handle handle)
+{
+       ioapic_remove(handle, 0, NULL, NULL);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                           ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
+       return 0;
+}
+
 static int power_on_slot(struct acpiphp_slot *slot)
 {
        acpi_status status;
@@ -792,10 +873,10 @@ static int power_on_slot(struct acpiphp_slot *slot)
                func = list_entry(l, struct acpiphp_func, sibling);
 
                if (func->flags & FUNC_HAS_PS0) {
-                       dbg("%s: executing _PS0\n", __FUNCTION__);
+                       dbg("%s: executing _PS0\n", __func__);
                        status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
                        if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS0 failed\n", __FUNCTION__);
+                               warn("%s: _PS0 failed\n", __func__);
                                retval = -1;
                                goto err_exit;
                        } else
@@ -830,7 +911,7 @@ static int power_off_slot(struct acpiphp_slot *slot)
                if (func->flags & FUNC_HAS_PS3) {
                        status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
                        if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS3 failed\n", __FUNCTION__);
+                               warn("%s: _PS3 failed\n", __func__);
                                retval = -1;
                                goto err_exit;
                        } else
@@ -849,10 +930,8 @@ static int power_off_slot(struct acpiphp_slot *slot)
 
 
 /**
- * acpiphp_max_busnr - return the highest reserved bus number under
- * the given bus.
+ * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
- *
  */
 static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
 {
@@ -881,7 +960,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
 /**
  * acpiphp_bus_add - add a new bus to acpi subsystem
  * @func: acpiphp_func of the bridge
- *
  */
 static int acpiphp_bus_add(struct acpiphp_func *func)
 {
@@ -926,9 +1004,8 @@ acpiphp_bus_add_out:
 /**
  * acpiphp_bus_trim - trim a bus from acpi subsystem
  * @handle: handle to acpi namespace
- *
  */
-int acpiphp_bus_trim(acpi_handle handle)
+static int acpiphp_bus_trim(acpi_handle handle)
 {
        struct acpi_device *device;
        int retval;
@@ -952,9 +1029,8 @@ int acpiphp_bus_trim(acpi_handle handle)
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
- *
  */
-static int enable_device(struct acpiphp_slot *slot)
+static int __ref enable_device(struct acpiphp_slot *slot)
 {
        struct pci_dev *dev;
        struct pci_bus *bus = slot->bridge->pci_bus;
@@ -1005,10 +1081,11 @@ static int enable_device(struct acpiphp_slot *slot)
 
        pci_bus_assign_resources(bus);
        acpiphp_sanitize_bus(bus);
+       acpiphp_set_hpp_values(slot->bridge->handle, bus);
+       list_for_each_entry(func, &slot->funcs, sibling)
+               acpiphp_configure_ioapics(func->handle);
        pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
-       acpiphp_set_hpp_values(slot->bridge->handle, bus);
-       acpiphp_configure_ioapics(slot->bridge->handle);
 
        /* associate pci_dev to our representation */
        list_for_each (l, &slot->funcs) {
@@ -1034,9 +1111,20 @@ static int enable_device(struct acpiphp_slot *slot)
        return retval;
 }
 
+static void disable_bridges(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (dev->subordinate) {
+                       disable_bridges(dev->subordinate);
+                       pci_disable_device(dev);
+               }
+       }
+}
 
 /**
  * disable_device - disable a slot
+ * @slot: ACPI PHP slot
  */
 static int disable_device(struct acpiphp_slot *slot)
 {
@@ -1058,6 +1146,19 @@ static int disable_device(struct acpiphp_slot *slot)
                        func->bridge = NULL;
                }
 
+               if (func->pci_dev) {
+                       pci_stop_bus_device(func->pci_dev);
+                       if (func->pci_dev->subordinate) {
+                               disable_bridges(func->pci_dev->subordinate);
+                               pci_disable_device(func->pci_dev);
+                       }
+               }
+       }
+
+       list_for_each (l, &slot->funcs) {
+               func = list_entry(l, struct acpiphp_func, sibling);
+
+               acpiphp_unconfigure_ioapics(func->handle);
                acpiphp_bus_trim(func->handle);
                /* try to remove anyway.
                 * acpiphp_bus_add might have been failed */
@@ -1079,19 +1180,20 @@ static int disable_device(struct acpiphp_slot *slot)
 
 /**
  * get_slot_status - get ACPI slot status
+ * @slot: ACPI PHP slot
  *
- * if a slot has _STA for each function and if any one of them
- * returned non-zero status, return it
+ * If a slot has _STA for each function and if any one of them
+ * returned non-zero status, return it.
  *
- * if a slot doesn't have _STA and if any one of its functions'
- * configuration space is configured, return 0x0f as a _STA
+ * If a slot doesn't have _STA and if any one of its functions'
+ * configuration space is configured, return 0x0f as a _STA.
  *
- * otherwise return 0
+ * Otherwise return 0.
  */
 static unsigned int get_slot_status(struct acpiphp_slot *slot)
 {
        acpi_status status;
-       unsigned long sta = 0;
+       unsigned long long sta = 0;
        u32 dvid;
        struct list_head *l;
        struct acpiphp_func *func;
@@ -1120,8 +1222,9 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
 
 /**
  * acpiphp_eject_slot - physically eject the slot
+ * @slot: ACPI PHP slot
  */
-static int acpiphp_eject_slot(struct acpiphp_slot *slot)
+int acpiphp_eject_slot(struct acpiphp_slot *slot)
 {
        acpi_status status;
        struct acpiphp_func *func;
@@ -1142,7 +1245,7 @@ static int acpiphp_eject_slot(struct acpiphp_slot *slot)
 
                        status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
                        if (ACPI_FAILURE(status)) {
-                               warn("%s: _EJ0 failed\n", __FUNCTION__);
+                               warn("%s: _EJ0 failed\n", __func__);
                                return -1;
                        } else
                                break;
@@ -1153,6 +1256,7 @@ static int acpiphp_eject_slot(struct acpiphp_slot *slot)
 
 /**
  * acpiphp_check_bridge - re-enumerate devices
+ * @bridge: where to begin re-enumeration
  *
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
@@ -1190,7 +1294,7 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                }
        }
 
-       dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
+       dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
 
  err_exit:
        return retval;
@@ -1206,16 +1310,20 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
                        (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
                return;
+
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+               return;
+
        pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-                       bridge->hpp.cache_line_size);
+                       bridge->hpp.t0->cache_line_size);
        pci_write_config_byte(dev, PCI_LATENCY_TIMER,
-                       bridge->hpp.latency_timer);
+                       bridge->hpp.t0->latency_timer);
        pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
-       if (bridge->hpp.enable_serr)
+       if (bridge->hpp.t0->enable_serr)
                pci_cmd |= PCI_COMMAND_SERR;
        else
                pci_cmd &= ~PCI_COMMAND_SERR;
-       if (bridge->hpp.enable_perr)
+       if (bridge->hpp.t0->enable_perr)
                pci_cmd |= PCI_COMMAND_PARITY;
        else
                pci_cmd &= ~PCI_COMMAND_PARITY;
@@ -1224,13 +1332,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
        /* Program bridge control value and child devices */
        if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
-                               bridge->hpp.latency_timer);
+                               bridge->hpp.t0->latency_timer);
                pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
-               if (bridge->hpp.enable_serr)
+               if (bridge->hpp.t0->enable_serr)
                        pci_bctl |= PCI_BRIDGE_CTL_SERR;
                else
                        pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
-               if (bridge->hpp.enable_perr)
+               if (bridge->hpp.t0->enable_perr)
                        pci_bctl |= PCI_BRIDGE_CTL_PARITY;
                else
                        pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
@@ -1250,6 +1358,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
 
        memset(&bridge, 0, sizeof(bridge));
        bridge.handle = handle;
+       bridge.pci_bus = bus;
        bridge.pci_dev = bus->self;
        decode_hpp(&bridge);
        list_for_each_entry(dev, &bus->devices, bus_list)
@@ -1339,15 +1448,43 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
  * ACPI event handlers
  */
 
+static acpi_status
+count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       int *count = (int *)context;
+       struct acpiphp_bridge *bridge;
+
+       bridge = acpiphp_handle_to_bridge(handle);
+       if (bridge)
+               (*count)++;
+       return AE_OK ;
+}
+
+static acpi_status
+check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       struct acpiphp_bridge *bridge;
+       char objname[64];
+       struct acpi_buffer buffer = { .length = sizeof(objname),
+                                     .pointer = objname };
+
+       bridge = acpiphp_handle_to_bridge(handle);
+       if (bridge) {
+               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+               dbg("%s: re-enumerating slots under %s\n",
+                       __func__, objname);
+               acpiphp_check_bridge(bridge);
+       }
+       return AE_OK ;
+}
+
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
- *
  * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_bridge structure
  *
- * handles ACPI event notification on {host,p2p} bridges
- *
+ * Handles ACPI event notification on {host,p2p} bridges.
  */
 static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context)
 {
@@ -1356,6 +1493,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
        struct acpi_buffer buffer = { .length = sizeof(objname),
                                      .pointer = objname };
        struct acpi_device *device;
+       int num_sub_bridges = 0;
 
        if (acpi_bus_get_device(handle, &device)) {
                /* This bridge must have just been physically inserted */
@@ -1364,7 +1502,12 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
        }
 
        bridge = acpiphp_handle_to_bridge(handle);
-       if (!bridge) {
+       if (type == ACPI_NOTIFY_BUS_CHECK) {
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
+                       count_sub_bridges, &num_sub_bridges, NULL);
+       }
+
+       if (!bridge && !num_sub_bridges) {
                err("cannot get bridge info\n");
                return;
        }
@@ -1374,24 +1517,31 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
                /* bus re-enumerate */
-               dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
-               acpiphp_check_bridge(bridge);
+               dbg("%s: Bus check notify on %s\n", __func__, objname);
+               if (bridge) {
+                       dbg("%s: re-enumerating slots under %s\n",
+                               __func__, objname);
+                       acpiphp_check_bridge(bridge);
+               }
+               if (num_sub_bridges)
+                       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                               ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL);
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
-               dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device check notify on %s\n", __func__, objname);
                acpiphp_check_bridge(bridge);
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
                /* wake event */
-               dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device wake notify on %s\n", __func__, objname);
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
-               dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device eject notify on %s\n", __func__, objname);
                if ((bridge->type != BRIDGE_TYPE_HOST) &&
                    (bridge->flags & BRIDGE_HAS_EJ0)) {
                        struct acpiphp_slot *slot;
@@ -1424,15 +1574,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
 
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
- *
  * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_func structure
  *
- * handles ACPI event notification on slots
- *
+ * Handles ACPI event notification on slots.
  */
-void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
+static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
 {
        struct acpiphp_func *func;
        char objname[64];
@@ -1446,24 +1594,24 @@ void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
                /* bus re-enumerate */
-               dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Bus check notify on %s\n", __func__, objname);
                acpiphp_enable_slot(func->slot);
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check : re-enumerate from parent bus */
-               dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device check notify on %s\n", __func__, objname);
                acpiphp_check_bridge(func->slot->bridge);
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
                /* wake event */
-               dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device wake notify on %s\n", __func__, objname);
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
-               dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
+               dbg("%s: Device eject notify on %s\n", __func__, objname);
                if (!(acpiphp_disable_slot(func->slot)))
                        acpiphp_eject_slot(func->slot);
                break;
@@ -1495,7 +1643,6 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
 
 /**
  * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
- *
  */
 int __init acpiphp_glue_init(void)
 {
@@ -1516,9 +1663,9 @@ int __init acpiphp_glue_init(void)
 /**
  * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
  *
- * This function frees all data allocated in acpiphp_glue_init()
+ * This function frees all data allocated in acpiphp_glue_init().
  */
-void __exit acpiphp_glue_exit(void)
+void  acpiphp_glue_exit(void)
 {
        acpi_pci_unregister_driver(&acpi_pci_hp_driver);
 }
@@ -1529,14 +1676,10 @@ void __exit acpiphp_glue_exit(void)
  */
 int __init acpiphp_get_num_slots(void)
 {
-       struct list_head *node;
        struct acpiphp_bridge *bridge;
-       int num_slots;
-
-       num_slots = 0;
+       int num_slots = 0;
 
-       list_for_each (node, &bridge_list) {
-               bridge = (struct acpiphp_bridge *)node;
+       list_for_each_entry (bridge, &bridge_list, list) {
                dbg("Bus %04x:%02x has %d slot%s\n",
                                pci_domain_nr(bridge->pci_bus),
                                bridge->pci_bus->number, bridge->nr_slots,
@@ -1554,7 +1697,6 @@ int __init acpiphp_get_num_slots(void)
  * acpiphp_for_each_slot - call function for each slot
  * @fn: callback function
  * @data: context to be passed to callback function
- *
  */
 static int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
 {
@@ -1580,6 +1722,7 @@ static int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
 
 /**
  * acpiphp_enable_slot - power on slot
+ * @slot: ACPI PHP slot
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
@@ -1598,7 +1741,7 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
                if (retval)
                        power_off_slot(slot);
        } else {
-               dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__);
+               dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
                power_off_slot(slot);
        }
 
@@ -1609,6 +1752,7 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
 
 /**
  * acpiphp_disable_slot - power off slot
+ * @slot: ACPI PHP slot
  */
 int acpiphp_disable_slot(struct acpiphp_slot *slot)
 {
@@ -1643,8 +1787,8 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 
 
 /*
- * latch closed:  1
- * latch   open:  0
+ * latch   open:  1
+ * latch closed:  0
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
@@ -1652,7 +1796,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 
        sta = get_slot_status(slot);
 
-       return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
+       return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
 }
 
 
@@ -1668,19 +1812,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 
        return (sta == 0) ? 0 : 1;
 }
-
-
-/*
- * pci address (seg/bus/dev)
- */
-u32 acpiphp_get_address(struct acpiphp_slot *slot)
-{
-       u32 address;
-       struct pci_bus *pci_bus = slot->bridge->pci_bus;
-
-       address = (pci_domain_nr(pci_bus) << 16) |
-                 (pci_bus->number << 8) |
-                 slot->device;
-
-       return address;
-}