From d17224194fae079166768e9ebd99d1ce169cf887 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Jun 2013 12:30:19 -0700 Subject: [PATCH] 3.9-stable patches 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 --- ...dling-of-dock-events-for-pci-devices.patch | 463 ++++++++++++++++++ ...interrupt-remapping-on-55xx-chipsets.patch | 179 +++++++ ...ack-acpi-based-hotplug-functionality.patch | 131 +++++ ...-when-host-bridge-receives-bus-check.patch | 115 +++++ queue-3.9/series | 4 + 5 files changed, 892 insertions(+) create mode 100644 queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch create mode 100644 queue-3.9/iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch create mode 100644 queue-3.9/libata-acpi-add-back-acpi-based-hotplug-functionality.patch create mode 100644 queue-3.9/pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.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 new file mode 100644 index 00000000000..27c946c30b7 --- /dev/null +++ b/queue-3.9/acpi-dock-pci-synchronous-handling-of-dock-events-for-pci-devices.patch @@ -0,0 +1,463 @@ +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/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 index 00000000000..2b0aa0db597 --- /dev/null +++ b/queue-3.9/iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch @@ -0,0 +1,179 @@ +From 03bbcb2e7e292838bb0244f5a7816d194c911d62 Mon Sep 17 00:00:00 2001 +From: Neil Horman +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 + +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 +CC: Prarit Bhargava +CC: Don Zickus +CC: Don Dutile +CC: Bjorn Helgaas +CC: Asit Mallick +CC: David Woodhouse +CC: linux-pci@vger.kernel.org +CC: Joerg Roedel +CC: Konrad Rzeszutek Wilk +CC: Arkadiusz Miśkiewicz +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++#include + + #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 + #include + #include ++#include + + 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 index 00000000000..48c9c730e47 --- /dev/null +++ b/queue-3.9/libata-acpi-add-back-acpi-based-hotplug-functionality.patch @@ -0,0 +1,131 @@ +From 44521527be36172864e6e7a6fba4b66e9aa48e40 Mon Sep 17 00:00:00 2001 +From: Aaron Lu +Date: Thu, 20 Jun 2013 09:38:34 +0800 +Subject: libata-acpi: add back ACPI based hotplug functionality + +From: Aaron Lu + +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 +Signed-off-by: Aaron Lu +Acked-by: Tejun Heo +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..119a2030380 --- /dev/null +++ b/queue-3.9/pci-acpiphp-re-enumerate-devices-when-host-bridge-receives-bus-check.patch @@ -0,0 +1,115 @@ +From 3f327e39b4b8f760c331bb2836735be6d83fbf53 Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Tue, 7 May 2013 11:06:03 -0600 +Subject: PCI: acpiphp: Re-enumerate devices when host bridge receives Bus Check + +From: Yinghai Lu + +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 +-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 +Tested-by: Gavin Guo +Signed-off-by: Yinghai Lu +Signed-off-by: Bjorn Helgaas +Reviewed-by: Jiang Liu +Acked-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + 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 diff --git a/queue-3.9/series b/queue-3.9/series index a343e436003..e3314305724 100644 --- a/queue-3.9/series +++ b/queue-3.9/series @@ -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 -- 2.47.3