diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-23 18:08:28 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-23 18:08:28 -0800 |
commit | 1dce1769c917763023a00ca2d66ff6d50ed0962b (patch) | |
tree | df79fcf25427f4a49a46662698117b2ca765ea51 | |
parent | 84a09ac6babf889cf41a4325c272a508dc57899b (diff) | |
download | patches-1dce1769c917763023a00ca2d66ff6d50ed0962b.tar.gz |
pci acpi hotplug patches
-rw-r--r-- | pci/acpi-export-acpi_bus_trim.patch | 58 | ||||
-rw-r--r-- | pci/acpi-remove-dock-event-handling-from-ibm_acpi.patch | 114 | ||||
-rw-r--r-- | pci/acpiphp-add-dock-event-handling.patch | 749 | ||||
-rw-r--r-- | pci/acpiphp-add-new-bus-to-acpi.patch | 157 | ||||
-rw-r--r-- | pci/acpiphp-slot-management-fix-v4.patch | 343 | ||||
-rw-r--r-- | series | 6 |
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 @@ -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.) |