diff options
author | Troy Kisky <troy.kisky@boundarydevices.com> | 2008-07-14 16:38:21 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-07-14 16:38:21 -0400 |
commit | 5a0d5f5ffa5d294d895ef54fc220c6182db63998 (patch) | |
tree | 6839d7a2dcb7beac8c9163a23c0afc2728fed8fa /drivers/i2c/busses/i2c-davinci.c | |
parent | 0ab56e20674b41dd0203d16b602aac8d9d26a70a (diff) |
i2c-davinci: Fix signal handling bug
If wait_for_completion_interruptible_timeout exits due
to a signal, the i2c bus was locking up.
Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-davinci.c')
-rw-r--r-- | drivers/i2c/busses/i2c-davinci.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c56f8fe4efe5..160857296952 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c | |||
@@ -85,6 +85,7 @@ | |||
85 | #define DAVINCI_I2C_MDR_MST (1 << 10) | 85 | #define DAVINCI_I2C_MDR_MST (1 << 10) |
86 | #define DAVINCI_I2C_MDR_TRX (1 << 9) | 86 | #define DAVINCI_I2C_MDR_TRX (1 << 9) |
87 | #define DAVINCI_I2C_MDR_XA (1 << 8) | 87 | #define DAVINCI_I2C_MDR_XA (1 << 8) |
88 | #define DAVINCI_I2C_MDR_RM (1 << 7) | ||
88 | #define DAVINCI_I2C_MDR_IRS (1 << 5) | 89 | #define DAVINCI_I2C_MDR_IRS (1 << 5) |
89 | 90 | ||
90 | #define DAVINCI_I2C_IMR_AAS (1 << 6) | 91 | #define DAVINCI_I2C_IMR_AAS (1 << 6) |
@@ -112,6 +113,7 @@ struct davinci_i2c_dev { | |||
112 | u8 *buf; | 113 | u8 *buf; |
113 | size_t buf_len; | 114 | size_t buf_len; |
114 | int irq; | 115 | int irq; |
116 | u8 terminate; | ||
115 | struct i2c_adapter adapter; | 117 | struct i2c_adapter adapter; |
116 | }; | 118 | }; |
117 | 119 | ||
@@ -283,20 +285,34 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) | |||
283 | MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1); | 285 | MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1); |
284 | davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); | 286 | davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); |
285 | 287 | ||
288 | dev->terminate = 0; | ||
286 | /* write the data into mode register */ | 289 | /* write the data into mode register */ |
287 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); | 290 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); |
288 | 291 | ||
289 | r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, | 292 | r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, |
290 | DAVINCI_I2C_TIMEOUT); | 293 | DAVINCI_I2C_TIMEOUT); |
291 | dev->buf_len = 0; | ||
292 | if (r < 0) | ||
293 | return r; | ||
294 | |||
295 | if (r == 0) { | 294 | if (r == 0) { |
296 | dev_err(dev->dev, "controller timed out\n"); | 295 | dev_err(dev->dev, "controller timed out\n"); |
297 | i2c_davinci_init(dev); | 296 | i2c_davinci_init(dev); |
297 | dev->buf_len = 0; | ||
298 | return -ETIMEDOUT; | 298 | return -ETIMEDOUT; |
299 | } | 299 | } |
300 | if (dev->buf_len) { | ||
301 | /* This should be 0 if all bytes were transferred | ||
302 | * or dev->cmd_err denotes an error. | ||
303 | * A signal may have aborted the transfer. | ||
304 | */ | ||
305 | if (r >= 0) { | ||
306 | dev_err(dev->dev, "abnormal termination buf_len=%i\n", | ||
307 | dev->buf_len); | ||
308 | r = -EREMOTEIO; | ||
309 | } | ||
310 | dev->terminate = 1; | ||
311 | wmb(); | ||
312 | dev->buf_len = 0; | ||
313 | } | ||
314 | if (r < 0) | ||
315 | return r; | ||
300 | 316 | ||
301 | /* no error */ | 317 | /* no error */ |
302 | if (likely(!dev->cmd_err)) | 318 | if (likely(!dev->cmd_err)) |
@@ -354,6 +370,27 @@ static u32 i2c_davinci_func(struct i2c_adapter *adap) | |||
354 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); | 370 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); |
355 | } | 371 | } |
356 | 372 | ||
373 | static void terminate_read(struct davinci_i2c_dev *dev) | ||
374 | { | ||
375 | u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); | ||
376 | w |= DAVINCI_I2C_MDR_NACK; | ||
377 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); | ||
378 | |||
379 | /* Throw away data */ | ||
380 | davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG); | ||
381 | if (!dev->terminate) | ||
382 | dev_err(dev->dev, "RDR IRQ while no data requested\n"); | ||
383 | } | ||
384 | static void terminate_write(struct davinci_i2c_dev *dev) | ||
385 | { | ||
386 | u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); | ||
387 | w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP; | ||
388 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); | ||
389 | |||
390 | if (!dev->terminate) | ||
391 | dev_err(dev->dev, "TDR IRQ while no data to send\n"); | ||
392 | } | ||
393 | |||
357 | /* | 394 | /* |
358 | * Interrupt service routine. This gets called whenever an I2C interrupt | 395 | * Interrupt service routine. This gets called whenever an I2C interrupt |
359 | * occurs. | 396 | * occurs. |
@@ -374,12 +411,15 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) | |||
374 | 411 | ||
375 | switch (stat) { | 412 | switch (stat) { |
376 | case DAVINCI_I2C_IVR_AL: | 413 | case DAVINCI_I2C_IVR_AL: |
414 | /* Arbitration lost, must retry */ | ||
377 | dev->cmd_err |= DAVINCI_I2C_STR_AL; | 415 | dev->cmd_err |= DAVINCI_I2C_STR_AL; |
416 | dev->buf_len = 0; | ||
378 | complete(&dev->cmd_complete); | 417 | complete(&dev->cmd_complete); |
379 | break; | 418 | break; |
380 | 419 | ||
381 | case DAVINCI_I2C_IVR_NACK: | 420 | case DAVINCI_I2C_IVR_NACK: |
382 | dev->cmd_err |= DAVINCI_I2C_STR_NACK; | 421 | dev->cmd_err |= DAVINCI_I2C_STR_NACK; |
422 | dev->buf_len = 0; | ||
383 | complete(&dev->cmd_complete); | 423 | complete(&dev->cmd_complete); |
384 | break; | 424 | break; |
385 | 425 | ||
@@ -401,9 +441,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) | |||
401 | davinci_i2c_write_reg(dev, | 441 | davinci_i2c_write_reg(dev, |
402 | DAVINCI_I2C_STR_REG, | 442 | DAVINCI_I2C_STR_REG, |
403 | DAVINCI_I2C_IMR_RRDY); | 443 | DAVINCI_I2C_IMR_RRDY); |
404 | } else | 444 | } else { |
405 | dev_err(dev->dev, "RDR IRQ while no " | 445 | /* signal can terminate transfer */ |
406 | "data requested\n"); | 446 | terminate_read(dev); |
447 | } | ||
407 | break; | 448 | break; |
408 | 449 | ||
409 | case DAVINCI_I2C_IVR_XRDY: | 450 | case DAVINCI_I2C_IVR_XRDY: |
@@ -420,9 +461,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) | |||
420 | davinci_i2c_write_reg(dev, | 461 | davinci_i2c_write_reg(dev, |
421 | DAVINCI_I2C_IMR_REG, | 462 | DAVINCI_I2C_IMR_REG, |
422 | w); | 463 | w); |
423 | } else | 464 | } else { |
424 | dev_err(dev->dev, "TDR IRQ while no data to " | 465 | /* signal can terminate transfer */ |
425 | "send\n"); | 466 | terminate_write(dev); |
467 | } | ||
426 | break; | 468 | break; |
427 | 469 | ||
428 | case DAVINCI_I2C_IVR_SCD: | 470 | case DAVINCI_I2C_IVR_SCD: |