Re: [PATCH] acpiphp: treat dck separate from dock bridge

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 2006-01-21 at 13:10 +0100, Pavel Machek wrote:
<snip>
> 
> Oopsen seems to be called because add_p2p_bridge is never called. I
> think it should be called for this device:
> 
> 0000:00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 81)
> 
> --- clean-mm//drivers/pci/hotplug/acpiphp_glue.c	2006-01-21 11:38:51.000000000 +0100
> +++ linux-mm/drivers/pci/hotplug/acpiphp_glue.c	2006-01-21 12:53:28.000000000 +0100
> @@ -454,16 +457,22 @@
>  		return AE_OK;
>  	}
>  
> +	printk("ADR ok\n");
> +
>  	device = (tmp >> 16) & 0xffff;
>  	function = tmp & 0xffff;
>  
>  	dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
>  
> +	printk("device, function = %lx\n", tmp);
> +
>  	if (!dev || !dev->subordinate)
>  		goto out;
>  
> +	printk("detect slots\n");
> +
>  	/* check if this bridge has ejectable slots */
> -	if (detect_ejectable_slots(handle) > 0) {
> +	if ((tmp == 0x1e0000) || (detect_ejectable_slots(handle) > 0)) {
>  		dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
>  		add_p2p_bridge(handle, dev);
>  	}
> 
> ...but then bridge->slots is still empty. I tried forcing
> is_ejectable(), but then I get:
> 
> Jan 21 13:09:52 amd kernel: acpiphp: ACPI Hot Plug PCI Controller
> Driver version: 0.5
> Jan 21 13:09:53 amd kernel: add_bridge
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0000
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 10000
> Jan 21 13:09:53 amd kernel: detect slots
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1e0000
> Jan 21 13:09:53 amd kernel: detect slots
> Jan 21 13:09:53 amd kernel: acpiphp_glue: found PCI-to-PCI bridge at
> PCI 0000:00:1e.0
> Jan 21 13:09:53 amd kernel: add_p2p_bridge
> Jan 21 13:09:53 amd kernel: acpiphp_glue: _HPP evaluation failed
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0001
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0000
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0001
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0002
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0007
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0006
> Jan 21 13:09:53 amd kernel: acpiphp_glue: Bus 0000:02 has 0 slots
> Jan 21 13:09:53 amd kernel: acpiphp_glue: Total 0 slots
> Jan 21 13:10:05 amd pam_limits[1345]: wrong limit value 'unlimited'
> 
> 								Pavel


Well, let's back up a bit.  I see a few things wrong.  Starting with
just the basics, it doesn't seem like we have even found your _DCK
method, otherwise find_num_slots should have reported 1.  If we had been
able to find the dock bridge, then adding the p2p bridge would have
worked as well.  Let's debug this problem first - Can you please try
this patch, making sure to load the module with debugging enabled:

modprobe acpiphp debug=1

and then send me the output of dmesg -s 10000?  Thanks for helping me
debug, I appreciate it.  This patch just adds some extra debugging info
to the code path that I would expect to be taken while trying to find
your _DCK method.  Other than that, it is unchanged.

Kristen

 drivers/pci/hotplug/acpiphp.h      |   11 +
 drivers/pci/hotplug/acpiphp_glue.c |  366 +++++++++++++++++++++++++++----------
 2 files changed, 284 insertions(+), 93 deletions(-)

--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp.h
@@ -148,6 +148,17 @@ struct acpiphp_func {
 	u32		flags;		/* see below */
 };
 
+
+struct acpiphp_dock_bridge {
+	acpi_handle dock_bridge_handle;
+	acpi_handle dck_handle;
+	struct acpiphp_func *func;
+	struct acpiphp_slot *slot;
+	u32 last_dock_time;
+	u32 flags;
+};
+
+
 /**
  * struct acpiphp_attention_info - device specific attention registration
  *
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp_glue.c
@@ -53,15 +53,14 @@
 #include "acpiphp.h"
 
 static LIST_HEAD(bridge_list);
+static struct acpiphp_dock_bridge dock_bridge;
 
 #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);
 
 /*
@@ -104,13 +103,26 @@ static int is_ejectable(acpi_handle hand
 }
 
 
+
+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;
+}
+
 /* callback routine to check the existence of ejectable slots */
 static acpi_status
 is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
 	int *count = (int *)context;
 
-	if (is_ejectable(handle)) {
+	if (is_ejectable(handle) || (handle == dock_bridge.dock_bridge_handle)) {
 		(*count)++;
 		/* only one ejectable slot is enough */
 		return AE_CTRL_TERMINATE;
@@ -120,7 +132,9 @@ is_ejectable_slot(acpi_handle handle, u3
 }
 
 
-static acpi_status handle_dock(struct acpiphp_func *func, int dock)
+
+
+static acpi_status handle_dock(int dock)
 {
 	acpi_status status;
 	struct acpi_object_list arg_list;
@@ -134,10 +148,13 @@ static acpi_status handle_dock(struct ac
 	arg_list.pointer = &arg;
 	arg.type = ACPI_TYPE_INTEGER;
 	arg.integer.value = dock;
-	status = acpi_evaluate_object(func->handle, "_DCK",
+	status = acpi_evaluate_object(dock_bridge.dck_handle, "_DCK",
 					&arg_list, &buffer);
 	if (ACPI_FAILURE(status))
 		err("%s: failed to dock!!\n", MY_NAME);
+	acpi_os_free(buffer.pointer);
+
+	dbg("%s: exit\n", __FUNCTION__);
 
 	return status;
 }
@@ -157,6 +174,7 @@ register_slot(acpi_handle handle, u32 lv
 	int device, function;
 	static int num_slots = 0;	/* XXX if we support I/O node hotplug... */
 
+
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
 
 	if (ACPI_FAILURE(status))
@@ -164,9 +182,10 @@ register_slot(acpi_handle handle, u32 lv
 
 	status = acpi_get_handle(handle, "_EJ0", &tmp);
 
-	if (ACPI_FAILURE(status))
+	if ((handle != dock_bridge.dock_bridge_handle) && ACPI_FAILURE(status))
 		return AE_OK;
 
+
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
@@ -178,7 +197,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;
@@ -189,6 +209,9 @@ 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;
+
 	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
 	if (ACPI_FAILURE(status))
 		sun = -1;
@@ -236,24 +259,22 @@ 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,
+	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 if (handle == dock_bridge.dock_bridge_handle) {
+		dock_bridge.func = newfunc;
+		dock_bridge.slot = slot;
+		status = AE_OK;
 	}
 
-	return AE_OK;
+	return status;
 }
 
 
@@ -544,11 +565,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);
@@ -713,33 +736,6 @@ 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)
@@ -771,26 +767,32 @@ static int acpiphp_bus_add(struct acpiph
 
 
 
-static void dock(void *data)
+
+/*
+ * the _DCK method can do funny things... and sometimes not
+ * hah-hah funny.
+ */
+static void post_dock_fixups(void)
 {
-	struct list_head *l;
-	struct acpiphp_func *func;
-	struct acpiphp_slot *slot = data;
+	struct pci_bus *bus = dock_bridge.slot->bridge->pci_bus;
+	u32 buses;
 
-	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) {
-			handle_dock(func, 1);
-			post_dock_fixups(slot, func);
-			slot->flags |= SLOT_POWEREDON;
-			if (get_slot_status(slot) == ACPI_STA_ALL) {
-				enable_device(slot);
-			}
-		}
+	/* 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);
 	}
-	slot->flags &= (~SLOT_DOCKING);
-	mutex_unlock(&slot->crit_sect);
 }
 
 
@@ -819,19 +821,6 @@ 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 */
@@ -857,11 +846,6 @@ 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)) {
@@ -871,6 +855,7 @@ static int power_off_slot(struct acpiphp
 			} else
 				break;
 		}
+
 	}
 
 	/* TBD: evaluate _STA to check if the slot is disabled */
@@ -882,6 +867,8 @@ static int power_off_slot(struct acpiphp
 }
 
 
+
+
 /**
  * get_func - given pci_dev & slot, get the matching acpiphp_func
  * @slot: slot to be scanned.
@@ -889,22 +876,27 @@ static int power_off_slot(struct acpiphp
  *
  * This function will check the list of acpiphp functions for
  * this slot and return the one that represents the given
- * pci_dev structure.
+ * pci_dev structure.  This function will incremente the ref
+ * pointer of the pci_dev struct as a side effect, so the caller
+ * must call pci_dev_put when they are done.
  */
 static struct acpiphp_func * get_func(struct acpiphp_slot *slot,
 					struct pci_dev *dev)
 {
-	struct list_head *l;
-	struct acpiphp_func *func;
+	struct acpiphp_func *func = NULL;
 	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_dev *pdev;
 
-	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;
+	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 NULL;
+	return func;
 }
 
 
@@ -987,8 +979,11 @@ static int enable_device(struct acpiphp_
 				if (pass && dev->subordinate) {
 					pci_bus_size_bridges(dev->subordinate);
 					func = get_func(slot, dev);
-					if (func)
+					if (func) {
 						acpiphp_bus_add(func);
+						/* side effect of get_func() */
+						pci_dev_put(dev);
+					}
 				}
 			}
 		}
@@ -1306,6 +1301,7 @@ static void handle_bridge_insertion(acpi
  * ACPI event handlers
  */
 
+
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
@@ -1439,6 +1435,47 @@ static void handle_hotplug_event_func(ac
 	}
 }
 
+
+
+static void
+handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
+{
+	acpi_handle dock = dock_bridge.dock_bridge_handle;
+
+	switch (type) {
+		case ACPI_NOTIFY_BUS_CHECK:
+			dbg("%s: Bus check notify\n",
+				__FUNCTION__);
+			dock_bridge.flags |= SLOT_DOCKING;
+			handle_dock(1);
+			if (dock) {
+				post_dock_fixups();
+				handle_hotplug_event_func(dock,
+					type, dock_bridge.func);
+			}
+			dock_bridge.flags &= ~(SLOT_DOCKING);
+			dock_bridge.last_dock_time = jiffies;
+			break;
+		case ACPI_NOTIFY_EJECT_REQUEST:
+			if (dock_bridge.flags & SLOT_DOCKING ||
+				dock_bridge.last_dock_time == jiffies) {
+				dbg("%s: Ignore bogus eject request\n",
+					__FUNCTION__);
+			} else {
+				dbg("%s: Eject notify\n", __FUNCTION__);
+				handle_dock(0);
+				handle_hotplug_event_func(dock,
+					type, dock_bridge.func);
+			}
+			break;
+		default:
+			warn("%s: unknown event type 0x%x\n",
+				__FUNCTION__, type);
+	}
+}
+
+
+
 static int is_root_bridge(acpi_handle handle)
 {
 	acpi_status status;
@@ -1468,6 +1505,130 @@ static int is_root_bridge(acpi_handle ha
 	return 0;
 }
 
+
+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 = { .length = sizeof(ejd_objname),
+					  .pointer = ejd_objname };
+	union acpi_object *ejd_obj;
+	union acpi_object *dck_obj;
+
+	dbg("%s: enter\n", __FUNCTION__);
+
+	status = acpi_get_handle(handle, "_EJD", &tmp);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: no _EJD methods found\n", __FUNCTION__);
+		return 0;
+	}
+
+	/* 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");
+		return 0;
+	}
+
+	ejd_obj = ejd_buffer.pointer;
+	dck_obj = buffer.pointer;
+	if (!strncmp(ejd_obj->string.pointer, dck_obj->string.pointer,
+		ejd_obj->string.length)) {
+		dbg("%s: found device dependent on dock\n", __FUNCTION__);
+		/* ok, this device is dependent on the dock device,
+		 * if it was the actual dock bridge, it would have
+		 * a PRT associated with it.
+		 */
+		status = acpi_get_handle(handle, "_PRT", &tmp);
+		if (ACPI_FAILURE(status))
+			return 0;
+
+		/* yippee, we found the dock bridge! */
+		dbg("%s: found dock bridge\n", __FUNCTION__);
+		*(rv) = handle;
+		return AE_CTRL_TERMINATE;
+	}
+	return AE_OK;
+}
+
+
+static acpi_handle
+get_dock_handle(acpi_handle handle)
+{
+	acpi_handle dock_bridge_handle = NULL;
+
+	dbg("%s: enter\n", __FUNCTION__);
+
+	/*
+	 * first see if we are the dock bridge.
+	 */
+	if (is_ejectable(handle))
+		return handle;
+
+	dbg("%s: not ejectable\n", __FUNCTION__);
+
+	/*
+	 * otherwise, we are going to have to find
+	 * the dock bridge by checking the _EJD list.
+	 */
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+		ACPI_UINT32_MAX, find_dock_ejd, handle, &dock_bridge_handle);
+
+	return dock_bridge_handle;
+}
+
+
+
+static acpi_status
+find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	int *count = (int *)context;
+
+	dbg("%s: enter\n", __FUNCTION__);
+
+	if (is_dock(handle)) {
+		/* found a dock.  Now we have to determine if
+		 * the _DCK method is within the scope of the
+		 * dock bridge, or outside it (as in the IBM x-series)
+		 */
+		dbg("%s: found dock\n", __FUNCTION__);
+		dock_bridge.dock_bridge_handle = get_dock_handle(handle);
+		dock_bridge.dck_handle = handle;
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+			handle_hotplug_event_dock, NULL);
+		(*count)++;
+	}
+
+	return AE_OK;
+}
+
+
+
+
+static int
+find_dock_bridge(void)
+{
+	int num = 0;
+
+	/* 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;
+}
+
+
+
+
 static acpi_status
 find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
@@ -1494,6 +1655,8 @@ int __init acpiphp_glue_init(void)
 {
 	int num = 0;
 
+	num = find_dock_bridge();
+
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 			ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
 
@@ -1513,6 +1676,17 @@ int __init acpiphp_glue_init(void)
  */
 void __exit acpiphp_glue_exit(void)
 {
+	acpi_handle handle = dock_bridge.dck_handle;
+
+	/* if we have a dock station handle, we should
+	 * remove the notify handler
+	 */
+	if (handle) {
+		if (ACPI_FAILURE(acpi_remove_notify_handler(handle,
+			ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
+			err("failed to remove dock notify handler\n");
+	}
+
 	acpi_pci_unregister_driver(&acpi_pci_hp_driver);
 }
 
@@ -1537,6 +1711,12 @@ int __init acpiphp_get_num_slots(void)
 		num_slots += bridge->nr_slots;
 	}
 
+	/* it's possible to have a dock station that doesn't actually
+	 * use a pci dock bridge.  For now, continue to allow this
+	 * to be handled by this driver.
+	 */
+	if (dock_bridge.dck_handle && !dock_bridge.dock_bridge_handle)
+		num_slots++;
 	dbg("Total %d slots\n", num_slots);
 	return num_slots;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux