drm/nouveau/mxm: call mxmi to determine revision before calling mxms
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Feb 2012 23:33:05 +0000 (09:33 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Mar 2012 07:14:57 +0000 (17:14 +1000)
There's a HP laptop out there where the MXM version in the VBIOS doesn't
match what the ACPI implementation is expecting.  These tables will accept
0x00 to MXMS to return latest version, but *only* if MXMI has been called
first..

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_mxm.c

index e5a64f0..07d0d1e 100644 (file)
@@ -582,6 +582,35 @@ mxm_shadow_dsm(struct drm_device *dev, u8 version)
 
 #define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
 
+static u8
+wmi_wmmx_mxmi(struct drm_device *dev, u8 version)
+{
+       u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
+       struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
+       struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+
+       status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+       if (ACPI_FAILURE(status)) {
+               MXM_DBG(dev, "WMMX MXMI returned %d\n", status);
+               return 0x00;
+       }
+
+       obj = retn.pointer;
+       if (obj->type == ACPI_TYPE_INTEGER) {
+               version = obj->integer.value;
+               MXM_DBG(dev, "WMMX MXMI version %d.%d\n",
+                            (version >> 4), version & 0x0f);
+       } else {
+               version = 0;
+               MXM_DBG(dev, "WMMX MXMI returned non-integer\n");
+       }
+
+       kfree(obj);
+       return version;
+}
+
 static bool
 mxm_shadow_wmi(struct drm_device *dev, u8 version)
 {
@@ -592,7 +621,15 @@ mxm_shadow_wmi(struct drm_device *dev, u8 version)
        union acpi_object *obj;
        acpi_status status;
 
-       if (!wmi_has_guid(WMI_WMMX_GUID))
+       if (!wmi_has_guid(WMI_WMMX_GUID)) {
+               MXM_DBG(dev, "WMMX GUID not found\n");
+               return false;
+       }
+
+       mxms_args[1] = wmi_wmmx_mxmi(dev, 0x00);
+       if (!mxms_args[1])
+               mxms_args[1] = wmi_wmmx_mxmi(dev, version);
+       if (!mxms_args[1])
                return false;
 
        status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);