Commit 842c2953 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/i2c: properly hand aux reply back to caller, and only retry on defer

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent febb8449
...@@ -33,7 +33,7 @@ struct nouveau_i2c_func { ...@@ -33,7 +33,7 @@ struct nouveau_i2c_func {
int (*sense_scl)(struct nouveau_i2c_port *); int (*sense_scl)(struct nouveau_i2c_port *);
int (*sense_sda)(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 (*pattern)(struct nouveau_i2c_port *, int pattern);
int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); 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); int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
......
...@@ -60,7 +60,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) ...@@ -60,7 +60,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
} }
static int 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 anx9805_i2c_port *chan = (void *)port;
struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
......
...@@ -30,7 +30,7 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) ...@@ -30,7 +30,7 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
if (port->func->aux) { if (port->func->aux) {
if (port->func->acquire) if (port->func->acquire)
port->func->acquire(port); 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; return -ENODEV;
} }
...@@ -41,7 +41,7 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) ...@@ -41,7 +41,7 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
if (port->func->aux) { if (port->func->aux) {
if (port->func->acquire) if (port->func->acquire)
port->func->acquire(port); 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; return -ENODEV;
} }
...@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (mcnt || remaining > 16) if (mcnt || remaining > 16)
cmd |= 4; /* MOT */ 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) if (ret < 0)
return ret; return ret;
......
...@@ -69,7 +69,8 @@ auxch_init(struct nouveau_i2c *aux, int ch) ...@@ -69,7 +69,8 @@ auxch_init(struct nouveau_i2c *aux, int ch)
} }
int 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 nouveau_i2c *aux = nouveau_i2c(base);
struct nv50_i2c_port *port = (void *)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) ...@@ -105,9 +106,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
ctrl |= size - 1; ctrl |= size - 1;
nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
/* retry transaction a number of times on failure... */ /* (maybe) retry transaction a number of times on failure... */
ret = -EREMOTEIO; for (retries = 0; !ret && retries < 32; retries++) {
for (retries = 0; retries < 32; retries++) {
/* reset, and delay a while if this is a retry */ /* reset, and delay a while if this is a retry */
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | 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) ...@@ -123,16 +123,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
udelay(1); udelay(1);
if (!timeout--) { if (!timeout--) {
AUX_ERR("tx req timeout 0x%08x\n", ctrl); AUX_ERR("tx req timeout 0x%08x\n", ctrl);
ret = -EIO;
goto out; goto out;
} }
} while (ctrl & 0x00010000); } while (ctrl & 0x00010000);
ret = 1;
/* read status, and check if transaction completed ok */ /* read status, and check if transaction completed ok */
stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
if (!(stat & 0x000f0f00)) { if ((stat & 0x000f0000) == 0x00080000 ||
ret = 0; (stat & 0x000f0000) == 0x00020000)
break; 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); 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) ...@@ -147,7 +152,7 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
out: out:
auxch_fini(aux, ch); auxch_fini(aux, ch);
return ret; return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
} }
void void
......
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