aboutsummaryrefslogtreecommitdiff
path: root/hw/net/fsl_etsec/etsec.c
diff options
context:
space:
mode:
authorMichael Davidsaver <mdavidsaver@gmail.com>2018-07-12 14:00:52 -0700
committerDavid Gibson <david@gibson.dropbear.id.au>2018-07-16 11:18:09 +1000
commitfd8e3381a00feb1e9878f6a3e2de11295f041f67 (patch)
treef203043baa4c09ee0679fbc0702514cb0a3272e0 /hw/net/fsl_etsec/etsec.c
parentb585395b655a6c1f9d9ebf1f0890e76d0708eed6 (diff)
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. Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/net/fsl_etsec/etsec.c')
-rw-r--r--hw/net/fsl_etsec/etsec.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 9da1932970..0b66274ce3 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -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,