aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-02-23 18:08:28 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-02-23 18:08:28 -0800
commit1dce1769c917763023a00ca2d66ff6d50ed0962b (patch)
treedf79fcf25427f4a49a46662698117b2ca765ea51
parent84a09ac6babf889cf41a4325c272a508dc57899b (diff)
downloadpatches-1dce1769c917763023a00ca2d66ff6d50ed0962b.tar.gz
pci acpi hotplug patches
-rw-r--r--pci/acpi-export-acpi_bus_trim.patch58
-rw-r--r--pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch114
-rw-r--r--pci/acpiphp-add-dock-event-handling.patch749
-rw-r--r--pci/acpiphp-add-new-bus-to-acpi.patch157
-rw-r--r--pci/acpiphp-slot-management-fix-v4.patch343
-rw-r--r--series6
6 files changed, 1427 insertions, 0 deletions
diff --git a/pci/acpi-export-acpi_bus_trim.patch b/pci/acpi-export-acpi_bus_trim.patch
new file mode 100644
index 0000000000000..babff977b1732
--- /dev/null
+++ b/pci/acpi-export-acpi_bus_trim.patch
@@ -0,0 +1,58 @@
+From kristen.c.accardi@intel.com Thu Feb 23 17:58:20 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+To: greg@kroah.com
+Subject: [patch 2/5] acpi: export acpi_bus_trim
+Date: Thu, 23 Feb 2006 17:56:01 -0800
+Message-Id: <1140746161.11750.76.camel@whizzy>
+
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+
+Export the acpi_bus_trim function so that the pci hotplug driver can
+use it.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/scan.c | 5 +++--
+ include/acpi/acpi_bus.h | 1 +
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/acpi/scan.c
++++ gregkh-2.6/drivers/acpi/scan.c
+@@ -23,7 +23,6 @@ static LIST_HEAD(acpi_device_list);
+ DEFINE_SPINLOCK(acpi_device_lock);
+ LIST_HEAD(acpi_wakeup_device_list);
+
+-static int acpi_bus_trim(struct acpi_device *start, int rmdevice);
+
+ static void acpi_device_release(struct kobject *kobj)
+ {
+@@ -1284,7 +1283,7 @@ int acpi_bus_start(struct acpi_device *d
+
+ EXPORT_SYMBOL(acpi_bus_start);
+
+-static int acpi_bus_trim(struct acpi_device *start, int rmdevice)
++int acpi_bus_trim(struct acpi_device *start, int rmdevice)
+ {
+ acpi_status status;
+ struct acpi_device *parent, *child;
+@@ -1337,6 +1336,8 @@ static int acpi_bus_trim(struct acpi_dev
+ }
+ return err;
+ }
++EXPORT_SYMBOL_GPL(acpi_bus_trim);
++
+
+ static int acpi_bus_scan_fixed(struct acpi_device *root)
+ {
+--- gregkh-2.6.orig/include/acpi/acpi_bus.h
++++ gregkh-2.6/include/acpi/acpi_bus.h
+@@ -330,6 +330,7 @@ int acpi_bus_register_driver(struct acpi
+ int acpi_bus_unregister_driver(struct acpi_driver *driver);
+ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
+ acpi_handle handle, int type);
++int acpi_bus_trim(struct acpi_device *start, int rmdevice);
+ int acpi_bus_start(struct acpi_device *device);
+
+ int acpi_match_ids(struct acpi_device *device, char *ids);
diff --git a/pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch b/pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch
new file mode 100644
index 0000000000000..1015de1e73052
--- /dev/null
+++ b/pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch
@@ -0,0 +1,114 @@
+From kristen.c.accardi@intel.com Thu Feb 23 17:59:27 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: [patch 4/5] acpi: remove dock event handling from ibm_acpi
+To: greg@kroah.com
+Date: Thu, 23 Feb 2006 17:56:06 -0800
+Message-Id: <1140746166.11750.78.camel@whizzy>
+
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+
+Remove dock station support from ibm_acpi by default. This support has
+been put into acpiphp instead. Allow ibm_acpi to continue to provide
+docking station support via config option for laptops/docking stations
+that are not supported by acpiphp.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/Kconfig | 12 ++++++++++++
+ drivers/acpi/ibm_acpi.c | 13 ++++++++++---
+ 2 files changed, 22 insertions(+), 3 deletions(-)
+
+--- gregkh-2.6.orig/drivers/acpi/Kconfig
++++ gregkh-2.6/drivers/acpi/Kconfig
+@@ -205,6 +205,18 @@ config ACPI_IBM
+
+ If you have an IBM ThinkPad laptop, say Y or M here.
+
++config ACPI_IBM_DOCK
++ bool "Legacy Docking Station Support"
++ depends on ACPI_IBM
++ default n
++ ---help---
++ Allows the ibm_acpi driver to handle docking station events.
++ This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will
++ allow locking and removing the laptop from the docking station,
++ but will not properly connect PCI devices.
++
++ If you are not sure, say N here.
++
+ config ACPI_TOSHIBA
+ tristate "Toshiba Laptop Extras"
+ depends on X86
+--- gregkh-2.6.orig/drivers/acpi/ibm_acpi.c
++++ gregkh-2.6/drivers/acpi/ibm_acpi.c
+@@ -160,13 +160,13 @@ IBM_HANDLE(cmos, root, "\\UCMS", /* R50,
+ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
+ "\\CMS", /* R40, R40e */
+ ); /* all others */
+-
++#ifdef CONFIG_ACPI_IBM_DOCK
+ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
+ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
+ "\\_SB.PCI0.PCI1.DOCK", /* all others */
+ "\\_SB.PCI.ISA.SLCE", /* 570 */
+ ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
+-
++#endif
+ IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
+ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
+@@ -844,7 +844,7 @@ static int _sta(acpi_handle handle)
+
+ return status;
+ }
+-
++#ifdef CONFIG_ACPI_IBM_DOCK
+ #define dock_docked() (_sta(dock_handle) & 1)
+
+ static int dock_read(char *p)
+@@ -907,6 +907,7 @@ static void dock_notify(struct ibm_struc
+ acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
+ }
+ }
++#endif
+
+ static int bay_status_supported;
+ static int bay_status2_supported;
+@@ -1574,6 +1575,7 @@ static struct ibm_struct ibms[] = {
+ .read = light_read,
+ .write = light_write,
+ },
++#ifdef CONFIG_ACPI_IBM_DOCK
+ {
+ .name = "dock",
+ .read = dock_read,
+@@ -1589,6 +1591,7 @@ static struct ibm_struct ibms[] = {
+ .handle = &pci_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
++#endif
+ {
+ .name = "bay",
+ .init = bay_init,
+@@ -1880,7 +1883,9 @@ IBM_PARAM(hotkey);
+ IBM_PARAM(bluetooth);
+ IBM_PARAM(video);
+ IBM_PARAM(light);
++#ifdef CONFIG_ACPI_IBM_DOCK
+ IBM_PARAM(dock);
++#endif
+ IBM_PARAM(bay);
+ IBM_PARAM(cmos);
+ IBM_PARAM(led);
+@@ -1927,7 +1932,9 @@ static int __init acpi_ibm_init(void)
+ IBM_HANDLE_INIT(hkey);
+ IBM_HANDLE_INIT(lght);
+ IBM_HANDLE_INIT(cmos);
++#ifdef CONFIG_ACPI_IBM_DOCK
+ IBM_HANDLE_INIT(dock);
++#endif
+ IBM_HANDLE_INIT(pci);
+ IBM_HANDLE_INIT(bay);
+ if (bay_handle)
diff --git a/pci/acpiphp-add-dock-event-handling.patch b/pci/acpiphp-add-dock-event-handling.patch
new file mode 100644
index 0000000000000..064b4d117ab57
--- /dev/null
+++ b/pci/acpiphp-add-dock-event-handling.patch
@@ -0,0 +1,749 @@
+From kristen.c.accardi@intel.com Thu Feb 23 17:58:57 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: [patch 3/5] acpiphp: add dock event handling
+To: greg@kroah.com
+Date: Thu, 23 Feb 2006 17:56:03 -0800
+Message-Id: <1140746163.11750.77.camel@whizzy>
+
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+
+These patches add generic dock event handling to acpiphp. If there are
+pci devices that need to be inserted/removed after the dock event, the
+event notification will be handed down to the normal pci hotplug event
+handler in acpiphp so that new bridges/devices can be enumerated.
+
+Because some dock stations do not have pci bridges or pci devices that
+need to be inserted after a dock, acpiphp will remain loaded to handle
+dock events even if no hotpluggable pci slots are discovered.
+
+You probably need to have the pci=assign-busses kernel parameter enabled
+to use these patches, and you may not allow ibm_acpi to handle docking
+notifications and use this patch.
+
+This patch incorporates feedback provided by many.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/hotplug/Makefile | 3
+ drivers/pci/hotplug/acpiphp.h | 36 +++
+ drivers/pci/hotplug/acpiphp_core.c | 7
+ drivers/pci/hotplug/acpiphp_dock.c | 438 +++++++++++++++++++++++++++++++++++++
+ drivers/pci/hotplug/acpiphp_glue.c | 85 +++++--
+ 5 files changed, 545 insertions(+), 24 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h
+@@ -161,6 +161,25 @@ struct acpiphp_attention_info
+ struct module *owner;
+ };
+
++
++struct dependent_device {
++ struct list_head device_list;
++ struct list_head pci_list;
++ acpi_handle handle;
++ struct acpiphp_func *func;
++};
++
++
++struct acpiphp_dock_station {
++ acpi_handle handle;
++ u32 last_dock_time;
++ u32 flags;
++ struct acpiphp_func *dock_bridge;
++ struct list_head dependent_devices;
++ struct list_head pci_dependent_devices;
++};
++
++
+ /* PCI bus bridge HID */
+ #define ACPI_PCI_HOST_HID "PNP0A03"
+
+@@ -198,6 +217,12 @@ struct acpiphp_attention_info
+ #define FUNC_HAS_PS1 (0x00000020)
+ #define FUNC_HAS_PS2 (0x00000040)
+ #define FUNC_HAS_PS3 (0x00000080)
++#define FUNC_HAS_DCK (0x00000100)
++#define FUNC_IS_DD (0x00000200)
++
++/* dock station flags */
++#define DOCK_DOCKING (0x00000001)
++#define DOCK_HAS_BRIDGE (0x00000002)
+
+ /* function prototypes */
+
+@@ -211,6 +236,7 @@ extern void acpiphp_glue_exit (void);
+ extern int acpiphp_get_num_slots (void);
+ extern struct acpiphp_slot *get_slot_from_id (int id);
+ typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
++void handle_hotplug_event_func(acpi_handle, u32, void*);
+
+ extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
+ extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
+@@ -220,6 +246,16 @@ extern u8 acpiphp_get_latch_status (stru
+ extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+ extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
+
++/* acpiphp_dock.c */
++extern int find_dock_station(void);
++extern void remove_dock_station(void);
++extern void add_dependent_device(struct dependent_device *new_dd);
++extern void add_pci_dependent_device(struct dependent_device *new_dd);
++extern struct dependent_device *get_dependent_device(acpi_handle handle);
++extern int is_dependent_device(acpi_handle handle);
++extern int detect_dependent_devices(acpi_handle *bridge_handle);
++extern struct dependent_device *alloc_dependent_device(acpi_handle handle);
++
+ /* variables */
+ extern int acpiphp_debug;
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_core.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_core.c
+@@ -429,14 +429,17 @@ static void __exit cleanup_slots (void)
+ static int __init acpiphp_init(void)
+ {
+ int retval;
++ int docking_station;
+
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+ acpiphp_debug = debug;
+
++ docking_station = find_dock_station();
++
+ /* read all the ACPI info from the system */
+ retval = init_acpi();
+- if (retval)
++ if (retval && !(docking_station))
+ return retval;
+
+ return init_slots();
+@@ -448,6 +451,8 @@ static void __exit acpiphp_exit(void)
+ cleanup_slots();
+ /* deallocate internal data structures etc. */
+ acpiphp_glue_exit();
++
++ remove_dock_station();
+ }
+
+ module_init(acpiphp_init);
+--- /dev/null
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_dock.c
+@@ -0,0 +1,438 @@
++/*
++ * ACPI PCI HotPlug dock functions to ACPI CA subsystem
++ *
++ * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com)
++ * Copyright (C) 2006 Intel Corporation
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
++ * NON INFRINGEMENT. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Send feedback to <kristen.c.accardi@intel.com>
++ *
++ */
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/smp_lock.h>
++#include <linux/mutex.h>
++
++#include "../pci.h"
++#include "pci_hotplug.h"
++#include "acpiphp.h"
++
++static struct acpiphp_dock_station *ds;
++#define MY_NAME "acpiphp_dock"
++
++
++int is_dependent_device(acpi_handle handle)
++{
++ return (get_dependent_device(handle) ? 1 : 0);
++}
++
++
++static acpi_status
++find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv)
++{
++ int *count = (int *)context;
++
++ if (is_dependent_device(handle)) {
++ (*count)++;
++ return AE_CTRL_TERMINATE;
++ } else {
++ return AE_OK;
++ }
++}
++
++
++
++
++void add_dependent_device(struct dependent_device *new_dd)
++{
++ list_add_tail(&new_dd->device_list, &ds->dependent_devices);
++}
++
++
++void add_pci_dependent_device(struct dependent_device *new_dd)
++{
++ list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices);
++}
++
++
++
++struct dependent_device * get_dependent_device(acpi_handle handle)
++{
++ struct dependent_device *dd;
++
++ if (!ds)
++ return NULL;
++
++ list_for_each_entry(dd, &ds->dependent_devices, device_list) {
++ if (handle == dd->handle)
++ return dd;
++ }
++ return NULL;
++}
++
++
++
++struct dependent_device *alloc_dependent_device(acpi_handle handle)
++{
++ struct dependent_device *dd;
++
++ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
++ if (dd) {
++ INIT_LIST_HEAD(&dd->pci_list);
++ INIT_LIST_HEAD(&dd->device_list);
++ dd->handle = handle;
++ }
++ return dd;
++}
++
++
++
++static int is_dock(acpi_handle handle)
++{
++ acpi_status status;
++ acpi_handle tmp;
++
++ status = acpi_get_handle(handle, "_DCK", &tmp);
++ if (ACPI_FAILURE(status)) {
++ return 0;
++ }
++ return 1;
++}
++
++
++
++static int dock_present(void)
++{
++ unsigned long sta;
++ acpi_status status;
++
++ if (ds) {
++ status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
++ if (ACPI_SUCCESS(status) && sta)
++ return 1;
++ }
++ return 0;
++}
++
++
++
++static void eject_dock(void)
++{
++ struct acpi_object_list arg_list;
++ union acpi_object arg;
++
++ arg_list.count = 1;
++ arg_list.pointer = &arg;
++ arg.type = ACPI_TYPE_INTEGER;
++ arg.integer.value = 1;
++
++ if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
++ &arg_list, NULL)) || dock_present())
++ warn("%s: failed to eject dock!\n", __FUNCTION__);
++
++ return;
++}
++
++
++
++
++static acpi_status handle_dock(int dock)
++{
++ acpi_status status;
++ struct acpi_object_list arg_list;
++ union acpi_object arg;
++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
++
++ dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking");
++
++ /* _DCK method has one argument */
++ arg_list.count = 1;
++ arg_list.pointer = &arg;
++ arg.type = ACPI_TYPE_INTEGER;
++ arg.integer.value = dock;
++ status = acpi_evaluate_object(ds->handle, "_DCK",
++ &arg_list, &buffer);
++ if (ACPI_FAILURE(status))
++ err("%s: failed to execute _DCK\n", __FUNCTION__);
++ acpi_os_free(buffer.pointer);
++
++ return status;
++}
++
++
++
++static inline void dock(void)
++{
++ handle_dock(1);
++}
++
++
++
++static inline void undock(void)
++{
++ handle_dock(0);
++}
++
++
++
++/*
++ * 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 void post_dock_fixups(void)
++{
++ struct pci_bus *bus;
++ u32 buses;
++ struct dependent_device *dd;
++
++ list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) {
++ bus = dd->func->slot->bridge->pci_bus;
++
++ /* 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);
++ }
++ }
++}
++
++
++
++static void hotplug_pci(u32 type)
++{
++ struct dependent_device *dd;
++
++ list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list)
++ handle_hotplug_event_func(dd->handle, type, dd->func);
++}
++
++
++
++static inline void begin_dock(void)
++{
++ ds->flags |= DOCK_DOCKING;
++}
++
++
++static inline void complete_dock(void)
++{
++ ds->flags &= ~(DOCK_DOCKING);
++ ds->last_dock_time = jiffies;
++}
++
++
++static int dock_in_progress(void)
++{
++ if (ds->flags & DOCK_DOCKING ||
++ ds->last_dock_time == jiffies) {
++ dbg("dock in progress\n");
++ return 1;
++ }
++ return 0;
++}
++
++
++
++static void
++handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
++{
++ dbg("%s: enter\n", __FUNCTION__);
++
++ switch (type) {
++ case ACPI_NOTIFY_BUS_CHECK:
++ dbg("BUS Check\n");
++ if (!dock_in_progress() && dock_present()) {
++ begin_dock();
++ dock();
++ if (!dock_present()) {
++ err("Unable to dock!\n");
++ break;
++ }
++ post_dock_fixups();
++ hotplug_pci(type);
++ complete_dock();
++ }
++ break;
++ case ACPI_NOTIFY_EJECT_REQUEST:
++ dbg("EJECT request\n");
++ if (!dock_in_progress() && dock_present()) {
++ hotplug_pci(type);
++ undock();
++ eject_dock();
++ if (dock_present())
++ err("Unable to undock!\n");
++ }
++ break;
++ }
++}
++
++
++
++
++static acpi_status
++find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
++{
++ acpi_status status;
++ acpi_handle tmp;
++ acpi_handle dck_handle = (acpi_handle) context;
++ char objname[64];
++ struct acpi_buffer buffer = { .length = sizeof(objname),
++ .pointer = objname };
++ struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
++ union acpi_object *ejd_obj;
++
++ status = acpi_get_handle(handle, "_EJD", &tmp);
++ if (ACPI_FAILURE(status))
++ return AE_OK;
++
++ /* make sure we are dependent on the dock device,
++ * by executing the _EJD method, then getting a handle
++ * to the device referenced by that name. If that
++ * device handle is the same handle as the dock station
++ * handle, then we are a device dependent on the dock station
++ */
++ acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
++ status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
++ if (ACPI_FAILURE(status)) {
++ err("Unable to execute _EJD!\n");
++ goto find_ejd_out;
++ }
++ ejd_obj = ejd_buffer.pointer;
++ status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp);
++ if (ACPI_FAILURE(status))
++ goto find_ejd_out;
++
++ if (tmp == dck_handle) {
++ struct dependent_device *dd;
++ dbg("%s: found device dependent on dock\n", __FUNCTION__);
++ dd = alloc_dependent_device(handle);
++ if (!dd) {
++ err("Can't allocate memory for dependent device!\n");
++ goto find_ejd_out;
++ }
++ add_dependent_device(dd);
++ }
++
++find_ejd_out:
++ acpi_os_free(ejd_buffer.pointer);
++ return AE_OK;
++}
++
++
++
++int detect_dependent_devices(acpi_handle *bridge_handle)
++{
++ acpi_status status;
++ int count;
++
++ count = 0;
++
++ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
++ (u32)1, find_dependent_device,
++ (void *)&count, NULL);
++
++ return count;
++}
++
++
++
++
++
++static acpi_status
++find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
++{
++ int *count = (int *)context;
++
++ if (is_dock(handle)) {
++ dbg("%s: found dock\n", __FUNCTION__);
++ ds = kzalloc(sizeof(*ds), GFP_KERNEL);
++ ds->handle = handle;
++ INIT_LIST_HEAD(&ds->dependent_devices);
++ INIT_LIST_HEAD(&ds->pci_dependent_devices);
++
++ /* look for devices dependent on dock station */
++ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
++ ACPI_UINT32_MAX, find_dock_ejd, handle, NULL);
++
++ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
++ handle_hotplug_event_dock, ds);
++ (*count)++;
++ }
++
++ return AE_OK;
++}
++
++
++
++
++int find_dock_station(void)
++{
++ int num = 0;
++
++ ds = NULL;
++
++ /* start from the root object, because some laptops define
++ * _DCK methods outside the scope of PCI (IBM x-series laptop)
++ */
++ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
++ ACPI_UINT32_MAX, find_dock, &num, NULL);
++
++ return num;
++}
++
++
++
++void remove_dock_station(void)
++{
++ struct dependent_device *dd, *tmp;
++ if (ds) {
++ if (ACPI_FAILURE(acpi_remove_notify_handler(ds->handle,
++ ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
++ err("failed to remove dock notify handler\n");
++
++ /* free all dependent devices */
++ list_for_each_entry_safe(dd, tmp, &ds->dependent_devices,
++ device_list)
++ kfree(dd);
++
++ /* no need to touch the pci_dependent_device list,
++ * cause all memory was freed above
++ */
++ kfree(ds);
++ }
++}
++
++
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_glue.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_glue.c
+@@ -57,7 +57,6 @@ static LIST_HEAD(bridge_list);
+ #define MY_NAME "acpiphp_glue"
+
+ static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+-static void handle_hotplug_event_func (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);
+
+@@ -125,6 +124,7 @@ register_slot(acpi_handle handle, u32 lv
+ 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;
+@@ -138,7 +138,7 @@ register_slot(acpi_handle handle, u32 lv
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+
+- if (ACPI_FAILURE(status))
++ if (ACPI_FAILURE(status) && !(is_dependent_device(handle)))
+ return AE_OK;
+
+ device = (adr >> 16) & 0xffff;
+@@ -152,7 +152,8 @@ register_slot(acpi_handle handle, u32 lv
+ INIT_LIST_HEAD(&newfunc->sibling);
+ newfunc->handle = handle;
+ newfunc->function = function;
+- newfunc->flags = FUNC_HAS_EJ0;
++ if (ACPI_SUCCESS(status))
++ newfunc->flags = FUNC_HAS_EJ0;
+
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+ newfunc->flags |= FUNC_HAS_STA;
+@@ -163,6 +164,19 @@ register_slot(acpi_handle handle, u32 lv
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
+ newfunc->flags |= FUNC_HAS_PS3;
+
++ 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;
+@@ -210,18 +224,35 @@ register_slot(acpi_handle handle, u32 lv
+ 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.
++ */
++ newfunc->flags &= ~FUNC_HAS_EJ0;
++ dd->func = newfunc;
++ add_pci_dependent_device(dd);
++ }
++
+ /* install notify handler */
+- status = acpi_install_notify_handler(handle,
++ if (!(newfunc->flags & FUNC_HAS_DCK)) {
++ status = acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_func,
+ newfunc);
+
+- if (ACPI_FAILURE(status)) {
+- err("failed to register interrupt notify handler\n");
+- return status;
+- }
++ if (ACPI_FAILURE(status))
++ err("failed to register interrupt notify handler\n");
++ } else
++ status = AE_OK;
+
+- return AE_OK;
++ return status;
+ }
+
+
+@@ -410,7 +441,8 @@ find_p2p_bridge(acpi_handle handle, u32
+ goto out;
+
+ /* check if this bridge has ejectable slots */
+- if (detect_ejectable_slots(handle) > 0) {
++ if ((detect_ejectable_slots(handle) > 0) ||
++ (detect_dependent_devices(handle) > 0)) {
+ dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
+ add_p2p_bridge(handle, dev);
+ }
+@@ -512,11 +544,13 @@ static void cleanup_bridge(struct acpiph
+ list_for_each_safe (list, tmp, &slot->funcs) {
+ struct acpiphp_func *func;
+ func = list_entry(list, struct acpiphp_func, sibling);
+- status = acpi_remove_notify_handler(func->handle,
++ if (!(func->flags & FUNC_HAS_DCK)) {
++ status = acpi_remove_notify_handler(func->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_func);
+- if (ACPI_FAILURE(status))
+- err("failed to remove notify handler\n");
++ if (ACPI_FAILURE(status))
++ err("failed to remove notify handler\n");
++ }
+ pci_dev_put(func->pci_dev);
+ list_del(list);
+ kfree(func);
+@@ -828,14 +862,21 @@ static int acpiphp_bus_add(struct acpiph
+ dbg("no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+- if (acpi_bus_get_device(func->handle, &device)) {
+- ret_val = acpi_bus_add(&device, pdevice, func->handle,
+- ACPI_BUS_TYPE_DEVICE);
+- if (ret_val) {
+- dbg("error adding bus, %x\n",
+- -ret_val);
+- goto acpiphp_bus_add_out;
+- }
++ if (!acpi_bus_get_device(func->handle, &device)) {
++ dbg("bus exists... trim\n");
++ /* this shouldn't be in here, so remove
++ * the bus then re-add it...
++ */
++ ret_val = acpi_bus_trim(device, 1);
++ dbg("acpi_bus_trim return %x\n", ret_val);
++ }
++
++ ret_val = acpi_bus_add(&device, pdevice, func->handle,
++ ACPI_BUS_TYPE_DEVICE);
++ if (ret_val) {
++ dbg("error adding bus, %x\n",
++ -ret_val);
++ goto acpiphp_bus_add_out;
+ }
+ /*
+ * try to start anyway. We could have failed to add
+@@ -1307,7 +1348,7 @@ static void handle_hotplug_event_bridge(
+ * handles ACPI event notification on slots
+ *
+ */
+-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
++void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
+ {
+ struct acpiphp_func *func;
+ char objname[64];
+--- gregkh-2.6.orig/drivers/pci/hotplug/Makefile
++++ gregkh-2.6/drivers/pci/hotplug/Makefile
+@@ -37,7 +37,8 @@ ibmphp-objs := ibmphp_core.o \
+ ibmphp_hpc.o
+
+ acpiphp-objs := acpiphp_core.o \
+- acpiphp_glue.o
++ acpiphp_glue.o \
++ acpiphp_dock.o
+
+ rpaphp-objs := rpaphp_core.o \
+ rpaphp_pci.o \
diff --git a/pci/acpiphp-add-new-bus-to-acpi.patch b/pci/acpiphp-add-new-bus-to-acpi.patch
new file mode 100644
index 0000000000000..7d437fd58365c
--- /dev/null
+++ b/pci/acpiphp-add-new-bus-to-acpi.patch
@@ -0,0 +1,157 @@
+From kristen.c.accardi@intel.com Thu Feb 23 17:56:35 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+To: greg@kroah.com
+Subject: [patch 1/5] acpiphp: add new bus to acpi
+Date: Thu, 23 Feb 2006 17:55:58 -0800
+Message-Id: <1140746158.11750.75.camel@whizzy>
+
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+
+If we add a new bridge with subordinate busses, we should call make sure
+that acpi is notified so that the PRT (if present) can be read and drivers
+who have registered on this bus will be notified when it is started.
+Also make sure to use the max reserved bus number for the starting the bus
+scan.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/hotplug/acpiphp_glue.c | 111 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 109 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_glue.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_glue.c
+@@ -751,6 +751,106 @@ static int power_off_slot(struct acpiphp
+ }
+
+
++
++/**
++ * 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)
++{
++ struct list_head *tmp;
++ unsigned char max, n;
++
++ /*
++ * pci_bus_max_busnr will return the highest
++ * reserved busnr for all these children.
++ * that is equivalent to the bus->subordinate
++ * value. We don't want to use the parent's
++ * bus->subordinate value because it could have
++ * padding in it.
++ */
++ max = bus->secondary;
++
++ list_for_each(tmp, &bus->children) {
++ n = pci_bus_max_busnr(pci_bus_b(tmp));
++ if (n > max)
++ max = n;
++ }
++ return max;
++}
++
++
++
++/**
++ * get_func - get a pointer to acpiphp_func given a slot, device
++ * @slot: slot to search
++ * @dev: pci_dev struct to match.
++ *
++ * This function will increase the reference count of pci_dev,
++ * so callers should call pci_dev_put when complete.
++ *
++ */
++static struct acpiphp_func *
++get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
++{
++ struct acpiphp_func *func = NULL;
++ struct pci_bus *bus = slot->bridge->pci_bus;
++ struct pci_dev *pdev;
++
++ list_for_each_entry(func, &slot->funcs, sibling) {
++ pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
++ func->function));
++ if (pdev) {
++ if (pdev == dev)
++ break;
++ pci_dev_put(pdev);
++ }
++ }
++ return func;
++}
++
++
++/**
++ * 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)
++{
++ acpi_handle phandle;
++ struct acpi_device *device, *pdevice;
++ int ret_val;
++
++ acpi_get_parent(func->handle, &phandle);
++ if (acpi_bus_get_device(phandle, &pdevice)) {
++ dbg("no parent device, assuming NULL\n");
++ pdevice = NULL;
++ }
++ if (acpi_bus_get_device(func->handle, &device)) {
++ ret_val = acpi_bus_add(&device, pdevice, func->handle,
++ ACPI_BUS_TYPE_DEVICE);
++ if (ret_val) {
++ dbg("error adding bus, %x\n",
++ -ret_val);
++ goto acpiphp_bus_add_out;
++ }
++ }
++ /*
++ * try to start anyway. We could have failed to add
++ * simply because this bus had previously been added
++ * on another add. Don't bother with the return value
++ * we just keep going.
++ */
++ ret_val = acpi_bus_start(device);
++
++acpiphp_bus_add_out:
++ return ret_val;
++}
++
++
++
+ /**
+ * enable_device - enable, configure a slot
+ * @slot: slot to be enabled
+@@ -788,7 +888,7 @@ static int enable_device(struct acpiphp_
+ goto err_exit;
+ }
+
+- max = bus->secondary;
++ max = acpiphp_max_busnr(bus);
+ for (pass = 0; pass < 2; pass++) {
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (PCI_SLOT(dev->devfn) != slot->device)
+@@ -796,8 +896,15 @@ static int enable_device(struct acpiphp_
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
+ max = pci_scan_bridge(bus, dev, max, pass);
+- if (pass && dev->subordinate)
++ if (pass && dev->subordinate) {
+ pci_bus_size_bridges(dev->subordinate);
++ func = get_func(slot, dev);
++ if (func) {
++ acpiphp_bus_add(func);
++ /* side effect of get_func */
++ pci_dev_put(dev);
++ }
++ }
+ }
+ }
+ }
diff --git a/pci/acpiphp-slot-management-fix-v4.patch b/pci/acpiphp-slot-management-fix-v4.patch
new file mode 100644
index 0000000000000..f21d89bbb10c6
--- /dev/null
+++ b/pci/acpiphp-slot-management-fix-v4.patch
@@ -0,0 +1,343 @@
+From kristen.c.accardi@intel.com Thu Feb 23 17:59:56 2006
+From: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
+Subject: [patch 5/5] acpiphp - slot management fix - V4
+To: greg@kroah.com
+Date: Thu, 23 Feb 2006 17:56:08 -0800
+Message-Id: <1140746168.11750.79.camel@whizzy>
+
+From: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
+
+o This patch removes IDs (for slots management).
+o This patch removes the slot register/unregister processes
+ from the init/exit phases. Instead, adds these processes
+ in the bridge add/cleanup phases.
+o Currently, this change doesn't have any meanings. But
+ these changes are needed to support p2p bridge(with
+ hotplug slot)
+
+Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/pci/hotplug/acpiphp.h | 8 --
+ drivers/pci/hotplug/acpiphp_core.c | 127 +++++++++++++++++--------------------
+ drivers/pci/hotplug/acpiphp_glue.c | 48 ++++++-------
+ 3 files changed, 86 insertions(+), 97 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h
+@@ -60,10 +60,7 @@ struct acpiphp_slot;
+ * struct slot - slot information for each *physical* slot
+ */
+ struct slot {
+- u8 number;
+ struct hotplug_slot *hotplug_slot;
+- struct list_head slot_list;
+-
+ struct acpiphp_slot *acpi_slot;
+ };
+
+@@ -119,9 +116,9 @@ struct acpiphp_slot {
+ struct acpiphp_bridge *bridge; /* parent */
+ struct list_head funcs; /* one slot may have different
+ objects (i.e. for each function) */
++ struct slot *slot;
+ struct mutex crit_sect;
+
+- u32 id; /* slot id (serial #) for hotplug core */
+ u8 device; /* pci device# */
+
+ u32 sun; /* ACPI _SUN (slot unique number) */
+@@ -229,12 +226,13 @@ struct acpiphp_dock_station {
+ /* acpiphp_core.c */
+ extern int acpiphp_register_attention(struct acpiphp_attention_info*info);
+ extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
++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);
+ extern int acpiphp_get_num_slots (void);
+-extern struct acpiphp_slot *get_slot_from_id (int id);
+ typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
+ void handle_hotplug_event_func(acpi_handle, u32, void*);
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_core.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_core.c
+@@ -44,8 +44,6 @@
+ #include "pci_hotplug.h"
+ #include "acpiphp.h"
+
+-static LIST_HEAD(slot_list);
+-
+ #define MY_NAME "acpiphp"
+
+ static int debug;
+@@ -341,62 +339,53 @@ static void release_slot(struct hotplug_
+ kfree(slot);
+ }
+
+-/**
+- * init_slots - initialize 'struct slot' structures for each slot
+- *
+- */
+-static int __init init_slots(void)
++/* callback routine to initialize 'struct slot' for each slot */
++int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ {
+ struct slot *slot;
++ struct hotplug_slot *hotplug_slot;
++ struct hotplug_slot_info *hotplug_slot_info;
+ int retval = -ENOMEM;
+- int i;
+
+- for (i = 0; i < num_slots; ++i) {
+- slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+- if (!slot)
+- goto error;
+- memset(slot, 0, sizeof(struct slot));
+-
+- slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+- if (!slot->hotplug_slot)
+- goto error_slot;
+- memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
+-
+- slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+- if (!slot->hotplug_slot->info)
+- goto error_hpslot;
+- memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
+-
+- slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+- if (!slot->hotplug_slot->name)
+- goto error_info;
+-
+- slot->number = i;
+-
+- slot->hotplug_slot->private = slot;
+- slot->hotplug_slot->release = &release_slot;
+- slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+-
+- slot->acpi_slot = get_slot_from_id(i);
+- slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
+- slot->hotplug_slot->info->attention_status = 0;
+- slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
+- slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
+- slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+- slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+-
+- make_slot_name(slot);
+-
+- retval = pci_hp_register(slot->hotplug_slot);
+- if (retval) {
+- err("pci_hp_register failed with error %d\n", retval);
+- goto error_name;
+- }
+-
+- /* add slot to our internal list */
+- list_add(&slot->slot_list, &slot_list);
+- info("Slot [%s] registered\n", slot->hotplug_slot->name);
+- }
++ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
++ if (!slot)
++ goto error;
++
++ slot->hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
++ if (!slot->hotplug_slot)
++ goto error_slot;
++
++ slot->hotplug_slot->info = kzalloc(sizeof(*hotplug_slot_info),
++ GFP_KERNEL);
++ if (!slot->hotplug_slot->info)
++ goto error_hpslot;
++
++ slot->hotplug_slot->name = kzalloc(SLOT_NAME_SIZE, GFP_KERNEL);
++ if (!slot->hotplug_slot->name)
++ goto error_info;
++
++ slot->hotplug_slot->private = slot;
++ slot->hotplug_slot->release = &release_slot;
++ slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
++
++ slot->acpi_slot = acpiphp_slot;
++ slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
++ slot->hotplug_slot->info->attention_status = 0;
++ slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
++ slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
++ slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
++ slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
++
++ acpiphp_slot->slot = slot;
++ make_slot_name(slot);
++
++ retval = pci_hp_register(slot->hotplug_slot);
++ if (retval) {
++ err("pci_hp_register failed with error %d\n", retval);
++ goto error_name;
++ }
++
++ info("Slot [%s] registered\n", slot->hotplug_slot->name);
+
+ return 0;
+ error_name:
+@@ -412,17 +401,16 @@ error:
+ }
+
+
+-static void __exit cleanup_slots (void)
++void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ {
+- struct list_head *tmp, *n;
+- struct slot *slot;
++ struct slot *slot = acpiphp_slot->slot;
++ int retval = 0;
+
+- list_for_each_safe (tmp, n, &slot_list) {
+- /* memory will be freed in release_slot callback */
+- slot = list_entry(tmp, struct slot, slot_list);
+- list_del(&slot->slot_list);
+- pci_hp_deregister(slot->hotplug_slot);
+- }
++ info ("Slot [%s] unregistered\n", slot->hotplug_slot->name);
++
++ retval = pci_hp_deregister(slot->hotplug_slot);
++ if (retval)
++ err("pci_hp_deregister failed with error %d\n", retval);
+ }
+
+
+@@ -439,16 +427,21 @@ static int __init acpiphp_init(void)
+
+ /* read all the ACPI info from the system */
+ retval = init_acpi();
+- if (retval && !(docking_station))
+- return retval;
+
+- return init_slots();
++ /* if we have found a docking station, we should
++ * go ahead and load even if init_acpi has found
++ * no slots. This handles the case when the _DCK
++ * method not defined under the actual dock bridge
++ */
++ if (docking_station)
++ return 0;
++ else
++ return retval;
+ }
+
+
+ static void __exit acpiphp_exit(void)
+ {
+- cleanup_slots();
+ /* deallocate internal data structures etc. */
+ acpiphp_glue_exit();
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_glue.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_glue.c
+@@ -128,8 +128,7 @@ register_slot(acpi_handle handle, u32 lv
+ acpi_handle tmp;
+ acpi_status status = AE_OK;
+ unsigned long adr, sun;
+- int device, function;
+- static int num_slots = 0; /* XXX if we support I/O node hotplug... */
++ int device, function, retval;
+
+ status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+
+@@ -198,7 +197,6 @@ register_slot(acpi_handle handle, u32 lv
+
+ memset(slot, 0, sizeof(struct acpiphp_slot));
+ slot->bridge = bridge;
+- slot->id = num_slots++;
+ slot->device = device;
+ slot->sun = sun;
+ INIT_LIST_HEAD(&slot->funcs);
+@@ -212,6 +210,11 @@ register_slot(acpi_handle handle, u32 lv
+ 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);
++ retval = acpiphp_register_hotplug_slot(slot);
++ if (retval) {
++ warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval);
++ goto err_exit;
++ }
+ }
+
+ newfunc->slot = slot;
+@@ -253,6 +256,14 @@ register_slot(acpi_handle handle, u32 lv
+ status = AE_OK;
+
+ return status;
++
++ err_exit:
++ bridge->nr_slots--;
++ bridge->slots = slot->next;
++ kfree(slot);
++ kfree(newfunc);
++
++ return AE_OK;
+ }
+
+
+@@ -335,9 +346,16 @@ static void init_bridge_misc(struct acpi
+ /* decode ACPI 2.0 _HPP (hot plug parameters) */
+ decode_hpp(bridge);
+
++ /* must be added to the list prior to calling register_slot */
++ list_add(&bridge->list, &bridge_list);
++
+ /* register all slot objects under this bridge */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
+ register_slot, bridge, NULL);
++ if (ACPI_FAILURE(status)) {
++ list_del(&bridge->list);
++ return;
++ }
+
+ /* install notify handler */
+ if (bridge->type != BRIDGE_TYPE_HOST) {
+@@ -350,8 +368,6 @@ static void init_bridge_misc(struct acpi
+ err("failed to register interrupt notify handler\n");
+ }
+ }
+-
+- list_add(&bridge->list, &bridge_list);
+ }
+
+
+@@ -555,6 +571,8 @@ static void cleanup_bridge(struct acpiph
+ list_del(list);
+ kfree(func);
+ }
++ acpiphp_unregister_hotplug_slot(slot);
++ list_del(&slot->funcs);
+ kfree(slot);
+ slot = next;
+ }
+@@ -1521,26 +1539,6 @@ static int acpiphp_for_each_slot(acpiphp
+ }
+ #endif
+
+-/* search matching slot from id */
+-struct acpiphp_slot *get_slot_from_id(int id)
+-{
+- struct list_head *node;
+- struct acpiphp_bridge *bridge;
+- struct acpiphp_slot *slot;
+-
+- list_for_each (node, &bridge_list) {
+- bridge = (struct acpiphp_bridge *)node;
+- for (slot = bridge->slots; slot; slot = slot->next)
+- if (slot->id == id)
+- return slot;
+- }
+-
+- /* should never happen! */
+- err("%s: no object for id %d\n", __FUNCTION__, id);
+- WARN_ON(1);
+- return NULL;
+-}
+-
+
+ /**
+ * acpiphp_enable_slot - power on slot
diff --git a/series b/series
index e4505fabea1f4..d8bc6a38e8f6a 100644
--- a/series
+++ b/series
@@ -157,6 +157,12 @@ pci/pci-fix-problems-with-msi-x-on-ia64.patch
pci/pci-pci-cardbus-cards-hidden-needs-pci-assign-busses-to-fix.patch
pci/pci-move-pci_dev_put-outside-a-spinlock.patch
+pci/acpiphp-add-new-bus-to-acpi.patch
+pci/acpi-export-acpi_bus_trim.patch
+pci/acpiphp-add-dock-event-handling.patch
+pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch
+pci/acpiphp-slot-management-fix-v4.patch
+
# usb patches queued for 2.6.16 (bugfixes, new ids, etc.)