aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Weinehall <david.weinehall@linux.intel.com>2015-08-21 09:52:01 -0400
committerJani Nikula <jani.nikula@intel.com>2015-08-24 03:34:09 -0400
commite2d6cf7f3696c87546f7fefe9bac79ee09db4bef (patch)
treed534b7ff4a5b0881a93fc709391edeedc06929d3
parentaf7080f555e556094762c03c31cabdbe072b16b6 (diff)
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 manageable. This fixes a regression introduced in commit 75067ddecf21271631bc018d2fb23ddd09b66aae Author: Antti Koskipaa <antti.koskipaa@linux.intel.com> Date: Fri Jul 10 14:10:55 2015 +0300 drm/i915: Per-DDI I_boost override since that commit changed the child device config size without updating the checks and memcpy. v2: Stricter size checks v3 by Jani: - Keep the checks strict, and warnigns verbose, but keep going anyway. - Take care to copy the max amount of child device config we can. - Fix the messages. Signed-off-by: David Weinehall <david.weinehall@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c37
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h6
2 files changed, 37 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 64e5b15ae0b6..be83b77aa018 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -1051,17 +1051,39 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
1051 const union child_device_config *p_child; 1051 const union child_device_config *p_child;
1052 union child_device_config *child_dev_ptr; 1052 union child_device_config *child_dev_ptr;
1053 int i, child_device_num, count; 1053 int i, child_device_num, count;
1054 u16 block_size; 1054 u8 expected_size;
1055 u16 block_size;
1055 1056
1056 p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); 1057 p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
1057 if (!p_defs) { 1058 if (!p_defs) {
1058 DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); 1059 DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
1059 return; 1060 return;
1060 } 1061 }
1061 if (p_defs->child_dev_size < sizeof(*p_child)) { 1062 if (bdb->version < 195) {
1062 DRM_ERROR("General definiton block child device size is too small.\n"); 1063 expected_size = sizeof(struct old_child_dev_config);
1064 } else if (bdb->version == 195) {
1065 expected_size = 37;
1066 } else if (bdb->version <= 197) {
1067 expected_size = 38;
1068 } else {
1069 expected_size = 38;
1070 BUILD_BUG_ON(sizeof(*p_child) < 38);
1071 DRM_DEBUG_DRIVER("Expected child device config size for VBT version %u not known; assuming %u\n",
1072 bdb->version, expected_size);
1073 }
1074
1075 /* The legacy sized child device config is the minimum we need. */
1076 if (p_defs->child_dev_size < sizeof(struct old_child_dev_config)) {
1077 DRM_ERROR("Child device config size %u is too small.\n",
1078 p_defs->child_dev_size);
1063 return; 1079 return;
1064 } 1080 }
1081
1082 /* Flag an error for unexpected size, but continue anyway. */
1083 if (p_defs->child_dev_size != expected_size)
1084 DRM_ERROR("Unexpected child device config size %u (expected %u for VBT version %u)\n",
1085 p_defs->child_dev_size, expected_size, bdb->version);
1086
1065 /* get the block size of general definitions */ 1087 /* get the block size of general definitions */
1066 block_size = get_blocksize(p_defs); 1088 block_size = get_blocksize(p_defs);
1067 /* get the number of child device */ 1089 /* get the number of child device */
@@ -1106,7 +1128,14 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
1106 1128
1107 child_dev_ptr = dev_priv->vbt.child_dev + count; 1129 child_dev_ptr = dev_priv->vbt.child_dev + count;
1108 count++; 1130 count++;
1109 memcpy(child_dev_ptr, p_child, sizeof(*p_child)); 1131
1132 /*
1133 * Copy as much as we know (sizeof) and is available
1134 * (child_dev_size) of the child device. Accessing the data must
1135 * depend on VBT version.
1136 */
1137 memcpy(child_dev_ptr, p_child,
1138 min_t(size_t, p_defs->child_dev_size, sizeof(*p_child)));
1110 } 1139 }
1111 return; 1140 return;
1112} 1141}
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 6d909efbf43f..06d0dbde2be6 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -203,9 +203,11 @@ struct bdb_general_features {
203#define DEVICE_PORT_DVOB 0x01 203#define DEVICE_PORT_DVOB 0x01
204#define DEVICE_PORT_DVOC 0x02 204#define DEVICE_PORT_DVOC 0x02
205 205
206/* We used to keep this struct but without any version control. We should avoid 206/*
207 * We used to keep this struct but without any version control. We should avoid
207 * using it in the future, but it should be safe to keep using it in the old 208 * using it in the future, but it should be safe to keep using it in the old
208 * code. */ 209 * code. Do not change; we rely on its size.
210 */
209struct old_child_dev_config { 211struct old_child_dev_config {
210 u16 handle; 212 u16 handle;
211 u16 device_type; 213 u16 device_type;