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.tools@xxxxxxxxx> --- drivers/gpu/drm/i915/display/intel_bios.c | 15 ++++--- 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, 59 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..d6442ec2dc70 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2268,12 +2268,14 @@ static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt) /** * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT + * @dev_priv: i915 device instance * @buf: pointer to a buffer to validate * @size: size of the buffer * * 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 +2298,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 +2362,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 +2419,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..6bd84964e989 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