aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-07 01:13:45 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 02:09:15 -0400
commit842c2953fc360f9661d7b8bdd90303d4c946f1ef (patch)
tree8cf394105cae140bf0c300c2f59db53c90a68098
parentfebb84491751f67783ab7f14366492661ce94235 (diff)
drm/nouveau/i2c: properly hand aux reply back to caller, and only retry on defer
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/i2c.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c23
4 files changed, 20 insertions, 14 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
index 7f50a858b16f..05f4453fd752 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
@@ -33,7 +33,7 @@ struct nouveau_i2c_func {
33 int (*sense_scl)(struct nouveau_i2c_port *); 33 int (*sense_scl)(struct nouveau_i2c_port *);
34 int (*sense_sda)(struct nouveau_i2c_port *); 34 int (*sense_sda)(struct nouveau_i2c_port *);
35 35
36 int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); 36 int (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
37 int (*pattern)(struct nouveau_i2c_port *, int pattern); 37 int (*pattern)(struct nouveau_i2c_port *, int pattern);
38 int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); 38 int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
39 int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); 39 int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
index 4b195ac4da66..29a5a7fe5c2b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
@@ -60,7 +60,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
60} 60}
61 61
62static int 62static int
63anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) 63anx9805_aux(struct nouveau_i2c_port *port, bool retry,
64 u8 type, u32 addr, u8 *data, u8 size)
64{ 65{
65 struct anx9805_i2c_port *chan = (void *)port; 66 struct anx9805_i2c_port *chan = (void *)port;
66 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; 67 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
index 5de074ad170b..73d027b281f2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
@@ -30,7 +30,7 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
30 if (port->func->aux) { 30 if (port->func->aux) {
31 if (port->func->acquire) 31 if (port->func->acquire)
32 port->func->acquire(port); 32 port->func->acquire(port);
33 return port->func->aux(port, 9, addr, data, size); 33 return port->func->aux(port, true, 9, addr, data, size);
34 } 34 }
35 return -ENODEV; 35 return -ENODEV;
36} 36}
@@ -41,7 +41,7 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
41 if (port->func->aux) { 41 if (port->func->aux) {
42 if (port->func->acquire) 42 if (port->func->acquire)
43 port->func->acquire(port); 43 port->func->acquire(port);
44 return port->func->aux(port, 8, addr, data, size); 44 return port->func->aux(port, true, 8, addr, data, size);
45 } 45 }
46 return -ENODEV; 46 return -ENODEV;
47} 47}
@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
74 if (mcnt || remaining > 16) 74 if (mcnt || remaining > 16)
75 cmd |= 4; /* MOT */ 75 cmd |= 4; /* MOT */
76 76
77 ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); 77 ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
78 if (ret < 0) 78 if (ret < 0)
79 return ret; 79 return ret;
80 80
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
index df6d3e4b68be..d790ef165f92 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
@@ -69,7 +69,8 @@ auxch_init(struct nouveau_i2c *aux, int ch)
69} 69}
70 70
71int 71int
72nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) 72nv94_aux(struct nouveau_i2c_port *base, bool retry,
73 u8 type, u32 addr, u8 *data, u8 size)
73{ 74{
74 struct nouveau_i2c *aux = nouveau_i2c(base); 75 struct nouveau_i2c *aux = nouveau_i2c(base);
75 struct nv50_i2c_port *port = (void *)base; 76 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 ctrl |= size - 1; 106 ctrl |= size - 1;
106 nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); 107 nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
107 108
108 /* retry transaction a number of times on failure... */ 109 /* (maybe) retry transaction a number of times on failure... */
109 ret = -EREMOTEIO; 110 for (retries = 0; !ret && retries < 32; retries++) {
110 for (retries = 0; retries < 32; retries++) {
111 /* reset, and delay a while if this is a retry */ 111 /* reset, and delay a while if this is a retry */
112 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); 112 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
113 nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); 113 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 udelay(1); 123 udelay(1);
124 if (!timeout--) { 124 if (!timeout--) {
125 AUX_ERR("tx req timeout 0x%08x\n", ctrl); 125 AUX_ERR("tx req timeout 0x%08x\n", ctrl);
126 ret = -EIO;
126 goto out; 127 goto out;
127 } 128 }
128 } while (ctrl & 0x00010000); 129 } while (ctrl & 0x00010000);
130 ret = 1;
129 131
130 /* read status, and check if transaction completed ok */ 132 /* read status, and check if transaction completed ok */
131 stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); 133 stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
132 if (!(stat & 0x000f0f00)) { 134 if ((stat & 0x000f0000) == 0x00080000 ||
133 ret = 0; 135 (stat & 0x000f0000) == 0x00020000)
134 break; 136 ret = retry ? 0 : 1;
135 } 137 if ((stat & 0x00000100))
138 ret = -ETIMEDOUT;
139 if ((stat & 0x00000e00))
140 ret = -EIO;
136 141
137 AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); 142 AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
138 } 143 }
@@ -147,7 +152,7 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
147 152
148out: 153out:
149 auxch_fini(aux, ch); 154 auxch_fini(aux, ch);
150 return ret; 155 return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
151} 156}
152 157
153void 158void