From patchwork Fri Sep 24 17:17:17 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 206932 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8OISSA1016693 for ; Fri, 24 Sep 2010 18:28:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756389Ab0IXS2Y (ORCPT ); Fri, 24 Sep 2010 14:28:24 -0400 Received: from queueout02-winn.ispmail.ntl.com ([81.103.221.56]:63822 "EHLO queueout02-winn.ispmail.ntl.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757335Ab0IXS2X (ORCPT ); Fri, 24 Sep 2010 14:28:23 -0400 Received: from aamtaout03-winn.ispmail.ntl.com ([81.103.221.35]) by mtaout03-winn.ispmail.ntl.com (InterMail vM.7.08.04.00 201-2186-134-20080326) with ESMTP id <20100924171720.MRZW3075.mtaout03-winn.ispmail.ntl.com@aamtaout03-winn.ispmail.ntl.com>; Fri, 24 Sep 2010 18:17:20 +0100 Received: from zog.reactivated.net ([86.14.215.141]) by aamtaout03-winn.ispmail.ntl.com (InterMail vG.2.02.00.01 201-2161-120-102-20060912) with ESMTP id <20100924171719.BRII1807.aamtaout03-winn.ispmail.ntl.com@zog.reactivated.net>; Fri, 24 Sep 2010 18:17:19 +0100 Received: by zog.reactivated.net (Postfix, from userid 1000) id B3A969D401B; Fri, 24 Sep 2010 18:17:17 +0100 (BST) From: Daniel Drake To: mchehab@infradead.org Cc: linux-media@vger.kernel.org Cc: corbet@lwn.net Subject: [PATCH 1/4] cafe_ccic: Fix hang in command write processing Message-Id: <20100924171717.B3A969D401B@zog.reactivated.net> Date: Fri, 24 Sep 2010 18:17:17 +0100 (BST) X-Cloudmark-Analysis: v=1.1 cv=3ENABmdyEd/Fm7fR7+mZIuMDn6+IErAeEhlfWBImZFk= c=1 sm=0 a=Sv6I5LUtbT0A:10 a=Op-mwl0xAAAA:8 a=xc8PKRhxtCrQAd0HRKAA:9 a=gAIU_hsJL3eyvhIAIiMA:7 a=ffU4tdkgws8TGlptnfmohpskmOIA:4 a=d4CUUju0HPYA:10 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 24 Sep 2010 18:28:28 +0000 (UTC) diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index be35e69..8ddd2b6 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -319,7 +319,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, { unsigned int rval; unsigned long flags; - DEFINE_WAIT(the_wait); spin_lock_irqsave(&cam->dev_lock, flags); rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); @@ -334,28 +333,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, cafe_reg_write(cam, REG_TWSIC1, rval); spin_unlock_irqrestore(&cam->dev_lock, flags); + /* Unfortunately, reading TWSIC1 too soon after sending a command + * causes the device to die. + * Use a busy-wait because we often send a large quantity of small + * commands at-once; using msleep() would cause a lot of context + * switches which take longer than 2ms, resulting in a noticable + * boot-time and capture-start delays. + */ + mdelay(2); + /* - * Time to wait for the write to complete. THIS IS A RACY - * WAY TO DO IT, but the sad fact is that reading the TWSIC1 - * register too quickly after starting the operation sends - * the device into a place that may be kinder and better, but - * which is absolutely useless for controlling the sensor. In - * practice we have plenty of time to get into our sleep state - * before the interrupt hits, and the worst case is that we - * time out and then see that things completed, so this seems - * the best way for now. + * Another sad fact is that sometimes, commands silently complete but + * cafe_smbus_write_done() never becomes aware of this. + * This happens at random and appears to possible occur with any + * command. + * We don't understand why this is. We work around this issue + * with the timeout in the wait below, assuming that all commands + * complete within the timeout. */ - do { - prepare_to_wait(&cam->smbus_wait, &the_wait, - TASK_UNINTERRUPTIBLE); - schedule_timeout(1); /* even 1 jiffy is too long */ - finish_wait(&cam->smbus_wait, &the_wait); - } while (!cafe_smbus_write_done(cam)); - -#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), CAFE_SMBUS_TIMEOUT); -#endif + spin_lock_irqsave(&cam->dev_lock, flags); rval = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags);