From: Peter Wu Date: Fri, 15 Jul 2016 13:12:17 +0000 (+0200) Subject: drm/nouveau/acpi: check for function 0x1B before using it X-Git-Tag: v3.16.39~215 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1e1c2e2d4e6a19932ec7832746a7da2617f783f0;p=thirdparty%2Fkernel%2Fstable.git drm/nouveau/acpi: check for function 0x1B before using it commit cba97805cb69d5b1a1d3bb108872c73b5bf0e205 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: 5addcf0a5f0fad ("nouveau: add runtime PM support (v0.9)") Reviewed-by: Hans de Goede Signed-off-by: Peter Wu Acked-by: Dave Airlie Signed-off-by: Ben Hutchings --- diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index f76e805dfc3a7..8f057ab38e277 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -45,6 +45,7 @@ static struct nouveau_dsm_priv { bool dsm_detected; bool optimus_detected; + bool optimus_flags_detected; acpi_handle dhandle; acpi_handle other_handle; acpi_handle rom_handle; @@ -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, - bool *has_mux, bool *has_opt) + bool *has_mux, bool *has_opt, + bool *has_opt_flags) { acpi_handle dhandle; bool supports_mux; @@ -238,6 +240,7 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out *dhandle_out = dhandle; *has_mux = supports_mux; *has_opt = !!optimus_funcs; + *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS); if (optimus_funcs) { uint32_t result; @@ -258,6 +261,7 @@ static bool nouveau_dsm_detect(void) acpi_handle dhandle = NULL; bool has_mux = false; bool has_optimus = false; + bool has_optimus_flags = false; int vga_count = 0; bool guid_valid; bool ret = false; @@ -272,13 +276,15 @@ static bool nouveau_dsm_detect(void) while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 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) { 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 */ @@ -289,6 +295,7 @@ static bool nouveau_dsm_detect(void) printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", acpi_method_name); nouveau_dsm_priv.optimus_detected = true; + nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags; ret = true; } else if (vga_count == 2 && has_mux && guid_valid) { nouveau_dsm_priv.dhandle = dhandle; @@ -332,8 +339,9 @@ void nouveau_switcheroo_optimus_dsm(void) if (!nouveau_dsm_priv.optimus_detected) return; - nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS, - 0x3, &result); + if (nouveau_dsm_priv.optimus_flags_detected) + 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_DSM_OPTIMUS_SET_POWERDOWN, &result);