LG Gram 2021 laptop 17Z95P-K.ADE9U1 OpRegion has

FW size: 0x2200
VBT size: 0x2000
BDB offset: 0x30
BDB size: 0x216e

Add intel_init_opregion_quirks to use FW size as VBT size on LG Gram
17Z95P-K.ADE9U1 and update intel_bios_is_valid_vbt to use FW size,
instead of VBT size if the quirk is applied, in range_overflows_t for
BDB size overflow check.  This fixes:

https://gitlab.freedesktop.org/drm/intel/-/issues/4763

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
---
 drivers/gpu/drm/i915/display/intel_bios.c     | 14 ++++---
 drivers/gpu/drm/i915/display/intel_bios.h     |  3 +-
 drivers/gpu/drm/i915/display/intel_opregion.c |  9 +++--
 drivers/gpu/drm/i915/display/intel_quirks.c   | 40 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_quirks.h   |  1 +
 drivers/gpu/drm/i915/i915_drv.h               |  1 +
 6 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c 
b/drivers/gpu/drm/i915/display/intel_bios.c
index 7d04572dd18b..4e960eb45a5a 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2273,7 +2273,8 @@ static const struct bdb_header *get_bdb_header(const 
struct vbt_header *vbt)
  *
  * Returns true on valid VBT.
  */
-bool intel_bios_is_valid_vbt(const void *buf, size_t size)
+bool intel_bios_is_valid_vbt(struct drm_i915_private *dev_priv,
+                            const void *buf, size_t size)
 {
        const struct vbt_header *vbt = buf;
        const struct bdb_header *bdb;
@@ -2296,16 +2297,17 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t 
size)
                return false;
        }
 
-       size = vbt->vbt_size;
-
        if (range_overflows_t(size_t,
                              vbt->bdb_offset,
                              sizeof(struct bdb_header),
-                             size)) {
+                             vbt->vbt_size)) {
                DRM_DEBUG_DRIVER("BDB header incomplete\n");
                return false;
        }
 
+       if (!(dev_priv->quirks & QUIRK_USE_FW_SIZE_AS_VBT_SIZE))
+               size = vbt->vbt_size;
+
        bdb = get_bdb_header(vbt);
        if (range_overflows_t(size_t, vbt->bdb_offset, bdb->bdb_size, size)) {
                DRM_DEBUG_DRIVER("BDB incomplete\n");
@@ -2359,7 +2361,7 @@ static struct vbt_header *spi_oprom_get_vbt(struct 
drm_i915_private *i915)
                *(vbt + store++) = data;
        }
 
-       if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+       if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
                goto err_free_vbt;
 
        drm_dbg_kms(&i915->drm, "Found valid VBT in SPI flash\n");
@@ -2416,7 +2418,7 @@ static struct vbt_header *oprom_get_vbt(struct 
drm_i915_private *i915)
 
        memcpy_fromio(vbt, p, vbt_size);
 
-       if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+       if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
                goto err_free_vbt;
 
        pci_unmap_rom(pdev, oprom);
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h 
b/drivers/gpu/drm/i915/display/intel_bios.h
index 4709c4d29805..368ee87390e7 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -231,7 +231,8 @@ struct mipi_pps_data {
 
 void intel_bios_init(struct drm_i915_private *dev_priv);
 void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
-bool intel_bios_is_valid_vbt(const void *buf, size_t size);
+bool intel_bios_is_valid_vbt(struct drm_i915_private *dev_priv,
+                            const void *buf, size_t size);
 bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
 bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 
*i2c_pin);
 bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port 
port);
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c 
b/drivers/gpu/drm/i915/display/intel_opregion.c
index af9d30f56cc1..7a9b4d72d18c 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -36,6 +36,7 @@
 #include "intel_display_types.h"
 #include "intel_opregion.h"
 #include "intel_pci_config.h"
+#include "intel_quirks.h"
 
 #define OPREGION_HEADER_OFFSET 0
 #define OPREGION_ACPI_OFFSET   0x100
@@ -817,7 +818,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private 
*dev_priv)
                return ret;
        }
 
-       if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
+       if (intel_bios_is_valid_vbt(dev_priv, fw->data, fw->size)) {
                opregion->vbt_firmware = kmemdup(fw->data, fw->size, 
GFP_KERNEL);
                if (opregion->vbt_firmware) {
                        drm_dbg_kms(&dev_priv->drm,
@@ -922,6 +923,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
        if (dmi_check_system(intel_no_opregion_vbt))
                goto out;
 
+       intel_init_opregion_quirks(dev_priv);
+
        if (opregion->header->over.major >= 2 && opregion->asle &&
            opregion->asle->rvda && opregion->asle->rvds) {
                resource_size_t rvda = opregion->asle->rvda;
@@ -944,7 +947,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
 
                vbt = opregion->rvda;
                vbt_size = opregion->asle->rvds;
-               if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+               if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
                        drm_dbg_kms(&dev_priv->drm,
                                    "Found valid VBT in ACPI OpRegion 
(RVDA)\n");
                        opregion->vbt = vbt;
@@ -969,7 +972,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
        vbt_size = (mboxes & MBOX_ASLE_EXT) ?
                OPREGION_ASLE_EXT_OFFSET : OPREGION_SIZE;
        vbt_size -= OPREGION_VBT_OFFSET;
-       if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+       if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
                drm_dbg_kms(&dev_priv->drm,
                            "Found valid VBT in ACPI OpRegion (Mailbox #4)\n");
                opregion->vbt = vbt;
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c 
b/drivers/gpu/drm/i915/display/intel_quirks.c
index c8488f5ebd04..c2604e8b5353 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -133,6 +133,36 @@ static const struct intel_dmi_quirk intel_dmi_quirks[] = {
        },
 };
 
+static void quirk_opregion_use_fw_size_as_vbt_size(struct drm_i915_private 
*i915)
+{
+       i915->quirks |= QUIRK_USE_FW_SIZE_AS_VBT_SIZE;
+       drm_info(&i915->drm, "Applying FW size as VBT size quirk in 
OpRegion\n");
+}
+
+static int intel_dmi_opregion_use_fw_size_as_vbt_size(const struct 
dmi_system_id *id)
+{
+       DRM_INFO("Use FW size as VBT size on %s in OpRegion\n", id->ident);
+       return 1;
+}
+
+static const struct intel_dmi_quirk intel_dmi_opregion_quirks[] = {
+       {
+               .dmi_id_list = &(const struct dmi_system_id[]) {
+                       {
+                               .callback = 
intel_dmi_opregion_use_fw_size_as_vbt_size,
+                               .ident = "LG Gram 17Z95P-K.ADE9U1",
+                               .matches = {DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LG 
Electronics"),
+                                           DMI_EXACT_MATCH(DMI_PRODUCT_NAME, 
"17Z95P-K.ADE9U1"),
+                                           DMI_EXACT_MATCH(DMI_BIOS_VERSION, 
"T4ZF0040 X64"),
+                                           DMI_EXACT_MATCH(DMI_BIOS_DATE, 
"10/06/2021"),
+                               },
+                       },
+                       { }
+               },
+               .hook = quirk_opregion_use_fw_size_as_vbt_size,
+       },
+};
+
 static struct intel_quirk intel_quirks[] = {
        /* Lenovo U160 cannot use SSC on LVDS */
        { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
@@ -213,3 +243,13 @@ void intel_init_quirks(struct drm_i915_private *i915)
                        intel_dmi_quirks[i].hook(i915);
        }
 }
+
+void intel_init_opregion_quirks(struct drm_i915_private *i915)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(intel_dmi_opregion_quirks); i++) {
+               if (dmi_check_system(*intel_dmi_opregion_quirks[i].dmi_id_list) 
!= 0)
+                       intel_dmi_opregion_quirks[i].hook(i915);
+       }
+}
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h 
b/drivers/gpu/drm/i915/display/intel_quirks.h
index b0fcff142a56..3a6a84e0d502 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.h
+++ b/drivers/gpu/drm/i915/display/intel_quirks.h
@@ -9,5 +9,6 @@
 struct drm_i915_private;
 
 void intel_init_quirks(struct drm_i915_private *dev_priv);
+void intel_init_opregion_quirks(struct drm_i915_private *dev_priv);
 
 #endif /* __INTEL_QUIRKS_H__ */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 890f1f6fbc49..08572fae2d97 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -403,6 +403,7 @@ struct i915_drrs {
 #define QUIRK_INCREASE_T12_DELAY (1<<6)
 #define QUIRK_INCREASE_DDI_DISABLED_TIME (1<<7)
 #define QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK (1<<8)
+#define QUIRK_USE_FW_SIZE_AS_VBT_SIZE (1<<9)
 
 struct intel_fbdev;
 
-- 
2.34.1

Reply via email to