Le 24/03/2016 15:37, Cyrille Pitchen a écrit :
> This patch removes two BUG_ON() used to notify about RX queue corruptions
> on macb (not gem) hardware without actually handling the error.
> 
> The new code skips corrupted frames but still processes faultless frames.
> Then it resets the RX queue before restarting the reception from a clean
> state.
> 
> This patch is a rework of an older patch proposed by Neil Armstrong:
> http://patchwork.ozlabs.org/patch/371525/
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>

Thanks for this rework of Neil's patch that was standing for a long time
in my backlog ;-).

Acked-by: Nicolas Ferre <nicolas.fe...@atmel.com>

Bye,

> ---
>  drivers/net/ethernet/cadence/macb.c | 59 
> ++++++++++++++++++++++++++++++-------
>  1 file changed, 49 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/ethernet/cadence/macb.c 
> b/drivers/net/ethernet/cadence/macb.c
> index 6619178ed77b..39447a337149 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -917,7 +917,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int 
> first_frag,
>               unsigned int frag_len = bp->rx_buffer_size;
>  
>               if (offset + frag_len > len) {
> -                     BUG_ON(frag != last_frag);
> +                     if (unlikely(frag != last_frag)) {
> +                             dev_kfree_skb_any(skb);
> +                             return -1;
> +                     }
>                       frag_len = len - offset;
>               }
>               skb_copy_to_linear_data_offset(skb, offset,
> @@ -945,11 +948,26 @@ static int macb_rx_frame(struct macb *bp, unsigned int 
> first_frag,
>       return 0;
>  }
>  
> +static inline void macb_init_rx_ring(struct macb *bp)
> +{
> +     int i;
> +     dma_addr_t addr;
> +
> +     addr = bp->rx_buffers_dma;
> +     for (i = 0; i < RX_RING_SIZE; i++) {
> +             bp->rx_ring[i].addr = addr;
> +             bp->rx_ring[i].ctrl = 0;
> +             addr += bp->rx_buffer_size;
> +     }
> +     bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
> +}
> +
>  static int macb_rx(struct macb *bp, int budget)
>  {
>       int received = 0;
>       unsigned int tail;
>       int first_frag = -1;
> +     int reset_rx_queue = 0;
>  
>       for (tail = bp->rx_tail; budget > 0; tail++) {
>               struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
> @@ -972,10 +990,18 @@ static int macb_rx(struct macb *bp, int budget)
>  
>               if (ctrl & MACB_BIT(RX_EOF)) {
>                       int dropped;
> -                     BUG_ON(first_frag == -1);
> +
> +                     if (unlikely(first_frag == -1)) {
> +                             reset_rx_queue = 1;
> +                             continue;
> +                     }
>  
>                       dropped = macb_rx_frame(bp, first_frag, tail);
>                       first_frag = -1;
> +                     if (unlikely(dropped < 0)) {
> +                             reset_rx_queue = 1;
> +                             continue;
> +                     }
>                       if (!dropped) {
>                               received++;
>                               budget--;
> @@ -983,6 +1009,26 @@ static int macb_rx(struct macb *bp, int budget)
>               }
>       }
>  
> +     if (unlikely(reset_rx_queue)) {
> +             unsigned long flags;
> +             u32 ctrl;
> +
> +             netdev_err(bp->dev, "RX queue corruption: reset it\n");
> +
> +             spin_lock_irqsave(&bp->lock, flags);
> +
> +             ctrl = macb_readl(bp, NCR);
> +             macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
> +
> +             macb_init_rx_ring(bp);
> +             macb_writel(bp, RBQP, bp->rx_ring_dma);
> +
> +             macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
> +
> +             spin_unlock_irqrestore(&bp->lock, flags);
> +             return received;
> +     }
> +
>       if (first_frag != -1)
>               bp->rx_tail = first_frag;
>       else
> @@ -1523,15 +1569,8 @@ static void gem_init_rings(struct macb *bp)
>  static void macb_init_rings(struct macb *bp)
>  {
>       int i;
> -     dma_addr_t addr;
>  
> -     addr = bp->rx_buffers_dma;
> -     for (i = 0; i < RX_RING_SIZE; i++) {
> -             bp->rx_ring[i].addr = addr;
> -             bp->rx_ring[i].ctrl = 0;
> -             addr += bp->rx_buffer_size;
> -     }
> -     bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
> +     macb_init_rx_ring(bp);
>  
>       for (i = 0; i < TX_RING_SIZE; i++) {
>               bp->queues[0].tx_ring[i].addr = 0;
> 


-- 
Nicolas Ferre

Reply via email to