diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 8ef7995db60c6..83838c03d9734 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -996,6 +996,8 @@ struct macb_dma_desc_ptp { * of the frame * @mapping: DMA address of the skb's fragment buffer * @size: size of the DMA mapped buffer + * @skb_len: skb->len as handed over by the stack, before padding and + * software FCS, only set for the last buffer of the frame * @mapped_as_page: true when buffer was mapped with skb_frag_dma_map(), * false when buffer was mapped with dma_map_single() */ @@ -1003,6 +1005,7 @@ struct macb_tx_skb { struct sk_buff *skb; dma_addr_t mapping; size_t size; + unsigned int skb_len; bool mapped_as_page; }; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index b6e824531081e..31e003a937211 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1355,8 +1355,8 @@ static void macb_tx_error_task(struct work_struct *work) bp->dev->stats.tx_packets++; queue->stats.tx_packets++; packets++; - bp->dev->stats.tx_bytes += skb->len; - queue->stats.tx_bytes += skb->len; + bp->dev->stats.tx_bytes += tx_skb->skb_len; + queue->stats.tx_bytes += tx_skb->skb_len; bytes += skb->len; } } else { @@ -1483,8 +1483,8 @@ static int macb_tx_complete(struct macb_queue *queue, int budget) skb->data); bp->dev->stats.tx_packets++; queue->stats.tx_packets++; - bp->dev->stats.tx_bytes += skb->len; - queue->stats.tx_bytes += skb->len; + bp->dev->stats.tx_bytes += tx_skb->skb_len; + queue->stats.tx_bytes += tx_skb->skb_len; packets++; bytes += skb->len; } @@ -2262,7 +2262,8 @@ static void macb_poll_controller(struct net_device *dev) static unsigned int macb_tx_map(struct macb *bp, struct macb_queue *queue, struct sk_buff *skb, - unsigned int hdrlen) + unsigned int hdrlen, + unsigned int skb_len) { dma_addr_t mapping; unsigned int len, entry, i, tx_head = queue->tx_head; @@ -2351,6 +2352,7 @@ static unsigned int macb_tx_map(struct macb *bp, /* This is the last buffer of the frame: save socket buffer */ tx_skb->skb = skb; + tx_skb->skb_len = skb_len; /* Update TX ring: update buffer descriptors in reverse order * to avoid race condition @@ -2474,6 +2476,13 @@ static inline int macb_clear_csum(struct sk_buff *skb) if (skb->ip_summed != CHECKSUM_PARTIAL) return 0; + /* The hardware lacks the RFC 768 substitution of 0xffff for a + * UDP checksum that computes to zero, complete UDP in software. + */ + if (skb->csum_offset == offsetof(struct udphdr, check) && + !ptp_one_step_sync(skb)) + return skb_checksum_help(skb); + /* make sure we can modify the header */ if (unlikely(skb_cow_head(skb, 0))) return -1; @@ -2543,7 +2552,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) struct macb *bp = netdev_priv(dev); struct macb_queue *queue = &bp->queues[queue_index]; unsigned int desc_cnt, nr_frags, frag_size, f; - unsigned int hdrlen; + unsigned int hdrlen, skb_len; unsigned long flags; bool is_lso; netdev_tx_t ret = NETDEV_TX_OK; @@ -2553,6 +2562,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } + skb_len = skb->len; if (macb_pad_and_fcs(&skb, dev)) { dev_kfree_skb_any(skb); return ret; @@ -2618,7 +2628,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Map socket buffer for DMA transfer */ - if (!macb_tx_map(bp, queue, skb, hdrlen)) { + if (!macb_tx_map(bp, queue, skb, hdrlen, skb_len)) { dev_kfree_skb_any(skb); goto unlock; }