lkml.org 
[lkml]   [2020]   [May]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.14 03/13] i2c: altera: Fix race between xfer_msg and isr thread
    Date
    From: Atsushi Nemoto <atsushi.nemoto@sord.co.jp>

    [ Upstream commit 5d4c7977499a736f3f80826bdc9744344ad55589 ]

    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 <atsushi.nemoto@sord.co.jp>
    Acked-by: Thor Thayer <thor.thayer@linux.intel.com>
    [wsa: updated commit message]
    Signed-off-by: Wolfram Sang <wsa@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/i2c/busses/i2c-altera.c | 10 +++++++++-
    1 file changed, 9 insertions(+), 1 deletion(-)

    diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c
    index 8915ee30a5b4..1d59eede537b 100644
    --- a/drivers/i2c/busses/i2c-altera.c
    +++ b/drivers/i2c/busses/i2c-altera.c
    @@ -81,6 +81,7 @@
    * @isr_mask: cached copy of local ISR enables.
    * @isr_status: cached copy of local ISR status.
    * @lock: spinlock for IRQ synchronization.
    + * @isr_mutex: mutex for IRQ thread.
    */
    struct altr_i2c_dev {
    void __iomem *base;
    @@ -97,6 +98,7 @@ struct altr_i2c_dev {
    u32 isr_mask;
    u32 isr_status;
    spinlock_t lock; /* IRQ synchronization */
    + struct mutex isr_mutex;
    };

    static void
    @@ -256,10 +258,11 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev)
    struct altr_i2c_dev *idev = _dev;
    u32 status = idev->isr_status;

    + mutex_lock(&idev->isr_mutex);
    if (!idev->msg) {
    dev_warn(idev->dev, "unexpected interrupt\n");
    altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
    - return IRQ_HANDLED;
    + goto out;
    }
    read = (idev->msg->flags & I2C_M_RD) != 0;

    @@ -312,6 +315,8 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev)
    complete(&idev->msg_complete);
    dev_dbg(idev->dev, "Message Complete\n");
    }
    +out:
    + mutex_unlock(&idev->isr_mutex);

    return IRQ_HANDLED;
    }
    @@ -323,6 +328,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
    u32 value;
    u8 addr = i2c_8bit_addr_from_msg(msg);

    + mutex_lock(&idev->isr_mutex);
    idev->msg = msg;
    idev->msg_len = msg->len;
    idev->buf = msg->buf;
    @@ -347,6 +353,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
    altr_i2c_int_enable(idev, imask, true);
    altr_i2c_fill_tx_fifo(idev);
    }
    + mutex_unlock(&idev->isr_mutex);

    time_left = wait_for_completion_timeout(&idev->msg_complete,
    ALTR_I2C_XFER_TIMEOUT);
    @@ -420,6 +427,7 @@ static int altr_i2c_probe(struct platform_device *pdev)
    idev->dev = &pdev->dev;
    init_completion(&idev->msg_complete);
    spin_lock_init(&idev->lock);
    + mutex_init(&idev->isr_mutex);

    ret = device_property_read_u32(idev->dev, "fifo-size",
    &idev->fifo_size);
    --
    2.25.1
    \
     
     \ /
      Last update: 2020-05-28 14:03    [W:2.325 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site