Commit 16eb0f34 authored by Jani Nikula's avatar Jani Nikula

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: 04ebaadb ("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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190208184254.24123-2-jani.nikula@intel.com
(cherry picked from commit a0f52c3d)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
parent fc89a38d
...@@ -124,7 +124,8 @@ struct opregion_asle { ...@@ -124,7 +124,8 @@ struct opregion_asle {
u64 fdss; u64 fdss;
u32 fdsp; u32 fdsp;
u32 stat; u32 stat;
u64 rvda; /* Physical address of raw vbt data */ u64 rvda; /* Physical (2.0) or relative from opregion (2.1+)
* address of raw VBT data. */
u32 rvds; /* Size of raw vbt data */ u32 rvds; /* Size of raw vbt data */
u8 rsvd[58]; u8 rsvd[58];
} __packed; } __packed;
...@@ -965,9 +966,24 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) ...@@ -965,9 +966,24 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
if (opregion->header->over.major >= 2 && opregion->asle && if (opregion->header->over.major >= 2 && opregion->asle &&
opregion->asle->rvda && opregion->asle->rvds) { opregion->asle->rvda && opregion->asle->rvds) {
opregion->rvda = memremap(opregion->asle->rvda, resource_size_t rvda = opregion->asle->rvda;
opregion->asle->rvds,
/*
* opregion 2.0: rvda is the physical VBT address.
*
* opregion 2.1+: rvda is unsigned, relative offset from
* opregion base, and should never point within opregion.
*/
if (opregion->header->over.major > 2 ||
opregion->header->over.minor >= 1) {
WARN_ON(rvda < OPREGION_SIZE);
rvda += asls;
}
opregion->rvda = memremap(rvda, opregion->asle->rvds,
MEMREMAP_WB); MEMREMAP_WB);
vbt = opregion->rvda; vbt = opregion->rvda;
vbt_size = opregion->asle->rvds; vbt_size = opregion->asle->rvds;
if (intel_bios_is_valid_vbt(vbt, vbt_size)) { if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
...@@ -977,6 +993,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) ...@@ -977,6 +993,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
goto out; goto out;
} else { } else {
DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n"); DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n");
memunmap(opregion->rvda);
opregion->rvda = NULL;
} }
} }
......
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