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? Yinghai -- 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