[PATCHv4] i2c: cadence: Fix the driver in interrupt flurry case
diff mbox series

Message ID 1551069922-15896-1-git-send-email-shubhrajyoti.datta@gmail.com
State Under Review
Headers show
Series
  • [PATCHv4] i2c: cadence: Fix the driver in interrupt flurry case
Related show

Commit Message

Shubhrajyoti Datta Feb. 25, 2019, 4:45 a.m. UTC
From: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>

In case there are a lot of interrupts then the hold bit is not
released. Protect the code by making it atomic by disabling interrupts.

Fixes: df8eb5691c4 ("i2c: Add driver for Cadence I2C controller")
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
---
v2: Update the wording
v3: Add fixes tag
v4: update fixes tag

 drivers/i2c/busses/i2c-cadence.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Michal Simek Feb. 25, 2019, 6:56 a.m. UTC | #1
On 25. 02. 19 5:45, shubhrajyoti.datta@gmail.com wrote:
> From: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> 
> In case there are a lot of interrupts then the hold bit is not
> released. Protect the code by making it atomic by disabling interrupts.
> 
> Fixes: df8eb5691c4 ("i2c: Add driver for Cadence I2C controller")
> Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> ---
> v2: Update the wording
> v3: Add fixes tag
> v4: update fixes tag
> 
>  drivers/i2c/busses/i2c-cadence.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
> index b136057..92829be 100644
> --- a/drivers/i2c/busses/i2c-cadence.c
> +++ b/drivers/i2c/busses/i2c-cadence.c
> @@ -365,6 +365,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
>  {
>  	unsigned int ctrl_reg;
>  	unsigned int isr_status;
> +	unsigned long flags;
>  
>  	id->p_recv_buf = id->p_msg->buf;
>  	id->recv_count = id->p_msg->len;
> @@ -405,6 +406,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
>  		cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
>  	}
>  
> +	local_irq_save(flags);
>  	/* Set the slave address in address register - triggers operation */
>  	cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
>  						CDNS_I2C_ADDR_OFFSET);
> @@ -413,6 +415,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
>  		((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
>  		(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
>  			cdns_i2c_clear_bus_hold(id);
> +	local_irq_restore(flags);
>  	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
>  }
>  
> 

Acked-by: Michal Simek <michal.simek@xilinx.com>

M
Wolfram Sang March 9, 2019, 9:52 a.m. UTC | #2
On Mon, Feb 25, 2019 at 07:56:28AM +0100, Michal Simek wrote:
> On 25. 02. 19 5:45, shubhrajyoti.datta@gmail.com wrote:
> > From: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> > 
> > In case there are a lot of interrupts then the hold bit is not
> > released. Protect the code by making it atomic by disabling interrupts.
> > 
> > Fixes: df8eb5691c4 ("i2c: Add driver for Cadence I2C controller")
> > Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> > ---
> > v2: Update the wording
> > v3: Add fixes tag
> > v4: update fixes tag
> > 
> >  drivers/i2c/busses/i2c-cadence.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
> > index b136057..92829be 100644
> > --- a/drivers/i2c/busses/i2c-cadence.c
> > +++ b/drivers/i2c/busses/i2c-cadence.c
> > @@ -365,6 +365,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> >  {
> >  	unsigned int ctrl_reg;
> >  	unsigned int isr_status;
> > +	unsigned long flags;
> >  
> >  	id->p_recv_buf = id->p_msg->buf;
> >  	id->recv_count = id->p_msg->len;
> > @@ -405,6 +406,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> >  		cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
> >  	}
> >  
> > +	local_irq_save(flags);
> >  	/* Set the slave address in address register - triggers operation */
> >  	cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
> >  						CDNS_I2C_ADDR_OFFSET);
> > @@ -413,6 +415,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> >  		((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
> >  		(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
> >  			cdns_i2c_clear_bus_hold(id);
> > +	local_irq_restore(flags);
> >  	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> >  }
> >  
> > 
> 
> Acked-by: Michal Simek <michal.simek@xilinx.com>

What if another CPU core processes the interrupt handler?
Shubhrajyoti Datta March 14, 2019, 8:57 a.m. UTC | #3
> > >     /* Set the slave address in address register - triggers operation */
> > >     cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
> > >                                             CDNS_I2C_ADDR_OFFSET);
> > > @@ -413,6 +415,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> > >             ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
> > >             (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
> > >                     cdns_i2c_clear_bus_hold(id);
> > > +   local_irq_restore(flags);
> > >     cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> > >  }
> > >
> > >
> >
> > Acked-by: Michal Simek <michal.simek@xilinx.com>
>
> What if another CPU core processes the interrupt handler?
>
The issue is that  due to  non i2c interrupts the  clear is not
released and the timeout is reached.
If those interrupts are serviced on the other core should  not be an issue.
Wolfram Sang March 14, 2019, 9:06 a.m. UTC | #4
> > What if another CPU core processes the interrupt handler?
> >
> The issue is that  due to  non i2c interrupts the  clear is not
> released and the timeout is reached.
> If those interrupts are serviced on the other core should  not be an issue.

Makes sense. Can you add a comment describing this to the patch?

Patch
diff mbox series

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index b136057..92829be 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -365,6 +365,7 @@  static void cdns_i2c_mrecv(struct cdns_i2c *id)
 {
 	unsigned int ctrl_reg;
 	unsigned int isr_status;
+	unsigned long flags;
 
 	id->p_recv_buf = id->p_msg->buf;
 	id->recv_count = id->p_msg->len;
@@ -405,6 +406,7 @@  static void cdns_i2c_mrecv(struct cdns_i2c *id)
 		cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
 	}
 
+	local_irq_save(flags);
 	/* Set the slave address in address register - triggers operation */
 	cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
 						CDNS_I2C_ADDR_OFFSET);
@@ -413,6 +415,7 @@  static void cdns_i2c_mrecv(struct cdns_i2c *id)
 		((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
 		(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
 			cdns_i2c_clear_bus_hold(id);
+	local_irq_restore(flags);
 	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
 }