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..d4a888b7b03ab 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1355,8 +1356,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 +1484,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 +2263,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 +2353,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 @@ -2440,6 +2443,17 @@ static netdev_features_t macb_features_check(struct sk_buff *skb, unsigned int nr_frags, f; unsigned int hdrlen; + /* The GEM skips the RFC 768 substitution of 0xffff for a zero + * UDPv4 checksum (UDPv6 is handled), have the core complete + * UDPv4 in software. One-step PTP sync frames keep the hardware + * path, the MAC rewrites their timestamp in flight. + */ + if (skb->ip_summed == CHECKSUM_PARTIAL && + vlan_get_protocol(skb) == htons(ETH_P_IP) && + skb->csum_offset == offsetof(struct udphdr, check) && + !ptp_one_step_sync(skb)) + features &= ~NETIF_F_CSUM_MASK; + /* Validate LSO compatibility */ /* there is only one buffer or protocol is not UDP */ @@ -2543,7 +2557,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 +2567,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 +2633,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; }