[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>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
a716e9d75f
commit
df2b9b0f9c
@@ -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,
|
|||||||
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
|
||||||
* Time to wait for the write to complete. THIS IS A RACY
|
* causes the device to die.
|
||||||
* WAY TO DO IT, but the sad fact is that reading the TWSIC1
|
* Use a busy-wait because we often send a large quantity of small
|
||||||
* register too quickly after starting the operation sends
|
* commands at-once; using msleep() would cause a lot of context
|
||||||
* the device into a place that may be kinder and better, but
|
* switches which take longer than 2ms, resulting in a noticable
|
||||||
* which is absolutely useless for controlling the sensor. In
|
* boot-time and capture-start delays.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
do {
|
mdelay(2);
|
||||||
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
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
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);
|
||||||
|
Reference in New Issue
Block a user