diff mbox

[1/2] i2c: qup: Cleared the error bits in ISR

Message ID 1462797871-8595-2-git-send-email-absahu@codeaurora.org
State Accepted
Headers show

Commit Message

Abhishek Sahu May 9, 2016, 12:44 p.m. UTC
1. Current QCOM I2C driver hangs when sending data to address 0x03-0x07
in some scenarios. The QUP controller generates invalid write in this
case, since these addresses are reserved for different bus formats.

2. Also, the error handling is done by I2C QUP ISR in the case of DMA
mode. The state need to be RESET in case of any error for clearing the
available data in FIFO, which otherwise leaves the BAM DMA controller
in hang state.

This patch fixes the above two issues by clearing the error bits from
I2C and QUP status in ISR in case of I2C error, QUP error and resets
the QUP state to clear the FIFO data.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

Comments

Sricharan Ramabadhran May 11, 2016, 3:57 p.m. UTC | #1
Hi,

> 1. Current QCOM I2C driver hangs when sending data to address 0x03-0x07
> in some scenarios. The QUP controller generates invalid write in this
case,
> since these addresses are reserved for different bus formats.
> 
> 2. Also, the error handling is done by I2C QUP ISR in the case of DMA
mode.
> The state need to be RESET in case of any error for clearing the available
> data in FIFO, which otherwise leaves the BAM DMA controller in hang state.
> 
> This patch fixes the above two issues by clearing the error bits from I2C
and
> QUP status in ISR in case of I2C error, QUP error and resets the QUP state
to
> clear the FIFO data.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index
> 23eaabb..8c2f1bc 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, void
> *dev)
>  	bus_err &= I2C_STATUS_ERROR_MASK;
>  	qup_err &= QUP_STATUS_ERROR_FLAGS;
> 
> -	if (qup_err) {
> -		/* Clear Error interrupt */
> +	/* Clear the error bits in QUP_ERROR_FLAGS */
> +	if (qup_err)
>  		writel(qup_err, qup->base + QUP_ERROR_FLAGS);
> -		goto done;
> -	}
> 
> -	if (bus_err) {
> -		/* Clear Error interrupt */
> +	/* Clear the error bits in QUP_I2C_STATUS */
> +	if (bus_err)
> +		writel(bus_err, qup->base + QUP_I2C_STATUS);
> +
> +	/* Reset the QUP State in case of error */
> +	if (qup_err || bus_err) {
>  		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
>  		goto done;
>  	}
       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the end,
when
       there is no error. So would it be fine if we do it there
unconditionally ?

Regards,
 Sricharan



--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Abhishek Sahu May 11, 2016, 5:34 p.m. UTC | #2
On 2016-05-11 21:27, Sricharan wrote:
> Hi,
> 
>> 1. Current QCOM I2C driver hangs when sending data to address 
>> 0x03-0x07
>> in some scenarios. The QUP controller generates invalid write in this
>> case,
>> since these addresses are reserved for different bus formats.
>> 
>> 2. Also, the error handling is done by I2C QUP ISR in the case of DMA
>> mode.
>> The state need to be RESET in case of any error for clearing the 
>> available
>> data in FIFO, which otherwise leaves the BAM DMA controller in hang 
>> state.
>> 
>> This patch fixes the above two issues by clearing the error bits from 
>> I2C
>> and
>> QUP status in ISR in case of I2C error, QUP error and resets the QUP 
>> state
>> to
>> clear the FIFO data.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 14 ++++++++------
>>  1 file changed, 8 insertions(+), 6 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index
>> 23eaabb..8c2f1bc 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, 
>> void
>> *dev)
>>  	bus_err &= I2C_STATUS_ERROR_MASK;
>>  	qup_err &= QUP_STATUS_ERROR_FLAGS;
>> 
>> -	if (qup_err) {
>> -		/* Clear Error interrupt */
>> +	/* Clear the error bits in QUP_ERROR_FLAGS */
>> +	if (qup_err)
>>  		writel(qup_err, qup->base + QUP_ERROR_FLAGS);
>> -		goto done;
>> -	}
>> 
>> -	if (bus_err) {
>> -		/* Clear Error interrupt */
>> +	/* Clear the error bits in QUP_I2C_STATUS */
>> +	if (bus_err)
>> +		writel(bus_err, qup->base + QUP_I2C_STATUS);
>> +
>> +	/* Reset the QUP State in case of error */
>> +	if (qup_err || bus_err) {
>>  		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
>>  		goto done;
>>  	}
>        In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the 
> end, when
>        there is no error. So would it be fine if we do it there 
> unconditionally ?
> 
> Regards,
>  Sricharan

RESET the QUP state wouldn't create any issue in the case of multiple 
calls.
The existing code also RESET the QUP state for bus_err but it is not 
clearing
status bits.
Sricharan Ramabadhran May 12, 2016, 2:28 a.m. UTC | #3
Hi,

> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-
> bounces@lists.infradead.org] On Behalf Of Abhishek Sahu
> Sent: Wednesday, May 11, 2016 11:04 PM
> To: Sricharan <sricharan@codeaurora.org>
> Cc: architt@codeaurora.org; wsa@the-dreams.de; linux-arm-
> msm@vger.kernel.org; ntelkar@codeaurora.org; linux-
> kernel@vger.kernel.org; dmaengine@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; andy.gross@linaro.org; linux-
> arm-kernel@lists.infradead.org
> Subject: RE: [PATCH 1/2] i2c: qup: Cleared the error bits in ISR
> 
> On 2016-05-11 21:27, Sricharan wrote:
> > Hi,
> >
> >> 1. Current QCOM I2C driver hangs when sending data to address
> >> 0x03-0x07
> >> in some scenarios. The QUP controller generates invalid write in this
> >> case, since these addresses are reserved for different bus formats.
> >>
> >> 2. Also, the error handling is done by I2C QUP ISR in the case of DMA
> >> mode.
> >> The state need to be RESET in case of any error for clearing the
> >> available data in FIFO, which otherwise leaves the BAM DMA controller
> >> in hang state.
> >>
> >> This patch fixes the above two issues by clearing the error bits from
> >> I2C and QUP status in ISR in case of I2C error, QUP error and resets
> >> the QUP state to clear the FIFO data.
> >>
> >> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> >> ---
> >>  drivers/i2c/busses/i2c-qup.c | 14 ++++++++------
> >>  1 file changed, 8 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/drivers/i2c/busses/i2c-qup.c
> >> b/drivers/i2c/busses/i2c-qup.c index 23eaabb..8c2f1bc 100644
> >> --- a/drivers/i2c/busses/i2c-qup.c
> >> +++ b/drivers/i2c/busses/i2c-qup.c
> >> @@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq,
> >> void
> >> *dev)
> >>  	bus_err &= I2C_STATUS_ERROR_MASK;
> >>  	qup_err &= QUP_STATUS_ERROR_FLAGS;
> >>
> >> -	if (qup_err) {
> >> -		/* Clear Error interrupt */
> >> +	/* Clear the error bits in QUP_ERROR_FLAGS */
> >> +	if (qup_err)
> >>  		writel(qup_err, qup->base + QUP_ERROR_FLAGS);
> >> -		goto done;
> >> -	}
> >>
> >> -	if (bus_err) {
> >> -		/* Clear Error interrupt */
> >> +	/* Clear the error bits in QUP_I2C_STATUS */
> >> +	if (bus_err)
> >> +		writel(bus_err, qup->base + QUP_I2C_STATUS);
> >> +
> >> +	/* Reset the QUP State in case of error */
> >> +	if (qup_err || bus_err) {
> >>  		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
> >>  		goto done;
> >>  	}
> >        In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at
> > the end, when
> >        there is no error. So would it be fine if we do it there
> > unconditionally ?
> >
> > Regards,
> >  Sricharan
> 
> RESET the QUP state wouldn't create any issue in the case of multiple
calls.
> The existing code also RESET the QUP state for bus_err but it is not
clearing
> status bits.
    So is there a difference that you see by setting it in isr for qup
errors ?
    Otherwise, its better to set it in one place unconditionally instead of
doing
    it in two places ?

Regards,
 Sricharan

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andy Gross May 12, 2016, 5:13 a.m. UTC | #4
On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:

<snip>

> >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
> >end, when
> >       there is no error. So would it be fine if we do it there
> >unconditionally ?
> >
> >Regards,
> > Sricharan
> 
> RESET the QUP state wouldn't create any issue in the case of multiple calls.
> The existing code also RESET the QUP state for bus_err but it is not
> clearing
> status bits.

It'd be better to not reset the QUP inside the ISR at all.  I think the better
solution is making the reset occur in the xfer function.  So just clear the bits
like you should in the isr, and defer reset till later.
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Abhishek Sahu May 12, 2016, 6:18 a.m. UTC | #5
On Thu, May 12, 2016 at 12:13:47AM -0500, Andy Gross wrote:
> On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:
> 
> <snip>
> 
> > >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
> > >end, when
> > >       there is no error. So would it be fine if we do it there
> > >unconditionally ?
> > >
> > >Regards,
> > > Sricharan
> > 
> > RESET the QUP state wouldn't create any issue in the case of multiple calls.
> > The existing code also RESET the QUP state for bus_err but it is not
> > clearing
> > status bits.
> 
> It'd be better to not reset the QUP inside the ISR at all.  I think the better
> solution is making the reset occur in the xfer function.  So just clear the bits
> like you should in the isr, and defer reset till later.

This is a HW workaround for QUP where we need to RESET the core in
ISR. When interrupt is level triggerd, more than one interrupt may
fire in error cases and QUP will generate these interrupts after
completion of current interrupt. Thus we reset the core immediately
in the ISR to ward off the next interrupt.
Andy Gross May 12, 2016, 5:58 p.m. UTC | #6
On Thu, May 12, 2016 at 11:48:43AM +0530, Abhishek Sahu wrote:
> On Thu, May 12, 2016 at 12:13:47AM -0500, Andy Gross wrote:
> > On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:
> > 
> > <snip>
> > 
> > > >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
> > > >end, when
> > > >       there is no error. So would it be fine if we do it there
> > > >unconditionally ?
> > > >
> > > >Regards,
> > > > Sricharan
> > > 
> > > RESET the QUP state wouldn't create any issue in the case of multiple calls.
> > > The existing code also RESET the QUP state for bus_err but it is not
> > > clearing
> > > status bits.
> > 
> > It'd be better to not reset the QUP inside the ISR at all.  I think the better
> > solution is making the reset occur in the xfer function.  So just clear the bits
> > like you should in the isr, and defer reset till later.
> 
> This is a HW workaround for QUP where we need to RESET the core in
> ISR. When interrupt is level triggerd, more than one interrupt may
> fire in error cases and QUP will generate these interrupts after
> completion of current interrupt. Thus we reset the core immediately
> in the ISR to ward off the next interrupt.

I wonder if that was just an expedient solution.  And it seems like it could be
a little racy as a poll is not being done to make sure the QUP state machine
transitions to reset.  Is there any documentation/errata on this?  Or is this
just from commit comments?


Regards,
Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Abhishek Sahu May 12, 2016, 7:32 p.m. UTC | #7
On Thu, May 12, 2016 at 12:58:30PM -0500, Andy Gross wrote:
> On Thu, May 12, 2016 at 11:48:43AM +0530, Abhishek Sahu wrote:
> > On Thu, May 12, 2016 at 12:13:47AM -0500, Andy Gross wrote:
> > > On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:
> > > 
> > > <snip>
> > > 
> > > > >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
> > > > >end, when
> > > > >       there is no error. So would it be fine if we do it there
> > > > >unconditionally ?
> > > > >
> > > > >Regards,
> > > > > Sricharan
> > > > 
> > > > RESET the QUP state wouldn't create any issue in the case of multiple calls.
> > > > The existing code also RESET the QUP state for bus_err but it is not
> > > > clearing
> > > > status bits.
> > > 
> > > It'd be better to not reset the QUP inside the ISR at all.  I think the better
> > > solution is making the reset occur in the xfer function.  So just clear the bits
> > > like you should in the isr, and defer reset till later.
> > 
> > This is a HW workaround for QUP where we need to RESET the core in
> > ISR. When interrupt is level triggerd, more than one interrupt may
> > fire in error cases and QUP will generate these interrupts after
> > completion of current interrupt. Thus we reset the core immediately
> > in the ISR to ward off the next interrupt.
> 
> I wonder if that was just an expedient solution.  And it seems like it could be
> a little racy as a poll is not being done to make sure the QUP state machine
> transitions to reset.  Is there any documentation/errata on this?  Or is this
> just from commit comments?
> 
> 
> Regards,
> Andy

Hi Andy,

Thanks for your comments. We have only added the patch for clearing
the error bits. This resetting of QUP is present in the base code
itself. Since this QUP is being used by all the QCOM chips that's why
we have not changed the existing QUP reset logic. We will look
into reset polling logic separately and will post the patch for the
same.

We got the input for QUP RESET by referring our working internal
drivers and we also faced the BAM hang issue in base upstream
driver, if we don't do this RESET. If we schedule any transfer
with DMA mode then the DMA Engine (BAM) will never get any interrupt
for these errors, since the QUP interrupt handles the error cases.
The BAM will generate the interrupt only when it will receive the
requested amount of data. This reset will clear the QUP FIFO and
we will get the BAM transfer completion interrupt by the existing
logic present in the base bam transfer function.
Andy Gross May 12, 2016, 8:05 p.m. UTC | #8
On 12 May 2016 at 14:32, Abhishek Sahu <absahu@codeaurora.org> wrote:
> On Thu, May 12, 2016 at 12:58:30PM -0500, Andy Gross wrote:
>> On Thu, May 12, 2016 at 11:48:43AM +0530, Abhishek Sahu wrote:
>> > On Thu, May 12, 2016 at 12:13:47AM -0500, Andy Gross wrote:
>> > > On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:
>> > >
>> > > <snip>
>> > >
>> > > > >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
>> > > > >end, when
>> > > > >       there is no error. So would it be fine if we do it there
>> > > > >unconditionally ?
>> > > > >
>> > > > >Regards,
>> > > > > Sricharan
>> > > >
>> > > > RESET the QUP state wouldn't create any issue in the case of multiple calls.
>> > > > The existing code also RESET the QUP state for bus_err but it is not
>> > > > clearing
>> > > > status bits.
>> > >
>> > > It'd be better to not reset the QUP inside the ISR at all.  I think the better
>> > > solution is making the reset occur in the xfer function.  So just clear the bits
>> > > like you should in the isr, and defer reset till later.
>> >
>> > This is a HW workaround for QUP where we need to RESET the core in
>> > ISR. When interrupt is level triggerd, more than one interrupt may
>> > fire in error cases and QUP will generate these interrupts after
>> > completion of current interrupt. Thus we reset the core immediately
>> > in the ISR to ward off the next interrupt.
>>
>> I wonder if that was just an expedient solution.  And it seems like it could be
>> a little racy as a poll is not being done to make sure the QUP state machine
>> transitions to reset.  Is there any documentation/errata on this?  Or is this
>> just from commit comments?
>>
>>
>> Regards,
>> Andy
>
> Hi Andy,
>
> Thanks for your comments. We have only added the patch for clearing
> the error bits. This resetting of QUP is present in the base code
> itself. Since this QUP is being used by all the QCOM chips that's why
> we have not changed the existing QUP reset logic. We will look
> into reset polling logic separately and will post the patch for the
> same.

Yeah, it is present in the current code.  I hadn't seen any errata on
this issue, so that is why I was curious.  In many cases, the code in
the mainline driver was carried forward from the downstream CAF
driver.  I know the two don't look that similar in some regards, but
in most cases the actions taken are the same, even if it is not
obvious.

> We got the input for QUP RESET by referring our working internal
> drivers and we also faced the BAM hang issue in base upstream
> driver, if we don't do this RESET. If we schedule any transfer
> with DMA mode then the DMA Engine (BAM) will never get any interrupt
> for these errors, since the QUP interrupt handles the error cases.
> The BAM will generate the interrupt only when it will receive the
> requested amount of data. This reset will clear the QUP FIFO and
> we will get the BAM transfer completion interrupt by the existing
> logic present in the base bam transfer function.

Right.  If the QUP has an issue and isn't processing data, and you
have a BAM transaction pending for this, you have to not only ack the
qup error, but also terminate the BAM transaction.

What test case are you using to test out the error path?  Something
other than NACKs?

Regards,

Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Abhishek Sahu May 12, 2016, 8:27 p.m. UTC | #9
On Thu, May 12, 2016 at 03:05:39PM -0500, Andy Gross wrote:
> On 12 May 2016 at 14:32, Abhishek Sahu <absahu@codeaurora.org> wrote:
> > On Thu, May 12, 2016 at 12:58:30PM -0500, Andy Gross wrote:
> >> On Thu, May 12, 2016 at 11:48:43AM +0530, Abhishek Sahu wrote:
> >> > On Thu, May 12, 2016 at 12:13:47AM -0500, Andy Gross wrote:
> >> > > On Wed, May 11, 2016 at 11:04:17PM +0530, Abhishek Sahu wrote:
> >> > >
> >> > > <snip>
> >> > >
> >> > > > >       In qup_i2c_xfer and qup_i2c_xfer_v2 state is set to RESET at the
> >> > > > >end, when
> >> > > > >       there is no error. So would it be fine if we do it there
> >> > > > >unconditionally ?
> >> > > > >
> >> > > > >Regards,
> >> > > > > Sricharan
> >> > > >
> >> > > > RESET the QUP state wouldn't create any issue in the case of multiple calls.
> >> > > > The existing code also RESET the QUP state for bus_err but it is not
> >> > > > clearing
> >> > > > status bits.
> >> > >
> >> > > It'd be better to not reset the QUP inside the ISR at all.  I think the better
> >> > > solution is making the reset occur in the xfer function.  So just clear the bits
> >> > > like you should in the isr, and defer reset till later.
> >> >
> >> > This is a HW workaround for QUP where we need to RESET the core in
> >> > ISR. When interrupt is level triggerd, more than one interrupt may
> >> > fire in error cases and QUP will generate these interrupts after
> >> > completion of current interrupt. Thus we reset the core immediately
> >> > in the ISR to ward off the next interrupt.
> >>
> >> I wonder if that was just an expedient solution.  And it seems like it could be
> >> a little racy as a poll is not being done to make sure the QUP state machine
> >> transitions to reset.  Is there any documentation/errata on this?  Or is this
> >> just from commit comments?
> >>
> >>
> >> Regards,
> >> Andy
> >
> > Hi Andy,
> >
> > Thanks for your comments. We have only added the patch for clearing
> > the error bits. This resetting of QUP is present in the base code
> > itself. Since this QUP is being used by all the QCOM chips that's why
> > we have not changed the existing QUP reset logic. We will look
> > into reset polling logic separately and will post the patch for the
> > same.
> 
> Yeah, it is present in the current code.  I hadn't seen any errata on
> this issue, so that is why I was curious.  In many cases, the code in
> the mainline driver was carried forward from the downstream CAF
> driver.  I know the two don't look that similar in some regards, but
> in most cases the actions taken are the same, even if it is not
> obvious.
> 
> > We got the input for QUP RESET by referring our working internal
> > drivers and we also faced the BAM hang issue in base upstream
> > driver, if we don't do this RESET. If we schedule any transfer
> > with DMA mode then the DMA Engine (BAM) will never get any interrupt
> > for these errors, since the QUP interrupt handles the error cases.
> > The BAM will generate the interrupt only when it will receive the
> > requested amount of data. This reset will clear the QUP FIFO and
> > we will get the BAM transfer completion interrupt by the existing
> > logic present in the base bam transfer function.
> 
> Right.  If the QUP has an issue and isn't processing data, and you
> have a BAM transaction pending for this, you have to not only ack the
> qup error, but also terminate the BAM transaction.
> 
> What test case are you using to test out the error path?  Something
> other than NACKs?
> 
> Regards,
> 
> Andy

Hi Andy,

We run the command i2cdetect for address 0x3 to 0x77. The QUP generates
write error for address 0x3 to 0x7 apart from other bus errors since
these are reserved addresses. I was getting the crash in non DMA mode
and BAM hang in DMA mode before putting the fix.

Also we have connected the I2C TPM and run the following script
overnight for both DMA and Non DMA mode.  The script checks for
all transfer length and we are generating multiple NACK and
Non NACK error before each valid transfer.

a=1

while [ $a -lt 4096 ]
do
   echo $a
   i2cdetect -y -a -r 0 0x03 0x77
   tpm-manager get_random $a
   i2cdetect -y -a -r 1 0x03 0x77
   a=`expr $a + 1`
done

--
Abhishek Sahu
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wolfram Sang June 18, 2016, 4:32 p.m. UTC | #10
> We run the command i2cdetect for address 0x3 to 0x77. The QUP generates
> write error for address 0x3 to 0x7 apart from other bus errors since
> these are reserved addresses. I was getting the crash in non DMA mode
> and BAM hang in DMA mode before putting the fix.
> 
> Also we have connected the I2C TPM and run the following script
> overnight for both DMA and Non DMA mode.  The script checks for
> all transfer length and we are generating multiple NACK and
> Non NACK error before each valid transfer.
> 
> a=1
> 
> while [ $a -lt 4096 ]
> do
>    echo $a
>    i2cdetect -y -a -r 0 0x03 0x77
>    tpm-manager get_random $a
>    i2cdetect -y -a -r 1 0x03 0x77
>    a=`expr $a + 1`
> done

So, what is the outcome of this discussion?
Abhishek Sahu June 20, 2016, 12:48 p.m. UTC | #11
On 2016-06-18 22:02, Wolfram Sang wrote:
>> We run the command i2cdetect for address 0x3 to 0x77. The QUP 
>> generates
>> write error for address 0x3 to 0x7 apart from other bus errors since
>> these are reserved addresses. I was getting the crash in non DMA mode
>> and BAM hang in DMA mode before putting the fix.
>> 
>> Also we have connected the I2C TPM and run the following script
>> overnight for both DMA and Non DMA mode.  The script checks for
>> all transfer length and we are generating multiple NACK and
>> Non NACK error before each valid transfer.
>> 
>> a=1
>> 
>> while [ $a -lt 4096 ]
>> do
>>    echo $a
>>    i2cdetect -y -a -r 0 0x03 0x77
>>    tpm-manager get_random $a
>>    i2cdetect -y -a -r 1 0x03 0x77
>>    a=`expr $a + 1`
>> done
> 
> So, what is the outcome of this discussion?

Discussion was regarding resetting the QUP state in ISR and it is the 
part of
existing code itself. The current patch only added the error checking 
for bus
errors so we can go ahead with this patch. I have shared the script 
which we
are using for testing error path.
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wolfram Sang July 15, 2016, 6:33 a.m. UTC | #12
On Mon, May 09, 2016 at 06:14:30PM +0530, Abhishek Sahu wrote:
> 1. Current QCOM I2C driver hangs when sending data to address 0x03-0x07
> in some scenarios. The QUP controller generates invalid write in this
> case, since these addresses are reserved for different bus formats.
> 
> 2. Also, the error handling is done by I2C QUP ISR in the case of DMA
> mode. The state need to be RESET in case of any error for clearing the
> available data in FIFO, which otherwise leaves the BAM DMA controller
> in hang state.
> 
> This patch fixes the above two issues by clearing the error bits from
> I2C and QUP status in ISR in case of I2C error, QUP error and resets
> the QUP state to clear the FIFO data.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

Applied to for-next, thanks!
diff mbox

Patch

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 23eaabb..8c2f1bc 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -213,14 +213,16 @@  static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 	bus_err &= I2C_STATUS_ERROR_MASK;
 	qup_err &= QUP_STATUS_ERROR_FLAGS;
 
-	if (qup_err) {
-		/* Clear Error interrupt */
+	/* Clear the error bits in QUP_ERROR_FLAGS */
+	if (qup_err)
 		writel(qup_err, qup->base + QUP_ERROR_FLAGS);
-		goto done;
-	}
 
-	if (bus_err) {
-		/* Clear Error interrupt */
+	/* Clear the error bits in QUP_I2C_STATUS */
+	if (bus_err)
+		writel(bus_err, qup->base + QUP_I2C_STATUS);
+
+	/* Reset the QUP State in case of error */
+	if (qup_err || bus_err) {
 		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
 		goto done;
 	}