Skip to content

Commit 16eb0f3

Browse files
committed
drm/i915/opregion: rvda is relative from opregion base in opregion 2.1+
Starting from opregion version 2.1 (roughly corresponding to ICL+) the RVDA field is relative from the beginning of opregion, not absolute address. Fix the error path while at it. v2: Make relative vs. absolute conditional on the opregion version, bumped for the purpose. Turned out there are machines relying on absolute RVDA in the wild. v3: Fix the version checks Fixes: 04ebaad ("drm/i915/opregion: handle VBT sizes bigger than 6 KB") Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190208184254.24123-2-jani.nikula@intel.com (cherry picked from commit a0f52c3) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
1 parent fc89a38 commit 16eb0f3

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

drivers/gpu/drm/i915/intel_opregion.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ struct opregion_asle {
124124
u64 fdss;
125125
u32 fdsp;
126126
u32 stat;
127-
u64 rvda; /* Physical address of raw vbt data */
127+
u64 rvda; /* Physical (2.0) or relative from opregion (2.1+)
128+
* address of raw VBT data. */
128129
u32 rvds; /* Size of raw vbt data */
129130
u8 rsvd[58];
130131
} __packed;
@@ -965,9 +966,24 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
965966

966967
if (opregion->header->over.major >= 2 && opregion->asle &&
967968
opregion->asle->rvda && opregion->asle->rvds) {
968-
opregion->rvda = memremap(opregion->asle->rvda,
969-
opregion->asle->rvds,
969+
resource_size_t rvda = opregion->asle->rvda;
970+
971+
/*
972+
* opregion 2.0: rvda is the physical VBT address.
973+
*
974+
* opregion 2.1+: rvda is unsigned, relative offset from
975+
* opregion base, and should never point within opregion.
976+
*/
977+
if (opregion->header->over.major > 2 ||
978+
opregion->header->over.minor >= 1) {
979+
WARN_ON(rvda < OPREGION_SIZE);
980+
981+
rvda += asls;
982+
}
983+
984+
opregion->rvda = memremap(rvda, opregion->asle->rvds,
970985
MEMREMAP_WB);
986+
971987
vbt = opregion->rvda;
972988
vbt_size = opregion->asle->rvds;
973989
if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
@@ -977,6 +993,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
977993
goto out;
978994
} else {
979995
DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n");
996+
memunmap(opregion->rvda);
997+
opregion->rvda = NULL;
980998
}
981999
}
9821000

0 commit comments

Comments
 (0)