From patchwork Mon Nov 19 20:23:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egbert Eich X-Patchwork-Id: 1769071 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id 9959DDF264 for ; Mon, 19 Nov 2012 20:50:59 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7E60EE6266 for ; Mon, 19 Nov 2012 12:50:59 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTP id 16FF4E6248 for ; Mon, 19 Nov 2012 12:41:30 -0800 (PST) Received: from relay2.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id 66E6FA3BA5; Mon, 19 Nov 2012 21:41:29 +0100 (CET) Received: from sles11.fritz.box (sles11.fritz.box [192.168.178.22]) by debian (Postfix) with ESMTP id F09DC3F32C; Mon, 19 Nov 2012 21:41:28 +0100 (CET) From: Egbert Eich To: dri-devel@lists.freedesktop.org Subject: [PATCH 10/17] DRM/KMS/EDID: Cache EDID blobs with extensions. Date: Mon, 19 Nov 2012 15:23:11 -0500 Message-Id: <1353356598-10634-11-git-send-email-eich@suse.de> X-Mailer: git-send-email 1.7.7 In-Reply-To: <1353356598-10634-1-git-send-email-eich@suse.de> References: <1353356598-10634-1-git-send-email-eich@suse.de> Cc: Egbert Eich , Takashi Iwai 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. Signed-off-by: Egbert Eich --- drivers/gpu/drm/drm_crtc.c | 1 + drivers/gpu/drm/drm_edid.c | 43 ++++++++++++++++++++++++++++++++++++++++++- include/drm/drm_crtc.h | 1 + include/drm/drm_edid.h | 1 + 4 files changed, 45 insertions(+), 1 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 3e7df61..410a54d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -431,6 +431,41 @@ fixup_edid(u8 **blockp, int valid_extensions) return (new ? valid_extensions : -ENOMEM); } +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 = kmalloc(size, GFP_KERNEL); + if (!new) + return false; + DRM_DEBUG_KMS("Got EDID for %s from cache.\n",drm_get_connector_name(connector)); + memcpy(new, connector->edid_cache, size); + 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 = kmalloc(size, GFP_KERNEL); + if (new) + memcpy(new, edid, size); + } + connector->edid_cache = new; +} + static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { @@ -462,10 +497,14 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) if (i == 4) goto 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; + /* 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) goto out; @@ -505,6 +544,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) no_more: fixup_edid(&block, valid_extensions); + drm_cache_edid(connector, (struct edid *)block); return block; @@ -513,6 +553,7 @@ carp: dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", drm_get_connector_name(connector), j); } + drm_cache_edid(connector, NULL); connector->bad_edid_counter++; out: 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__ */