From patchwork Thu Nov 22 10:23:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egbert Eich X-Patchwork-Id: 1783361 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 3F8E13FC64 for ; Thu, 22 Nov 2012 11:02:59 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 35526E5EAC for ; Thu, 22 Nov 2012 03:02:59 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.126.186]) by gabe.freedesktop.org (Postfix) with ESMTP id 813C0E5CCE for ; Thu, 22 Nov 2012 02:51:10 -0800 (PST) Received: from debian (p5DCF0728.dip0.t-ipconnect.de [93.207.7.40]) by mrelayeu.kundenserver.de (node=mrbap1) with ESMTP (Nemesis) id 0LaaY3-1Sq68k0DIV-00mDbU; Thu, 22 Nov 2012 11:51:05 +0100 Received: from sles11.fritz.box (sles11.fritz.box [192.168.178.22]) by debian (Postfix) with ESMTP id 3B8EB3F35E; Thu, 22 Nov 2012 11:51:04 +0100 (CET) From: Egbert Eich To: dri-devel@lists.freedesktop.org Subject: [PATCH v2 13/18] DRM/KMS/EDID: Cache EDID blobs with extensions (v2) Date: Thu, 22 Nov 2012 05:23:03 -0500 Message-Id: <1353579788-30637-14-git-send-email-eich@suse.com> X-Mailer: git-send-email 1.7.7 In-Reply-To: <1353579788-30637-1-git-send-email-eich@suse.com> References: <1353356598-10634-1-git-send-email-eich@suse.de> <1353579788-30637-1-git-send-email-eich@suse.com> X-Provags-ID: V02:K0:L3vx1UbufMF1RxOoWjIGb44MpjzLyUnKCcs8/1wxrXB QmWKqvQ2TNIu0H8ImFYz76nCOZb1VR/FGiuCya2Uv6ZZPSxAjj MkcojcRrtTlIf9Cc/jwcTGltfWakhXCg+EAU4iN2MbOk0okj8p UhZWmftZf6I5TxjNfVTESdcgUkJ6Lh13ZFBi0WCoq8hwBC/Wbt KA+l13/4eaRIZVeOOVvxHN4WXKJwmuBPPuv4lh+mIiaZYoG15r 68xIYkHJHO0yHEiRkabLfre0Jfq3dUc0goQkmXYWs7NrcbgQgW FCQWHk1Kdi3JTmsmSIoM6aLl4f7Gph6qUPbCY+7QW10aZdoeB0 FQd608DbttwIp4x8fRqU= Cc: Egbert Eich , tiwai@suse.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org According the the VESA specs there can be up to 254 EEDID extension blocks. Since we may read the EDID (including extensions) in 10 second intervals to probe for display hotplugging (at least in cases where no hardware hotplug detection exists) and I2C transfer is rather slow we may end up consuming a considerable amount on CPU time for just that. This patch caches the EDID block if it contains at least one extension. To determine if the blocks match we only tranfer the base block, on a match we use the cached data. V2: Use kmemdup() instead of a kmalloc()/memcpy() combo, erase cache when reading a 'firmware'-supplied EDID or on error. Signed-off-by: Egbert Eich --- drivers/gpu/drm/drm_crtc.c | 1 + drivers/gpu/drm/drm_edid.c | 57 +++++++++++++++++++++++++++++++++++++------ include/drm/drm_crtc.h | 1 + include/drm/drm_edid.h | 1 + 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3533609..e283355 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -598,6 +598,7 @@ void drm_connector_cleanup(struct drm_connector *connector) drm_mode_remove(connector, mode); mutex_lock(&dev->mode_config.mutex); + drm_cache_edid(connector, NULL); drm_mode_object_put(dev, &connector->base); list_del(&connector->head); dev->mode_config.num_connector--; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a47fa7f..28b877c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -419,6 +419,38 @@ fixup_edid(u8 **blockp, int valid_extensions) } } +static bool +compare_get_edid_from_cache(struct drm_connector *connector, struct edid **edidp) +{ + if (connector->edid_cache && + connector->edid_cache->prod_code[0] == (*edidp)->prod_code[0] && + connector->edid_cache->prod_code[1] == (*edidp)->prod_code[1] && + connector->edid_cache->serial == (*edidp)->serial && + connector->edid_cache->input == (*edidp)->input) { + int size = (connector->edid_cache->extensions + 1) * EDID_LENGTH; + struct edid *new = kmemdup(connector->edid_cache, size, GFP_KERNEL); + if (!new) + return false; + DRM_DEBUG_KMS("Got EDID for %s from cache.\n", drm_get_connector_name(connector)); + kfree(*edidp); + *edidp = new; + return true; + } + return false; +} + +void +drm_cache_edid(struct drm_connector *connector, struct edid *edid) +{ + struct edid *new = NULL; + kfree(connector->edid_cache); + if (edid) { + int size = (edid->extensions + 1) * EDID_LENGTH; + new = kmemdup(edid, size, GFP_KERNEL); + } + connector->edid_cache = new; +} + static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { @@ -429,28 +461,30 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE /* check if the user has specified a 'firmware' EDID file */ block = (u8 *)drm_load_edid_firmware(connector); - if (block) + if (block) { + drm_cache_edid(connector, NULL); return block; + } #endif if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) - return NULL; + goto error; /* base block fetch */ for (i = 0; i < 4; i++) { if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) - goto out; + goto error_free; if (drm_edid_block_valid(block, 0, print_bad_edid)) break; if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { connector->null_edid_counter++; - goto carp; + goto error_carp; } } if (i == 4) - goto carp; + goto error_carp; - /* if there's no extensions, we're done */ + /* if there are no extensions, we're done - don't bother caching */ if (block[EDID_EXTENSION_FLAG_OFFSET] == 0) return block; @@ -458,6 +492,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) if (block[EDID_VERSION_MINOR_OFFSET] < 3) goto done_fix_extension_count; + /* see if EDID is in the cache - no need to read all extension blocks */ + if (compare_get_edid_from_cache(connector, (struct edid **)&block)) + return block; + new = krealloc(block, (block[EDID_EXTENSION_FLAG_OFFSET] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) { dev_warn(connector->dev->dev, "%s: cannot allocate memory for %d EDID blocks: truncating.\n", @@ -500,18 +538,21 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) done_fix_extension_count: fixup_edid(&block, valid_extensions); + drm_cache_edid(connector, (valid_extensions > 0) ? (struct edid *)block : NULL); return block; -carp: +error_carp: if (print_bad_edid) { dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", drm_get_connector_name(connector), j); } connector->bad_edid_counter++; -out: +error_free: kfree(block); +error: + drm_cache_edid(connector, NULL); return NULL; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 49dd8c2..6a1054c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -601,6 +601,7 @@ struct drm_connector { struct drm_encoder *encoder; /* currently active encoder */ /* EDID bits */ + struct edid *edid_cache; uint8_t eld[MAX_ELD_BYTES]; bool dvi_dual; int max_tmds_clock; /* in MHz */ diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 53c619c..c880510 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -256,5 +256,6 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct edid *drm_load_edid_firmware(struct drm_connector *connector); #endif int drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int len); +void drm_cache_edid(struct drm_connector *connector, struct edid *edid); #endif /* __DRM_EDID_H__ */