summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cafe_ccic.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2010-09-24 19:17:17 +0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 05:17:04 +0200
commitdf2b9b0f9c02689ce3b3f0b5dbc6c9b272bbe1ab (patch)
treecb36b0bd7fde50dd3042bfe38d58a118790dc69d /drivers/media/video/cafe_ccic.c
parent[media] go7007: MJPEG buffer overflow (diff)
downloadlinux-df2b9b0f9c02689ce3b3f0b5dbc6c9b272bbe1ab.tar.xz
linux-df2b9b0f9c02689ce3b3f0b5dbc6c9b272bbe1ab.zip
[media] cafe_ccic: Fix hang in command write processing
This patch, which basically reverts 6d77444ac, fixes an occasional on-boot or on-capture hang on the XO-1 laptop. It seems like the cafe hardware is flakier than we thought and that in some cases, the commands get executed but are never reported as completed (even if we substantially increase the delays before reading registers). Reintroduce the 1-second CAFE_SMBUS_TIMEOUT to catch and avoid this strange hardware bug. Signed-off-by: Daniel Drake <dsd@laptop.org> Acked-by: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cafe_ccic.c')
-rw-r--r--drivers/media/video/cafe_ccic.c36
1 files changed, 17 insertions, 19 deletions
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 2ffb6df955b3..05d810ad454a 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -363,7 +363,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);
@@ -378,28 +377,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);