etsec: fix IRQ (un)masking
PATCH 1/1 etsec: fix IRQ (un)masking
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.
To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Also fix probable typo "IEVENT_TXF | IEVENT_TXF", and update IRQ pins on reset.
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)
hw/net/fsl_etsec/etsec.c +36 -32
@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c\n" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;
@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,
@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }
@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }
@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :
@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,
hw/net/fsl_etsec/etsec.h +2 -0
@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);
hw/net/fsl_etsec/registers.h +10 -0
@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)
hw/net/fsl_etsec/rings.c +1 -11
@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Signature · 1 line
2.11.0
Quoted 11 lines · Michael Davidsaver
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.Signed-off-by Michael Davidsaver <[email protected]>
Looks sane, but I would like to get an R-b from someone who knows FSL better than me before applying.
Quoted 178 lines
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)hw/net/fsl_etsec/etsec.c +36
-32@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c\n" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,hw/net/fsl_etsec/etsec.h +2
-0@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);hw/net/fsl_etsec/registers.h +10
-0@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)hw/net/fsl_etsec/rings.c +1
-11@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Quoted 8 lines · David Gibson
Quoted 7 lines · Michael Davidsaver
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Quoted 7 lines
Quoted 4 lines
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.Signed-off-by Michael Davidsaver <[email protected]>Looks sane, but I would like to get an R-b from someone who knows FSL better than me before applying.
Any progress on finding a candidate to comment?
Quoted 179 lines
Quoted 178 lines
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)hw/net/fsl_etsec/etsec.c +36
-32@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c\n" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,hw/net/fsl_etsec/etsec.h +2
-0@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);hw/net/fsl_etsec/registers.h +10
-0@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)hw/net/fsl_etsec/rings.c +1
-11@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Quoted 12 lines · Michael Davidsaver
Quoted 11 lines · David Gibson
Quoted 10 lines · Michael Davidsaver
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Michael Davidsaver <[email protected]>Looks sane, but I would like to get an R-b from someone who knows FSL better than me before applying.
Any progress on finding a candidate to comment?
I'm afraid not, I was kind of hoping someone would respond on list.
Quoted 183 lines
Quoted 181 lines
Quoted 180 lines
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)hw/net/fsl_etsec/etsec.c +36
-32@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c\n" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,hw/net/fsl_etsec/etsec.h +2
-0@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);hw/net/fsl_etsec/registers.h +10
-0@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)hw/net/fsl_etsec/rings.c +1
-11@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Quoted 6 lines · Michael Davidsaver
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.To avoid problems like this in future, consolidate IRQ pin update logic in one function.
it makes sense.
Quoted 2 lines
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.
Thanks,
C.
Quoted 16 lines
Signed-off-by Michael Davidsaver <[email protected]>--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)hw/net/fsl_etsec/etsec.c +0
-0@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 )
hw/net/fsl_etsec/etsec.c static const int debug_etsec; · line 61
Quoted 10 lines
hw/net/fsl_etsec/etsec.c +10
-0+/* call after any change to IEVENT or IMASK */ +void etsec_update_irq (eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK );
you could make these bools. this is minor.
Quoted 153 lines
hw/net/fsl_etsec/etsec.c +25
-32+DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c\n" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + + etsec_update_irq(etsec);> } static ssize_t etsec_receive(NetClientState *nc,hw/net/fsl_etsec/etsec.h +2
-0@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);hw/net/fsl_etsec/registers.h +10
-0@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)hw/net/fsl_etsec/rings.c +1
-11@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Quoted 7 lines · Michael Davidsaver
Quoted 6 lines
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Quoted 6 lines
it makes sense.
Quoted 2 lines
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.Reviewed-by Cédric Le Goater <[email protected]>
Thanks for the review Cédric. Unfortunately, I've mislaid the original patch.
Michael, can you resend with Cédric's R-b included, please.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 1/1 etsec: fix IRQ (un)masking
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.
To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Also fix probable typo "IEVENT_TXF | IEVENT_TXF", and update IRQ pins on reset.
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)
hw/net/fsl_etsec/etsec.c +36 -32
@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;
@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,
@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }
@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }
@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :
@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,
hw/net/fsl_etsec/etsec.h +2 -0
@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);
hw/net/fsl_etsec/registers.h +10 -0
@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)
hw/net/fsl_etsec/rings.c +1 -11
@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Signature · 1 line
2.11.0
David Gibson
AppliedQuoted 4 lines · Michael Davidsaver
Interrupt conditions occurring while masked are not being signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.
Quoted 8 lines
To avoid problems like this in future, consolidate IRQ pin update logic in one function.
Also fix probable typo "
IEVENT_TXF|IEVENT_TXF", and update IRQ pins on reset.Signed-off-by Michael Davidsaver <[email protected]>Reviewed-by Cédric Le Goater <[email protected]>
Applied to ppc-for-3.0.
Quoted 178 lines
--- hw/net/fsl_etsec/etsec.c | 68 +++++++++++++++++++++++--------------------- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/registers.h | 10 +++++++ hw/net/fsl_etsec/rings.c | 12 +------- 4 files changed, 49 insertions(+), 43 deletions(-)hw/net/fsl_etsec/etsec.c +36
-32@@ -49,6 +49,28 @@ static const int debug_etsec; } \ }while (0 ) +/* call after any change to IEVENT or IMASK */ +void etsec_update_irq(eTSEC *etsec) +{ +uint32_t ievent = etsec->regs[IEVENT ].value; +uint32_t imask = etsec->regs[IMASK ].value; +uint32_t active = ievent & imask; + +int tx = !!(active &IEVENT_TX_MASK ); +int rx = !!(active &IEVENT_RX_MASK ); +int err = !!(active &IEVENT_ERR_MASK ); + +DPRINTF ("%s IRQ ievent=%" PRIx32" imask=%" PRIx32" %c%c%c" , + __func__, ievent, imask, + tx ?'T' :'_' , + rx ?'R' :'_' , + err ?'E' :'_' ); + +qemu_set_irq (etsec->tx_irq, tx); +qemu_set_irq (etsec->rx_irq, rx); +qemu_set_irq (etsec->err_irq, err); +} +static uint64_t etsec_read (void *opaque,hwaddr addr,unsigned size) {eTSEC *etsec = opaque;@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC *etsec, etsec->regs[RBPTR0 + (reg_index -RBASE0 )].value = value & ~0x7 ; } -static void write_ievent (eTSEC *etsec, -eTSEC_Register *reg, -uint32_t reg_index, -uint32_t value) -{ -/* Write 1 to clear */ - reg->value &= ~value; - -if (!(reg->value & (IEVENT_TXF |IEVENT_TXF ))) { -qemu_irq_lower (etsec->tx_irq); - } -if (!(reg->value & (IEVENT_RXF |IEVENT_RXF ))) { -qemu_irq_lower (etsec->rx_irq); - } - -if (!(reg->value & (IEVENT_MAG |IEVENT_GTSC |IEVENT_GRSC |IEVENT_TXC | -IEVENT_RXC |IEVENT_BABR |IEVENT_BABT |IEVENT_LC | -IEVENT_CRL |IEVENT_FGPI |IEVENT_FIR |IEVENT_FIQ | -IEVENT_DPE |IEVENT_PERR |IEVENT_EBERR |IEVENT_TXE | -IEVENT_XFUN |IEVENT_BSY |IEVENT_MSRO |IEVENT_MMRD | -IEVENT_MMRW ))) { -qemu_irq_lower (etsec->err_irq); - } -} - static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index,@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful receive stop now */ etsec->regs[IEVENT ].value |=IEVENT_GRSC ; -if (etsec->regs[IMASK ].value &IMASK_GRSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC *etsec, }else {/* Graceful transmit stop now */ etsec->regs[IEVENT ].value |=IEVENT_GTSC ; -if (etsec->regs[IMASK ].value &IMASK_GTSCEN ) { -qemu_irq_raise (etsec->err_irq); - } +etsec_update_irq (etsec); } }@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,switch (reg_index) {case IEVENT : -write_ievent (etsec, reg, reg_index, value); +/* Write 1 to clear */ + reg->value &= ~value; + +etsec_update_irq (etsec); +break ; + +case IMASK : + reg->value = value; + +etsec_update_irq (etsec);break ;case DMACTRL :@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)MII_SR_EXTENDED_STATUS |MII_SR_100T2_HD_CAPS |MII_SR_100T2_FD_CAPS |MII_SR_10T_HD_CAPS |MII_SR_10T_FD_CAPS |MII_SR_100X_HD_CAPS |MII_SR_100X_FD_CAPS |MII_SR_100T4_CAPS ; + +etsec_update_irq (etsec); } static ssize_t etsec_receive(NetClientState *nc,hw/net/fsl_etsec/etsec.h +2
-0@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddr base,qemu_irq rx_irq, qemu_irq err_irq); +void etsec_update_irq (eTSEC *etsec); +void etsec_walk_tx_ring (eTSEC *etsec,int ring_nbr);void etsec_walk_rx_ring (eTSEC *etsec,int ring_nbr);ssize_t etsec_rx_ring_write (eTSEC *etsec,const uint8_t *buf,size_t size);hw/net/fsl_etsec/registers.h +10
-0@@ -74,6 +74,16 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[];#define IEVENT_RXC (1 << 30)#define IEVENT_BABR (1 << 31) +/* Mapping between interrupt pin and interrupt flags */ +#define IEVENT_RX_MASK (IEVENT_RXF | IEVENT_RXB) +#define IEVENT_TX_MASK (IEVENT_TXF | IEVENT_TXB) +#define IEVENT_ERR_MASK (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | \ + IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | \ + IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | \ + IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | \ + IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | \ + IEVENT_MMRW) +#define IMASK_RXFEN (1 << 7)#define IMASK_GRSCEN (1 << 8)#define IMASK_RXBEN (1 << 15)hw/net/fsl_etsec/rings.c +1
-11@@ -152,17 +152,7 @@ static void ievent_set(eTSEC *etsec, { etsec->regs[IEVENT ].value |= flags; -if ((flags &IEVENT_TXB && etsec->regs[IMASK ].value &IMASK_TXBEN ) - || (flags &IEVENT_TXF && etsec->regs[IMASK ].value &IMASK_TXFEN )) { -qemu_irq_raise (etsec->tx_irq); -RING_DEBUG ("%s Raise Tx IRQ\n" , __func__); - } - -if ((flags &IEVENT_RXB && etsec->regs[IMASK ].value &IMASK_RXBEN ) - || (flags &IEVENT_RXF && etsec->regs[IMASK ].value &IMASK_RXFEN )) { -qemu_irq_raise (etsec->rx_irq); -RING_DEBUG ("%s Raise Rx IRQ\n" , __func__); - } +etsec_update_irq (etsec); }static void tx_padding_and_crc (eTSEC *etsec,uint32_t min_frame_len)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson