--- /dev/null
+From d3a7051841f0a4bcb1ee26a1b721c6150cc4c2b1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Thu, 18 Aug 2022 22:22:23 +0300
+Subject: drm/i915/bios: Use hardcoded fp_timing size for generating LFP data pointers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+commit d3a7051841f0a4bcb1ee26a1b721c6150cc4c2b1 upstream.
+
+The current scheme for generating the LFP data table pointers
+(when the block including them is missing from the VBT) expects
+the 0xffff sequence to only appear in the fp_timing terminator
+entries. However some VBTs also have extra 0xffff sequences
+elsewhere in the LFP data. When looking for the terminators
+we may end up finding those extra sequeneces insted, which means
+we deduce the wrong size for the fp_timing table. The code
+then notices the inconsistent looking values and gives up on
+the generated data table pointers, preventing us from parsing
+the LFP data table entirely.
+
+Let's give up on the "search for the terminators" approach
+and instead just hardcode the expected size for the fp_timing
+table.
+
+We have enough sanity checks in place to make sure we
+shouldn't end up parsing total garbage even if that size
+should change in the future (although that seems unlikely
+as the fp_timing and dvo_timing tables have been declared
+obsolete as of VBT version 229).
+
+Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6592
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220818192223.29881-3-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/display/intel_bios.c | 46 +++++++++++-------------------
+ 1 file changed, 18 insertions(+), 28 deletions(-)
+
+--- a/drivers/gpu/drm/i915/display/intel_bios.c
++++ b/drivers/gpu/drm/i915/display/intel_bios.c
+@@ -337,18 +337,6 @@ static bool fixup_lfp_data_ptrs(const vo
+ return validate_lfp_data_ptrs(bdb, ptrs);
+ }
+
+-static const void *find_fp_timing_terminator(const u8 *data, int size)
+-{
+- int i;
+-
+- for (i = 0; i < size - 1; i++) {
+- if (data[i] == 0xff && data[i+1] == 0xff)
+- return &data[i];
+- }
+-
+- return NULL;
+-}
+-
+ static int make_lfp_data_ptr(struct lvds_lfp_data_ptr_table *table,
+ int table_size, int total_size)
+ {
+@@ -372,11 +360,22 @@ static void next_lfp_data_ptr(struct lvd
+ static void *generate_lfp_data_ptrs(struct drm_i915_private *i915,
+ const void *bdb)
+ {
+- int i, size, table_size, block_size, offset;
+- const void *t0, *t1, *block;
++ int i, size, table_size, block_size, offset, fp_timing_size;
+ struct bdb_lvds_lfp_data_ptrs *ptrs;
++ const void *block;
+ void *ptrs_block;
+
++ /*
++ * The hardcoded fp_timing_size is only valid for
++ * modernish VBTs. All older VBTs definitely should
++ * include block 41 and thus we don't need to
++ * generate one.
++ */
++ if (i915->vbt.version < 155)
++ return NULL;
++
++ fp_timing_size = 38;
++
+ block = find_raw_section(bdb, BDB_LVDS_LFP_DATA);
+ if (!block)
+ return NULL;
+@@ -385,17 +384,8 @@ static void *generate_lfp_data_ptrs(stru
+
+ block_size = get_blocksize(block);
+
+- size = block_size;
+- t0 = find_fp_timing_terminator(block, size);
+- if (!t0)
+- return NULL;
+-
+- size -= t0 - block - 2;
+- t1 = find_fp_timing_terminator(t0 + 2, size);
+- if (!t1)
+- return NULL;
+-
+- size = t1 - t0;
++ size = fp_timing_size + sizeof(struct lvds_dvo_timing) +
++ sizeof(struct lvds_pnp_id);
+ if (size * 16 > block_size)
+ return NULL;
+
+@@ -413,7 +403,7 @@ static void *generate_lfp_data_ptrs(stru
+ table_size = sizeof(struct lvds_dvo_timing);
+ size = make_lfp_data_ptr(&ptrs->ptr[0].dvo_timing, table_size, size);
+
+- table_size = t0 - block + 2;
++ table_size = fp_timing_size;
+ size = make_lfp_data_ptr(&ptrs->ptr[0].fp_timing, table_size, size);
+
+ if (ptrs->ptr[0].fp_timing.table_size)
+@@ -428,14 +418,14 @@ static void *generate_lfp_data_ptrs(stru
+ return NULL;
+ }
+
+- size = t1 - t0;
++ size = fp_timing_size + sizeof(struct lvds_dvo_timing) +
++ sizeof(struct lvds_pnp_id);
+ for (i = 1; i < 16; i++) {
+ next_lfp_data_ptr(&ptrs->ptr[i].fp_timing, &ptrs->ptr[i-1].fp_timing, size);
+ next_lfp_data_ptr(&ptrs->ptr[i].dvo_timing, &ptrs->ptr[i-1].dvo_timing, size);
+ next_lfp_data_ptr(&ptrs->ptr[i].panel_pnp_id, &ptrs->ptr[i-1].panel_pnp_id, size);
+ }
+
+- size = t1 - t0;
+ table_size = sizeof(struct lvds_lfp_panel_name);
+
+ if (16 * (size + table_size) <= block_size) {
--- /dev/null
+From 4e78d6023c15c6acce8fbe42e13027c460395522 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Thu, 18 Aug 2022 22:22:22 +0300
+Subject: drm/i915/bios: Validate fp_timing terminator presence
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+commit 4e78d6023c15c6acce8fbe42e13027c460395522 upstream.
+
+Validate the LFP data block a bit hardwer by making sure the
+fp_timing terminators (0xffff) are where we expect them to be.
+
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220818192223.29881-2-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_bios.c | 60 ++++++++++++++++--------------
+ 1 file changed, 32 insertions(+), 28 deletions(-)
+
+--- a/drivers/gpu/drm/i915/display/intel_bios.c
++++ b/drivers/gpu/drm/i915/display/intel_bios.c
+@@ -135,18 +135,6 @@ static u32 raw_block_offset(const void *
+ return block - bdb;
+ }
+
+-/* size of the block excluding the header */
+-static u32 raw_block_size(const void *bdb, enum bdb_block_id section_id)
+-{
+- const void *block;
+-
+- block = find_raw_section(bdb, section_id);
+- if (!block)
+- return 0;
+-
+- return get_blocksize(block);
+-}
+-
+ struct bdb_block_entry {
+ struct list_head node;
+ enum bdb_block_id section_id;
+@@ -231,9 +219,14 @@ static bool validate_lfp_data_ptrs(const
+ {
+ int fp_timing_size, dvo_timing_size, panel_pnp_id_size, panel_name_size;
+ int data_block_size, lfp_data_size;
++ const void *data_block;
+ int i;
+
+- data_block_size = raw_block_size(bdb, BDB_LVDS_LFP_DATA);
++ data_block = find_raw_section(bdb, BDB_LVDS_LFP_DATA);
++ if (!data_block)
++ return false;
++
++ data_block_size = get_blocksize(data_block);
+ if (data_block_size == 0)
+ return false;
+
+@@ -261,21 +254,6 @@ static bool validate_lfp_data_ptrs(const
+ if (16 * lfp_data_size > data_block_size)
+ return false;
+
+- /*
+- * Except for vlv/chv machines all real VBTs seem to have 6
+- * unaccounted bytes in the fp_timing table. And it doesn't
+- * appear to be a really intentional hole as the fp_timing
+- * 0xffff terminator is always within those 6 missing bytes.
+- */
+- if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size &&
+- fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size != lfp_data_size)
+- return false;
+-
+- if (ptrs->ptr[0].fp_timing.offset + fp_timing_size > ptrs->ptr[0].dvo_timing.offset ||
+- ptrs->ptr[0].dvo_timing.offset + dvo_timing_size != ptrs->ptr[0].panel_pnp_id.offset ||
+- ptrs->ptr[0].panel_pnp_id.offset + panel_pnp_id_size != lfp_data_size)
+- return false;
+-
+ /* make sure the table entries have uniform size */
+ for (i = 1; i < 16; i++) {
+ if (ptrs->ptr[i].fp_timing.table_size != fp_timing_size ||
+@@ -289,6 +267,23 @@ static bool validate_lfp_data_ptrs(const
+ return false;
+ }
+
++ /*
++ * Except for vlv/chv machines all real VBTs seem to have 6
++ * unaccounted bytes in the fp_timing table. And it doesn't
++ * appear to be a really intentional hole as the fp_timing
++ * 0xffff terminator is always within those 6 missing bytes.
++ */
++ if (fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size == lfp_data_size)
++ fp_timing_size += 6;
++
++ if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size)
++ return false;
++
++ if (ptrs->ptr[0].fp_timing.offset + fp_timing_size != ptrs->ptr[0].dvo_timing.offset ||
++ ptrs->ptr[0].dvo_timing.offset + dvo_timing_size != ptrs->ptr[0].panel_pnp_id.offset ||
++ ptrs->ptr[0].panel_pnp_id.offset + panel_pnp_id_size != lfp_data_size)
++ return false;
++
+ /* make sure the tables fit inside the data block */
+ for (i = 0; i < 16; i++) {
+ if (ptrs->ptr[i].fp_timing.offset + fp_timing_size > data_block_size ||
+@@ -300,6 +295,15 @@ static bool validate_lfp_data_ptrs(const
+ if (ptrs->panel_name.offset + 16 * panel_name_size > data_block_size)
+ return false;
+
++ /* make sure fp_timing terminators are present at expected locations */
++ for (i = 0; i < 16; i++) {
++ const u16 *t = data_block + ptrs->ptr[i].fp_timing.offset +
++ fp_timing_size - 2;
++
++ if (*t != 0xffff)
++ return false;
++ }
++
+ return true;
+ }
+