Skip to content

Commit 5d4c797

Browse files
AtsushiNemotowsakernel
authored andcommitted
i2c: altera: Fix race between xfer_msg and isr thread
Use a mutex to protect access to idev->msg_len, idev->buf, etc. which are modified by both altr_i2c_xfer_msg() and altr_i2c_isr(). This is the minimal fix for easy backporting. A cleanup to remove the spinlock will be added later. Signed-off-by: Atsushi Nemoto <[email protected]> Acked-by: Thor Thayer <[email protected]> [wsa: updated commit message] Signed-off-by: Wolfram Sang <[email protected]>
1 parent ab7cf7e commit 5d4c797

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

drivers/i2c/busses/i2c-altera.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
* @isr_mask: cached copy of local ISR enables.
7171
* @isr_status: cached copy of local ISR status.
7272
* @lock: spinlock for IRQ synchronization.
73+
* @isr_mutex: mutex for IRQ thread.
7374
*/
7475
struct altr_i2c_dev {
7576
void __iomem *base;
@@ -86,6 +87,7 @@ struct altr_i2c_dev {
8687
u32 isr_mask;
8788
u32 isr_status;
8889
spinlock_t lock; /* IRQ synchronization */
90+
struct mutex isr_mutex;
8991
};
9092

9193
static void
@@ -245,10 +247,11 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev)
245247
struct altr_i2c_dev *idev = _dev;
246248
u32 status = idev->isr_status;
247249

250+
mutex_lock(&idev->isr_mutex);
248251
if (!idev->msg) {
249252
dev_warn(idev->dev, "unexpected interrupt\n");
250253
altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
251-
return IRQ_HANDLED;
254+
goto out;
252255
}
253256
read = (idev->msg->flags & I2C_M_RD) != 0;
254257

@@ -301,6 +304,8 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev)
301304
complete(&idev->msg_complete);
302305
dev_dbg(idev->dev, "Message Complete\n");
303306
}
307+
out:
308+
mutex_unlock(&idev->isr_mutex);
304309

305310
return IRQ_HANDLED;
306311
}
@@ -312,6 +317,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
312317
u32 value;
313318
u8 addr = i2c_8bit_addr_from_msg(msg);
314319

320+
mutex_lock(&idev->isr_mutex);
315321
idev->msg = msg;
316322
idev->msg_len = msg->len;
317323
idev->buf = msg->buf;
@@ -336,6 +342,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
336342
altr_i2c_int_enable(idev, imask, true);
337343
altr_i2c_fill_tx_fifo(idev);
338344
}
345+
mutex_unlock(&idev->isr_mutex);
339346

340347
time_left = wait_for_completion_timeout(&idev->msg_complete,
341348
ALTR_I2C_XFER_TIMEOUT);
@@ -409,6 +416,7 @@ static int altr_i2c_probe(struct platform_device *pdev)
409416
idev->dev = &pdev->dev;
410417
init_completion(&idev->msg_complete);
411418
spin_lock_init(&idev->lock);
419+
mutex_init(&idev->isr_mutex);
412420

413421
ret = device_property_read_u32(idev->dev, "fifo-size",
414422
&idev->fifo_size);

0 commit comments

Comments
 (0)