[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 18/39] hw/net/allwinner-sun8i-emac: traverse transmit queue using
From: |
Peter Maydell |
Subject: |
[PULL 18/39] hw/net/allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value |
Date: |
Fri, 12 Mar 2021 13:51:19 +0000 |
From: Niek Linnenbank <nieklinnenbank@gmail.com>
Currently the emulated EMAC for sun8i always traverses the transmit queue
from the head when transferring packets. It searches for a list of consecutive
descriptors whichs are flagged as ready for processing and transmits their
payloads
accordingly. The controller stops processing once it finds a descriptor that is
not
marked ready.
While the above behaviour works in most situations, it is not the same as the
actual
EMAC in hardware. Actual hardware uses the TX_CUR_DESC register value to keep
track
of the last position in the transmit queue and continues processing from that
position
when software triggers the start of DMA processing. The currently emulated
behaviour can
lead to packet loss on transmit when software fills the transmit queue with
ready
descriptors that overlap the tail of the circular list.
This commit modifies the emulated EMAC for sun8i such that it processes
the transmit queue using the TX_CUR_DESC register in the same way as hardware.
Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-id: 20210310195820.21950-2-nieklinnenbank@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/net/allwinner-sun8i-emac.c | 62 +++++++++++++++++++----------------
1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
index bf91803d65a..ff611f18fbd 100644
--- a/hw/net/allwinner-sun8i-emac.c
+++ b/hw/net/allwinner-sun8i-emac.c
@@ -339,35 +339,40 @@ static void
allwinner_sun8i_emac_update_irq(AwSun8iEmacState *s)
qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0);
}
-static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
- FrameDescriptor *desc,
- size_t min_size)
+static bool allwinner_sun8i_emac_desc_owned(FrameDescriptor *desc,
+ size_t min_buf_size)
{
- uint32_t paddr = desc->next;
-
- dma_memory_read(&s->dma_as, paddr, desc, sizeof(*desc));
-
- if ((desc->status & DESC_STATUS_CTL) &&
- (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
- return paddr;
- } else {
- return 0;
- }
+ return (desc->status & DESC_STATUS_CTL) && (min_buf_size == 0 ||
+ (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_buf_size);
}
-static uint32_t allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
- FrameDescriptor *desc,
- uint32_t start_addr,
- size_t min_size)
+static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
+ FrameDescriptor *desc,
+ uint32_t phys_addr)
+{
+ dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc));
+}
+
+static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
+ FrameDescriptor *desc)
+{
+ const uint32_t nxt = desc->next;
+ allwinner_sun8i_emac_get_desc(s, desc, nxt);
+ return nxt;
+}
+
+static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState *s,
+ FrameDescriptor *desc,
+ uint32_t start_addr,
+ size_t min_size)
{
uint32_t desc_addr = start_addr;
/* Note that the list is a cycle. Last entry points back to the head. */
while (desc_addr != 0) {
- dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc));
+ allwinner_sun8i_emac_get_desc(s, desc, desc_addr);
- if ((desc->status & DESC_STATUS_CTL) &&
- (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
+ if (allwinner_sun8i_emac_desc_owned(desc, min_size)) {
return desc_addr;
} else if (desc->next == start_addr) {
break;
@@ -383,14 +388,14 @@ static uint32_t
allwinner_sun8i_emac_rx_desc(AwSun8iEmacState *s,
FrameDescriptor *desc,
size_t min_size)
{
- return allwinner_sun8i_emac_get_desc(s, desc, s->rx_desc_curr, min_size);
+ return allwinner_sun8i_emac_find_desc(s, desc, s->rx_desc_curr, min_size);
}
static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
- FrameDescriptor *desc,
- size_t min_size)
+ FrameDescriptor *desc)
{
- return allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_head, min_size);
+ allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_curr);
+ return s->tx_desc_curr;
}
static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
@@ -470,7 +475,8 @@ static ssize_t allwinner_sun8i_emac_receive(NetClientState
*nc,
bytes_left -= desc_bytes;
/* Move to the next descriptor */
- s->rx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc, 64);
+ s->rx_desc_curr = allwinner_sun8i_emac_find_desc(s, &desc, desc.next,
+
AW_SUN8I_EMAC_MIN_PKT_SZ);
if (!s->rx_desc_curr) {
/* Not enough buffer space available */
s->int_sta |= INT_STA_RX_BUF_UA;
@@ -495,10 +501,10 @@ static void
allwinner_sun8i_emac_transmit(AwSun8iEmacState *s)
size_t transmitted = 0;
static uint8_t packet_buf[2048];
- s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc, 0);
+ s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc);
/* Read all transmit descriptors */
- while (s->tx_desc_curr != 0) {
+ while (allwinner_sun8i_emac_desc_owned(&desc, 0)) {
/* Read from physical memory into packet buffer */
bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
@@ -524,7 +530,7 @@ static void allwinner_sun8i_emac_transmit(AwSun8iEmacState
*s)
packet_bytes = 0;
transmitted++;
}
- s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc, 0);
+ s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc);
}
/* Raise transmit completed interrupt */
--
2.20.1
- [PULL 05/39] virtio-iommu: Handle non power of 2 range invalidations, (continued)
- [PULL 05/39] virtio-iommu: Handle non power of 2 range invalidations, Peter Maydell, 2021/03/12
- [PULL 07/39] hw/arm/smmuv3: Enforce invalidation on a power of two range, Peter Maydell, 2021/03/12
- [PULL 04/39] dma: Introduce dma_aligned_pow2_mask(), Peter Maydell, 2021/03/12
- [PULL 13/39] target/arm: Update find_last_active for PREDDESC, Peter Maydell, 2021/03/12
- [PULL 15/39] target/arm: Update CNTP for PREDDESC, Peter Maydell, 2021/03/12
- [PULL 08/39] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling, Peter Maydell, 2021/03/12
- [PULL 09/39] hw/arm/smmuv3: Uniformize sid traces, Peter Maydell, 2021/03/12
- [PULL 11/39] target/arm: Fix sve_zip_p vs odd vector lengths, Peter Maydell, 2021/03/12
- [PULL 21/39] tests/acceptance: update sunxi kernel from armbian to 5.10.16, Peter Maydell, 2021/03/12
- [PULL 14/39] target/arm: Update BRKA, BRKB, BRKN for PREDDESC, Peter Maydell, 2021/03/12
- [PULL 18/39] hw/net/allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value,
Peter Maydell <=
- [PULL 24/39] accel: kvm: Fix kvm_type invocation, Peter Maydell, 2021/03/12
- [PULL 27/39] hw/misc: Add NPCM7XX MFT Module, Peter Maydell, 2021/03/12
- [PULL 29/39] hw/arm: Connect PWM fans in NPCM7XX boards, Peter Maydell, 2021/03/12
- [PULL 35/39] hw/display/pxa2xx_lcd: Remove dest_width state field, Peter Maydell, 2021/03/12
- [PULL 26/39] hw/misc: Add GPIOs for duty in NPCM7xx PWM, Peter Maydell, 2021/03/12
- [PULL 34/39] hw/display/pxa2xx_lcd: Remove dead code for non-32-bpp surfaces, Peter Maydell, 2021/03/12
- [PULL 16/39] target/arm: Update WHILE for PREDDESC, Peter Maydell, 2021/03/12
- [PULL 23/39] hw/timer/sse-timer: Propagate eventual error in sse_timer_realize(), Peter Maydell, 2021/03/12
- [PULL 12/39] target/arm: Fix sve_punpk_p vs odd vector lengths, Peter Maydell, 2021/03/12
- [PULL 19/39] tests/acceptance/boot_linux_console: remove Armbian 19.11.3 bionic test for orangepi-pc machine, Peter Maydell, 2021/03/12