On Tue, Mar 29, 2022 at 09:42:14PM +0300, Jani Nikula wrote:
Add edid_block_check() that only checks the EDID block validity, without any actions. Turns out it's simple and crystal clear.
Rewrite drm_edid_block_valid() around it, keeping all the functionality fairly closely the same, warts and all. Turns out it's incredibly complicated for a function you'd expect to be simple, with all the fixing and printing and special casing. (Maybe we'll want to simplify it in the future.)
Cc: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Jani Nikula jani.nikula@intel.com
drivers/gpu/drm/drm_edid.c | 150 ++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 62 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 481643751d10..04eb6949c9c8 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1668,10 +1668,55 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) } EXPORT_SYMBOL(drm_edid_are_equal);
+enum edid_block_status {
- EDID_BLOCK_OK = 0,
- EDID_BLOCK_NULL,
- EDID_BLOCK_HEADER_CORRUPT,
- EDID_BLOCK_HEADER_REPAIR,
- EDID_BLOCK_HEADER_FIXED,
- EDID_BLOCK_CHECKSUM,
- EDID_BLOCK_VERSION,
+};
+static enum edid_block_status edid_block_check(const void *_block, bool base)
s/base/is_base_block/ or something?
+{
- const struct edid *block = _block;
- if (!block)
return EDID_BLOCK_NULL;
- if (base) {
int score = drm_edid_header_is_valid(block);
if (score < clamp(edid_fixup, 6, 8))
That should clamp to 0-8?
Might be nicer to just define a .set() op for the modparam and check it there, but that's clearly material for a separate patch.
return EDID_BLOCK_HEADER_CORRUPT;
if (score < 8)
return EDID_BLOCK_HEADER_REPAIR;
- }
- if (edid_block_compute_checksum(block) != edid_block_get_checksum(block))
return EDID_BLOCK_CHECKSUM;
- if (base) {
if (block->version != 1)
return EDID_BLOCK_VERSION;
- }
- return EDID_BLOCK_OK;
+}
+static bool edid_block_status_valid(enum edid_block_status status, int tag) +{
- return status == EDID_BLOCK_OK ||
status == EDID_BLOCK_HEADER_FIXED ||
(status == EDID_BLOCK_CHECKSUM && tag == CEA_EXT);
+}
/**
- drm_edid_block_valid - Sanity check the EDID block (base or extension)
- @raw_edid: pointer to raw EDID block
- @block: type of block to validate (0 for base, extension otherwise)
- @block_num: type of block to validate (0 for base, extension otherwise)
- @print_bad_edid: if true, dump bad EDID blocks to the console
- @edid_corrupt: if true, the header or checksum is invalid
@@ -1680,88 +1725,69 @@ EXPORT_SYMBOL(drm_edid_are_equal);
- Return: True if the block is valid, false otherwise.
*/ -bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, +bool drm_edid_block_valid(u8 *_block, int block_num, bool print_bad_edid, bool *edid_corrupt) {
- u8 csum;
- struct edid *edid = (struct edid *)raw_edid;
- struct edid *block = (struct edid *)_block;
- enum edid_block_status status;
- bool base = block_num == 0;
- bool valid;
- if (WARN_ON(!raw_edid))
- if (WARN_ON(!block)) return false;
- if (edid_fixup > 8 || edid_fixup < 0)
edid_fixup = 6;
- if (block == 0) {
int score = drm_edid_header_is_valid(raw_edid);
- status = edid_block_check(block, base);
- if (status == EDID_BLOCK_HEADER_REPAIR) {
DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
edid_header_fix(block);
if (score == 8) {
if (edid_corrupt)
*edid_corrupt = false;
} else if (score >= edid_fixup) {
/* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6
* The corrupt flag needs to be set here otherwise, the
* fix-up code here will correct the problem, the
* checksum is correct and the test fails
*/
if (edid_corrupt)
*edid_corrupt = true;
DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
edid_header_fix(raw_edid);
} else {
if (edid_corrupt)
*edid_corrupt = true;
goto bad;
}
/* Retry with fixed header, update status if that worked. */
status = edid_block_check(block, base);
if (status == EDID_BLOCK_OK)
}status = EDID_BLOCK_HEADER_FIXED;
- csum = edid_block_compute_checksum(raw_edid);
- if (csum != edid_block_get_checksum(raw_edid)) {
if (edid_corrupt)
- if (edid_corrupt) {
/*
* Unknown major version isn't corrupt but we can't use it. Only
* the base block can reset edid_corrupt to false.
*/
if (base && (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION))
*edid_corrupt = false;
else if (status != EDID_BLOCK_OK) *edid_corrupt = true;
/* allow CEA to slide through, switches mangle this */
if (edid_block_tag(raw_edid) == CEA_EXT) {
DRM_DEBUG("EDID checksum is invalid, remainder is %d\n", csum);
DRM_DEBUG("Assuming a KVM switch modified the CEA block but left the original checksum\n");
} else {
if (print_bad_edid)
DRM_NOTE("EDID checksum is invalid, remainder is %d\n", csum);
goto bad;
}
}
/* per-block-type checks */
switch (edid_block_tag(raw_edid)) {
case 0: /* base */
if (edid->version != 1) {
DRM_NOTE("EDID has major version %d, instead of 1\n", edid->version);
goto bad;
- /* Determine whether we can use this block with this status. */
- valid = edid_block_status_valid(status, edid_block_tag(block));
- /* Some fairly random status printouts. */
- if (status == EDID_BLOCK_CHECKSUM) {
if (valid) {
DRM_DEBUG("EDID block checksum is invalid, remainder is %d\n",
edid_block_compute_checksum(block));
DRM_DEBUG("Assuming a KVM switch modified the block but left the original checksum\n");
} else if (print_bad_edid) {
DRM_NOTE("EDID block checksum is invalid, remainder is %d\n",
}edid_block_compute_checksum(block));
if (edid->revision > 4)
DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
This debug message seems to disappear. Intentional?
break;
- default:
break;
- } else if (status == EDID_BLOCK_VERSION) {
DRM_NOTE("EDID has major version %d, instead of 1\n",
}block->version);
- return true;
-bad:
- if (print_bad_edid) {
if (edid_is_zero(raw_edid, EDID_LENGTH)) {
- if (!valid && print_bad_edid) {
} else { pr_notice("Raw EDID:\n"); print_hex_dump(KERN_NOTICE, " \t", DUMP_PREFIX_NONE, 16, 1,if (edid_is_zero(block, EDID_LENGTH)) { pr_notice("EDID block is all zeroes\n");
raw_edid, EDID_LENGTH, false);
} }block, EDID_LENGTH, false);
- return false;
- return valid;
} EXPORT_SYMBOL(drm_edid_block_valid);
-- 2.30.2