Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756922Ab2BWUgV (ORCPT ); Thu, 23 Feb 2012 15:36:21 -0500 Received: from smtp.fireflyinternet.com ([109.228.6.236]:38768 "EHLO fireflyinternet.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1756616Ab2BWUgT (ORCPT ); Thu, 23 Feb 2012 15:36:19 -0500 X-Greylist: delayed 2555 seconds by postgrey-1.27 at vger.kernel.org; Thu, 23 Feb 2012 15:36:19 EST X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.66.37; From: Chris Wilson To: linux-kernel@vger.kernel.org Cc: dri-devel@lists.freedesktop.org, Linus Torvalds , Chris Wilson , Eugeni Dodonov , Dave Airlie , Alex Deucher Subject: [PATCH] drm: Reduce the number of retries whilst reading EDIDs Date: Thu, 23 Feb 2012 19:52:51 +0000 Message-Id: <1330026771-19937-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.9.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Originating-IP: 78.156.66.37 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3968 Lines: 104 i2c retries if sees an EGAIN, drm_do_probe_ddc_edid retries until it gets a result and *then* drm_do_get_edid retries until it gets a result it is happy with. All in all, that is a lot of processor intensive looping in cases where we do not expect and cannot get valid data - for example on Intel with disconnected hardware we will busy-spin until we hit the i2c timeout. This is then repeated for every connector when querying the current status of outputs. So to improve the situation, we can trim the number of retries for reading the base block and to check for a reschedule before proceeding so that we do not hog the machine whilst probing outputs. (Though since we will be likely blocking the graphics device, the user is still going to notice the latency.) Reported-by: Linus Torvalds Reported-by: Stephan Bärwolf Signed-off-by: Chris Wilson Cc: Eugeni Dodonov Cc: Dave Airlie Cc: Alex Deucher --- drivers/gpu/drm/drm_edid.c | 30 +++++++++++++++++++++++------- 1 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ece03fc..4409cd4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -35,6 +35,9 @@ #include "drm_edid.h" #include "drm_edid_modes.h" +#define EDID_PROBE_RETRIES 1 +#define EDID_READ_RETRIES 5 + #define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ ((edid)->version == (maj) && (edid)->revision > (min))) @@ -239,11 +242,12 @@ EXPORT_SYMBOL(drm_edid_is_valid); * Try to fetch EDID information by calling i2c driver function. */ static int -drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, - int block, int len) +drm_get_edid_block(struct i2c_adapter *adapter, + unsigned char *buf, int block, int len, + int retries) { unsigned char start = block * EDID_LENGTH; - int ret, retries = 5; + int ret; /* The core i2c driver will automatically retry the transfer if the * adapter reports EAGAIN. However, we find that bit-banging transfers @@ -293,7 +297,19 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /* base block fetch */ for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) + /* EDID transfer may be quite processor intensive and last + * a long time. For example, when waiting for a timeout on + * a non-existent connector whilst using bit-banging. As a + * result we can end up hogging the machine, so give someone + * else the chance to run first. But when we have started a + * transfer don't interrupt until finished. + */ + if (need_resched()) + schedule(); + + if (drm_get_edid_block(adapter, + block, 0, EDID_LENGTH, + EDID_PROBE_RETRIES)) goto out; if (drm_edid_block_valid(block)) break; @@ -316,9 +332,9 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) for (j = 1; j <= block[0x7e]; j++) { for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, + if (drm_get_edid_block(adapter, block + (valid_extensions + 1) * EDID_LENGTH, - j, EDID_LENGTH)) + j, EDID_LENGTH, EDID_READ_RETRIES)) goto out; if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) { valid_extensions++; @@ -362,7 +378,7 @@ drm_probe_ddc(struct i2c_adapter *adapter) { unsigned char out; - return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0); + return drm_get_edid_block(adapter, &out, 0, 1, EDID_PROBE_RETRIES) == 0; } /** -- 1.7.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/