[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v1 2/2] hw: allwinner-i2c: Fix TWI_CNTR_INT_FLAG
From: |
qianfanguijin |
Subject: |
[PATCH v1 2/2] hw: allwinner-i2c: Fix TWI_CNTR_INT_FLAG |
Date: |
Fri, 17 Feb 2023 17:42:07 +0800 |
From: qianfan Zhao <qianfanguijin@163.com>
TWI_CNTR_INT_FLAG is W1C(write 1 to clear and write 0 has non-effect)
register, we should lower interrupt when the guest write this bit.
The linux kernel will hang in irq handler(mv64xxx_i2c_intr) if no
device connected on the i2c bus, next is the trace log:
[ 7.004130] axp20x-i2c 0-0034: AXP20x variant AXP221 found
allwinner_i2c_rw write CNTR[0x0c]: e4 { A_ACK M_STA BUS_EN INT_EN }
allwinner_i2c_rw read CNTR[0x0c]: cc { A_ACK INT_FLAG BUS_EN INT_EN }
allwinner_i2c_rw read STAT[0x10]: 08 { STAT_M_STA_TX }
allwinner_i2c_rw write DATA[0x08]: 68
allwinner_i2c_rw write CNTR[0x0c]: c4 { A_ACK BUS_EN INT_EN }
allwinner_i2c_rw write CNTR[0x0c]: cc { A_ACK INT_FLAG BUS_EN INT_EN }
allwinner_i2c_rw read CNTR[0x0c]: cc { A_ACK INT_FLAG BUS_EN INT_EN }
allwinner_i2c_rw read STAT[0x10]: 20 { STAT_M_ADDR_WR_NACK }
allwinner_i2c_rw write CNTR[0x0c]: 54 { A_ACK M_STP BUS_EN }
allwinner_i2c_rw write CNTR[0x0c]: 4c { A_ACK INT_FLAG BUS_EN }
allwinner_i2c_rw read CNTR[0x0c]: 4c { A_ACK INT_FLAG BUS_EN }
allwinner_i2c_rw read STAT[0x10]: f8 { STAT_IDLE }
allwinner_i2c_rw write CNTR[0x0c]: 54 { A_ACK M_STP BUS_EN }
allwinner_i2c_rw write CNTR[0x0c]: 4c { A_ACK INT_FLAG BUS_EN }
allwinner_i2c_rw read CNTR[0x0c]: 4c { A_ACK INT_FLAG BUS_EN }
allwinner_i2c_rw read STAT[0x10]: f8 { STAT_IDLE }
Fix it.
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
---
hw/i2c/allwinner-i2c.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c
index 36b387520f..86a77d4a59 100644
--- a/hw/i2c/allwinner-i2c.c
+++ b/hw/i2c/allwinner-i2c.c
@@ -443,8 +443,9 @@ static void allwinner_i2c_write(void *opaque, hwaddr offset,
s->stat = STAT_FROM_STA(STAT_IDLE);
s->cntr &= ~TWI_CNTR_M_STP;
}
- if ((s->cntr & TWI_CNTR_INT_FLAG) == 0) {
- /* Interrupt flag cleared */
+ if (s->cntr & TWI_CNTR_INT_FLAG) {
+ /* Write 1 to clear this flag */
+ s->cntr &= ~TWI_CNTR_INT_FLAG;
qemu_irq_lower(s->irq);
}
if ((s->cntr & TWI_CNTR_A_ACK) == 0) {
--
2.25.1