diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-05-07 01:13:45 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-06-11 02:09:15 -0400 |
commit | 842c2953fc360f9661d7b8bdd90303d4c946f1ef (patch) | |
tree | 8cf394105cae140bf0c300c2f59db53c90a68098 | |
parent | febb84491751f67783ab7f14366492661ce94235 (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.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c | 23 |
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 | ||
62 | static int | 62 | static int |
63 | anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) | 63 | anx9805_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 | ||
71 | int | 71 | int |
72 | nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) | 72 | nv94_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 | ||
148 | out: | 153 | out: |
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 | ||
153 | void | 158 | void |