public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* [patch] acpiphp: handle dock stations
@ 2006-02-01 23:30 Kristen Carlson Accardi
  2006-02-02  5:09 ` [Pcihpd-discuss] " Kenji Kaneshige
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Kristen Carlson Accardi @ 2006-02-01 23:30 UTC (permalink / raw)
  To: pcihpd-discuss
  Cc: greg, len.brown, pavel, linux-kernel, muneda.takahiro, linux-acpi


From: 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>

---
Greg - this patch is against 2.6.16-rc1-git5 and replaces the patch
pci-hotplug-acpiphp-handle-dock-bridges.patch in your tree.  I assume
the other patches I sent originally are still applied.  I moved all
the dock stuff into a separate file because I felt it was starting
to clutter acpiphp_glue.c a bit.  I don't think this will conflict
with anything anyone else is working on.

 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(-)

Index: linux-2.6.16-rc1/drivers/pci/hotplug/Makefile
===================================================================
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/Makefile
+++ linux-2.6.16-rc1/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	\
Index: linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-2.6.16-rc1/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;
 
Index: linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-2.6.16-rc1/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);
Index: linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp_dock.c
===================================================================
--- /dev/null
+++ linux-2.6.16-rc1/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);
+	}
+}
+
+
Index: linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-2.6.16-rc1/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);
@@ -1302,7 +1329,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];


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Pcihpd-discuss] [patch] acpiphp: handle dock stations
  2006-02-01 23:30 [patch] acpiphp: handle dock stations Kristen Carlson Accardi
@ 2006-02-02  5:09 ` Kenji Kaneshige
  2006-02-06 13:15 ` Pavel Machek
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Kenji Kaneshige @ 2006-02-02  5:09 UTC (permalink / raw)
  To: Kristen Carlson Accardi
  Cc: pcihpd-discuss, greg, len.brown, pavel, linux-kernel,
	muneda.takahiro, linux-acpi

Kristen Carlson Accardi wrote:
> +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;
> +}
(snip.)
> +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;
> +}

Those look very similar...



> +
> +	/* 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))) {

I don't think you need to compare pathnames.
Why not just compare ACPI handles like below?

	if (dck_handle == tmp) {
		...

Thanks,
Kenji Kaneshige


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] acpiphp: handle dock stations
  2006-02-01 23:30 [patch] acpiphp: handle dock stations Kristen Carlson Accardi
  2006-02-02  5:09 ` [Pcihpd-discuss] " Kenji Kaneshige
@ 2006-02-06 13:15 ` Pavel Machek
  2006-02-06 13:21 ` Pavel Machek
  2006-02-13  1:50 ` [Pcihpd-discuss] " MUNEDA Takahiro
  3 siblings, 0 replies; 7+ messages in thread
From: Pavel Machek @ 2006-02-06 13:15 UTC (permalink / raw)
  To: Kristen Carlson Accardi
  Cc: pcihpd-discuss, greg, len.brown, linux-kernel, muneda.takahiro,
	linux-acpi

Hi!

> From: 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.

It still registers my docking bridge as -1:

acpiphp: ACPI Hot Plug PCI Controller Driver version: 0.5
acpiphp: Slot [4294967295] registered
acpiphp_ibm: ibm_find_acpi_device:  Failed to get device
information<3>acpiphp_ibm: ibm_find_acpi_device:  Failed to get device
information<3>acpiphp_ibm: ibm_find_acpi_device:  Failed to get device
information<3>acpiphp_ibm: ibm_acpiphp_init: acpi_walk_namespace
failed
radeonfb: Retrieved PLL infos from BIOS

...which is still better than not registering it at all :-).

This one actually does not oops at insertion into dock. Good!

It detects insertion into dock:

Feb  6 14:13:00 amd kernel: acpi_bus-0073 [62] bus_get_device        :
No context for object [c1d2c408]
Feb  6 14:13:01 amd kernel: PCI: Bus 3, cardbus bridge: 0000:02:00.0
Feb  6 14:13:01 amd kernel:   IO window: 00004000-000040ff
Feb  6 14:13:01 amd kernel:   IO window: 00004400-000044ff
Feb  6 14:13:01 amd kernel:   PREFETCH window: e8000000-e9ffffff
Feb  6 14:13:01 amd kernel:   MEM window: c2000000-c3ffffff
Feb  6 14:13:01 amd kernel: PCI: Bus 7, cardbus bridge: 0000:02:00.1
Feb  6 14:13:01 amd kernel:   IO window: 00004800-000048ff
Feb  6 14:13:01 amd kernel:   IO window: 00004c00-00004cff
Feb  6 14:13:01 amd kernel:   PREFETCH window: ea000000-ebffffff
Feb  6 14:13:01 amd kernel:   MEM window: c4000000-c5ffffff

When I press eject button, I get

Feb  6 14:13:27 amd kernel: acpi_bus-0073 [72] bus_get_device        :
No context for object [c1d2c408]

and dock fan stops (but machine is not unlocked):

root@amd:/sys/bus/pci/slots/4294967295# cat *
0
0000:02:03
cat: attention: Invalid argument
0
0

...but I can't remove machine.
								Pavel
-- 
Web maintainer for suspend.sf.net (www.sf.net/projects/suspend) wanted...

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] acpiphp: handle dock stations
  2006-02-01 23:30 [patch] acpiphp: handle dock stations Kristen Carlson Accardi
  2006-02-02  5:09 ` [Pcihpd-discuss] " Kenji Kaneshige
  2006-02-06 13:15 ` Pavel Machek
@ 2006-02-06 13:21 ` Pavel Machek
  2006-02-13  1:50 ` [Pcihpd-discuss] " MUNEDA Takahiro
  3 siblings, 0 replies; 7+ messages in thread
From: Pavel Machek @ 2006-02-06 13:21 UTC (permalink / raw)
  To: Kristen Carlson Accardi
  Cc: pcihpd-discuss, greg, len.brown, linux-kernel, muneda.takahiro,
	linux-acpi

Hi!

> 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.

Even while machine is locked in dock, I don't see aditional devices at
lspci. Is there some additional steps I need to do?

-rw-r--r--  1 root root 4096 Feb  6 14:17 attention

..should probably be write-only. It seems to only return errors on
read, anyway.

Is there a way to physicaly remove my machine from dock? echo 0 >
power should do it, right? Well, it does not :-).

								Pavel
-- 
Web maintainer for suspend.sf.net (www.sf.net/projects/suspend) wanted...

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Pcihpd-discuss] [patch] acpiphp: handle dock stations
  2006-02-01 23:30 [patch] acpiphp: handle dock stations Kristen Carlson Accardi
                   ` (2 preceding siblings ...)
  2006-02-06 13:21 ` Pavel Machek
@ 2006-02-13  1:50 ` MUNEDA Takahiro
  2006-02-13 15:57   ` Kenji Kaneshige
  3 siblings, 1 reply; 7+ messages in thread
From: MUNEDA Takahiro @ 2006-02-13  1:50 UTC (permalink / raw)
  To: Kristen Carlson Accardi
  Cc: pcihpd-discuss, greg, len.brown, pavel, muneda.takahiro,
	linux-acpi

Hi Kristen,

At Wed, 1 Feb 2006 15:30:05 -0800,
Kristen Carlson Accardi <kristenc@cs.pdx.edu> wrote:
> 
> 
> From: kristen.c.accardi@intel.com
> +	/* 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;
>  }

I tried 2.6.12-rc2-mm1(includes this patch) on my Tiger box,
I could not insmod the acpiphp module because of the NaT
consumption.

My box does not have any _DCK method, so find_dock() returns
without making any acpiphp_dock_station struct. Therefore,
NaT consumption has occurred at get_dependent_device().

Here is a log.

pci_hotplug: PCI Hot Plug PCI Core version: 0.5
acpiphp: ACPI Hot Plug PCI Controller Driver version: 0.5
acpiphp_glue: found PCI-to-PCI bridge at PCI 0000:02:1f.0
acpiphp_glue: _HPP parameter = (10, 40, 01, 01)
acpiphp_glue: found ACPI PCI Hotplug slot 1 at PCI 0000:06:01
insmod[5085]: NaT consumption 17179869216 [1]
Modules linked in: acpiphp pci_hotplug sunrpc binfmt_misc thermal processor fan container button ehci_hcd

Pid: 5085, CPU 1, comm:               insmod
psr : 00001010081a6018 ifs : 8000000000000006 ip  : [<a000000200112080>]    Not tainted
ip is at get_dependent_device+0x20/0xe0 [acpiphp]
unat: 0000000000000000 pfs : 0000000000000795 rsc : 0000000000000003
rnat: 0000000000000002 bsps: 0000000000000013 pr  : 00000000059a1569
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr: 0009804c8a70033f
csd : 0000000000000000 ssd : 0000000000000000
b0  : a00000020010dcb0 b6  : a0000001003e99e0 b7  : a0000001003ce860
f6  : 0fffafffffffff0000000 f7  : 0ffdb8000000000000000
f8  : 0ffff8000000000000000 f9  : 100038000000000000000
f10 : 0fffafffffffff0000000 f11 : 1003e0000000000000000
r1  : a0000002001124f8 r2  : 000000000000038b r3  : e0000001040c0f78
r8  : 0000000000000000 r9  : 0000000000000018 r10 : a0000002001189e0
r11 : e0000002ffd34840 r12 : e0000001040c7de0 r13 : e0000001040c0000
r14 : 0000000000000000 r15 : e0000002ffdc69a8 r16 : e0000002ffd35810
r17 : a00000010095af70 r18 : ffffffffffffffff r19 : a00000010095a090
r20 : 0000000000000007 r21 : a00000010095a0a0 r22 : 0000000000000000
r23 : a00000010095af90 r24 : a00000010087f698 r25 : a00000010087f690
r26 : a000000100944248 r27 : 0000000000000000 r28 : a000000100968b8e
r29 : 0000000000003556 r30 : 0000000000000000 r31 : a00000010095a338

Call Trace:
 [<a000000100011f50>] show_stack+0x50/0xa0
                                sp=e0000001040c77f0 bsp=e0000001040c1548
 [<a000000100012820>] show_regs+0x820/0x840
                                sp=e0000001040c79c0 bsp=e0000001040c1500
 [<a000000100036a70>] die+0x1d0/0x280
                                sp=e0000001040c79c0 bsp=e0000001040c14b8
 [<a000000100036b60>] die_if_kernel+0x40/0x60
                                sp=e0000001040c79e0 bsp=e0000001040c1488
 [<a0000001000382a0>] ia64_fault+0x1140/0x1180
                                sp=e0000001040c79e0 bsp=e0000001040c1408
 [<a00000010000c3c0>] ia64_leave_kernel+0x0/0x280
                                sp=e0000001040c7c10 bsp=e0000001040c1408
 [<a000000200112080>] get_dependent_device+0x20/0xe0 [acpiphp]
                                sp=e0000001040c7de0 bsp=e0000001040c13d0
 [<a00000020010dcb0>] register_slot+0x710/0x860 [acpiphp]
                                sp=e0000001040c7de0 bsp=e0000001040c1358
 [<a0000001003f3530>] acpi_ns_walk_namespace+0x130/0x2a0
                                sp=e0000001040c7e00 bsp=e0000001040c12e0
 [<a0000001003eed10>] acpi_walk_namespace+0x90/0xe0
                                sp=e0000001040c7e00 bsp=e0000001040c1290
 [<a00000020010e270>] init_bridge_misc+0x70/0x180 [acpiphp]
                                sp=e0000001040c7e00 bsp=e0000001040c1268
 [<a00000020010e6d0>] find_p2p_bridge+0x350/0x400 [acpiphp]
                                sp=e0000001040c7e00 bsp=e0000001040c1220
 [<a0000001003f3530>] acpi_ns_walk_namespace+0x130/0x2a0
                                sp=e0000001040c7e10 bsp=e0000001040c11a0
 [<a0000001003eed10>] acpi_walk_namespace+0x90/0xe0
                                sp=e0000001040c7e10 bsp=e0000001040c1150
 [<a00000020010eb50>] add_bridge+0x3d0/0x440 [acpiphp]
                                sp=e0000001040c7e10 bsp=e0000001040c1118
 [<a00000010040f090>] acpi_pci_register_driver+0x110/0x180
                                sp=e0000001040c7e20 bsp=e0000001040c10e0
 [<a0000002000d88f0>] acpiphp_glue_init+0x90/0xc0 [acpiphp]
                                sp=e0000001040c7e20 bsp=e0000001040c10c8
 [<a0000002000d8260>] acpiphp_init+0x80/0x680 [acpiphp]
                                sp=e0000001040c7e30 bsp=e0000001040c1078
 [<a0000001000cc620>] sys_init_module+0x1c0/0x440
                                sp=e0000001040c7e30 bsp=e0000001040c1008
 [<a00000010000c220>] ia64_ret_from_syscall+0x0/0x20
                                sp=e0000001040c7e30 bsp=e0000001040c1008
 [<a000000000010640>] __kernel_syscall_via_break+0x0/0x20
                                sp=e0000001040c8000 bsp=e0000001040c1008

Thanks,
MUNE


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Pcihpd-discuss] [patch] acpiphp: handle dock stations
  2006-02-13  1:50 ` [Pcihpd-discuss] " MUNEDA Takahiro
@ 2006-02-13 15:57   ` Kenji Kaneshige
  2006-02-14  0:41     ` MUNEDA Takahiro
  0 siblings, 1 reply; 7+ messages in thread
From: Kenji Kaneshige @ 2006-02-13 15:57 UTC (permalink / raw)
  To: MUNEDA Takahiro, Kristen Carlson Accardi
  Cc: pcihpd-discuss, greg, len.brown, pavel, linux-acpi

Hi Kristen, Takahiro,

MUNEDA Takahiro wrote:
> 
> I tried 2.6.12-rc2-mm1(includes this patch) on my Tiger box,
> I could not insmod the acpiphp module because of the NaT
> consumption.
> 
> My box does not have any _DCK method, so find_dock() returns
> without making any acpiphp_dock_station struct. Therefore,
> NaT consumption has occurred at get_dependent_device().
> 

This problem will be fixed by the following patch.

Thanks,
Kenji Kaneshige


The get_dependent_device() function must check if ds is not NULL,
otherwise it will cause kernel panic on the system that has no _DCK
method.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>

 drivers/pci/hotplug/acpiphp_dock.c |    3 +++
 1 files changed, 3 insertions(+)

Index: linux-2.6.16-rc2-mm1/drivers/pci/hotplug/acpiphp_dock.c
===================================================================
--- linux-2.6.16-rc2-mm1.orig/drivers/pci/hotplug/acpiphp_dock.c	2006-02-09 20:03:03.000000000 +0900
+++ linux-2.6.16-rc2-mm1/drivers/pci/hotplug/acpiphp_dock.c	2006-02-14 00:11:15.000000000 +0900
@@ -88,6 +88,9 @@
 {
 	struct dependent_device *dd;
 
+	if (!ds)
+		return NULL;
+
 	list_for_each_entry(dd, &ds->dependent_devices, device_list) {
 		if (handle == dd->handle)
 			return dd;


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Pcihpd-discuss] [patch] acpiphp: handle dock stations
  2006-02-13 15:57   ` Kenji Kaneshige
@ 2006-02-14  0:41     ` MUNEDA Takahiro
  0 siblings, 0 replies; 7+ messages in thread
From: MUNEDA Takahiro @ 2006-02-14  0:41 UTC (permalink / raw)
  To: Kenji Kaneshige
  Cc: MUNEDA Takahiro, Kristen Carlson Accardi, pcihpd-discuss, greg,
	len.brown, pavel, linux-acpi

Hi Kenji,

At Tue, 14 Feb 2006 00:57:38 +0900,
Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> wrote:
> 
> Hi Kristen, Takahiro,
> 
> MUNEDA Takahiro wrote:
> > 
> > I tried 2.6.12-rc2-mm1(includes this patch) on my Tiger box,
> > I could not insmod the acpiphp module because of the NaT
> > consumption.
> > 
> > My box does not have any _DCK method, so find_dock() returns
> > without making any acpiphp_dock_station struct. Therefore,
> > NaT consumption has occurred at get_dependent_device().
> > 
> 
> This problem will be fixed by the following patch.
> 
> Thanks,
> Kenji Kaneshige
> 
> 
> The get_dependent_device() function must check if ds is not NULL,
> otherwise it will cause kernel panic on the system that has no _DCK
> method.

Thank you for your patch.
It works on my Tiger box well.

Thanks,
MUNE


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-02-14  0:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-01 23:30 [patch] acpiphp: handle dock stations Kristen Carlson Accardi
2006-02-02  5:09 ` [Pcihpd-discuss] " Kenji Kaneshige
2006-02-06 13:15 ` Pavel Machek
2006-02-06 13:21 ` Pavel Machek
2006-02-13  1:50 ` [Pcihpd-discuss] " MUNEDA Takahiro
2006-02-13 15:57   ` Kenji Kaneshige
2006-02-14  0:41     ` MUNEDA Takahiro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox