Commit 047fe6e6 authored by David Weinehall's avatar David Weinehall Committed by Daniel Vetter

drm/i915: Allow parsing of variable size child device entries from VBT

VBT version 196 increased the size of common_child_dev_config. The parser
code assumed that the size of this structure would not change.

The modified code now copies the amount needed based on the VBT version,
and emits a debug message if the VBT version is unknown (too new);
since the struct config block won't shrink in newer versions it should
be harmless to copy the maximum known size in such cases, so that's
what we do, but emitting the warning is probably sensible anyway.

In the longer run it might make sense to modify the parser code to
use a version/feature mapping, rather than hardcoding things like this,
but for now the variants are fairly managable.

This fixes a regression introduced in

commit 90e4f159
Author: Ville Syrjälä <ville.syrjala@linux.intel.com>
Date:   Wed Mar 25 18:45:58 2015 +0200

    drm/i915: Fix the VBT child device parsing for BSW

since we're hitting a DRM_ERROR on older platforms with this.

v2: Stricter size checks
Signed-off-by: default avatarDavid Weinehall <david.weinehall@linux.intel.com>
[danvet: Fixup format string.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 5eb3e5a5
...@@ -1075,15 +1075,34 @@ parse_device_mapping(struct drm_i915_private *dev_priv, ...@@ -1075,15 +1075,34 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
const union child_device_config *p_child; const union child_device_config *p_child;
union child_device_config *child_dev_ptr; union child_device_config *child_dev_ptr;
int i, child_device_num, count; int i, child_device_num, count;
u16 block_size; u8 expected_size;
u16 block_size;
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) { if (!p_defs) {
DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
return; return;
} }
if (p_defs->child_dev_size < sizeof(*p_child)) { if (bdb->version < 195) {
DRM_ERROR("General definiton block child device size is too small.\n"); expected_size = 33;
} else if (bdb->version == 195) {
expected_size = 37;
} else if (bdb->version <= 197) {
expected_size = 38;
} else {
expected_size = 38;
DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n",
expected_size, bdb->version);
}
if (expected_size > sizeof(*p_child)) {
DRM_ERROR("child_device_config cannot fit in p_child\n");
return;
}
if (p_defs->child_dev_size != expected_size) {
DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n",
p_defs->child_dev_size, expected_size, bdb->version);
return; return;
} }
/* get the block size of general definitions */ /* get the block size of general definitions */
...@@ -1130,7 +1149,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, ...@@ -1130,7 +1149,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
child_dev_ptr = dev_priv->vbt.child_dev + count; child_dev_ptr = dev_priv->vbt.child_dev + count;
count++; count++;
memcpy(child_dev_ptr, p_child, sizeof(*p_child)); memcpy(child_dev_ptr, p_child, p_defs->child_dev_size);
} }
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment