According to the "VFxxx Controller Reference Manual" (and the comment block starting at line 97), Vybrid requires writing a one for clearing an interrupt flag. Syncing with the method for clearing I2SR_IIF in i2c_imx_isr().
Signed-off-by: Christian Eggers ceggers@arri.de Cc: stable@vger.kernel.org --- drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 0ab5381aa012..d8b2e632dd10 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -425,6 +425,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a /* check for arbitration lost */ if (temp & I2SR_IAL) { temp &= ~I2SR_IAL; + temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); return -EAGAIN; }
Hello,
On Thu, Sep 17, 2020 at 02:20:27PM +0200, Christian Eggers wrote:
According to the "VFxxx Controller Reference Manual" (and the comment block starting at line 97), Vybrid requires writing a one for clearing an interrupt flag. Syncing with the method for clearing I2SR_IIF in i2c_imx_isr().
Signed-off-by: Christian Eggers ceggers@arri.de Cc: stable@vger.kernel.org
drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 0ab5381aa012..d8b2e632dd10 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -425,6 +425,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a /* check for arbitration lost */ if (temp & I2SR_IAL) { temp &= ~I2SR_IAL;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); return -EAGAIN;
This looks strange. First the flag is cleared and then it is (in some cases) set again.
If I2SR_IIF is set in temp you ack this irq without handling it. (Which might happen if atomic is set and irqs are off?!)
I see this idiom is used in a few more places in the driver already, I didn't check but these might have the same problem maybe?
Best regards Uwe
Hello Uwe,
On Thursday, 17 September 2020, 16:02:35 CEST, Uwe Kleine-König wrote:
Hello,
On Thu, Sep 17, 2020 at 02:20:27PM +0200, Christian Eggers wrote: ...
/* check for arbitration lost */ if (temp & I2SR_IAL) { temp &= ~I2SR_IAL;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); return -EAGAIN;
...
This looks strange. First the flag is cleared and then it is (in some cases) set again.
i.MX controllers require writing a 0 to clear these bits. Vybrid controllers need writing a 1 for the same.
If I2SR_IIF is set in temp you ack this irq without handling it. (Which might happen if atomic is set and irqs are off?!)
This patch is only about using the correct processor specific value for acknowledging an IRQ... But I think that returning EAGAIN (which aborts the transfer) should be handling enough. At the next transfer, the controller will be set back to master mode.
I see this idiom is used in a few more places in the driver already, I didn't check but these might have the same problem maybe?
Best regards Christian
On Thu, Sep 17, 2020 at 04:13:50PM +0200, Christian Eggers wrote:
Hello Uwe,
On Thursday, 17 September 2020, 16:02:35 CEST, Uwe Kleine-König wrote:
Hello,
On Thu, Sep 17, 2020 at 02:20:27PM +0200, Christian Eggers wrote: ...
/* check for arbitration lost */ if (temp & I2SR_IAL) { temp &= ~I2SR_IAL;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); return -EAGAIN;
...
This looks strange. First the flag is cleared and then it is (in some cases) set again.
i.MX controllers require writing a 0 to clear these bits. Vybrid controllers need writing a 1 for the same.
Yes, I understood that.
If I2SR_IIF is set in temp you ack this irq without handling it. (Which might happen if atomic is set and irqs are off?!)
This patch is only about using the correct processor specific value for acknowledging an IRQ... But I think that returning EAGAIN (which aborts the transfer) should be handling enough. At the next transfer, the controller will be set back to master mode.
Either you didn't understand what I meant, or I don't understand why you consider your patch right anyhow. So I try to explain in other and more words.
IMHO the intention here (and also what happens on i.MX) is that exactly the AL interrupt pending bit should be cleared and the IF irq is supposed to be untouched.
Given there are only two irq flags in the I2SR register (which is called IBSR on Vybrid) the status quo (i.e. without your patch) is:
On i.MX IAL is cleared On Vybrid IIF (which is called IBIF there) is cleared.
With your patch we get:
On i.MX IAL is cleared On Vybrid both IIF (aka IBIF) and IAL (aka IBAL) are cleared.
To get it right for both SoC types you have to do (e.g.):
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ I2SR_IAL;
(and in i2c_imx_isr() the same using I2SR_IIF instead of I2SR_IAL because there currently IAL might be cleared by mistake on Vybrid).
I considered creating a patch, but as I don't have a Vybrid on my desk and on i.MX there is no change, I let you do this.
Best regards Uwe
Hi Uwe,
On Friday, 25 September 2020, 10:11:01 CEST, Uwe Kleine-König wrote:
On Thu, Sep 17, 2020 at 04:13:50PM +0200, Christian Eggers wrote:
On Thursday, 17 September 2020, 16:02:35 CEST, Uwe Kleine-König wrote:
On Thu, Sep 17, 2020 at 02:20:27PM +0200, Christian Eggers wrote: ...
/* check for arbitration lost */ if (temp & I2SR_IAL) { temp &= ~I2SR_IAL;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); return -EAGAIN;
...
This looks strange. First the flag is cleared and then it is (in some cases) set again.
i.MX controllers require writing a 0 to clear these bits. Vybrid controllers need writing a 1 for the same.
Yes, I understood that.
If I2SR_IIF is set in temp you ack this irq without handling it. (Which might happen if atomic is set and irqs are off?!)
This patch is only about using the correct processor specific value for acknowledging an IRQ... But I think that returning EAGAIN (which aborts the transfer) should be handling enough. At the next transfer, the controller will be set back to master mode.
Either you didn't understand what I meant, or I don't understand why you consider your patch right anyhow.
Probably both.
So I try to explain in other and more words.
IMHO the intention here (and also what happens on i.MX) is that exactly the AL interrupt pending bit should be cleared and the IF irq is supposed to be untouched.
Yes.
Given there are only two irq flags in the I2SR register (which is called IBSR on Vybrid) ...
Vybrid: ======= +-------+-----+------+-----+------+-----+-----+------+------+ | BIT | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-------+-----+------+-----+------+-----+-----+------+------+ | READ | TCF | IAAS | IBB | IBAL | 0 | SRW | IBIF | RXAK | +-------+-----+------+-----+------+-----+-----+------+------+ | WRITE | - | - | - | W1C | - | - | W1C | - | +-------+-----+------+-----+-^^^--+-----+-----+-^^^--+------+
i.MX: ======= +-------+-----+------+-----+------+-----+-----+------+------+ | BIT | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-------+-----+------+-----+------+-----+-----+------+------+ | READ | ICF | IAAS | IBB | IAL | 0 | SRW | IIF | RXAK | +-------+-----+------+-----+------+-----+-----+------+------+ | WRITE | - | - | - | W0C | - | - | W0C | - | +-------+-----+------+-----+-^^^--+-----+-----+-^^^--+------+
... the status quo (i.e. without your patch) is:
On i.MX IAL is cleared
Yes
On Vybrid IIF (which is called IBIF there) is cleared.
If IBIF is set, then it's cleared (probably by accident). But in the "if (temp & I2SR_IAL)" condition, I focus on the IBAL flag, not IBIF.
With your patch we get:
On i.MX IAL is cleared
Yes
On Vybrid both IIF (aka IBIF) and IAL (aka IBAL) are cleared.
Agree. IBAL is cleared by intention, IBIF by accident (if set). Do you see any problem if IBIF is also cleared?
To get it right for both SoC types you have to do (e.g.):
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ I2SR_IAL;
Sorry, even if this is correct, it looks hard to understand for me.
(and in i2c_imx_isr() the same using I2SR_IIF instead of I2SR_IAL because there currently IAL might be cleared by mistake on Vybrid).
I considered creating a patch, but as I don't have a Vybrid on my desk and on i.MX there is no change, I let you do this.
I also don't own a Vybrid system. I consider my patch correct in terms of clearing the IBAL flag (which was wrong before). Additional work may be useful for NOT clearing the other status flag. I also would like to keep this task for somebody who owns a Vybrid system. But the other patches in this series fixes some more important problems, so maybe you could give your acknowledge anyhow.
Best regards Christian
Hello Christian,
On Fri, Oct 02, 2020 at 10:01:30AM +0200, Christian Eggers wrote:
On Friday, 25 September 2020, 10:11:01 CEST, Uwe Kleine-König wrote:
On Thu, Sep 17, 2020 at 04:13:50PM +0200, Christian Eggers wrote: IMHO the intention here (and also what happens on i.MX) is that exactly the AL interrupt pending bit should be cleared and the IF irq is supposed to be untouched.
Yes.
Given there are only two irq flags in the I2SR register (which is called IBSR on Vybrid) ...
Vybrid:
+-------+-----+------+-----+------+-----+-----+------+------+ | BIT | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-------+-----+------+-----+------+-----+-----+------+------+ | READ | TCF | IAAS | IBB | IBAL | 0 | SRW | IBIF | RXAK | +-------+-----+------+-----+------+-----+-----+------+------+ | WRITE | - | - | - | W1C | - | - | W1C | - | +-------+-----+------+-----+-^^^--+-----+-----+-^^^--+------+
i.MX:
+-------+-----+------+-----+------+-----+-----+------+------+ | BIT | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-------+-----+------+-----+------+-----+-----+------+------+ | READ | ICF | IAAS | IBB | IAL | 0 | SRW | IIF | RXAK | +-------+-----+------+-----+------+-----+-----+------+------+ | WRITE | - | - | - | W0C | - | - | W0C | - | +-------+-----+------+-----+-^^^--+-----+-----+-^^^--+------+
... the status quo (i.e. without your patch) is:
On i.MX IAL is cleared
Yes
On Vybrid IIF (which is called IBIF there) is cleared.
If IBIF is set, then it's cleared (probably by accident). But in the "if (temp & I2SR_IAL)" condition, I focus on the IBAL flag, not IBIF.
With your patch we get:
On i.MX IAL is cleared
Yes
On Vybrid both IIF (aka IBIF) and IAL (aka IBAL) are cleared.
Agree. IBAL is cleared by intention, IBIF by accident (if set). Do you see any problem if IBIF is also cleared?
Yes. If there is a real problem I'm not sure, but it's enough of an issue that there are possible side effects on Vybrid. I refuse to think about real problems given that it is so easy to make it right.
To get it right for both SoC types you have to do (e.g.):
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ I2SR_IAL;
Sorry, even if this is correct, it looks hard to understand for me.
Maybe a comment would be appropriate, something like:
/* * i2sr_clr_opcode is the value to clear all interrupts. Here we * want to clear no irq but I2SR_IAL, so we write * ~i2sr_clr_opcode with just the I2SR_IAL bit toggled. */
Maybe put this comment together with the code in a new function to have it only once.
(and in i2c_imx_isr() the same using I2SR_IIF instead of I2SR_IAL because there currently IAL might be cleared by mistake on Vybrid).
I considered creating a patch, but as I don't have a Vybrid on my desk and on i.MX there is no change, I let you do this.
I also don't own a Vybrid system. I consider my patch correct in terms of clearing the IBAL flag (which was wrong before). Additional work may be useful for NOT clearing the other status flag. I also would like to keep this task for somebody who owns a Vybrid system. But the other patches in this series fixes some more important problems, so maybe you could give your acknowledge anyhow.
No, please don't replace one bug found by another (now) known bug. Still more given that the newly introduced bug is much harder to trigger and debug.
Best regards Uwe
linux-stable-mirror@lists.linaro.org