aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFederico Vaga <federico.vaga@cern.ch>2019-02-14 03:51:30 -0500
committerWolfram Sang <wsa@the-dreams.de>2019-02-14 11:55:20 -0500
commite7663ef5ae0f02e3b902eb0305dec981333eb3e1 (patch)
treec2186d1e3285863a6e136daa472b4e58ce7b81c6 /drivers
parent0940d24912e9256fdf172f84c54ffd91680f05d0 (diff)
i2c: ocores: stop transfer on timeout
Detecting a timeout is ok, but we also need to assert a STOP command on the bus in order to prevent it from generating interrupts when there are no on going transfers. Example: very long transmission. 1. ocores_xfer: START a transfer 2. ocores_isr : handle byte by byte the transfer 3. ocores_xfer: goes in timeout [[bugfix here]] 4. ocores_xfer: return to I2C subsystem and to the I2C driver 5. I2C driver : it may clean up the i2c_msg memory 6. ocores_isr : receives another interrupt (pending bytes to be transferred) but the i2c_msg memory is invalid now So, since the transfer was too long, we have to detect the timeout and STOP the transfer. Another point is that we have a critical region here. When handling the timeout condition we may have a running IRQ handler. For this reason I introduce a spinlock. In order to make easier to understan locking I have: - added a new function to handle timeout - modified the current ocores_process() function in order to be protected by the new spinlock Like this it is obvious at first sight that this locking serializes the execution of ocores_process() and ocores_process_timeout() Signed-off-by: Federico Vaga <federico.vaga@cern.ch> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-ocores.c54
1 files changed, 45 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 87f9caacba85..aa852028d8c1 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -25,7 +25,12 @@
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/log2.h> 27#include <linux/log2.h>
28#include <linux/spinlock.h>
28 29
30/**
31 * @process_lock: protect I2C transfer process.
32 * ocores_process() and ocores_process_timeout() can't run in parallel.
33 */
29struct ocores_i2c { 34struct ocores_i2c {
30 void __iomem *base; 35 void __iomem *base;
31 u32 reg_shift; 36 u32 reg_shift;
@@ -36,6 +41,7 @@ struct ocores_i2c {
36 int pos; 41 int pos;
37 int nmsgs; 42 int nmsgs;
38 int state; /* see STATE_ */ 43 int state; /* see STATE_ */
44 spinlock_t process_lock;
39 struct clk *clk; 45 struct clk *clk;
40 int ip_clock_khz; 46 int ip_clock_khz;
41 int bus_clock_khz; 47 int bus_clock_khz;
@@ -141,19 +147,26 @@ static void ocores_process(struct ocores_i2c *i2c)
141{ 147{
142 struct i2c_msg *msg = i2c->msg; 148 struct i2c_msg *msg = i2c->msg;
143 u8 stat = oc_getreg(i2c, OCI2C_STATUS); 149 u8 stat = oc_getreg(i2c, OCI2C_STATUS);
150 unsigned long flags;
151
152 /*
153 * If we spin here is because we are in timeout, so we are going
154 * to be in STATE_ERROR. See ocores_process_timeout()
155 */
156 spin_lock_irqsave(&i2c->process_lock, flags);
144 157
145 if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { 158 if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
146 /* stop has been sent */ 159 /* stop has been sent */
147 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); 160 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
148 wake_up(&i2c->wait); 161 wake_up(&i2c->wait);
149 return; 162 goto out;
150 } 163 }
151 164
152 /* error? */ 165 /* error? */
153 if (stat & OCI2C_STAT_ARBLOST) { 166 if (stat & OCI2C_STAT_ARBLOST) {
154 i2c->state = STATE_ERROR; 167 i2c->state = STATE_ERROR;
155 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 168 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
156 return; 169 goto out;
157 } 170 }
158 171
159 if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { 172 if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
@@ -163,7 +176,7 @@ static void ocores_process(struct ocores_i2c *i2c)
163 if (stat & OCI2C_STAT_NACK) { 176 if (stat & OCI2C_STAT_NACK) {
164 i2c->state = STATE_ERROR; 177 i2c->state = STATE_ERROR;
165 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 178 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
166 return; 179 goto out;
167 } 180 }
168 } else 181 } else
169 msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); 182 msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
@@ -184,14 +197,14 @@ static void ocores_process(struct ocores_i2c *i2c)
184 197
185 oc_setreg(i2c, OCI2C_DATA, addr); 198 oc_setreg(i2c, OCI2C_DATA, addr);
186 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); 199 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
187 return; 200 goto out;
188 } else 201 } else
189 i2c->state = (msg->flags & I2C_M_RD) 202 i2c->state = (msg->flags & I2C_M_RD)
190 ? STATE_READ : STATE_WRITE; 203 ? STATE_READ : STATE_WRITE;
191 } else { 204 } else {
192 i2c->state = STATE_DONE; 205 i2c->state = STATE_DONE;
193 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); 206 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
194 return; 207 goto out;
195 } 208 }
196 } 209 }
197 210
@@ -202,6 +215,9 @@ static void ocores_process(struct ocores_i2c *i2c)
202 oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); 215 oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
203 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); 216 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
204 } 217 }
218
219out:
220 spin_unlock_irqrestore(&i2c->process_lock, flags);
205} 221}
206 222
207static irqreturn_t ocores_isr(int irq, void *dev_id) 223static irqreturn_t ocores_isr(int irq, void *dev_id)
@@ -213,9 +229,24 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
213 return IRQ_HANDLED; 229 return IRQ_HANDLED;
214} 230}
215 231
232/**
233 * Process timeout event
234 * @i2c: ocores I2C device instance
235 */
236static void ocores_process_timeout(struct ocores_i2c *i2c)
237{
238 unsigned long flags;
239
240 spin_lock_irqsave(&i2c->process_lock, flags);
241 i2c->state = STATE_ERROR;
242 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
243 spin_unlock_irqrestore(&i2c->process_lock, flags);
244}
245
216static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 246static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
217{ 247{
218 struct ocores_i2c *i2c = i2c_get_adapdata(adap); 248 struct ocores_i2c *i2c = i2c_get_adapdata(adap);
249 int ret;
219 250
220 i2c->msg = msgs; 251 i2c->msg = msgs;
221 i2c->pos = 0; 252 i2c->pos = 0;
@@ -225,11 +256,14 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
225 oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); 256 oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
226 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); 257 oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
227 258
228 if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || 259 ret = wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
229 (i2c->state == STATE_DONE), HZ)) 260 (i2c->state == STATE_DONE), HZ);
230 return (i2c->state == STATE_DONE) ? num : -EIO; 261 if (ret == 0) {
231 else 262 ocores_process_timeout(i2c);
232 return -ETIMEDOUT; 263 return -ETIMEDOUT;
264 }
265
266 return (i2c->state == STATE_DONE) ? num : -EIO;
233} 267}
234 268
235static int ocores_init(struct device *dev, struct ocores_i2c *i2c) 269static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
@@ -422,6 +456,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
422 if (!i2c) 456 if (!i2c)
423 return -ENOMEM; 457 return -ENOMEM;
424 458
459 spin_lock_init(&i2c->process_lock);
460
425 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 461 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
426 i2c->base = devm_ioremap_resource(&pdev->dev, res); 462 i2c->base = devm_ioremap_resource(&pdev->dev, res);
427 if (IS_ERR(i2c->base)) 463 if (IS_ERR(i2c->base))