--- /dev/null
+From f244d8b623dae7a7bc695b0336f67729b95a9736 Mon Sep 17 00:00:00 2001
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+Date: Tue, 31 Dec 2013 13:39:42 +0100
+Subject: ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+commit f244d8b623dae7a7bc695b0336f67729b95a9736 upstream.
+
+The changes in the ACPI-based PCI hotplug (ACPIPHP) subsystem made
+during the 3.12 development cycle uncovered a problem with VGA
+switcheroo that on some systems, when the device-specific method
+(ATPX in the radeon case, _DSM in the nouveau case) is used to turn
+off the discrete graphics, the BIOS generates ACPI hotplug events for
+that device and those events cause ACPIPHP to attempt to remove the
+device from the system (they are events for a device that was present
+previously and is not present any more, so that's what should be done
+according to the spec). Then, the system stops functioning correctly.
+
+Since the hotplug events in question were simply silently ignored
+previously, the least intrusive way to address that problem is to
+make ACPIPHP ignore them again. For this purpose, introduce a new
+ACPI device flag, no_hotplug, and modify ACPIPHP to ignore hotplug
+events for PCI devices whose ACPI companions have that flag set.
+Next, make the radeon and nouveau switcheroo detection code set the
+no_hotplug flag for the discrete graphics' ACPI companion.
+
+Fixes: bbd34fcdd1b2 (ACPI / hotplug / PCI: Register all devices under the given bridge)
+References: https://bugzilla.kernel.org/show_bug.cgi?id=61891
+References: https://bugzilla.kernel.org/show_bug.cgi?id=64891
+Reported-and-tested-by: Mike Lothian <mike@fireburn.co.uk>
+Reported-and-tested-by: <madcatx@atlas.cz>
+Reported-and-tested-by: Joaquín Aramendía <samsagax@gmail.com>
+Cc: Alex Deucher <alexdeucher@gmail.com>
+Cc: Dave Airlie <airlied@linux.ie>
+Cc: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/acpi/bus.c | 10 ++++++++++
+ drivers/gpu/drm/nouveau/nouveau_acpi.c | 16 ++++++++++++++--
+ drivers/gpu/drm/radeon/radeon_atpx_handler.c | 16 ++++++++++++++--
+ drivers/pci/hotplug/acpiphp_glue.c | 26 +++++++++++++++++++++++---
+ include/acpi/acpi_bus.h | 4 +++-
+ 5 files changed, 64 insertions(+), 8 deletions(-)
+
+--- a/drivers/acpi/bus.c
++++ b/drivers/acpi/bus.c
+@@ -156,6 +156,16 @@ int acpi_bus_get_private_data(acpi_handl
+ }
+ EXPORT_SYMBOL(acpi_bus_get_private_data);
+
++void acpi_bus_no_hotplug(acpi_handle handle)
++{
++ struct acpi_device *adev = NULL;
++
++ acpi_bus_get_device(handle, &adev);
++ if (adev)
++ adev->flags.no_hotplug = true;
++}
++EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug);
++
+ static void acpi_print_osc_error(acpi_handle handle,
+ struct acpi_osc_context *context, char *error)
+ {
+--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
++++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
+@@ -51,6 +51,7 @@ static struct nouveau_dsm_priv {
+ bool dsm_detected;
+ bool optimus_detected;
+ acpi_handle dhandle;
++ acpi_handle other_handle;
+ acpi_handle rom_handle;
+ } nouveau_dsm_priv;
+
+@@ -260,9 +261,10 @@ static int nouveau_dsm_pci_probe(struct
+ if (!dhandle)
+ return false;
+
+- if (!acpi_has_method(dhandle, "_DSM"))
++ if (!acpi_has_method(dhandle, "_DSM")) {
++ nouveau_dsm_priv.other_handle = dhandle;
+ return false;
+-
++ }
+ if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
+ retval |= NOUVEAU_DSM_HAS_MUX;
+
+@@ -328,6 +330,16 @@ static bool nouveau_dsm_detect(void)
+ printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
+ acpi_method_name);
+ nouveau_dsm_priv.dsm_detected = true;
++ /*
++ * On some systems hotplug events are generated for the device
++ * being switched off when _DSM is executed. They cause ACPI
++ * hotplug to trigger and attempt to remove the device from
++ * the system, which causes it to break down. Prevent that from
++ * happening by setting the no_hotplug flag for the involved
++ * ACPI device objects.
++ */
++ acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle);
++ acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle);
+ ret = true;
+ }
+
+--- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
++++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+@@ -34,6 +34,7 @@ static struct radeon_atpx_priv {
+ bool atpx_detected;
+ /* handle for device - and atpx */
+ acpi_handle dhandle;
++ acpi_handle other_handle;
+ struct radeon_atpx atpx;
+ } radeon_atpx_priv;
+
+@@ -448,9 +449,10 @@ static bool radeon_atpx_pci_probe_handle
+ return false;
+
+ status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
+- if (ACPI_FAILURE(status))
++ if (ACPI_FAILURE(status)) {
++ radeon_atpx_priv.other_handle = dhandle;
+ return false;
+-
++ }
+ radeon_atpx_priv.dhandle = dhandle;
+ radeon_atpx_priv.atpx.handle = atpx_handle;
+ return true;
+@@ -527,6 +529,16 @@ static bool radeon_atpx_detect(void)
+ printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
+ acpi_method_name);
+ radeon_atpx_priv.atpx_detected = true;
++ /*
++ * On some systems hotplug events are generated for the device
++ * being switched off when ATPX is executed. They cause ACPI
++ * hotplug to trigger and attempt to remove the device from
++ * the system, which causes it to break down. Prevent that from
++ * happening by setting the no_hotplug flag for the involved
++ * ACPI device objects.
++ */
++ acpi_bus_no_hotplug(radeon_atpx_priv.dhandle);
++ acpi_bus_no_hotplug(radeon_atpx_priv.other_handle);
+ return true;
+ }
+ return false;
+--- a/drivers/pci/hotplug/acpiphp_glue.c
++++ b/drivers/pci/hotplug/acpiphp_glue.c
+@@ -645,6 +645,24 @@ static void disable_slot(struct acpiphp_
+ slot->flags &= (~SLOT_ENABLED);
+ }
+
++static bool acpiphp_no_hotplug(acpi_handle handle)
++{
++ struct acpi_device *adev = NULL;
++
++ acpi_bus_get_device(handle, &adev);
++ return adev && adev->flags.no_hotplug;
++}
++
++static bool slot_no_hotplug(struct acpiphp_slot *slot)
++{
++ struct acpiphp_func *func;
++
++ list_for_each_entry(func, &slot->funcs, sibling)
++ if (acpiphp_no_hotplug(func_to_handle(func)))
++ return true;
++
++ return false;
++}
+
+ /**
+ * get_slot_status - get ACPI slot status
+@@ -703,7 +721,8 @@ static void trim_stale_devices(struct pc
+ unsigned long long sta;
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+- alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
++ alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL)
++ || acpiphp_no_hotplug(handle);
+ }
+ if (!alive) {
+ u32 v;
+@@ -743,8 +762,9 @@ static void acpiphp_check_bridge(struct
+ struct pci_dev *dev, *tmp;
+
+ mutex_lock(&slot->crit_sect);
+- /* wake up all functions */
+- if (get_slot_status(slot) == ACPI_STA_ALL) {
++ if (slot_no_hotplug(slot)) {
++ ; /* do nothing */
++ } else if (get_slot_status(slot) == ACPI_STA_ALL) {
+ /* remove stale devices if any */
+ list_for_each_entry_safe(dev, tmp, &bus->devices,
+ bus_list)
+--- a/include/acpi/acpi_bus.h
++++ b/include/acpi/acpi_bus.h
+@@ -169,7 +169,8 @@ struct acpi_device_flags {
+ u32 ejectable:1;
+ u32 power_manageable:1;
+ u32 match_driver:1;
+- u32 reserved:27;
++ u32 no_hotplug:1;
++ u32 reserved:26;
+ };
+
+ /* File System */
+@@ -357,6 +358,7 @@ extern struct kobject *acpi_kobj;
+ extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
+ void acpi_bus_private_data_handler(acpi_handle, void *);
+ int acpi_bus_get_private_data(acpi_handle, void **);
++void acpi_bus_no_hotplug(acpi_handle handle);
+ extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
+ extern int register_acpi_notifier(struct notifier_block *);
+ extern int unregister_acpi_notifier(struct notifier_block *);
--- /dev/null
+From 187b5b5d520c2318a1f88fb8d8913a9d7fbf7d92 Mon Sep 17 00:00:00 2001
+From: Zhang Rui <rui.zhang@intel.com>
+Date: Tue, 3 Sep 2013 08:32:00 +0800
+Subject: nouveau_acpi: convert acpi_get_handle() to acpi_has_method()
+
+From: Zhang Rui <rui.zhang@intel.com>
+
+commit 187b5b5d520c2318a1f88fb8d8913a9d7fbf7d92 upstream.
+
+acpi_has_method() is a new ACPI API introduced to check
+the existence of an ACPI control method.
+
+It can be used to replace acpi_get_handle() in the case that
+1. the calling function doesn't need the ACPI handle of the control method.
+and
+2. the calling function doesn't care the reason why the method is unavailable.
+
+Convert acpi_get_handle() to acpi_has_method()
+in drivers/gpu/drm/nouveau/nouveau_acpi.c in this patch.
+
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+CC: Ben Skeggs <bskeggs@redhat.com>
+CC: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/nouveau/nouveau_acpi.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
++++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
+@@ -253,18 +253,15 @@ static struct vga_switcheroo_handler nou
+
+ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
+ {
+- acpi_handle dhandle, nvidia_handle;
+- acpi_status status;
++ acpi_handle dhandle;
+ int retval = 0;
+
+ dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+
+- status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
+- if (ACPI_FAILURE(status)) {
++ if (!acpi_has_method(dhandle, "_DSM"))
+ return false;
+- }
+
+ if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
+ retval |= NOUVEAU_DSM_HAS_MUX;