Skip to content

Commit 86bbed8

Browse files
fengidriNipaLocal
authored andcommitted
eea: introduce ethtool support
Add basic driver framework for the Alibaba Elastic Ethernet Adapter(EEA). This commit introduces ethtool support. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Dust Li <dust.li@linux.alibaba.com> Reviewed-by: Philo Lu <lulie@linux.alibaba.com> Signed-off-by: Wen Gu <guwen@linux.alibaba.com> Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Signed-off-by: NipaLocal <nipa@local>
1 parent 15cd785 commit 86bbed8

File tree

7 files changed

+383
-4
lines changed

7 files changed

+383
-4
lines changed

drivers/net/ethernet/alibaba/eea/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ eea-y := eea_ring.o \
44
eea_net.o \
55
eea_pci.o \
66
eea_adminq.o \
7+
eea_ethtool.o \
78
eea_tx.o \
89
eea_rx.o
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Driver for Alibaba Elastic Ethernet Adapter.
4+
*
5+
* Copyright (C) 2025 Alibaba Inc.
6+
*/
7+
8+
#include <linux/ethtool.h>
9+
#include <linux/ethtool_netlink.h>
10+
11+
#include "eea_adminq.h"
12+
13+
struct eea_stat_desc {
14+
char desc[ETH_GSTRING_LEN];
15+
size_t offset;
16+
};
17+
18+
#define EEA_TX_STAT(m) {#m, offsetof(struct eea_tx_stats, m)}
19+
#define EEA_RX_STAT(m) {#m, offsetof(struct eea_rx_stats, m)}
20+
21+
static const struct eea_stat_desc eea_rx_stats_desc[] = {
22+
EEA_RX_STAT(descs),
23+
EEA_RX_STAT(kicks),
24+
};
25+
26+
static const struct eea_stat_desc eea_tx_stats_desc[] = {
27+
EEA_TX_STAT(descs),
28+
EEA_TX_STAT(kicks),
29+
};
30+
31+
#define EEA_TX_STATS_LEN ARRAY_SIZE(eea_tx_stats_desc)
32+
#define EEA_RX_STATS_LEN ARRAY_SIZE(eea_rx_stats_desc)
33+
34+
static void eea_get_drvinfo(struct net_device *netdev,
35+
struct ethtool_drvinfo *info)
36+
{
37+
struct eea_net *enet = netdev_priv(netdev);
38+
struct eea_device *edev = enet->edev;
39+
40+
strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
41+
strscpy(info->bus_info, eea_pci_name(edev), sizeof(info->bus_info));
42+
}
43+
44+
static void eea_get_ringparam(struct net_device *netdev,
45+
struct ethtool_ringparam *ring,
46+
struct kernel_ethtool_ringparam *kernel_ring,
47+
struct netlink_ext_ack *extack)
48+
{
49+
struct eea_net *enet = netdev_priv(netdev);
50+
51+
ring->rx_max_pending = enet->cfg_hw.rx_ring_depth;
52+
ring->tx_max_pending = enet->cfg_hw.tx_ring_depth;
53+
ring->rx_pending = enet->cfg.rx_ring_depth;
54+
ring->tx_pending = enet->cfg.tx_ring_depth;
55+
56+
kernel_ring->tcp_data_split = enet->cfg.split_hdr ?
57+
ETHTOOL_TCP_DATA_SPLIT_ENABLED :
58+
ETHTOOL_TCP_DATA_SPLIT_DISABLED;
59+
}
60+
61+
static int eea_set_ringparam(struct net_device *netdev,
62+
struct ethtool_ringparam *ring,
63+
struct kernel_ethtool_ringparam *kernel_ring,
64+
struct netlink_ext_ack *extack)
65+
{
66+
struct eea_net *enet = netdev_priv(netdev);
67+
struct eea_net_init_ctx ctx;
68+
bool need_update = false;
69+
struct eea_net_cfg *cfg;
70+
bool sh;
71+
72+
enet_init_ctx(enet, &ctx);
73+
74+
cfg = &ctx.cfg;
75+
76+
if (ring->rx_pending != cfg->rx_ring_depth)
77+
need_update = true;
78+
79+
if (ring->tx_pending != cfg->tx_ring_depth)
80+
need_update = true;
81+
82+
sh = kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED;
83+
if (sh != !!(cfg->split_hdr))
84+
need_update = true;
85+
86+
if (!need_update)
87+
return 0;
88+
89+
cfg->rx_ring_depth = ring->rx_pending;
90+
cfg->tx_ring_depth = ring->tx_pending;
91+
92+
cfg->split_hdr = sh ? enet->cfg_hw.split_hdr : 0;
93+
94+
return eea_reset_hw_resources(enet, &ctx);
95+
}
96+
97+
static int eea_set_channels(struct net_device *netdev,
98+
struct ethtool_channels *channels)
99+
{
100+
struct eea_net *enet = netdev_priv(netdev);
101+
u16 queue_pairs = channels->combined_count;
102+
struct eea_net_init_ctx ctx;
103+
struct eea_net_cfg *cfg;
104+
105+
enet_init_ctx(enet, &ctx);
106+
107+
cfg = &ctx.cfg;
108+
109+
cfg->rx_ring_num = queue_pairs;
110+
cfg->tx_ring_num = queue_pairs;
111+
112+
return eea_reset_hw_resources(enet, &ctx);
113+
}
114+
115+
static void eea_get_channels(struct net_device *netdev,
116+
struct ethtool_channels *channels)
117+
{
118+
struct eea_net *enet = netdev_priv(netdev);
119+
120+
channels->combined_count = enet->cfg.rx_ring_num;
121+
channels->max_combined = enet->cfg_hw.rx_ring_num;
122+
}
123+
124+
static void eea_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
125+
{
126+
struct eea_net *enet = netdev_priv(netdev);
127+
u8 *p = data;
128+
u32 i, j;
129+
130+
if (stringset != ETH_SS_STATS)
131+
return;
132+
133+
for (i = 0; i < enet->cfg.rx_ring_num; i++) {
134+
for (j = 0; j < EEA_RX_STATS_LEN; j++)
135+
ethtool_sprintf(&p, "rx%u_%s", i,
136+
eea_rx_stats_desc[j].desc);
137+
}
138+
139+
for (i = 0; i < enet->cfg.tx_ring_num; i++) {
140+
for (j = 0; j < EEA_TX_STATS_LEN; j++)
141+
ethtool_sprintf(&p, "tx%u_%s", i,
142+
eea_tx_stats_desc[j].desc);
143+
}
144+
}
145+
146+
static int eea_get_sset_count(struct net_device *netdev, int sset)
147+
{
148+
struct eea_net *enet = netdev_priv(netdev);
149+
150+
if (sset != ETH_SS_STATS)
151+
return -EOPNOTSUPP;
152+
153+
return enet->cfg.rx_ring_num * EEA_RX_STATS_LEN +
154+
enet->cfg.tx_ring_num * EEA_TX_STATS_LEN;
155+
}
156+
157+
static void eea_stats_fill_for_q(struct u64_stats_sync *syncp, u32 num,
158+
const struct eea_stat_desc *desc,
159+
u64 *data, u32 idx)
160+
{
161+
void *stats_base = syncp;
162+
u32 start, i;
163+
164+
do {
165+
start = u64_stats_fetch_begin(syncp);
166+
for (i = 0; i < num; i++)
167+
data[idx + i] =
168+
u64_stats_read(stats_base + desc[i].offset);
169+
170+
} while (u64_stats_fetch_retry(syncp, start));
171+
}
172+
173+
static void eea_get_ethtool_stats(struct net_device *netdev,
174+
struct ethtool_stats *stats, u64 *data)
175+
{
176+
struct eea_net *enet = netdev_priv(netdev);
177+
u32 i, idx = 0;
178+
179+
for (i = 0; i < enet->cfg.rx_ring_num; i++) {
180+
struct eea_net_rx *rx = enet->rx[i];
181+
182+
eea_stats_fill_for_q(&rx->stats.syncp, EEA_RX_STATS_LEN,
183+
eea_rx_stats_desc, data, idx);
184+
185+
idx += EEA_RX_STATS_LEN;
186+
}
187+
188+
for (i = 0; i < enet->cfg.tx_ring_num; i++) {
189+
struct eea_net_tx *tx = &enet->tx[i];
190+
191+
eea_stats_fill_for_q(&tx->stats.syncp, EEA_TX_STATS_LEN,
192+
eea_tx_stats_desc, data, idx);
193+
194+
idx += EEA_TX_STATS_LEN;
195+
}
196+
}
197+
198+
void eea_update_rx_stats(struct eea_rx_stats *rx_stats,
199+
struct eea_rx_ctx_stats *stats)
200+
{
201+
u64_stats_update_begin(&rx_stats->syncp);
202+
u64_stats_add(&rx_stats->descs, stats->descs);
203+
u64_stats_add(&rx_stats->packets, stats->packets);
204+
u64_stats_add(&rx_stats->bytes, stats->bytes);
205+
u64_stats_add(&rx_stats->drops, stats->drops);
206+
u64_stats_add(&rx_stats->split_hdr_bytes, stats->split_hdr_bytes);
207+
u64_stats_add(&rx_stats->split_hdr_packets, stats->split_hdr_packets);
208+
u64_stats_add(&rx_stats->length_errors, stats->length_errors);
209+
u64_stats_update_end(&rx_stats->syncp);
210+
}
211+
212+
void eea_stats(struct net_device *netdev, struct rtnl_link_stats64 *tot)
213+
{
214+
struct eea_net *enet = netdev_priv(netdev);
215+
u64 packets, bytes;
216+
u32 start;
217+
int i;
218+
219+
if (enet->rx) {
220+
for (i = 0; i < enet->cfg.rx_ring_num; i++) {
221+
struct eea_net_rx *rx = enet->rx[i];
222+
223+
do {
224+
start = u64_stats_fetch_begin(&rx->stats.syncp);
225+
packets = u64_stats_read(&rx->stats.packets);
226+
bytes = u64_stats_read(&rx->stats.bytes);
227+
} while (u64_stats_fetch_retry(&rx->stats.syncp,
228+
start));
229+
230+
tot->rx_packets += packets;
231+
tot->rx_bytes += bytes;
232+
}
233+
}
234+
235+
if (enet->tx) {
236+
for (i = 0; i < enet->cfg.tx_ring_num; i++) {
237+
struct eea_net_tx *tx = &enet->tx[i];
238+
239+
do {
240+
start = u64_stats_fetch_begin(&tx->stats.syncp);
241+
packets = u64_stats_read(&tx->stats.packets);
242+
bytes = u64_stats_read(&tx->stats.bytes);
243+
} while (u64_stats_fetch_retry(&tx->stats.syncp,
244+
start));
245+
246+
tot->tx_packets += packets;
247+
tot->tx_bytes += bytes;
248+
}
249+
}
250+
}
251+
252+
static int eea_get_link_ksettings(struct net_device *netdev,
253+
struct ethtool_link_ksettings *cmd)
254+
{
255+
struct eea_net *enet = netdev_priv(netdev);
256+
257+
cmd->base.speed = enet->speed;
258+
cmd->base.duplex = enet->duplex;
259+
cmd->base.port = PORT_OTHER;
260+
261+
return 0;
262+
}
263+
264+
const struct ethtool_ops eea_ethtool_ops = {
265+
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT,
266+
.get_drvinfo = eea_get_drvinfo,
267+
.get_link = ethtool_op_get_link,
268+
.get_ringparam = eea_get_ringparam,
269+
.set_ringparam = eea_set_ringparam,
270+
.set_channels = eea_set_channels,
271+
.get_channels = eea_get_channels,
272+
.get_strings = eea_get_strings,
273+
.get_sset_count = eea_get_sset_count,
274+
.get_ethtool_stats = eea_get_ethtool_stats,
275+
.get_link_ksettings = eea_get_link_ksettings,
276+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Driver for Alibaba Elastic Ethernet Adapter.
4+
*
5+
* Copyright (C) 2025 Alibaba Inc.
6+
*/
7+
8+
#ifndef __EEA_ETHTOOL_H__
9+
#define __EEA_ETHTOOL_H__
10+
11+
struct eea_tx_stats {
12+
struct u64_stats_sync syncp;
13+
u64_stats_t descs;
14+
u64_stats_t packets;
15+
u64_stats_t bytes;
16+
u64_stats_t drops;
17+
u64_stats_t kicks;
18+
};
19+
20+
struct eea_rx_ctx_stats {
21+
u64 descs;
22+
u64 packets;
23+
u64 bytes;
24+
u64 drops;
25+
u64 split_hdr_bytes;
26+
u64 split_hdr_packets;
27+
28+
u64 length_errors;
29+
};
30+
31+
struct eea_rx_stats {
32+
struct u64_stats_sync syncp;
33+
u64_stats_t descs;
34+
u64_stats_t packets;
35+
u64_stats_t bytes;
36+
u64_stats_t drops;
37+
u64_stats_t kicks;
38+
u64_stats_t split_hdr_bytes;
39+
u64_stats_t split_hdr_packets;
40+
41+
u64_stats_t length_errors;
42+
};
43+
44+
void eea_update_rx_stats(struct eea_rx_stats *rx_stats,
45+
struct eea_rx_ctx_stats *stats);
46+
void eea_stats(struct net_device *netdev, struct rtnl_link_stats64 *tot);
47+
48+
extern const struct ethtool_ops eea_ethtool_ops;
49+
50+
#endif

drivers/net/ethernet/alibaba/eea/eea_net.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ static const struct net_device_ops eea_netdev = {
437437
.ndo_stop = eea_netdev_stop,
438438
.ndo_start_xmit = eea_tx_xmit,
439439
.ndo_validate_addr = eth_validate_addr,
440+
.ndo_get_stats64 = eea_stats,
440441
.ndo_features_check = passthru_features_check,
441442
.ndo_tx_timeout = eea_tx_timeout,
442443
};
@@ -454,6 +455,7 @@ static struct eea_net *eea_netdev_alloc(struct eea_device *edev, u32 pairs)
454455
}
455456

456457
netdev->netdev_ops = &eea_netdev;
458+
netdev->ethtool_ops = &eea_ethtool_ops;
457459
SET_NETDEV_DEV(netdev, edev->dma_dev);
458460

459461
enet = netdev_priv(netdev);

drivers/net/ethernet/alibaba/eea/eea_net.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/netdevice.h>
1313

1414
#include "eea_adminq.h"
15+
#include "eea_ethtool.h"
1516
#include "eea_ring.h"
1617

1718
#define EEA_VER_MAJOR 1
@@ -38,6 +39,8 @@ struct eea_net_tx {
3839
u32 index;
3940

4041
char name[16];
42+
43+
struct eea_tx_stats stats;
4144
};
4245

4346
struct eea_rx_meta {
@@ -90,6 +93,8 @@ struct eea_net_rx {
9093

9194
struct napi_struct napi;
9295

96+
struct eea_rx_stats stats;
97+
9398
u16 irq_n;
9499

95100
char name[16];

0 commit comments

Comments
 (0)