Commit 1e1c2e2d authored by Peter Wu's avatar Peter Wu Committed by Ben Hutchings

drm/nouveau/acpi: check for function 0x1B before using it

commit cba97805 upstream.

Do not unconditionally invoke function 0x1B without checking for its
availability, it leads to an infinite loop on some firmware.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104791
Fixes: 5addcf0a ("nouveau: add runtime PM support (v0.9)")
Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarPeter Wu <peter@lekensteyn.nl>
Acked-by: Dave Airlie <airlied@redhat.com
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 0933b897
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
static struct nouveau_dsm_priv { static struct nouveau_dsm_priv {
bool dsm_detected; bool dsm_detected;
bool optimus_detected; bool optimus_detected;
bool optimus_flags_detected;
acpi_handle dhandle; acpi_handle dhandle;
acpi_handle other_handle; acpi_handle other_handle;
acpi_handle rom_handle; acpi_handle rom_handle;
...@@ -213,7 +214,8 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = { ...@@ -213,7 +214,8 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
}; };
static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out, static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
bool *has_mux, bool *has_opt) bool *has_mux, bool *has_opt,
bool *has_opt_flags)
{ {
acpi_handle dhandle; acpi_handle dhandle;
bool supports_mux; bool supports_mux;
...@@ -238,6 +240,7 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out ...@@ -238,6 +240,7 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out
*dhandle_out = dhandle; *dhandle_out = dhandle;
*has_mux = supports_mux; *has_mux = supports_mux;
*has_opt = !!optimus_funcs; *has_opt = !!optimus_funcs;
*has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
if (optimus_funcs) { if (optimus_funcs) {
uint32_t result; uint32_t result;
...@@ -258,6 +261,7 @@ static bool nouveau_dsm_detect(void) ...@@ -258,6 +261,7 @@ static bool nouveau_dsm_detect(void)
acpi_handle dhandle = NULL; acpi_handle dhandle = NULL;
bool has_mux = false; bool has_mux = false;
bool has_optimus = false; bool has_optimus = false;
bool has_optimus_flags = false;
int vga_count = 0; int vga_count = 0;
bool guid_valid; bool guid_valid;
bool ret = false; bool ret = false;
...@@ -272,13 +276,15 @@ static bool nouveau_dsm_detect(void) ...@@ -272,13 +276,15 @@ static bool nouveau_dsm_detect(void)
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++; vga_count++;
nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus); nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
&has_optimus_flags);
} }
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) { while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
vga_count++; vga_count++;
nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus); nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
&has_optimus_flags);
} }
/* find the optimus DSM or the old v1 DSM */ /* find the optimus DSM or the old v1 DSM */
...@@ -289,6 +295,7 @@ static bool nouveau_dsm_detect(void) ...@@ -289,6 +295,7 @@ static bool nouveau_dsm_detect(void)
printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
acpi_method_name); acpi_method_name);
nouveau_dsm_priv.optimus_detected = true; nouveau_dsm_priv.optimus_detected = true;
nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
ret = true; ret = true;
} else if (vga_count == 2 && has_mux && guid_valid) { } else if (vga_count == 2 && has_mux && guid_valid) {
nouveau_dsm_priv.dhandle = dhandle; nouveau_dsm_priv.dhandle = dhandle;
...@@ -332,8 +339,9 @@ void nouveau_switcheroo_optimus_dsm(void) ...@@ -332,8 +339,9 @@ void nouveau_switcheroo_optimus_dsm(void)
if (!nouveau_dsm_priv.optimus_detected) if (!nouveau_dsm_priv.optimus_detected)
return; return;
nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS, if (nouveau_dsm_priv.optimus_flags_detected)
0x3, &result); nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
0x3, &result);
nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result); NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment