From: qianfan Zhao <qianfangui...@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 <qianfangui...@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