Commit df2b9b0f authored by Daniel Drake's avatar Daniel Drake Committed by Mauro Carvalho Chehab

[media] cafe_ccic: Fix hang in command write processing

This patch, which basically reverts 6d77444a, 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: default avatarDaniel Drake <dsd@laptop.org>
Acked-by: default avatarJonathan Corbet <corbet@lwn.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a716e9d7
...@@ -363,7 +363,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, ...@@ -363,7 +363,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
{ {
unsigned int rval; unsigned int rval;
unsigned long flags; unsigned long flags;
DEFINE_WAIT(the_wait);
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
...@@ -378,28 +377,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, ...@@ -378,28 +377,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
cafe_reg_write(cam, REG_TWSIC1, rval); cafe_reg_write(cam, REG_TWSIC1, rval);
spin_unlock_irqrestore(&cam->dev_lock, flags); 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 * Another sad fact is that sometimes, commands silently complete but
* WAY TO DO IT, but the sad fact is that reading the TWSIC1 * cafe_smbus_write_done() never becomes aware of this.
* register too quickly after starting the operation sends * This happens at random and appears to possible occur with any
* the device into a place that may be kinder and better, but * command.
* which is absolutely useless for controlling the sensor. In * We don't understand why this is. We work around this issue
* practice we have plenty of time to get into our sleep state * with the timeout in the wait below, assuming that all commands
* before the interrupt hits, and the worst case is that we * complete within the timeout.
* time out and then see that things completed, so this seems
* the best way for now.
*/ */
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), wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
CAFE_SMBUS_TIMEOUT); CAFE_SMBUS_TIMEOUT);
#endif
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
rval = cafe_reg_read(cam, REG_TWSIC1); rval = cafe_reg_read(cam, REG_TWSIC1);
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment