From: Greg Kroah-Hartman Date: Thu, 27 Jun 2013 19:42:04 +0000 (-0700) Subject: delete queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices... X-Git-Tag: v3.9.9~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=32a57b108a6770ea078224d58b7364f30080151d;p=thirdparty%2Fkernel%2Fstable-queue.git delete queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch --- diff --git a/queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch b/queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch deleted file mode 100644 index 27c946c30b7..00000000000 --- a/queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch +++ /dev/null @@ -1,463 +0,0 @@ -From 21a31013f774c726bd199526cd673acc6432b21d Mon Sep 17 00:00:00 2001 -From: "Rafael J. Wysocki" -Date: Mon, 24 Jun 2013 11:22:53 +0200 -Subject: ACPI / dock / PCI: Synchronous handling of dock events for PCI devices - -From: "Rafael J. Wysocki" - -commit 21a31013f774c726bd199526cd673acc6432b21d upstream. - -The interactions between the ACPI dock driver and the ACPI-based PCI -hotplug (acpiphp) are currently problematic because of ordering -issues during hot-remove operations. - -First of all, the current ACPI glue code expects that physical -devices will always be deleted before deleting the companion ACPI -device objects. Otherwise, acpi_unbind_one() will fail with a -warning message printed to the kernel log, for example: - -[ 185.026073] usb usb5: Oops, 'acpi_handle' corrupt -[ 185.035150] pci 0000:1b:00.0: Oops, 'acpi_handle' corrupt -[ 185.035515] pci 0000:18:02.0: Oops, 'acpi_handle' corrupt -[ 180.013656] port1: Oops, 'acpi_handle' corrupt - -This means, in particular, that struct pci_dev objects have to -be deleted before the struct acpi_device objects they are "glued" -with. - -Now, the following happens the during the undocking of an ACPI-based -dock station: - 1) hotplug_dock_devices() invokes registered hotplug callbacks to - destroy physical devices associated with the ACPI device objects - depending on the dock station. It calls dd->ops->handler() for - each of those device objects. - 2) For PCI devices dd->ops->handler() points to - handle_hotplug_event_func() that queues up a separate work item - to execute _handle_hotplug_event_func() for the given device and - returns immediately. That work item will be executed later. - 3) hotplug_dock_devices() calls dock_remove_acpi_device() for each - device depending on the dock station. This runs acpi_bus_trim() - for each of them, which causes the underlying ACPI device object - to be destroyed, but the work items queued up by - handle_hotplug_event_func() haven't been started yet. - 4) _handle_hotplug_event_func() queued up in step 2) are executed - and cause the above failure to happen, because the PCI devices - they handle do not have the companion ACPI device objects any - more (those objects have been deleted in step 3). - -The possible breakage doesn't end here, though, because -hotplug_dock_devices() may return before at least some of the -_handle_hotplug_event_func() work items spawned by it have a -chance to complete and then undock() will cause _DCK to be -evaluated and that will cause the devices handled by the -_handle_hotplug_event_func() to go away possibly while they are -being accessed. - -This means that dd->ops->handler() for PCI devices should not point -to handle_hotplug_event_func(). Instead, it should point to a -function that will do the work of _handle_hotplug_event_func() -synchronously. For this reason, introduce such a function, -hotplug_event_func(), and modity acpiphp_dock_ops to point to -it as the handler. - -Unfortunately, however, this is not sufficient, because if the dock -code were not changed further, hotplug_event_func() would now -deadlock with hotplug_dock_devices() that called it, since it would -run unregister_hotplug_dock_device() which in turn would attempt to -acquire the dock station's hp_lock mutex already acquired by -hotplug_dock_devices(). - -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, during 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(), that call -get_bridge() and put_bridge(), respectively, on the acpiphp bridge -holding the given device, 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. - -This change is based on two earlier patches from Jiang Liu. - -References: https://bugzilla.kernel.org/show_bug.cgi?id=59501 -Reported-and-tested-by: Alexander E. Patrakov -Tracked-down-by: Jiang Liu -Tested-by: Illya Klymov -Signed-off-by: Rafael J. Wysocki -Acked-by: Yinghai Lu -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/acpi/dock.c | 141 +++++++++++++++++++++++++------------ - drivers/pci/hotplug/acpiphp_glue.c | 46 ++++++++---- - include/acpi/acpi_drivers.h | 8 +- - 3 files changed, 135 insertions(+), 60 deletions(-) - ---- a/drivers/acpi/dock.c -+++ b/drivers/acpi/dock.c -@@ -66,20 +66,21 @@ struct dock_station { - spinlock_t dd_lock; - struct mutex hp_lock; - struct list_head dependent_devices; -- struct list_head hotplug_devices; - - struct list_head sibling; - struct platform_device *dock_device; - }; - static LIST_HEAD(dock_stations); - static int dock_station_count; -+static DEFINE_MUTEX(hotplug_lock); - - struct dock_dependent_device { - struct list_head list; -- struct list_head hotplug_list; - acpi_handle handle; -- const struct acpi_dock_ops *ops; -- void *context; -+ const struct acpi_dock_ops *hp_ops; -+ void *hp_context; -+ unsigned int hp_refcount; -+ void (*hp_release)(void *); - }; - - #define DOCK_DOCKING 0x00000001 -@@ -111,7 +112,6 @@ add_dock_dependent_device(struct dock_st - - dd->handle = handle; - INIT_LIST_HEAD(&dd->list); -- INIT_LIST_HEAD(&dd->hotplug_list); - - spin_lock(&ds->dd_lock); - list_add_tail(&dd->list, &ds->dependent_devices); -@@ -121,35 +121,90 @@ add_dock_dependent_device(struct dock_st - } - - /** -- * dock_add_hotplug_device - associate a hotplug handler with the dock station -- * @ds: The dock station -- * @dd: The dependent device struct -- * -- * Add the dependent device to the dock's hotplug device list -- */ --static void --dock_add_hotplug_device(struct dock_station *ds, -- struct dock_dependent_device *dd) --{ -- mutex_lock(&ds->hp_lock); -- list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); -- mutex_unlock(&ds->hp_lock); -+ * dock_init_hotplug - Initialize a hotplug device on a docking station. -+ * @dd: Dock-dependent device. -+ * @ops: Dock operations to attach to the dependent device. -+ * @context: Data to pass to the @ops callbacks and @release. -+ * @init: Optional initialization routine to run after setting up context. -+ * @release: Optional release routine to run on removal. -+ */ -+static int dock_init_hotplug(struct dock_dependent_device *dd, -+ const struct acpi_dock_ops *ops, void *context, -+ void (*init)(void *), void (*release)(void *)) -+{ -+ int ret = 0; -+ -+ mutex_lock(&hotplug_lock); -+ -+ if (dd->hp_context) { -+ ret = -EEXIST; -+ } else { -+ dd->hp_refcount = 1; -+ dd->hp_ops = ops; -+ dd->hp_context = context; -+ dd->hp_release = release; -+ } -+ -+ if (!WARN_ON(ret) && init) -+ init(context); -+ -+ mutex_unlock(&hotplug_lock); -+ return ret; - } - - /** -- * dock_del_hotplug_device - remove a hotplug handler from the dock station -- * @ds: The dock station -- * @dd: the dependent device struct -+ * dock_release_hotplug - Decrement hotplug reference counter of dock device. -+ * @dd: Dock-dependent device. - * -- * Delete the dependent device from the dock's hotplug device list -+ * Decrement the reference counter of @dd and if 0, detach its hotplug -+ * operations from it, reset its context pointer and run the optional release -+ * routine if present. - */ --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); - } - - /** -@@ -360,9 +415,8 @@ static void hotplug_dock_devices(struct - /* - * First call driver specific hotplug functions - */ -- list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) -- if (dd->ops && dd->ops->handler) -- dd->ops->handler(dd->handle, event, dd->context); -+ list_for_each_entry(dd, &ds->dependent_devices, list) -+ dock_hotplug_event(dd, event, false); - - /* - * Now make sure that an acpi_device is created for each -@@ -398,9 +452,8 @@ static void dock_event(struct dock_stati - if (num == DOCK_EVENT) - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); - -- list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) -- if (dd->ops && dd->ops->uevent) -- dd->ops->uevent(dd->handle, event, dd->context); -+ list_for_each_entry(dd, &ds->dependent_devices, list) -+ dock_hotplug_event(dd, event, true); - - if (num != DOCK_EVENT) - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); -@@ -570,19 +623,24 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifi - * @handle: the handle of the device - * @ops: handlers to call after docking - * @context: device specific data -+ * @init: Optional initialization routine to run after registration -+ * @release: Optional release routine to run on unregistration - * - * If a driver would like to perform a hotplug operation after a dock - * event, they can register an acpi_notifiy_handler to be called by - * the dock driver after _DCK is executed. - */ --int --register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, -- void *context) -+int register_hotplug_dock_device(acpi_handle handle, -+ const struct acpi_dock_ops *ops, void *context, -+ void (*init)(void *), void (*release)(void *)) - { - struct dock_dependent_device *dd; - struct dock_station *dock_station; - int ret = -EINVAL; - -+ if (WARN_ON(!context)) -+ return -EINVAL; -+ - if (!dock_station_count) - return -ENODEV; - -@@ -597,12 +655,8 @@ register_hotplug_dock_device(acpi_handle - * ops - */ - dd = find_dock_dependent_device(dock_station, handle); -- if (dd) { -- dd->ops = ops; -- dd->context = context; -- dock_add_hotplug_device(dock_station, dd); -+ if (dd && !dock_init_hotplug(dd, ops, context, init, release)) - ret = 0; -- } - } - - return ret; -@@ -624,7 +678,7 @@ void unregister_hotplug_dock_device(acpi - list_for_each_entry(dock_station, &dock_stations, sibling) { - dd = find_dock_dependent_device(dock_station, handle); - if (dd) -- dock_del_hotplug_device(dock_station, dd); -+ dock_release_hotplug(dd); - } - } - EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); -@@ -953,7 +1007,6 @@ static int __init dock_add(acpi_handle h - mutex_init(&dock_station->hp_lock); - spin_lock_init(&dock_station->dd_lock); - INIT_LIST_HEAD(&dock_station->sibling); -- INIT_LIST_HEAD(&dock_station->hotplug_devices); - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); - INIT_LIST_HEAD(&dock_station->dependent_devices); - ---- a/drivers/pci/hotplug/acpiphp_glue.c -+++ b/drivers/pci/hotplug/acpiphp_glue.c -@@ -60,6 +60,7 @@ static LIST_HEAD(bridge_list); - static void handle_hotplug_event_bridge (acpi_handle, u32, void *); - static void acpiphp_sanitize_bus(struct pci_bus *bus); - static void acpiphp_set_hpp_values(struct pci_bus *bus); -+static void hotplug_event_func(acpi_handle handle, u32 type, void *context); - static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); - - /* callback routine to check for the existence of a pci dock device */ -@@ -112,7 +113,7 @@ static int post_dock_fixups(struct notif - - - static const struct acpi_dock_ops acpiphp_dock_ops = { -- .handler = handle_hotplug_event_func, -+ .handler = hotplug_event_func, - }; - - /* Check whether the PCI device is managed by native PCIe hotplug driver */ -@@ -144,6 +145,20 @@ static bool device_is_managed_by_native_ - return true; - } - -+static void acpiphp_dock_init(void *data) -+{ -+ struct acpiphp_func *func = data; -+ -+ get_bridge(func->slot->bridge); -+} -+ -+static void acpiphp_dock_release(void *data) -+{ -+ struct acpiphp_func *func = data; -+ -+ put_bridge(func->slot->bridge); -+} -+ - /* callback routine to register each ACPI PCI slot object */ - static acpi_status - register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) -@@ -262,7 +277,8 @@ register_slot(acpi_handle handle, u32 lv - */ - newfunc->flags &= ~FUNC_HAS_EJ0; - if (register_hotplug_dock_device(handle, -- &acpiphp_dock_ops, newfunc)) -+ &acpiphp_dock_ops, newfunc, -+ acpiphp_dock_init, acpiphp_dock_release)) - dbg("failed to register dock device\n"); - - /* we need to be notified when dock events happen -@@ -1231,22 +1247,12 @@ static void handle_hotplug_event_bridge( - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); - } - --static void _handle_hotplug_event_func(struct work_struct *work) -+static void hotplug_event_func(acpi_handle handle, u32 type, void *context) - { -- struct acpiphp_func *func; -+ struct acpiphp_func *func = context; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; -- struct acpi_hp_work *hp_work; -- acpi_handle handle; -- u32 type; -- -- hp_work = container_of(work, struct acpi_hp_work, work); -- handle = hp_work->handle; -- type = hp_work->type; -- func = (struct acpiphp_func *)hp_work->context; -- -- acpi_scan_lock_acquire(); - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - -@@ -1279,6 +1285,18 @@ static void _handle_hotplug_event_func(s - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -+} -+ -+static void _handle_hotplug_event_func(struct work_struct *work) -+{ -+ struct acpi_hp_work *hp_work; -+ struct acpiphp_func *func; -+ -+ hp_work = container_of(work, struct acpi_hp_work, work); -+ func = hp_work->context; -+ acpi_scan_lock_acquire(); -+ -+ hotplug_event_func(hp_work->handle, hp_work->type, func); - - acpi_scan_lock_release(); - kfree(hp_work); /* allocated in handle_hotplug_event_func */ ---- a/include/acpi/acpi_drivers.h -+++ b/include/acpi/acpi_drivers.h -@@ -124,7 +124,9 @@ extern int register_dock_notifier(struct - extern void unregister_dock_notifier(struct notifier_block *nb); - extern int register_hotplug_dock_device(acpi_handle handle, - const struct acpi_dock_ops *ops, -- void *context); -+ void *context, -+ void (*init)(void *), -+ void (*release)(void *)); - extern void unregister_hotplug_dock_device(acpi_handle handle); - #else - static inline int is_dock_device(acpi_handle handle) -@@ -140,7 +142,9 @@ static inline void unregister_dock_notif - } - static inline int register_hotplug_dock_device(acpi_handle handle, - const struct acpi_dock_ops *ops, -- void *context) -+ void *context, -+ void (*init)(void *), -+ void (*release)(void *)) - { - return -ENODEV; - } diff --git a/queue-3.9/series b/queue-3.9/series index e3314305724..d4868fc08d9 100644 --- a/queue-3.9/series +++ b/queue-3.9/series @@ -16,5 +16,4 @@ net-tg3-avoid-delay-during-mmio-access.patch rt2800-fix-rt5390-rt3290-tx-power-settings-regression.patch libata-acpi-add-back-acpi-based-hotplug-functionality.patch pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch -acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch