drm/nouveau/i2c: properly hand aux reply back to caller, and only retry on defer
authorBen Skeggs <bskeggs@redhat.com>
Wed, 7 May 2014 05:13:45 +0000 (15:13 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 11 Jun 2014 06:09:15 +0000 (16:09 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c

index 7f50a858b16f68395a3fe0b84c5bd9f275e8849f..05f4453fd752838adcde844357045ef7577de0cd 100644 (file)
@@ -33,7 +33,7 @@ struct nouveau_i2c_func {
        int  (*sense_scl)(struct nouveau_i2c_port *);
        int  (*sense_sda)(struct nouveau_i2c_port *);
 
-       int  (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8);
+       int  (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
        int  (*pattern)(struct nouveau_i2c_port *, int pattern);
        int  (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
        int  (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
index 4b195ac4da6609dc2be937415822d5bf33ad1b35..29a5a7fe5c2b5d5e9103f1836e55b5d5aa92d49c 100644 (file)
@@ -60,7 +60,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
 }
 
 static int
-anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
+anx9805_aux(struct nouveau_i2c_port *port, bool retry,
+           u8 type, u32 addr, u8 *data, u8 size)
 {
        struct anx9805_i2c_port *chan = (void *)port;
        struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
index 5de074ad170b42ae37722ba8975018428b59a485..73d027b281f2d520996ff53f4149c59573174fd5 100644 (file)
@@ -30,7 +30,7 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
        if (port->func->aux) {
                if (port->func->acquire)
                        port->func->acquire(port);
-               return port->func->aux(port, 9, addr, data, size);
+               return port->func->aux(port, true, 9, addr, data, size);
        }
        return -ENODEV;
 }
@@ -41,7 +41,7 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
        if (port->func->aux) {
                if (port->func->acquire)
                        port->func->acquire(port);
-               return port->func->aux(port, 8, addr, data, size);
+               return port->func->aux(port, true, 8, addr, data, size);
        }
        return -ENODEV;
 }
@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        if (mcnt || remaining > 16)
                                cmd |= 4; /* MOT */
 
-                       ret = port->func->aux(port, cmd, msg->addr, ptr, cnt);
+                       ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
                        if (ret < 0)
                                return ret;
 
index df6d3e4b68bef1c5975f47f42cd1d6caa35a9b4d..d790ef165f922fa571aad7c94328afe1ea2d81d8 100644 (file)
@@ -69,7 +69,8 @@ auxch_init(struct nouveau_i2c *aux, int ch)
 }
 
 int
-nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
+nv94_aux(struct nouveau_i2c_port *base, bool retry,
+        u8 type, u32 addr, u8 *data, u8 size)
 {
        struct nouveau_i2c *aux = nouveau_i2c(base);
        struct nv50_i2c_port *port = (void *)base;
@@ -105,9 +106,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
        ctrl |= size - 1;
        nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
 
-       /* retry transaction a number of times on failure... */
-       ret = -EREMOTEIO;
-       for (retries = 0; retries < 32; retries++) {
+       /* (maybe) retry transaction a number of times on failure... */
+       for (retries = 0; !ret && retries < 32; retries++) {
                /* reset, and delay a while if this is a retry */
                nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
                nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
@@ -123,16 +123,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
                        udelay(1);
                        if (!timeout--) {
                                AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+                               ret = -EIO;
                                goto out;
                        }
                } while (ctrl & 0x00010000);
+               ret = 1;
 
                /* read status, and check if transaction completed ok */
                stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
-               if (!(stat & 0x000f0f00)) {
-                       ret = 0;
-                       break;
-               }
+               if ((stat & 0x000f0000) == 0x00080000 ||
+                   (stat & 0x000f0000) == 0x00020000)
+                       ret = retry ? 0 : 1;
+               if ((stat & 0x00000100))
+                       ret = -ETIMEDOUT;
+               if ((stat & 0x00000e00))
+                       ret = -EIO;
 
                AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
        }
@@ -147,7 +152,7 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
 
 out:
        auxch_fini(aux, ch);
-       return ret;
+       return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
 }
 
 void