diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-07 12:15:10 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-07 12:15:10 -0800 |
commit | 6270aa63b3ee5dcf78aa915719a0425bbee176ee (patch) | |
tree | a1dc773f8ec9fd1bc7954f46337c5c6c8f2a8f6e /pci | |
parent | 641e80f1e8bdbcc54e037795ab9bbfc072551500 (diff) | |
download | patches-6270aa63b3ee5dcf78aa915719a0425bbee176ee.tar.gz |
pci patches
Diffstat (limited to 'pci')
-rw-r--r-- | pci/acpiphp-handle-dock-stations.patch | 650 | ||||
-rw-r--r-- | pci/pci-hotplug-acpiphp-handle-dock-bridges.patch | 330 | ||||
-rw-r--r-- | pci/pci-hotplug-convert-semaphores-to-mutex.patch | 32 |
3 files changed, 657 insertions, 355 deletions
diff --git a/pci/acpiphp-handle-dock-stations.patch b/pci/acpiphp-handle-dock-stations.patch new file mode 100644 index 0000000000000..3d1d9819190b2 --- /dev/null +++ b/pci/acpiphp-handle-dock-stations.patch @@ -0,0 +1,650 @@ +From kristenc@cs.pdx.edu Wed Feb 1 15:30:56 2006 +Date: Wed, 1 Feb 2006 15:30:05 -0800 +From: Kristen Carlson Accardi <kristenc@cs.pdx.edu> +Cc: <greg@kroah.com>, <len.brown@intel.com>, <pavel@ucw.cz>, <muneda.takahiro@jp.fujitsu.com> +Subject: [patch] acpiphp: handle dock stations +Message-ID: <20060201233005.GA4999@nerpa> +Content-Disposition: inline + + +From: Kristen Carlson Accardi kristen.c.accardi@intel.com + +This patch will add hot add/remove of docking stations to acpiphp. Because +some docking stations will have a _DCK method that is not associated with +a dock bridge, we use the _EJD method to determine which devices are +dependent on the dock device, then try to find which of these dependent +devices are pci devices. We register a separate event handler with acpi +to handle dock notifications, but if we have discovered any pci devices +dependent on the dock station, we notify the acpiphp driver to rescan +the correct bus. If no pci devices are found, but there is still a _DCK method +present, the driver will stay loaded to deal with the dock notifications. + +This patch does not implement full _EJD support yet - it just uses it +to find the dock bridge (if it exists) for rescanning pci. It also does +not attempt to add devices that are not enumerable via pci. It will +stay loaded even if we find a dock station with no p2p dock bridge +to handle the dock notifications. I will likely move all the dependent +device stuff out of acpiphp and into acpi in the future because some +of that code can be used by any device that has _EJD, not just pci +hotplug - but for now we'll leave it here. + +You cannot use this patch and the ibm_acpi driver at same time due to +the fact that both drivers attempt to register for dock notifications. + +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 | 368 +++++++++++++++++++++++++++++++++++++ + drivers/pci/hotplug/acpiphp_glue.c | 53 ++++- + 5 files changed, 452 insertions(+), 15 deletions(-) + +--- 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 \ +--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h ++++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h +@@ -160,6 +160,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" + +@@ -197,6 +216,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 */ + +@@ -210,6 +235,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); +@@ -219,6 +245,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,368 @@ ++/* ++ * 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) ++{ ++ struct dependent_device *dd; ++ ++ if (!ds) ++ return 0; ++ ++ list_for_each_entry(dd, &ds->dependent_devices, device_list) { ++ if (handle == dd->handle) ++ return 1; ++ } ++ return 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; ++ ++ 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 acpi_status handle_dock(acpi_handle handle, int dock) ++{ ++ acpi_status status; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ++ ++ /* _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(handle, "_DCK", ++ &arg_list, &buffer); ++ if (ACPI_FAILURE(status)) ++ err("%s: failed to dock!!\n", __FUNCTION__); ++ acpi_os_free(buffer.pointer); ++ ++ return status; ++} ++ ++ ++ ++/* ++ * the _DCK method can do funny things... and sometimes not ++ * hah-hah funny. ++ */ ++static void post_dock_fixups(struct acpiphp_slot *slot) ++{ ++ struct pci_bus *bus = slot->bridge->pci_bus; ++ u32 buses; ++ ++ /* 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 ++handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context) ++{ ++ struct acpiphp_dock_station *station = ++ (struct acpiphp_dock_station *) context; ++ struct dependent_device *dd; ++ ++ switch (type) { ++ case ACPI_NOTIFY_BUS_CHECK: ++ station->flags |= DOCK_DOCKING; ++ handle_dock(station->handle, 1); ++ /* TBD - this should be done probably similar ++ * to pci quirks, because only certain laptops ++ * will need certain fixups done. ++ */ ++ list_for_each_entry(dd, &ds->pci_dependent_devices, ++ pci_list) ++ post_dock_fixups(dd->func->slot); ++ ++ list_for_each_entry(dd, &ds->pci_dependent_devices, ++ pci_list) ++ handle_hotplug_event_func(dd->handle, ++ type, dd->func); ++ station->flags &= ~(DOCK_DOCKING); ++ station->last_dock_time = jiffies; ++ break; ++ case ACPI_NOTIFY_EJECT_REQUEST: ++ if (station->flags & DOCK_DOCKING || ++ station->last_dock_time == jiffies) { ++ } else { ++ handle_dock(station->handle, 0); ++ list_for_each_entry(dd, ++ &ds->pci_dependent_devices, pci_list) ++ ++ handle_hotplug_event_func(dd->handle, ++ type, dd->func); ++ } ++ 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]; ++ char ejd_objname[64]; ++ struct acpi_buffer buffer = { .length = sizeof(objname), ++ .pointer = objname }; ++ struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ++ struct acpi_buffer ejd_name_buffer = { .length = sizeof(objname), ++ .pointer = ejd_objname }; ++ union acpi_object *ejd_obj; ++ union acpi_object *dck_obj; ++ ++ status = acpi_get_handle(handle, "_EJD", &tmp); ++ if (ACPI_FAILURE(status)) ++ return AE_OK; ++ ++ /* make sure we are dependent on the dock device */ ++ 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; ++ } ++ ++ /* because acpi_get_name will pad the names if they are less ++ * than 4 characters, we can't compare the strings returned ++ * from _EJD with those returned from acpi_get_name. So, ++ * we have to get a handle to the object referenced by _EJD ++ * and then call get name on that. ++ */ ++ ejd_obj = ejd_buffer.pointer; ++ status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp); ++ if (ACPI_FAILURE(status)) ++ goto find_ejd_out; ++ acpi_get_name(tmp, ACPI_FULL_PATHNAME, &ejd_name_buffer); ++ ++ dck_obj = buffer.pointer; ++ if (!strncmp(ejd_objname, objname, strlen(ejd_objname))) { ++ 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; ++ 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(dd, &ds->dependent_devices, device_list) { ++ list_del(&dd->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,28 @@ 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; ++ 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"); + } + +- return AE_OK; ++ return status; + } + + +@@ -410,7 +434,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 +537,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); +@@ -1200,7 +1227,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]; diff --git a/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch b/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch deleted file mode 100644 index 6e828b9da83ec..0000000000000 --- a/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch +++ /dev/null @@ -1,330 +0,0 @@ -From kristen.c.accardi@intel.com Tue Jan 17 16:54:09 2006 -From: Kristen Accardi <kristen.c.accardi@intel.com> -Subject: PCI Hotplug: acpiphp: handle dock bridges -Cc: <len.brown@intel.com>, <pavel@ucw.cz> -Date: Tue, 17 Jan 2006 16:56:59 -0800 -Message-Id: <1137545819.19858.47.camel@whizzy> - -This patch will modify the acpiphp driver to handle docking and undocking -events and hot adding of the PCI devices on the dock station. It currently -has a workaround for a problem with acpi where the -acpi threads will deadlock and never return from executing the _DCK method. -As a workaround, I spawn a separate thread to do the dock. In addition, -I've found that some _DCK methods do some bad things, so have implemented -a fixups section for after docking that will no doubt grow as more laptops -get tested. This patch CONFLICTS with some acpi plugins that try to do -their own docking support (such as ibm_acpi), so you cannot use this driver -and the conflicting driver simultaneously. - - -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 | 2 - drivers/pci/hotplug/acpiphp_glue.c | 207 ++++++++++++++++++++++++++++++++++++- - 2 files changed, 204 insertions(+), 5 deletions(-) - ---- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h -+++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h -@@ -188,6 +188,7 @@ struct acpiphp_attention_info - #define SLOT_POWEREDON (0x00000001) - #define SLOT_ENABLED (0x00000002) - #define SLOT_MULTIFUNCTION (0x00000004) -+#define SLOT_DOCKING (0x00000008) - - /* function flags */ - -@@ -197,6 +198,7 @@ struct acpiphp_attention_info - #define FUNC_HAS_PS1 (0x00000020) - #define FUNC_HAS_PS2 (0x00000040) - #define FUNC_HAS_PS3 (0x00000080) -+#define FUNC_HAS_DCK (0x00000100) - - /* function prototypes */ - ---- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_glue.c -+++ gregkh-2.6/drivers/pci/hotplug/acpiphp_glue.c -@@ -55,12 +55,14 @@ - static LIST_HEAD(bridge_list); - - #define MY_NAME "acpiphp_glue" -- -+static struct work_struct dock_task; -+static int enable_device(struct acpiphp_slot *slot); - 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); -- -+static void dock(void *data); -+static unsigned int get_slot_status(struct acpiphp_slot *slot); - - /* - * initialization & terminatation routines -@@ -118,6 +120,30 @@ is_ejectable_slot(acpi_handle handle, u3 - } - - -+static acpi_status handle_dock(struct acpiphp_func *func, 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: enter\n", __FUNCTION__); -+ -+ /* _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(func->handle, "_DCK", -+ &arg_list, &buffer); -+ if (ACPI_FAILURE(status)) -+ err("%s: failed to dock!!\n", MY_NAME); -+ -+ return status; -+} -+ -+ -+ - /* callback routine to register each ACPI PCI slot object */ - static acpi_status - register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) -@@ -210,6 +236,12 @@ register_slot(acpi_handle handle, u32 lv - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); - } - -+ /* install dock notify handler */ -+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { -+ newfunc->flags |= FUNC_HAS_DCK; -+ INIT_WORK(&dock_task, dock, slot); -+ } -+ - /* install notify handler */ - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, -@@ -681,6 +713,88 @@ static int acpiphp_configure_ioapics(acp - return 0; - } - -+/* -+ * the _DCK method can do funny things... and sometimes not -+ * hah-hah funny. -+ */ -+static void post_dock_fixups(struct acpiphp_slot *slot, -+ struct acpiphp_func *func) -+{ -+ struct pci_bus *bus = slot->bridge->pci_bus; -+ u32 buses; -+ -+ /* 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 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; -+ } -+ ret_val = acpi_bus_add(&device, pdevice, func->handle, -+ ACPI_BUS_TYPE_DEVICE); -+ if (ret_val) -+ dbg("cannot add bridge to acpi list\n"); -+ -+ /* -+ * try to start anyway. We could have failed to add -+ * simply because this bus had previously been added -+ * on another dock. Don't bother with the return value -+ * we just keep going. -+ */ -+ ret_val = acpi_bus_start(device); -+ -+ return ret_val; -+} -+ -+ -+ -+static void dock(void *data) -+{ -+ struct list_head *l; -+ struct acpiphp_func *func; -+ struct acpiphp_slot *slot = data; -+ -+ down(&slot->crit_sect); -+ list_for_each(l, &slot->funcs) { -+ func = list_entry(l, struct acpiphp_func, sibling); -+ if (func->flags & FUNC_HAS_DCK) { -+ handle_dock(func, 1); -+ post_dock_fixups(slot, func); -+ slot->flags |= SLOT_POWEREDON; -+ if (get_slot_status(slot) == ACPI_STA_ALL) { -+ enable_device(slot); -+ } -+ } -+ } -+ slot->flags &= (~SLOT_DOCKING); -+ up(&slot->crit_sect); -+} -+ -+ -+ - static int power_on_slot(struct acpiphp_slot *slot) - { - acpi_status status; -@@ -705,6 +819,19 @@ static int power_on_slot(struct acpiphp_ - } else - break; - } -+ -+ if (func->flags & FUNC_HAS_DCK) { -+ dbg("%s: executing _DCK\n", __FUNCTION__); -+ slot->flags |= SLOT_DOCKING; -+ /* -+ * FIXME - work around for acpi. Right -+ * now if we call _DCK from this thread, -+ * we block forever. -+ */ -+ schedule_work(&dock_task); -+ retval = -1; -+ goto err_exit; -+ } - } - - /* TBD: evaluate _STA to check if the slot is enabled */ -@@ -730,7 +857,11 @@ static int power_off_slot(struct acpiphp - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); -- -+ if (func->flags & FUNC_HAS_DCK) { -+ dbg("%s: undock commencing\n", __FUNCTION__); -+ handle_dock(func, 0); -+ dbg("%s: undock complete\n", __FUNCTION__); -+ } - if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { -@@ -752,6 +883,63 @@ static int power_off_slot(struct acpiphp - - - /** -+ * get_func - given pci_dev & slot, get the matching acpiphp_func -+ * @slot: slot to be scanned. -+ * @dev: pci_dev to match -+ * -+ * This function will check the list of acpiphp functions for -+ * this slot and return the one that represents the given -+ * pci_dev structure. -+ */ -+static struct acpiphp_func * get_func(struct acpiphp_slot *slot, -+ struct pci_dev *dev) -+{ -+ struct list_head *l; -+ struct acpiphp_func *func; -+ struct pci_bus *bus = slot->bridge->pci_bus; -+ -+ list_for_each (l, &slot->funcs) { -+ func = list_entry(l, struct acpiphp_func, sibling); -+ if (pci_get_slot(bus, PCI_DEVFN(slot->device, -+ func->function)) == dev) -+ return func; -+ } -+ return NULL; -+} -+ -+ -+ -+/** acpiphp_max_busnr - find the max reserved busnr for this bus -+ * @bus: the bus to scan -+ */ -+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; -+} -+ -+ -+ -+ -+/** - * enable_device - enable, configure a slot - * @slot: slot to be enabled - * -@@ -788,7 +976,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 +984,12 @@ 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); -+ } - } - } - } -@@ -1231,6 +1423,11 @@ static void handle_hotplug_event_func(ac - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ -+ if (func->slot->flags & SLOT_DOCKING) { -+ /* ignore if we are in the middle of docking */ -+ dbg("eject request in the middle of a dock\n"); -+ break; -+ } - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); diff --git a/pci/pci-hotplug-convert-semaphores-to-mutex.patch b/pci/pci-hotplug-convert-semaphores-to-mutex.patch index a40cbb1b8fa9e..2cbbc23a6d7fd 100644 --- a/pci/pci-hotplug-convert-semaphores-to-mutex.patch +++ b/pci/pci-hotplug-convert-semaphores-to-mutex.patch @@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/pci/hotplug/acpiphp.h | 3 - - drivers/pci/hotplug/acpiphp_glue.c | 16 +++--- + drivers/pci/hotplug/acpiphp_glue.c | 12 ++-- drivers/pci/hotplug/cpqphp.h | 3 - drivers/pci/hotplug/cpqphp_core.c | 14 ++--- drivers/pci/hotplug/cpqphp_ctrl.c | 56 ++++++++++----------- @@ -34,7 +34,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/pci/hotplug/shpchp.h | 3 - drivers/pci/hotplug/shpchp_ctrl.c | 98 ++++++++++++++++++------------------- drivers/pci/hotplug/shpchp_hpc.c | 2 - 13 files changed, 145 insertions(+), 139 deletions(-) + 13 files changed, 143 insertions(+), 137 deletions(-) --- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h +++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h @@ -66,7 +66,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> #include "../pci.h" #include "pci_hotplug.h" -@@ -214,7 +214,7 @@ register_slot(acpi_handle handle, u32 lv +@@ -202,7 +202,7 @@ register_slot(acpi_handle handle, u32 lv slot->device = device; slot->sun = sun; INIT_LIST_HEAD(&slot->funcs); @@ -75,25 +75,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> slot->next = bridge->slots; bridge->slots = slot; -@@ -777,7 +777,7 @@ static void dock(void *data) - struct acpiphp_func *func; - struct acpiphp_slot *slot = data; - -- down(&slot->crit_sect); -+ mutex_lock(&slot->crit_sect); - list_for_each(l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_DCK) { -@@ -790,7 +790,7 @@ static void dock(void *data) - } - } - slot->flags &= (~SLOT_DOCKING); -- up(&slot->crit_sect); -+ mutex_unlock(&slot->crit_sect); - } - - -@@ -1598,7 +1598,7 @@ int acpiphp_enable_slot(struct acpiphp_s +@@ -1428,7 +1428,7 @@ int acpiphp_enable_slot(struct acpiphp_s { int retval; @@ -102,7 +84,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* wake up all functions */ retval = power_on_slot(slot); -@@ -1610,7 +1610,7 @@ int acpiphp_enable_slot(struct acpiphp_s +@@ -1440,7 +1440,7 @@ int acpiphp_enable_slot(struct acpiphp_s retval = enable_device(slot); err_exit: @@ -111,7 +93,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> return retval; } -@@ -1621,7 +1621,7 @@ int acpiphp_disable_slot(struct acpiphp_ +@@ -1451,7 +1451,7 @@ int acpiphp_disable_slot(struct acpiphp_ { int retval = 0; @@ -120,7 +102,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* unconfigure all functions */ retval = disable_device(slot); -@@ -1634,7 +1634,7 @@ int acpiphp_disable_slot(struct acpiphp_ +@@ -1464,7 +1464,7 @@ int acpiphp_disable_slot(struct acpiphp_ goto err_exit; err_exit: |