* [PATCH] ACPIPHP / radeon: Fix VGA switcheroo problem related to hotplug events
@ 2013-12-28 22:13 Rafael J. Wysocki
2013-12-29 21:36 ` [PATCH][update] ACPIPHP / radeon / nouveau: " Rafael J. Wysocki
0 siblings, 1 reply; 5+ messages in thread
From: Rafael J. Wysocki @ 2013-12-28 22:13 UTC (permalink / raw)
To: ACPI Devel Maling List
Cc: LKML, Linux PCI, Mika Westerberg, Mike Lothian, madcatx,
Alex Deucher, Dave Airlie, Takashi Iwai
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
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) 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 switcheroo detection code set the no_hotplug
flag for the discrete graphics' ACPI companion.
References: https://bugzilla.kernel.org/show_bug.cgi?id=61891
Fixes: bbd34fcdd1b2 (ACPI / hotplug / PCI: Register all devices under the given bridge)
Reported-and-tested-by: Mike Lothian <mike@fireburn.co.uk>
Reported-and-tested-by: <madcatx@atlas.cz>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Cc: Takashi Iwai <tiwai@suse.de>
---
Hi All,
I have an analogous change for nouveau in the works and if that really turns
out to be the same issue, I'll just add the nouveau changes to this patch
and resend.
Thanks,
Rafael
---
drivers/gpu/drm/radeon/radeon_atpx_handler.c | 20 ++++++++++++++++++--
drivers/pci/hotplug/acpiphp_glue.c | 26 +++++++++++++++++++++++---
include/acpi/acpi_bus.h | 3 ++-
3 files changed, 43 insertions(+), 6 deletions(-)
Index: linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
===================================================================
--- linux-pm.orig/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -33,6 +33,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;
@@ -451,9 +452,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;
@@ -526,10 +528,24 @@ static bool radeon_atpx_detect(void)
}
if (has_atpx && vga_count == 2) {
+ struct acpi_device *adev = NULL;
+
acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
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 ACPI device
+ * object in question.
+ */
+ acpi_bus_get_device(radeon_atpx_priv.other_handle, &adev);
+ if (adev)
+ adev->flags.no_hotplug = true;
+
return true;
}
return false;
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/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 */
Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -643,6 +643,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
@@ -701,7 +719,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;
@@ -741,8 +760,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)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH][update] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug events
2013-12-28 22:13 [PATCH] ACPIPHP / radeon: Fix VGA switcheroo problem related to hotplug events Rafael J. Wysocki
@ 2013-12-29 21:36 ` Rafael J. Wysocki
2013-12-30 9:20 ` Mika Westerberg
2013-12-31 21:14 ` [PATCH][update 2] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug Rafael J. Wysocki
0 siblings, 2 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2013-12-29 21:36 UTC (permalink / raw)
To: ACPI Devel Maling List
Cc: LKML, Linux PCI, Mika Westerberg, Mike Lothian, madcatx,
Alex Deucher, Dave Airlie, Takashi Iwai,
Joaquín Aramendía
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
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-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>
Cc: 3.12+ <stable@vger.kernel.org> # 3.12+
---
Hi All,
According to recent testing results, the nouveau part is needed to address
that issue on systems with analogous layouts.
Thanks,
Rafael
---
drivers/gpu/drm/nouveau/nouveau_acpi.c | 20 ++++++++++++++++++--
drivers/gpu/drm/radeon/radeon_atpx_handler.c | 20 ++++++++++++++++++--
drivers/pci/hotplug/acpiphp_glue.c | 26 +++++++++++++++++++++++---
include/acpi/acpi_bus.h | 3 ++-
4 files changed, 61 insertions(+), 8 deletions(-)
Index: linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
===================================================================
--- linux-pm.orig/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -33,6 +33,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;
@@ -451,9 +452,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;
@@ -526,10 +528,24 @@ static bool radeon_atpx_detect(void)
}
if (has_atpx && vga_count == 2) {
+ struct acpi_device *adev = NULL;
+
acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
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 ACPI device
+ * object in question.
+ */
+ acpi_bus_get_device(radeon_atpx_priv.other_handle, &adev);
+ if (adev)
+ adev->flags.no_hotplug = true;
+
return true;
}
return false;
Index: linux-pm/drivers/gpu/drm/nouveau/nouveau_acpi.c
===================================================================
--- linux-pm.orig/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ linux-pm/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;
@@ -333,11 +335,25 @@ static bool nouveau_dsm_detect(void)
nouveau_dsm_priv.optimus_detected = true;
ret = true;
} else if (vga_count == 2 && has_dsm && guid_valid) {
+ struct acpi_device *adev = NULL;
+
acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
&buffer);
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 ACPI device
+ * object in question.
+ */
+ acpi_bus_get_device(nouveau_dsm_priv.other_handle, &adev);
+ if (adev)
+ adev->flags.no_hotplug = true;
+
ret = true;
}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/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 */
Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -643,6 +643,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
@@ -701,7 +719,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;
@@ -741,8 +760,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)
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH][update] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug events
2013-12-29 21:36 ` [PATCH][update] ACPIPHP / radeon / nouveau: " Rafael J. Wysocki
@ 2013-12-30 9:20 ` Mika Westerberg
2013-12-30 12:52 ` Rafael J. Wysocki
2013-12-31 21:14 ` [PATCH][update 2] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug Rafael J. Wysocki
1 sibling, 1 reply; 5+ messages in thread
From: Mika Westerberg @ 2013-12-30 9:20 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: ACPI Devel Maling List, LKML, Linux PCI, Mike Lothian, madcatx,
Alex Deucher, Dave Airlie, Takashi Iwai,
Joaquín Aramendía
On Sun, Dec 29, 2013 at 10:36:56PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> 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-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>
> Cc: 3.12+ <stable@vger.kernel.org> # 3.12+
FWIW, Thunderbolt hotplug still works fine after this patch is applied :)
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH][update] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug events
2013-12-30 9:20 ` Mika Westerberg
@ 2013-12-30 12:52 ` Rafael J. Wysocki
0 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2013-12-30 12:52 UTC (permalink / raw)
To: Mika Westerberg
Cc: ACPI Devel Maling List, LKML, Linux PCI, Mike Lothian, madcatx,
Alex Deucher, Dave Airlie, Takashi Iwai,
Joaquín Aramendía
On Monday, December 30, 2013 11:20:43 AM Mika Westerberg wrote:
> On Sun, Dec 29, 2013 at 10:36:56PM +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >
> > 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-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>
> > Cc: 3.12+ <stable@vger.kernel.org> # 3.12+
>
> FWIW, Thunderbolt hotplug still works fine after this patch is applied :)
I've checked that, but thanks for the confirmation!
Rafael
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH][update 2] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug
2013-12-29 21:36 ` [PATCH][update] ACPIPHP / radeon / nouveau: " Rafael J. Wysocki
2013-12-30 9:20 ` Mika Westerberg
@ 2013-12-31 21:14 ` Rafael J. Wysocki
1 sibling, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2013-12-31 21:14 UTC (permalink / raw)
To: ACPI Devel Maling List
Cc: LKML, Linux PCI, Mika Westerberg, Mike Lothian, madcatx,
Alex Deucher, Dave Airlie, Takashi Iwai,
Joaquín Aramendía
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
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>
Cc: 3.12+ <stable@vger.kernel.org> # 3.12+
---
Hi All,
One more update here. Because the device the hotplug events are generated for
may be either the one with the "switching" ACPI method (ATPX or _DSM) or the
second one, no_hotplug needs to be set for the both of them.
This version has been retested and appears to work for both the radeon and
nouveau cases.
Thanks and Happy New Year,
Rafael
---
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(-)
Index: linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
===================================================================
--- linux-pm.orig/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ linux-pm/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -33,6 +33,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;
@@ -451,9 +452,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;
@@ -530,6 +532,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;
Index: linux-pm/drivers/gpu/drm/nouveau/nouveau_acpi.c
===================================================================
--- linux-pm.orig/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ linux-pm/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;
@@ -338,6 +340,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;
}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/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 */
@@ -344,6 +345,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 *);
Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -643,6 +643,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
@@ -701,7 +719,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;
@@ -741,8 +760,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)
Index: linux-pm/drivers/acpi/bus.c
===================================================================
--- linux-pm.orig/drivers/acpi/bus.c
+++ linux-pm/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)
{
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-12-31 21:00 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-28 22:13 [PATCH] ACPIPHP / radeon: Fix VGA switcheroo problem related to hotplug events Rafael J. Wysocki
2013-12-29 21:36 ` [PATCH][update] ACPIPHP / radeon / nouveau: " Rafael J. Wysocki
2013-12-30 9:20 ` Mika Westerberg
2013-12-30 12:52 ` Rafael J. Wysocki
2013-12-31 21:14 ` [PATCH][update 2] ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox