--- /dev/null
+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;
+ }
--- /dev/null
+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 */
+
--- /dev/null
+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 */
--- /dev/null
+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