Commit 14544d09 authored by Chris Wilson's avatar Chris Wilson Committed by Daniel Vetter

drm/edid: Only print the bad edid when aborting

Currently, if drm.debug is enabled, we get a DRM_ERROR message on the
intermediate edid reads. This causes transient failures in CI which
flags up the sporadic EDID read failures, which are recovered by
rereading the EDID automatically. This patch combines the reporting done
by drm_do_get_edid() itself with the bad block printing from
get_edid_block(), into a single warning associated with the connector
once all attempts to retrieve the EDID fail.

v2: Print the whole EDID, marking up the bad/zero blocks. This requires
recording the whole of the raw edid, then a second pass to reduce it to
the valid extensions.
v3: Fix invalid/valid extension fumble.

References: https://bugs.freedesktop.org/show_bug.cgi?id=98228Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarSean Paul <seanpaul@chromium.org>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20161024113821.26263-1-chris@chris-wilson.co.uk
parent c170a14e
...@@ -1260,6 +1260,34 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len) ...@@ -1260,6 +1260,34 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
return ret == xfers ? 0 : -1; return ret == xfers ? 0 : -1;
} }
static void connector_bad_edid(struct drm_connector *connector,
u8 *edid, int num_blocks)
{
int i;
if (connector->bad_edid_counter++ && !(drm_debug & DRM_UT_KMS))
return;
dev_warn(connector->dev->dev,
"%s: EDID is invalid:\n",
connector->name);
for (i = 0; i < num_blocks; i++) {
u8 *block = edid + i * EDID_LENGTH;
char prefix[20];
if (drm_edid_is_zero(block, EDID_LENGTH))
sprintf(prefix, "\t[%02x] ZERO ", i);
else if (!drm_edid_block_valid(block, i, false, NULL))
sprintf(prefix, "\t[%02x] BAD ", i);
else
sprintf(prefix, "\t[%02x] GOOD ", i);
print_hex_dump(KERN_WARNING,
prefix, DUMP_PREFIX_NONE, 16, 1,
block, EDID_LENGTH, false);
}
}
/** /**
* drm_do_get_edid - get EDID data using a custom EDID block read function * drm_do_get_edid - get EDID data using a custom EDID block read function
* @connector: connector we're probing * @connector: connector we're probing
...@@ -1283,7 +1311,6 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -1283,7 +1311,6 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
{ {
int i, j = 0, valid_extensions = 0; int i, j = 0, valid_extensions = 0;
u8 *edid, *new; u8 *edid, *new;
bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
return NULL; return NULL;
...@@ -1292,7 +1319,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -1292,7 +1319,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (get_edid_block(data, edid, 0, EDID_LENGTH)) if (get_edid_block(data, edid, 0, EDID_LENGTH))
goto out; goto out;
if (drm_edid_block_valid(edid, 0, print_bad_edid, if (drm_edid_block_valid(edid, 0, false,
&connector->edid_corrupt)) &connector->edid_corrupt))
break; break;
if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) { if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
...@@ -1304,54 +1331,60 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -1304,54 +1331,60 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
goto carp; goto carp;
/* if there's no extensions, we're done */ /* if there's no extensions, we're done */
if (edid[0x7e] == 0) valid_extensions = edid[0x7e];
if (valid_extensions == 0)
return (struct edid *)edid; return (struct edid *)edid;
new = krealloc(edid, (edid[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new) if (!new)
goto out; goto out;
edid = new; edid = new;
for (j = 1; j <= edid[0x7e]; j++) { for (j = 1; j <= edid[0x7e]; j++) {
u8 *block = edid + (valid_extensions + 1) * EDID_LENGTH; u8 *block = edid + j * EDID_LENGTH;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (get_edid_block(data, block, j, EDID_LENGTH)) if (get_edid_block(data, block, j, EDID_LENGTH))
goto out; goto out;
if (drm_edid_block_valid(block, j, if (drm_edid_block_valid(block, j, false, NULL))
print_bad_edid, NULL)) {
valid_extensions++;
break; break;
}
} }
if (i == 4 && print_bad_edid) { if (i == 4)
dev_warn(connector->dev->dev, valid_extensions--;
"%s: Ignoring invalid EDID block %d.\n",
connector->name, j);
connector->bad_edid_counter++;
}
} }
if (valid_extensions != edid[0x7e]) { if (valid_extensions != edid[0x7e]) {
u8 *base;
connector_bad_edid(connector, edid, edid[0x7e] + 1);
edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
edid[0x7e] = valid_extensions; edid[0x7e] = valid_extensions;
new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
new = kmalloc((valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new) if (!new)
goto out; goto out;
base = new;
for (i = 0; i <= edid[0x7e]; i++) {
u8 *block = edid + i * EDID_LENGTH;
if (!drm_edid_block_valid(block, i, false, NULL))
continue;
memcpy(base, block, EDID_LENGTH);
base += EDID_LENGTH;
}
kfree(edid);
edid = new; edid = new;
} }
return (struct edid *)edid; return (struct edid *)edid;
carp: carp:
if (print_bad_edid) { connector_bad_edid(connector, edid, 1);
dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
connector->name, j);
}
connector->bad_edid_counter++;
out: out:
kfree(edid); kfree(edid);
return NULL; return 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