aboutsummaryrefslogtreecommitdiff
path: root/hw/net/allwinner-sun8i-emac.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/net/allwinner-sun8i-emac.c')
-rw-r--r--hw/net/allwinner-sun8i-emac.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
index bf91803d65..ff611f18fb 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;
+ return (desc->status & DESC_STATUS_CTL) && (min_buf_size == 0 ||
+ (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_buf_size);
+}
- dma_memory_read(&s->dma_as, paddr, desc, sizeof(*desc));
+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));
+}
- if ((desc->status & DESC_STATUS_CTL) &&
- (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
- return paddr;
- } else {
- return 0;
- }
+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_get_desc(AwSun8iEmacState *s,
- FrameDescriptor *desc,
- uint32_t start_addr,
- size_t min_size)
+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 */