On Saturday, June 22, 2013 05:22:20 PM Yinghai Lu wrote: > On Sat, Jun 22, 2013 at 2:25 PM, Rafael J. Wysocki <rjw@xxxxxxx> wrote: > > From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> > > > > To resolve that deadlock use the observation that > > unregister_hotplug_dock_device() won't need to acquire hp_lock > > if PCI bridges the devices on the dock station depend on are > > prevented from being removed prematurely while the first loop in > > hotplug_dock_devices() is in progress. > > > > To make that possible, introduce a mechanism by which the callers of > > register_hotplug_dock_device() can provide "init" and "release" > > routines that will be executed, respectively, after the addition > > and removal of the physical device object associated with the > > given ACPI device handle. Make acpiphp use two new functions, > > acpiphp_dock_init() and acpiphp_dock_release(), respectively, > > calling get_bridge() and put_bridge() on the PCI bridge holding the > > given device, respectively, for this purpose. > > > > In addition to that, remove the dock station's list of > > "hotplug devices" and make the dock code always walk the whole list > > of "dependent devices" instead in such a way that the loops in > > hotplug_dock_devices() and dock_event() (replacing the loops over > > "hotplug devices") will take references to the list entries that > > register_hotplug_dock_device() has been called for. That prevents > > the "release" routines associated with those entries from being > > called while the given entry is being processed and for PCI > > devices this means that their bridges won't be removed (by a > > concurrent thread) while hotplug_event_func() handling them is > > being executed. > .. > > -static void > > -dock_del_hotplug_device(struct dock_station *ds, > > - struct dock_dependent_device *dd) > > +static void dock_release_hotplug(struct dock_dependent_device *dd) > > { > > - mutex_lock(&ds->hp_lock); > > - list_del(&dd->hotplug_list); > > - mutex_unlock(&ds->hp_lock); > > + void (*release)(void *) = NULL; > > + void *context = NULL; > > + > > + mutex_lock(&hotplug_lock); > > + > > + if (dd->hp_context && !--dd->hp_refcount) { > > + dd->hp_ops = NULL; > > + context = dd->hp_context; > > + dd->hp_context = NULL; > > + release = dd->hp_release; > > + dd->hp_release = NULL; > > + } > > + > > + if (release && context) > > + release(context); > > + > > + mutex_unlock(&hotplug_lock); > > +} > > + > > +static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, > > + bool uevent) > > +{ > > + acpi_notify_handler cb = NULL; > > + bool run = false; > > + > > + mutex_lock(&hotplug_lock); > > + > > + if (dd->hp_context) { > > + run = true; > > + dd->hp_refcount++; > > + if (dd->hp_ops) > > + cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler; > > + } > > + > > + mutex_unlock(&hotplug_lock); > > + > > + if (!run) > > + return; > > + > > + if (cb) > > + cb(dd->handle, event, dd->hp_context); > > + > > + dock_release_hotplug(dd); > > during DOCKING, dock_release_hotplug get called too? Yes, we need to drop down the refcount we've just bumped up. Thanks, Rafael -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html