]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2013 19:30:19 +0000 (12:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2013 19:30:19 +0000 (12:30 -0700)
added patches:
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
libata-acpi-add-back-acpi-based-hotplug-functionality.patch
pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch

queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch [new file with mode: 0644]
queue-3.9/iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch [new file with mode: 0644]
queue-3.9/libata-acpi-add-back-acpi-based-hotplug-functionality.patch [new file with mode: 0644]
queue-3.9/pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch [new file with mode: 0644]
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
new file mode 100644 (file)
index 0000000..27c946c
--- /dev/null
@@ -0,0 +1,463 @@
+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;
+ }
diff --git a/queue-3.9/iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch b/queue-3.9/iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch
new file mode 100644 (file)
index 0000000..2b0aa0d
--- /dev/null
@@ -0,0 +1,179 @@
+From 03bbcb2e7e292838bb0244f5a7816d194c911d62 Mon Sep 17 00:00:00 2001
+From: Neil Horman <nhorman@tuxdriver.com>
+Date: Tue, 16 Apr 2013 16:38:32 -0400
+Subject: iommu/vt-d: add quirk for broken interrupt remapping on 55XX chipsets
+
+From: Neil Horman <nhorman@tuxdriver.com>
+
+commit 03bbcb2e7e292838bb0244f5a7816d194c911d62 upstream.
+
+A few years back intel published a spec update:
+http://www.intel.com/content/dam/doc/specification-update/5520-and-5500-chipset-ioh-specification-update.pdf
+
+For the 5520 and 5500 chipsets which contained an errata (specificially errata
+53), which noted that these chipsets can't properly do interrupt remapping, and
+as a result the recommend that interrupt remapping be disabled in bios.  While
+many vendors have a bios update to do exactly that, not all do, and of course
+not all users update their bios to a level that corrects the problem.  As a
+result, occasionally interrupts can arrive at a cpu even after affinity for that
+interrupt has be moved, leading to lost or spurrious interrupts (usually
+characterized by the message:
+kernel: do_IRQ: 7.71 No irq handler for vector (irq -1)
+
+There have been several incidents recently of people seeing this error, and
+investigation has shown that they have system for which their BIOS level is such
+that this feature was not properly turned off.  As such, it would be good to
+give them a reminder that their systems are vulnurable to this problem.  For
+details of those that reported the problem, please see:
+https://bugzilla.redhat.com/show_bug.cgi?id=887006
+
+[ Joerg: Removed CONFIG_IRQ_REMAP ifdef from early-quirks.c ]
+
+Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
+CC: Prarit Bhargava <prarit@redhat.com>
+CC: Don Zickus <dzickus@redhat.com>
+CC: Don Dutile <ddutile@redhat.com>
+CC: Bjorn Helgaas <bhelgaas@google.com>
+CC: Asit Mallick <asit.k.mallick@intel.com>
+CC: David Woodhouse <dwmw2@infradead.org>
+CC: linux-pci@vger.kernel.org
+CC: Joerg Roedel <joro@8bytes.org>
+CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+CC: Arkadiusz Miƛkiewicz <arekm@maven.pl>
+Signed-off-by: Joerg Roedel <joro@8bytes.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/include/asm/irq_remapping.h |    3 +++
+ arch/x86/kernel/early-quirks.c       |   20 ++++++++++++++++++++
+ drivers/iommu/intel_irq_remapping.c  |   10 ++++++++++
+ drivers/iommu/irq_remapping.c        |    6 ++++++
+ drivers/iommu/irq_remapping.h        |    2 ++
+ 5 files changed, 41 insertions(+)
+
+--- a/arch/x86/include/asm/irq_remapping.h
++++ b/arch/x86/include/asm/irq_remapping.h
+@@ -23,11 +23,13 @@
+ #define __X86_IRQ_REMAPPING_H
+ #include <asm/io_apic.h>
++#include <linux/irq.h>
+ #ifdef CONFIG_IRQ_REMAP
+ extern void setup_irq_remapping_ops(void);
+ extern int irq_remapping_supported(void);
++extern void set_irq_remapping_broken(void);
+ extern int irq_remapping_prepare(void);
+ extern int irq_remapping_enable(void);
+ extern void irq_remapping_disable(void);
+@@ -54,6 +56,7 @@ void irq_remap_modify_chip_defaults(stru
+ static inline void setup_irq_remapping_ops(void) { }
+ static inline int irq_remapping_supported(void) { return 0; }
++static inline void set_irq_remapping_broken(void) { }
+ static inline int irq_remapping_prepare(void) { return -ENODEV; }
+ static inline int irq_remapping_enable(void) { return -ENODEV; }
+ static inline void irq_remapping_disable(void) { }
+--- a/arch/x86/kernel/early-quirks.c
++++ b/arch/x86/kernel/early-quirks.c
+@@ -18,6 +18,7 @@
+ #include <asm/apic.h>
+ #include <asm/iommu.h>
+ #include <asm/gart.h>
++#include <asm/irq_remapping.h>
+ static void __init fix_hypertransport_config(int num, int slot, int func)
+ {
+@@ -192,6 +193,21 @@ static void __init ati_bugs_contd(int nu
+ }
+ #endif
++static void __init intel_remapping_check(int num, int slot, int func)
++{
++      u8 revision;
++
++      revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
++
++      /*
++       * Revision 0x13 of this chipset supports irq remapping
++       * but has an erratum that breaks its behavior, flag it as such
++       */
++      if (revision == 0x13)
++              set_irq_remapping_broken();
++
++}
++
+ #define QFLAG_APPLY_ONCE      0x1
+ #define QFLAG_APPLIED         0x2
+ #define QFLAG_DONE            (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
+@@ -221,6 +237,10 @@ static struct chipset early_qrk[] __init
+         PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+         PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
++      { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST,
++        PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
++      { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
++        PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
+       {}
+ };
+--- a/drivers/iommu/intel_irq_remapping.c
++++ b/drivers/iommu/intel_irq_remapping.c
+@@ -524,6 +524,16 @@ static int __init intel_irq_remapping_su
+       if (disable_irq_remap)
+               return 0;
++      if (irq_remap_broken) {
++              WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
++                         "This system BIOS has enabled interrupt remapping\n"
++                         "on a chipset that contains an erratum making that\n"
++                         "feature unstable.  To maintain system stability\n"
++                         "interrupt remapping is being disabled.  Please\n"
++                         "contact your BIOS vendor for an update\n");
++              disable_irq_remap = 1;
++              return 0;
++      }
+       if (!dmar_ir_support())
+               return 0;
+--- a/drivers/iommu/irq_remapping.c
++++ b/drivers/iommu/irq_remapping.c
+@@ -18,6 +18,7 @@
+ int irq_remapping_enabled;
+ int disable_irq_remap;
++int irq_remap_broken;
+ int disable_sourceid_checking;
+ int no_x2apic_optout;
+@@ -210,6 +211,11 @@ void __init setup_irq_remapping_ops(void
+ #endif
+ }
++void set_irq_remapping_broken(void)
++{
++      irq_remap_broken = 1;
++}
++
+ int irq_remapping_supported(void)
+ {
+       if (disable_irq_remap)
+--- a/drivers/iommu/irq_remapping.h
++++ b/drivers/iommu/irq_remapping.h
+@@ -32,6 +32,7 @@ struct pci_dev;
+ struct msi_msg;
+ extern int disable_irq_remap;
++extern int irq_remap_broken;
+ extern int disable_sourceid_checking;
+ extern int no_x2apic_optout;
+ extern int irq_remapping_enabled;
+@@ -89,6 +90,7 @@ extern struct irq_remap_ops amd_iommu_ir
+ #define irq_remapping_enabled 0
+ #define disable_irq_remap     1
++#define irq_remap_broken      0
+ #endif /* CONFIG_IRQ_REMAP */
diff --git a/queue-3.9/libata-acpi-add-back-acpi-based-hotplug-functionality.patch b/queue-3.9/libata-acpi-add-back-acpi-based-hotplug-functionality.patch
new file mode 100644 (file)
index 0000000..48c9c73
--- /dev/null
@@ -0,0 +1,131 @@
+From 44521527be36172864e6e7a6fba4b66e9aa48e40 Mon Sep 17 00:00:00 2001
+From: Aaron Lu <aaron.lu@intel.com>
+Date: Thu, 20 Jun 2013 09:38:34 +0800
+Subject: libata-acpi: add back ACPI based hotplug functionality
+
+From: Aaron Lu <aaron.lu@intel.com>
+
+commit 44521527be36172864e6e7a6fba4b66e9aa48e40 upstream.
+
+Commit 30dcf76acc69 "libata: migrate ACPI code over to new bindings"
+mistakenly dropped the code to register hotplug notificaion handler
+for ATA port/devices, causing regression for people using ATA bay,
+as kernel bug #59871 shows.
+
+Fix this by adding back the hotplug notification handler registration
+code.  Since this code has to be run once and notification needs to
+be installed on every ATA port/devices handle no matter if there is
+actual device attached, we can't do this in binding time for ATA
+device ACPI handle, as the binding only occurs when a SCSI device is
+created, i.e. there is device attached.  So introduce the
+ata_acpi_hotplug_init() function to loop scan all ATA ACPI handles
+and if it is available, install the notificaion handler for it during
+ATA init time.
+
+With the ATA ACPI handle binding to SCSI device tree, it is possible
+now that when the SCSI hotplug work removes the SCSI device, the ACPI
+unbind function will find that the corresponding ACPI device has
+already been deleted by dock driver, causing a scaring message like:
+[  128.263966] scsi 4:0:0:0: Oops, 'acpi_handle' corrupt
+Fix this by waiting for SCSI hotplug task finish in our notificaion
+handler, so that the removal of ACPI device done in ACPI unbind
+function triggered by the removal of SCSI device is run earlier when
+ACPI device is still available.
+
+[rjw: Rebased]
+References: https://bugzilla.kernel.org/show_bug.cgi?id=59871
+Reported-bisected-and-tested-by: Dirk Griesbach <spamthis@freenet.de>
+Signed-off-by: Aaron Lu <aaron.lu@intel.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/ata/libata-acpi.c |   37 ++++++++++++++++++++++++++++++++++++-
+ drivers/ata/libata-core.c |    2 ++
+ drivers/ata/libata.h      |    2 ++
+ 3 files changed, 40 insertions(+), 1 deletion(-)
+
+--- a/drivers/ata/libata-acpi.c
++++ b/drivers/ata/libata-acpi.c
+@@ -157,8 +157,10 @@ static void ata_acpi_handle_hotplug(stru
+       spin_unlock_irqrestore(ap->lock, flags);
+-      if (wait)
++      if (wait) {
+               ata_port_wait_eh(ap);
++              flush_work(&ap->hotplug_task.work);
++      }
+ }
+ static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+@@ -215,6 +217,39 @@ static const struct acpi_dock_ops ata_ac
+       .uevent = ata_acpi_ap_uevent,
+ };
++void ata_acpi_hotplug_init(struct ata_host *host)
++{
++      int i;
++
++      for (i = 0; i < host->n_ports; i++) {
++              struct ata_port *ap = host->ports[i];
++              acpi_handle handle;
++              struct ata_device *dev;
++
++              if (!ap)
++                      continue;
++
++              handle = ata_ap_acpi_handle(ap);
++              if (handle) {
++                      /* we might be on a docking station */
++                      register_hotplug_dock_device(handle,
++                                                   &ata_acpi_ap_dock_ops, ap,
++                                                   NULL, NULL);
++              }
++
++              ata_for_each_dev(dev, &ap->link, ALL) {
++                      handle = ata_dev_acpi_handle(dev);
++                      if (!handle)
++                              continue;
++
++                      /* we might be on a docking station */
++                      register_hotplug_dock_device(handle,
++                                                   &ata_acpi_dev_dock_ops,
++                                                   dev, NULL, NULL);
++              }
++      }
++}
++
+ /**
+  * ata_acpi_dissociate - dissociate ATA host from ACPI objects
+  * @host: target ATA host
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -6148,6 +6148,8 @@ int ata_host_register(struct ata_host *h
+       if (rc)
+               goto err_tadd;
++      ata_acpi_hotplug_init(host);
++
+       /* set cable, sata_spd_limit and report */
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+--- a/drivers/ata/libata.h
++++ b/drivers/ata/libata.h
+@@ -122,6 +122,7 @@ extern int ata_acpi_register(void);
+ extern void ata_acpi_unregister(void);
+ extern void ata_acpi_bind(struct ata_device *dev);
+ extern void ata_acpi_unbind(struct ata_device *dev);
++extern void ata_acpi_hotplug_init(struct ata_host *host);
+ #else
+ static inline void ata_acpi_dissociate(struct ata_host *host) { }
+ static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
+@@ -134,6 +135,7 @@ static inline int ata_acpi_register(void
+ static inline void ata_acpi_unregister(void) { }
+ static inline void ata_acpi_bind(struct ata_device *dev) { }
+ static inline void ata_acpi_unbind(struct ata_device *dev) { }
++static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
+ #endif
+ /* libata-scsi.c */
diff --git a/queue-3.9/pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch b/queue-3.9/pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch
new file mode 100644 (file)
index 0000000..119a203
--- /dev/null
@@ -0,0 +1,115 @@
+From 3f327e39b4b8f760c331bb2836735be6d83fbf53 Mon Sep 17 00:00:00 2001
+From: Yinghai Lu <yinghai@kernel.org>
+Date: Tue, 7 May 2013 11:06:03 -0600
+Subject: PCI: acpiphp: Re-enumerate devices when host bridge receives Bus Check
+
+From: Yinghai Lu <yinghai@kernel.org>
+
+commit 3f327e39b4b8f760c331bb2836735be6d83fbf53 upstream.
+
+When a PCI host bridge device receives a Bus Check notification, we
+must re-enumerate starting with the bridge to discover changes (devices
+that have been added or removed).
+
+Prior to 668192b678 ("PCI: acpiphp: Move host bridge hotplug to
+pci_root.c"), this happened in _handle_hotplug_event_bridge().  After that
+commit, _handle_hotplug_event_bridge() is not installed for host bridges,
+and the host bridge notify handler, _handle_hotplug_event_root() did not
+re-enumerate.
+
+This patch adds re-enumeration to _handle_hotplug_event_root().
+
+This fixes cases where we don't notice the addition or removal of
+PCI devices, e.g., the PCI-to-USB ExpressCard in the bugzilla below.
+
+-v1: Backport of 3f327e39b4 to v3.9 by Bjorn Helgaas <bhelgaas@google.com>
+-v2: use request_module("acpiphp") for acpiphp as module instead of built-in.
+
+[bhelgaas: changelog, references]
+Reference: https://lkml.kernel.org/r/CAAh6nkmbKR3HTqm5ommevsBwhL_u0N8Rk7Wsms_LfP=nBgKNew@mail.gmail.com
+Reference: https://bugzilla.kernel.org/show_bug.cgi?id=57961
+Reported-by: Gavin Guo <tuffkidtt@gmail.com>
+Tested-by: Gavin Guo <tuffkidtt@gmail.com>
+Signed-off-by: Yinghai Lu <yinghai@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Jiang Liu <jiang.liu@huawei.com>
+Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/pci_root.c            |    7 ++++++-
+ drivers/pci/hotplug/acpiphp_glue.c |   14 ++++++++++++++
+ include/linux/pci-acpi.h           |    2 ++
+ 3 files changed, 22 insertions(+), 1 deletion(-)
+
+--- a/drivers/acpi/pci_root.c
++++ b/drivers/acpi/pci_root.c
+@@ -665,6 +665,7 @@ static void handle_root_bridge_removal(s
+               kfree(ej_event);
+ }
++void (*acpiphp_check_host_bridge)(acpi_handle handle);
+ static void _handle_hotplug_event_root(struct work_struct *work)
+ {
+       struct acpi_pci_root *root;
+@@ -687,7 +688,11 @@ static void _handle_hotplug_event_root(s
+               /* bus enumerate */
+               printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
+                                (char *)buffer.pointer);
+-              if (!root)
++              if (root) {
++                      request_module("acpiphp");
++                      if (acpiphp_check_host_bridge)
++                              acpiphp_check_host_bridge(handle);
++              } else
+                       handle_root_bridge_insertion(handle);
+               break;
+--- a/drivers/pci/hotplug/acpiphp_glue.c
++++ b/drivers/pci/hotplug/acpiphp_glue.c
+@@ -1122,6 +1122,18 @@ check_sub_bridges(acpi_handle handle, u3
+       return AE_OK ;
+ }
++static void __acpiphp_check_host_bridge(acpi_handle handle)
++{
++      struct acpiphp_bridge *bridge;
++
++      bridge = acpiphp_handle_to_bridge(handle);
++      if (bridge)
++              acpiphp_check_bridge(bridge);
++
++      acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
++              ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
++}
++
+ static void _handle_hotplug_event_bridge(struct work_struct *work)
+ {
+       struct acpiphp_bridge *bridge;
+@@ -1305,6 +1317,7 @@ static struct acpi_pci_driver acpi_pci_h
+ int __init acpiphp_glue_init(void)
+ {
+       acpi_pci_register_driver(&acpi_pci_hp_driver);
++      acpiphp_check_host_bridge = __acpiphp_check_host_bridge;
+       return 0;
+ }
+@@ -1317,6 +1330,7 @@ int __init acpiphp_glue_init(void)
+  */
+ void  acpiphp_glue_exit(void)
+ {
++      acpiphp_check_host_bridge = NULL;
+       acpi_pci_unregister_driver(&acpi_pci_hp_driver);
+ }
+--- a/include/linux/pci-acpi.h
++++ b/include/linux/pci-acpi.h
+@@ -43,6 +43,8 @@ static inline acpi_handle acpi_pci_get_b
+ }
+ #endif
++extern void (*acpiphp_check_host_bridge)(acpi_handle handle);
++
+ #ifdef CONFIG_ACPI_APEI
+ extern bool aer_acpi_firmware_first(void);
+ #else
index a343e4360035d3d01b4052736efc754d5df365e3..e331430572404518a899268471befdd7d12c6e7b 100644 (file)
@@ -14,3 +14,7 @@ dlci-acquire-rtnl_lock-before-calling-__dev_get_by_name.patch
 dlci-validate-the-net-device-in-dlci_del.patch
 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