From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out30-112.freemail.mail.aliyun.com (out30-112.freemail.mail.aliyun.com [115.124.30.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 69B6A373C06 for ; Thu, 12 Mar 2026 02:28:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.112 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773282492; cv=none; b=pu6PYK39s+bYDYvr0U+OkD+RsUFLrzz4KulBIGS31OWtEWo7/YAhvgLCvAD6L0AY7nmOnJCraHtDT++yAfwcnLYxVwqqrh36US3P1w3eXn/HjOZg1ZYCzYIjhoI4LbUTJ1P9Cb0Nbs05iN/QVgK6T5qfGpRimy6l6t6C1DvvaiA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773282492; c=relaxed/simple; bh=BS4gGxy6ck7i03/V6Iorm25IWoj54igQ7QFieuJBtks=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=OeHQLAi4ckTYMiheb5MTCiQwhvbRpUL+ekOxf9YJqXM+TXRZK/T7H0Jt3GeI3tUplho16YhXgG5yJSbPxybcMYkRSBawpsWufy6jTh7rqW+u2mXELamnyfLaPVwrF80KTHy7NYRc0aaKD23jcgM1ZpYyTbkr5ORjczy0g3b/djI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=PAFg4aqq; arc=none smtp.client-ip=115.124.30.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="PAFg4aqq" DKIM-Signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1773282487; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=1PSPcFYoQ51+LX8HRHkzQP2mthd9P/G4W2K8R/osQI8=; b=PAFg4aqqcsSLfdkFW4D1Oey6YJz4W9rCrlEekSCQkb/Z1eu0ql4NS5VyPEiR+llvuXw4T7eFpkdqZOA/65QSMZn2ciiAQvURHdaIs4RVNlHtGxGtDRiXQVeUwC8wJqhb4g2wm88EOOfAVl1OIRRD8tVNW8AMQyiq5PBO6G51hlo= Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0X-mnpfA_1773282486 cluster:ay36) by smtp.aliyun-inc.com; Thu, 12 Mar 2026 10:28:07 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Xuan Zhuo , Wen Gu , Philo Lu , Vadim Fedorenko , Dong Yibo , Heiner Kallweit , Dust Li , Andrew Lunn Subject: [PATCH net-next v29 7/8] eea: introduce ethtool support Date: Thu, 12 Mar 2026 10:28:00 +0800 Message-Id: <20260312022801.90699-8-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20260312022801.90699-1-xuanzhuo@linux.alibaba.com> References: <20260312022801.90699-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 2825a2ca1173 Content-Transfer-Encoding: 8bit Add basic driver framework for the Alibaba Elastic Ethernet Adapter(EEA). This commit introduces ethtool support. Reviewed-by: Andrew Lunn Reviewed-by: Dust Li Reviewed-by: Philo Lu Signed-off-by: Wen Gu Signed-off-by: Xuan Zhuo --- drivers/net/ethernet/alibaba/eea/Makefile | 1 + .../net/ethernet/alibaba/eea/eea_ethtool.c | 243 ++++++++++++++++++ .../net/ethernet/alibaba/eea/eea_ethtool.h | 49 ++++ drivers/net/ethernet/alibaba/eea/eea_net.c | 1 + drivers/net/ethernet/alibaba/eea/eea_net.h | 5 + drivers/net/ethernet/alibaba/eea/eea_rx.c | 27 +- drivers/net/ethernet/alibaba/eea/eea_tx.c | 24 +- 7 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/alibaba/eea/eea_ethtool.c create mode 100644 drivers/net/ethernet/alibaba/eea/eea_ethtool.h diff --git a/drivers/net/ethernet/alibaba/eea/Makefile b/drivers/net/ethernet/alibaba/eea/Makefile index fa34a005fa01..8f8fbb8d2d9a 100644 --- a/drivers/net/ethernet/alibaba/eea/Makefile +++ b/drivers/net/ethernet/alibaba/eea/Makefile @@ -4,5 +4,6 @@ eea-y := eea_ring.o \ eea_net.o \ eea_pci.o \ eea_adminq.o \ + eea_ethtool.o \ eea_tx.o \ eea_rx.o diff --git a/drivers/net/ethernet/alibaba/eea/eea_ethtool.c b/drivers/net/ethernet/alibaba/eea/eea_ethtool.c new file mode 100644 index 000000000000..011a5532f8c2 --- /dev/null +++ b/drivers/net/ethernet/alibaba/eea/eea_ethtool.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Alibaba Elastic Ethernet Adapter. + * + * Copyright (C) 2025 Alibaba Inc. + */ + +#include +#include +#include + +#include "eea_adminq.h" + +struct eea_stat_desc { + char desc[ETH_GSTRING_LEN]; + size_t offset; +}; + +#define EEA_TX_STAT(m) {#m, offsetof(struct eea_tx_stats, m)} +#define EEA_RX_STAT(m) {#m, offsetof(struct eea_rx_stats, m)} + +static const struct eea_stat_desc eea_rx_stats_desc[] = { + EEA_RX_STAT(descs), + EEA_RX_STAT(kicks), +}; + +static const struct eea_stat_desc eea_tx_stats_desc[] = { + EEA_TX_STAT(descs), + EEA_TX_STAT(kicks), +}; + +#define EEA_TX_STATS_LEN ARRAY_SIZE(eea_tx_stats_desc) +#define EEA_RX_STATS_LEN ARRAY_SIZE(eea_rx_stats_desc) + +static void eea_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct eea_net *enet = netdev_priv(netdev); + struct eea_device *edev = enet->edev; + + strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + strscpy(info->bus_info, eea_pci_name(edev), sizeof(info->bus_info)); +} + +static void eea_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *extack) +{ + struct eea_net *enet = netdev_priv(netdev); + + ring->rx_max_pending = enet->cfg_hw.rx_ring_depth; + ring->tx_max_pending = enet->cfg_hw.tx_ring_depth; + ring->rx_pending = enet->cfg.rx_ring_depth; + ring->tx_pending = enet->cfg.tx_ring_depth; + + kernel_ring->tcp_data_split = enet->cfg.split_hdr ? + ETHTOOL_TCP_DATA_SPLIT_ENABLED : + ETHTOOL_TCP_DATA_SPLIT_DISABLED; +} + +static int eea_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *extack) +{ + struct eea_net *enet = netdev_priv(netdev); + struct eea_net_init_ctx ctx; + bool need_update = false; + struct eea_net_cfg *cfg; + bool sh; + + eea_init_ctx(enet, &ctx); + + cfg = &ctx.cfg; + + if (ring->rx_pending != cfg->rx_ring_depth) + need_update = true; + + if (ring->tx_pending != cfg->tx_ring_depth) + need_update = true; + + sh = kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED; + if (sh != !!(cfg->split_hdr)) + need_update = true; + + if (!need_update) + return 0; + + cfg->rx_ring_depth = ring->rx_pending; + cfg->tx_ring_depth = ring->tx_pending; + + cfg->split_hdr = sh ? enet->cfg_hw.split_hdr : 0; + + return eea_reset_hw_resources(enet, &ctx); +} + +static int eea_set_channels(struct net_device *netdev, + struct ethtool_channels *channels) +{ + struct eea_net *enet = netdev_priv(netdev); + u16 queue_pairs = channels->combined_count; + struct eea_net_init_ctx ctx; + struct eea_net_cfg *cfg; + + eea_init_ctx(enet, &ctx); + + cfg = &ctx.cfg; + + cfg->rx_ring_num = queue_pairs; + cfg->tx_ring_num = queue_pairs; + + return eea_reset_hw_resources(enet, &ctx); +} + +static void eea_get_channels(struct net_device *netdev, + struct ethtool_channels *channels) +{ + struct eea_net *enet = netdev_priv(netdev); + + channels->combined_count = enet->cfg.rx_ring_num; + channels->max_combined = enet->cfg_hw.rx_ring_num; +} + +static void eea_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + struct eea_net *enet = netdev_priv(netdev); + u8 *p = data; + u32 i, j; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < enet->cfg.rx_ring_num; i++) { + for (j = 0; j < EEA_RX_STATS_LEN; j++) + ethtool_sprintf(&p, "rx%u_%s", i, + eea_rx_stats_desc[j].desc); + } + + for (i = 0; i < enet->cfg.tx_ring_num; i++) { + for (j = 0; j < EEA_TX_STATS_LEN; j++) + ethtool_sprintf(&p, "tx%u_%s", i, + eea_tx_stats_desc[j].desc); + } +} + +static int eea_get_sset_count(struct net_device *netdev, int sset) +{ + struct eea_net *enet = netdev_priv(netdev); + + if (sset != ETH_SS_STATS) + return -EOPNOTSUPP; + + return enet->cfg.rx_ring_num * EEA_RX_STATS_LEN + + enet->cfg.tx_ring_num * EEA_TX_STATS_LEN; +} + +static void eea_stats_fill_for_q(struct u64_stats_sync *syncp, u32 num, + const struct eea_stat_desc *desc, + u64 *data, u32 idx) +{ + void *stats_base = syncp; + u32 start, i; + + do { + start = u64_stats_fetch_begin(syncp); + for (i = 0; i < num; i++) + data[idx + i] = + u64_stats_read(stats_base + desc[i].offset); + + } while (u64_stats_fetch_retry(syncp, start)); +} + +static void eea_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct eea_net *enet = netdev_priv(netdev); + u32 i, idx = 0; + + ASSERT_RTNL(); + + if (enet->rx) { + for (i = 0; i < enet->cfg.rx_ring_num; i++) { + struct eea_net_rx *rx = enet->rx[i]; + + eea_stats_fill_for_q(&rx->stats.syncp, EEA_RX_STATS_LEN, + eea_rx_stats_desc, data, idx); + + idx += EEA_RX_STATS_LEN; + } + } + + if (enet->tx) { + for (i = 0; i < enet->cfg.tx_ring_num; i++) { + struct eea_net_tx *tx = &enet->tx[i]; + + eea_stats_fill_for_q(&tx->stats.syncp, EEA_TX_STATS_LEN, + eea_tx_stats_desc, data, idx); + + idx += EEA_TX_STATS_LEN; + } + } +} + +void eea_update_rx_stats(struct eea_rx_stats *rx_stats, + struct eea_rx_ctx_stats *stats) +{ + u64_stats_update_begin(&rx_stats->syncp); + u64_stats_add(&rx_stats->descs, stats->descs); + u64_stats_add(&rx_stats->packets, stats->packets); + u64_stats_add(&rx_stats->bytes, stats->bytes); + u64_stats_add(&rx_stats->drops, stats->drops); + u64_stats_add(&rx_stats->split_hdr_bytes, stats->split_hdr_bytes); + u64_stats_add(&rx_stats->split_hdr_packets, stats->split_hdr_packets); + u64_stats_add(&rx_stats->length_errors, stats->length_errors); + u64_stats_update_end(&rx_stats->syncp); +} + +static int eea_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct eea_net *enet = netdev_priv(netdev); + + cmd->base.speed = enet->speed; + cmd->base.duplex = enet->duplex; + cmd->base.port = PORT_OTHER; + + return 0; +} + +const struct ethtool_ops eea_ethtool_ops = { + .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT, + .get_drvinfo = eea_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ringparam = eea_get_ringparam, + .set_ringparam = eea_set_ringparam, + .set_channels = eea_set_channels, + .get_channels = eea_get_channels, + .get_strings = eea_get_strings, + .get_sset_count = eea_get_sset_count, + .get_ethtool_stats = eea_get_ethtool_stats, + .get_link_ksettings = eea_get_link_ksettings, +}; diff --git a/drivers/net/ethernet/alibaba/eea/eea_ethtool.h b/drivers/net/ethernet/alibaba/eea/eea_ethtool.h new file mode 100644 index 000000000000..a437065d1cab --- /dev/null +++ b/drivers/net/ethernet/alibaba/eea/eea_ethtool.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Driver for Alibaba Elastic Ethernet Adapter. + * + * Copyright (C) 2025 Alibaba Inc. + */ + +#ifndef __EEA_ETHTOOL_H__ +#define __EEA_ETHTOOL_H__ + +struct eea_tx_stats { + struct u64_stats_sync syncp; + u64_stats_t descs; + u64_stats_t packets; + u64_stats_t bytes; + u64_stats_t drops; + u64_stats_t kicks; +}; + +struct eea_rx_ctx_stats { + u64 descs; + u64 packets; + u64 bytes; + u64 drops; + u64 split_hdr_bytes; + u64 split_hdr_packets; + + u64 length_errors; +}; + +struct eea_rx_stats { + struct u64_stats_sync syncp; + u64_stats_t descs; + u64_stats_t packets; + u64_stats_t bytes; + u64_stats_t drops; + u64_stats_t kicks; + u64_stats_t split_hdr_bytes; + u64_stats_t split_hdr_packets; + + u64_stats_t length_errors; +}; + +void eea_update_rx_stats(struct eea_rx_stats *rx_stats, + struct eea_rx_ctx_stats *stats); + +extern const struct ethtool_ops eea_ethtool_ops; + +#endif diff --git a/drivers/net/ethernet/alibaba/eea/eea_net.c b/drivers/net/ethernet/alibaba/eea/eea_net.c index 10120b45af06..9d4ac6729d46 100644 --- a/drivers/net/ethernet/alibaba/eea/eea_net.c +++ b/drivers/net/ethernet/alibaba/eea/eea_net.c @@ -587,6 +587,7 @@ static struct eea_net *eea_netdev_alloc(struct eea_device *edev, u32 pairs) } netdev->netdev_ops = &eea_netdev; + netdev->ethtool_ops = &eea_ethtool_ops; SET_NETDEV_DEV(netdev, edev->dma_dev); enet = netdev_priv(netdev); diff --git a/drivers/net/ethernet/alibaba/eea/eea_net.h b/drivers/net/ethernet/alibaba/eea/eea_net.h index 5a607947a76e..fa14976aa335 100644 --- a/drivers/net/ethernet/alibaba/eea/eea_net.h +++ b/drivers/net/ethernet/alibaba/eea/eea_net.h @@ -12,6 +12,7 @@ #include #include "eea_adminq.h" +#include "eea_ethtool.h" #include "eea_ring.h" #define EEA_VER_MAJOR 1 @@ -33,6 +34,8 @@ struct eea_net_tx { u32 index; char name[16]; + + struct eea_tx_stats stats; }; struct eea_rx_meta { @@ -85,6 +88,8 @@ struct eea_net_rx { struct napi_struct *napi; + struct eea_rx_stats stats; + char name[16]; struct eea_net_rx_pkt_ctx pkt; diff --git a/drivers/net/ethernet/alibaba/eea/eea_rx.c b/drivers/net/ethernet/alibaba/eea/eea_rx.c index 6b8f83ad4cba..82025abf611a 100644 --- a/drivers/net/ethernet/alibaba/eea/eea_rx.c +++ b/drivers/net/ethernet/alibaba/eea/eea_rx.c @@ -30,6 +30,8 @@ struct eea_rx_ctx { u32 frame_sz; struct eea_rx_meta *meta; + + struct eea_rx_ctx_stats stats; }; static struct eea_rx_meta *eea_rx_meta_get(struct eea_net_rx *rx) @@ -204,6 +206,7 @@ static int eea_harden_check_overflow(struct eea_rx_ctx *ctx, if (unlikely(ctx->len > max_len)) { pr_debug("%s: rx error: len %u exceeds truesize %u\n", enet->netdev->name, ctx->len, max_len); + ++ctx->stats.length_errors; return -EINVAL; } @@ -222,6 +225,7 @@ static int eea_harden_check_size(struct eea_rx_ctx *ctx, struct eea_net *enet) if (unlikely(ctx->hdr_len < ETH_HLEN)) { pr_debug("%s: short hdr %u\n", enet->netdev->name, ctx->hdr_len); + ++ctx->stats.length_errors; return -EINVAL; } @@ -229,6 +233,7 @@ static int eea_harden_check_size(struct eea_rx_ctx *ctx, struct eea_net *enet) pr_debug("%s: rx error: hdr len %u exceeds hdr buffer size %u\n", enet->netdev->name, ctx->hdr_len, enet->cfg.split_hdr); + ++ctx->stats.length_errors; return -EINVAL; } @@ -237,6 +242,7 @@ static int eea_harden_check_size(struct eea_rx_ctx *ctx, struct eea_net *enet) if (unlikely(ctx->len < ETH_HLEN)) { pr_debug("%s: short packet %u\n", enet->netdev->name, ctx->len); + ++ctx->stats.length_errors; return -EINVAL; } @@ -378,6 +384,7 @@ static int process_remain_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx) err: dev_kfree_skb(rx->pkt.head_skb); + ++ctx->stats.drops; rx->pkt.do_drop = true; rx->pkt.head_skb = NULL; return 0; @@ -406,6 +413,7 @@ static int process_first_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx) return 0; err: + ++ctx->stats.drops; rx->pkt.do_drop = true; return 0; } @@ -456,6 +464,8 @@ static int eea_rx_desc_to_ctx(struct eea_net_rx *rx, if (ctx->flags & EEA_DESC_F_SPLIT_HDR) { ctx->hdr_len = le16_to_cpu(desc->len_ex) & EEA_RX_CDESC_HDR_LEN_MASK; + ctx->stats.split_hdr_bytes += ctx->hdr_len; + ++ctx->stats.split_hdr_packets; } ctx->more = ctx->flags & EEA_RING_DESC_F_MORE; @@ -507,6 +517,7 @@ static int eea_cleanrx(struct eea_net_rx *rx, int budget, if (!ctx->more && rx->pkt.head_skb) { eea_submit_skb(rx, rx->pkt.head_skb, desc); + ctx->stats.bytes += rx->pkt.recv_len; ++packets; } @@ -514,17 +525,20 @@ static int eea_cleanrx(struct eea_net_rx *rx, int budget, eea_rx_meta_put(rx, meta); ack: ering_cq_ack_desc(rx->ering, 1); + ++ctx->stats.descs; if (!ctx->more) memset(&rx->pkt, 0, sizeof(rx->pkt)); } + ctx->stats.packets = packets; + return packets; } static bool eea_rx_post(struct eea_net *enet, struct eea_net_rx *rx) { - u32 tailroom, headroom, room, len; + u32 tailroom, headroom, room, flags, len; struct eea_rx_meta *meta; struct eea_rx_desc *desc; int err = 0, num = 0; @@ -564,9 +578,14 @@ static bool eea_rx_post(struct eea_net *enet, struct eea_net_rx *rx) ++num; } - if (num) + if (num) { ering_kick(rx->ering); + flags = u64_stats_update_begin_irqsave(&rx->stats.syncp); + u64_stats_inc(&rx->stats.kicks); + u64_stats_update_end_irqrestore(&rx->stats.syncp, flags); + } + /* true means busy, napi should be called again. */ return !!err; } @@ -588,6 +607,8 @@ static int eea_poll(struct napi_struct *napi, int budget) if (rx->ering->num_free > budget) busy |= eea_rx_post(enet, rx); + eea_update_rx_stats(&rx->stats, &ctx.stats); + busy |= received >= budget; if (busy) @@ -723,6 +744,8 @@ struct eea_net_rx *eea_alloc_rx(struct eea_net_init_ctx *ctx, u32 idx) rx->index = idx; snprintf(rx->name, sizeof(rx->name), "rx.%u", idx); + u64_stats_init(&rx->stats.syncp); + /* ering */ ering = ering_alloc(idx * 2, ctx->cfg.rx_ring_depth, ctx->edev, ctx->cfg.rx_sq_desc_size, diff --git a/drivers/net/ethernet/alibaba/eea/eea_tx.c b/drivers/net/ethernet/alibaba/eea/eea_tx.c index ddb744cbb1a9..4c4c314cc7f9 100644 --- a/drivers/net/ethernet/alibaba/eea/eea_tx.c +++ b/drivers/net/ethernet/alibaba/eea/eea_tx.c @@ -127,6 +127,13 @@ static u32 eea_clean_tx(struct eea_net_tx *tx, int budget) ering_cq_ack_desc(tx->ering, desc_n); } + if (stats.packets) { + u64_stats_update_begin(&tx->stats.syncp); + u64_stats_add(&tx->stats.bytes, stats.bytes); + u64_stats_add(&tx->stats.packets, stats.packets); + u64_stats_update_end(&tx->stats.syncp); + } + return stats.packets; } @@ -261,6 +268,10 @@ static int eea_tx_post_skb(struct eea_net_tx *tx, struct sk_buff *skb) meta->num = shinfo->nr_frags + 1; ering_sq_commit_desc(tx->ering); + u64_stats_update_begin(&tx->stats.syncp); + u64_stats_add(&tx->stats.descs, meta->num); + u64_stats_update_end(&tx->stats.syncp); + return 0; err_cancel: @@ -273,6 +284,10 @@ static int eea_tx_post_skb(struct eea_net_tx *tx, struct sk_buff *skb) static void eea_tx_kick(struct eea_net_tx *tx) { ering_kick(tx->ering); + + u64_stats_update_begin(&tx->stats.syncp); + u64_stats_inc(&tx->stats.kicks); + u64_stats_update_end(&tx->stats.syncp); } netdev_tx_t eea_tx_xmit(struct sk_buff *skb, struct net_device *netdev) @@ -288,8 +303,13 @@ netdev_tx_t eea_tx_xmit(struct sk_buff *skb, struct net_device *netdev) skb_tx_timestamp(skb); err = eea_tx_post_skb(tx, skb); - if (unlikely(err)) + if (unlikely(err)) { + u64_stats_update_begin(&tx->stats.syncp); + u64_stats_inc(&tx->stats.drops); + u64_stats_update_end(&tx->stats.syncp); + dev_kfree_skb_any(skb); + } /* NETDEV_TX_BUSY is expensive. So stop advancing the TX queue. */ n = MAX_SKB_FRAGS + 1; @@ -348,6 +368,8 @@ int eea_alloc_tx(struct eea_net_init_ctx *ctx, struct eea_net_tx *tx, u32 idx) struct eea_ring *ering; u32 i; + u64_stats_init(&tx->stats.syncp); + snprintf(tx->name, sizeof(tx->name), "tx.%u", idx); ering = ering_alloc(idx * 2 + 1, ctx->cfg.tx_ring_depth, ctx->edev, -- 2.32.0.3.g01195cf9f