qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 2/2] hw/net/allwinner-sun8i-emac: traverse transmit queue usi


From: Philippe Mathieu-Daudé
Subject: Re: [PATCH 2/2] hw/net/allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value
Date: Fri, 12 Feb 2021 00:29:54 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0

On 2/11/21 11:00 PM, Niek Linnenbank wrote:
> 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>
> ---
>  hw/net/allwinner-sun8i-emac.c | 58 +++++++++++++++++++----------------
>  1 file changed, 32 insertions(+), 26 deletions(-)

LGTM but I'd feel safer with another review on top.
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
> index 042768922c..e586c147e5 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 */
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]