xfer_read() waits for the HDMI I2C transaction to reach
I2C_TRANSACTION_DONE, but it ignores both timeout and signal returns from
wait_for_completion_interruptible_timeout().  If the interrupt never
advances the transaction state, the loop can wait forever.

Return -ETIMEDOUT when the completion wait expires, propagate interrupted
waits, and make the I2C master_xfer callback return the first transfer
error instead of reporting a successful message count.

Signed-off-by: Pengpeng Hou <[email protected]>
---
 drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c 
b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
index 2a7916ca5..a780643f2 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
@@ -98,6 +98,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg 
*pmsg)
        struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
        struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
        u32 temp;
+       int ret;
 
        i2c_dev->status = I2C_STAT_INIT;
        i2c_dev->msg = pmsg;
@@ -109,9 +110,14 @@ static int xfer_read(struct i2c_adapter *adap, struct 
i2c_msg *pmsg)
        HDMI_WRITE(HDMI_HI2CHCR, temp);
        HDMI_READ(HDMI_HI2CHCR);
 
-       while (i2c_dev->status != I2C_TRANSACTION_DONE)
-               wait_for_completion_interruptible_timeout(&i2c_dev->complete,
+       while (i2c_dev->status != I2C_TRANSACTION_DONE) {
+               ret = 
wait_for_completion_interruptible_timeout(&i2c_dev->complete,
                                                                10 * HZ);
+               if (ret < 0)
+                       return ret;
+               if (!ret)
+                       return -ETIMEDOUT;
+       }
 
        return 0;
 }
@@ -130,7 +136,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter 
*adap,
 {
        struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
        struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
-       int i;
+       int i, ret = 0;
 
        mutex_lock(&i2c_dev->i2c_lock);
 
@@ -142,9 +148,11 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter 
*adap,
        for (i = 0; i < num; i++) {
                if (pmsg->len && pmsg->buf) {
                        if (pmsg->flags & I2C_M_RD)
-                               xfer_read(adap, pmsg);
+                               ret = xfer_read(adap, pmsg);
                        else
-                               xfer_write(adap, pmsg);
+                               ret = xfer_write(adap, pmsg);
+                       if (ret)
+                               break;
                }
                pmsg++;         /* next message */
        }
@@ -154,6 +162,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter 
*adap,
 
        mutex_unlock(&i2c_dev->i2c_lock);
 
+       if (ret)
+               return ret;
+
        return i;
 }
 
-- 
2.50.1 (Apple Git-155)

Reply via email to