From patchwork Fri Apr 10 16:12:47 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Todd Previte X-Patchwork-Id: 6197941 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 40D5A9F2EC for ; Fri, 10 Apr 2015 16:13:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2C5C32034F for ; Fri, 10 Apr 2015 16:13:10 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id EE7BC203EB for ; Fri, 10 Apr 2015 16:13:08 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4BBA66E9BD; Fri, 10 Apr 2015 09:13:08 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-pa0-f41.google.com (mail-pa0-f41.google.com [209.85.220.41]) by gabe.freedesktop.org (Postfix) with ESMTP id C75EA6E9BD; Fri, 10 Apr 2015 09:13:07 -0700 (PDT) Received: by pabsx10 with SMTP id sx10so25813535pab.3; Fri, 10 Apr 2015 09:13:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=urUPSFj2tLlVgse0h1L2Hg5tVThmosmd3iID9yJpRA0=; b=iySqSQTiGhqn4LeHHjdTMZk/gWQ3Vzdk1we/0r0FCbieCZiN0RE0m1x21LMJf7wuaQ FEG9Es+SfzH6QDMonRWsKd3WmYVco5shk54174JTurcYMsVlhmkbLq1UEtHCe+mRfO4M uDwuf7HdRuCb/5oiUCKklBJ56W3ZAc9AhZfj4iWSgpxnBYqV0YssXFdAwD9zxcyI+E83 XB2mTsR3SDOyR4TUzOqKoK75HN98QYvBwv6nHNaKyVjrOKsiIaiNzzP2syzwjBEmb7nq lDdAgjp9ir5H3DxTV5tKPRcSz9qnbJRWLYeB3JZMje7mVON+TaiVwBv79rGlpgU54kxf fvcw== X-Received: by 10.68.139.225 with SMTP id rb1mr3904390pbb.93.1428682387695; Fri, 10 Apr 2015 09:13:07 -0700 (PDT) Received: from localhost.localdomain (ip70-162-72-208.ph.ph.cox.net. [70.162.72.208]) by mx.google.com with ESMTPSA id dk3sm2682849pbb.91.2015.04.10.09.13.06 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 10 Apr 2015 09:13:07 -0700 (PDT) From: Todd Previte To: intel-gfx@lists.freedesktop.org Subject: [PATCH 06/11] drm/i915: Add supporting structure for Displayport Link CTS test 4.2.2.6 Date: Fri, 10 Apr 2015 09:12:47 -0700 Message-Id: <1428682372-21586-7-git-send-email-tprevite@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1428682372-21586-1-git-send-email-tprevite@gmail.com> References: <1428682372-21586-1-git-send-email-tprevite@gmail.com> Cc: dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Displayport compliance test 4.2.2.6 requires that a source device be capable of detecting a corrupt EDID. The test specification states that the sink device sets up the EDID with an invalid checksum. To do this, the sink sets up an invalid EDID header, expecting the source device to generate the checksum and compare it to the value stored in the last byte of the block data. Unfortunately, the DRM EDID reading and parsing functions are actually too good in this case; the header is fixed before the checksum is computed and thus the code never sees the invalid checksum. This results in a failure to pass the compliance test. To correct this issue, a checksum is generated when the EDID header is detected as corrupted. If the checksum is invalid, it sets the header_corrupt flag and logs the errors. In the case of a more seriously damaged header (fixup score less than the threshold) the code does not generate the checksum but does set the header_corrupt flag. V2: - Removed the static bool global - Added a bool to the drm_connector struct to reaplce the static one for holding the status of raw edid header corruption detection - Modified the function signature of the is_valid function to take an additional parameter to store the corruption detected value - Fixed the other callers of the above is_valid function V3: - Updated the commit message to be more clear about what and why this patch does what it does. - Added comment in code to clarify the operations there - Removed compliance variable and check_link_status update; those have been moved to a later patch - Removed variable assignment from the bottom of the test handler Signed-off-by: Todd Previte Cc: dri-devel@lists.freedesktop.org --- drivers/gpu/drm/drm_edid.c | 31 ++++++++++++++++++++++++++----- drivers/gpu/drm/drm_edid_load.c | 7 +++++-- drivers/gpu/drm/i2c/tda998x_drv.c | 4 ++-- include/drm/drm_crtc.h | 8 +++++++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 53bc7a6..12e5be7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1005,7 +1005,6 @@ int drm_edid_header_is_valid(const u8 *raw_edid) for (i = 0; i < sizeof(edid_header); i++) if (raw_edid[i] == edid_header[i]) score++; - return score; } EXPORT_SYMBOL(drm_edid_header_is_valid); @@ -1047,7 +1046,8 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length) * * 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 *raw_edid, int block, bool print_bad_edid, + bool *header_corrupt) { u8 csum; struct edid *edid = (struct edid *)raw_edid; @@ -1062,9 +1062,27 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) int score = drm_edid_header_is_valid(raw_edid); if (score == 8) ; else if (score >= edid_fixup) { + /* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6 + * In order to properly generate the invalid checksum + * required for this test, it must be generated using + * the raw EDID data. Otherwise, the fix-up code here + * will correct the problem, the checksum is then correct + * and the test fails + */ + csum = drm_edid_block_checksum(raw_edid); + if (csum) { + DRM_DEBUG_DRIVER("Invalid EDID header, score = %d\n", score); + DRM_DEBUG_DRIVER("Invalid EDID checksum %d\n", csum); + if (header_corrupt) + *header_corrupt = 1; + } DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); memcpy(raw_edid, edid_header, sizeof(edid_header)); } else { + if (header_corrupt) { + DRM_DEBUG_DRIVER("Invalid EDID header\n"); + *header_corrupt = 1; + } goto bad; } } @@ -1129,7 +1147,7 @@ bool drm_edid_is_valid(struct edid *edid) return false; for (i = 0; i <= edid->extensions; i++) - if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true)) + if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true, NULL)) return false; return true; @@ -1232,7 +1250,8 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, for (i = 0; i < 4; i++) { if (get_edid_block(data, block, 0, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block, 0, print_bad_edid)) + if (drm_edid_block_valid(block, 0, print_bad_edid, + &connector->edid_header_corrupt)) break; if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { connector->null_edid_counter++; @@ -1257,7 +1276,9 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) { + if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, + print_bad_edid, + &connector->edid_header_corrupt)) { valid_extensions++; break; } diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 732cb6f..1505494 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -216,7 +216,8 @@ static void *edid_load(struct drm_connector *connector, const char *name, goto out; } - if (!drm_edid_block_valid(edid, 0, print_bad_edid)) { + if (!drm_edid_block_valid(edid, 0, print_bad_edid, + &connector->edid_header_corrupt)) { connector->bad_edid_counter++; DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", name); @@ -229,7 +230,9 @@ static void *edid_load(struct drm_connector *connector, const char *name, if (i != valid_extensions + 1) memcpy(edid + (valid_extensions + 1) * EDID_LENGTH, edid + i * EDID_LENGTH, EDID_LENGTH); - if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid)) + if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, + print_bad_edid, + &connector->edid_header_corrupt)) valid_extensions++; } diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a9041d1..9c3d6b3 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1106,7 +1106,7 @@ static uint8_t *do_get_edid(struct tda998x_priv *priv) if (read_edid_block(priv, block, 0)) goto fail; - if (!drm_edid_block_valid(block, 0, print_bad_edid)) + if (!drm_edid_block_valid(block, 0, print_bad_edid, NULL)) goto fail; /* if there's no extensions, we're done */ @@ -1123,7 +1123,7 @@ static uint8_t *do_get_edid(struct tda998x_priv *priv) if (read_edid_block(priv, ext_block, j)) goto fail; - if (!drm_edid_block_valid(ext_block, j, print_bad_edid)) + if (!drm_edid_block_valid(ext_block, j, print_bad_edid, NULL)) goto fail; valid_extensions++; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0261417..e31a4b3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -719,6 +719,11 @@ struct drm_connector { int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ unsigned bad_edid_counter; + /* Flag for raw EDID header corruption - used in Displayport compliance testing + * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 + */ + bool edid_header_corrupt; + struct dentry *debugfs_entry; struct drm_connector_state *state; @@ -1436,7 +1441,8 @@ extern void drm_set_preferred_mode(struct drm_connector *connector, int hpref, int vpref); extern int drm_edid_header_is_valid(const u8 *raw_edid); -extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); +extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, bool *header_corrupt); + extern bool drm_edid_is_valid(struct edid *edid); extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,