]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
delete queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2013 19:42:04 +0000 (12:42 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2013 19:42:04 +0000 (12:42 -0700)
queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch [deleted file]
queue-3.9/series

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 (file)
index 27c946c..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-From 21a31013f774c726bd199526cd673acc6432b21d Mon Sep 17 00:00:00 2001
-From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
-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" <rafael.j.wysocki@intel.com>
-
-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 <patrakov@gmail.com>
-Tracked-down-by: Jiang Liu <jiang.liu@huawei.com>
-Tested-by: Illya Klymov <xanf@xanf.me>
-Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-Acked-by: Yinghai Lu <yinghai@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- 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;
- }
index e331430572404518a899268471befdd7d12c6e7b..d4868fc08d91dc54aa4e27174cd3ee5fe233094a 100644 (file)
@@ -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