The device reports two Rx completion fields to the driver related to checksums: l2_csum and l4_csum_unnecessary. l2_csum is the ones' complement sum of the frame starting from the end of the ethernet header. l4_csum_unnecessary means the device validated the l4 checksum of the packet. This is only supported for tcp or udp in ipv4/ipv6/4-in-6/6-in-6. Report checksum none/complete/unnecessary counts via netdev qstats API. Signed-off-by: Daniel Zahka --- v2: - convert l2_csum with cpu_to_le16() before csum_unfold(), since the device reports it in network byte order and skb->csum was wrong on big-endian hosts --- drivers/net/ethernet/meta/mpnic/mpnic_csr.h | 2 ++ drivers/net/ethernet/meta/mpnic/mpnic_netdev.c | 14 ++++++++++- drivers/net/ethernet/meta/mpnic/mpnic_netdev.h | 3 +++ drivers/net/ethernet/meta/mpnic/mpnic_txrx.c | 34 ++++++++++++++++++++++++++ drivers/net/ethernet/meta/mpnic/mpnic_txrx.h | 3 +++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_csr.h b/drivers/net/ethernet/meta/mpnic/mpnic_csr.h index 62304be203e6..1c86f114ab0c 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_csr.h +++ b/drivers/net/ethernet/meta/mpnic/mpnic_csr.h @@ -60,6 +60,8 @@ enum { #define MPNIC_RCD_AL_PAGE_FIN DESC_BIT(53) /* Metadata Completion Descriptors */ +#define MPNIC_RCD_META_L2_CSUM DESC_GENMASK(47, 32) +#define MPNIC_RCD_META_L4_CSUM_UNNECESSARY DESC_BIT(52) #define MPNIC_RCD_META_ERR_MAC_EOP DESC_BIT(53) #define MPNIC_RCD_META_ERR_TRUNCATED_FRAME DESC_BIT(54) #define MPNIC_RCD_META_UNCORRECTABLE_ERR_MASK \ diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_netdev.c b/drivers/net/ethernet/meta/mpnic/mpnic_netdev.c index d386672738fc..35173f8999cb 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_netdev.c +++ b/drivers/net/ethernet/meta/mpnic/mpnic_netdev.c @@ -167,10 +167,12 @@ static void mpnic_get_queue_stats_rx(struct net_device *dev, int idx, { struct mpnic_net *mpn = netdev_priv(dev); struct mpnic_ring *rxr = mpn->rx[idx]; + u64 csum_unnecessary, csum_complete; u64 bytes, packets, alloc_failed; struct mpnic_queue_stats *stats; struct mpnic_q_triad *qt; unsigned int start; + u64 csum_none; if (!rxr) return; @@ -181,6 +183,9 @@ static void mpnic_get_queue_stats_rx(struct net_device *dev, int idx, bytes = u64_stats_read(&stats->rcq.bytes); packets = u64_stats_read(&stats->rcq.packets); alloc_failed = u64_stats_read(&stats->rcq.alloc_failed); + csum_complete = u64_stats_read(&stats->rcq.csum_complete); + csum_unnecessary = u64_stats_read(&stats->rcq.csum_unnecessary); + csum_none = u64_stats_read(&stats->rcq.csum_none); } while (u64_stats_fetch_retry(&stats->syncp, start)); qt = container_of(rxr, struct mpnic_q_triad, cmpl); @@ -190,6 +195,9 @@ static void mpnic_get_queue_stats_rx(struct net_device *dev, int idx, rx->bytes = bytes; rx->packets = packets; rx->alloc_fail = alloc_failed; + rx->csum_complete = csum_complete; + rx->csum_unnecessary = csum_unnecessary; + rx->csum_none = csum_none; } static void mpnic_get_queue_stats_tx(struct net_device *dev, int idx, @@ -248,6 +256,9 @@ static void mpnic_get_base_stats(struct net_device *dev, rx->bytes = base->rx.bytes; rx->packets = base->rx.packets; rx->alloc_fail = base->rx.alloc_failed; + rx->csum_complete = base->rx.csum_complete; + rx->csum_unnecessary = base->rx.csum_unnecessary; + rx->csum_none = base->rx.csum_none; } static const struct netdev_stat_ops mpnic_stat_ops = { @@ -310,7 +321,8 @@ struct net_device *mpnic_netdev_alloc(struct mpnic_dev *mpd) netdev->features |= NETIF_F_SG | - NETIF_F_HW_CSUM; + NETIF_F_HW_CSUM | + NETIF_F_RXCSUM; netdev->hw_features |= netdev->features; netdev->vlan_features |= netdev->features; diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_netdev.h b/drivers/net/ethernet/meta/mpnic/mpnic_netdev.h index 94f7a3355c5c..76ec9811e79e 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_netdev.h +++ b/drivers/net/ethernet/meta/mpnic/mpnic_netdev.h @@ -26,6 +26,9 @@ struct mpnic_base_stats { u64 dropped; u64 alloc_failed; u64 errors; + u64 csum_complete; + u64 csum_unnecessary; + u64 csum_none; } rx; unsigned int num_tx_queues; diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c index 65de6d999d54..a35ce8998409 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c +++ b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c @@ -655,9 +655,34 @@ static void mpnic_put_pkt_buff(struct mpnic_pkt_ctxt *ctxt, bool napi) page_pool_put_full_page(page->pp, page, napi); } +static void mpnic_rx_csum(u64 rcd, struct sk_buff *skb, + unsigned int *csum_complete, + unsigned int *csum_unnecessary, + unsigned int *csum_none) +{ + skb_checksum_none_assert(skb); + + if (!(skb->dev->features & NETIF_F_RXCSUM)) { + (*csum_none)++; + return; + } + + if (FIELD_GET(MPNIC_RCD_META_L4_CSUM_UNNECESSARY, rcd)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + (*csum_unnecessary)++; + } else { + u16 csum = FIELD_GET(MPNIC_RCD_META_L2_CSUM, rcd); + + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = csum_unfold((__force __sum16)cpu_to_le16(csum)); + (*csum_complete)++; + } +} + static int mpnic_clean_rcq(struct mpnic_napi_vector *nv, struct mpnic_q_triad *qt, int budget) { + unsigned int csum_complete = 0, csum_unnecessary = 0, csum_none = 0; unsigned int packets = 0, bytes = 0, dropped = 0, errors = 0; struct mpnic_ring *rcq = &qt->cmpl; struct mpnic_rcq_state *state; @@ -700,6 +725,8 @@ static int mpnic_clean_rcq(struct mpnic_napi_vector *nv, } if (likely(skb)) { + mpnic_rx_csum(rcd, skb, &csum_complete, + &csum_unnecessary, &csum_none); napi_gro_receive(&nv->napi, skb); } else { mpnic_put_pkt_buff(&state->pkt, true); @@ -732,6 +759,9 @@ static int mpnic_clean_rcq(struct mpnic_napi_vector *nv, u64_stats_add(&rcq->stats.rcq.dropped, dropped); u64_stats_add(&rcq->stats.rcq.alloc_failed, alloc_failed); u64_stats_add(&rcq->stats.rcq.errors, errors); + u64_stats_add(&rcq->stats.rcq.csum_complete, csum_complete); + u64_stats_add(&rcq->stats.rcq.csum_unnecessary, csum_unnecessary); + u64_stats_add(&rcq->stats.rcq.csum_none, csum_none); u64_stats_update_end(&rcq->stats.syncp); /* Allocate buffers, force dma_wmb(), and then start writing tails */ @@ -806,6 +836,10 @@ static void mpnic_aggregate_ring_rcq_counters(struct mpnic_base_stats *base, base->rx.dropped += u64_stats_read(&rcq->stats.rcq.dropped); base->rx.alloc_failed += u64_stats_read(&rcq->stats.rcq.alloc_failed); base->rx.errors += u64_stats_read(&rcq->stats.rcq.errors); + base->rx.csum_complete += u64_stats_read(&rcq->stats.rcq.csum_complete); + base->rx.csum_unnecessary += + u64_stats_read(&rcq->stats.rcq.csum_unnecessary); + base->rx.csum_none += u64_stats_read(&rcq->stats.rcq.csum_none); } static struct mpnic_base_stats *mpnic_base_stats_prepare(struct mpnic_net *mpn) diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h index a6dff9dc32d6..714f09f4160e 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h +++ b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h @@ -103,6 +103,9 @@ struct mpnic_queue_stats { u64_stats_t dropped; u64_stats_t alloc_failed; u64_stats_t errors; + u64_stats_t csum_complete; + u64_stats_t csum_unnecessary; + u64_stats_t csum_none; } rcq; struct { u64_stats_t alloc_failed; -- 2.52.0