1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
3
4#include <linux/pci.h>
5#include <linux/phy.h>
6#include <linux/ethtool.h>
7
8#include "wx_type.h"
9#include "wx_ethtool.h"
10#include "wx_hw.h"
11#include "wx_lib.h"
12
13struct wx_stats {
14	char stat_string[ETH_GSTRING_LEN];
15	size_t sizeof_stat;
16	off_t stat_offset;
17};
18
19#define WX_STAT(str, m) { \
20		.stat_string = str, \
21		.sizeof_stat = sizeof(((struct wx *)0)->m), \
22		.stat_offset = offsetof(struct wx, m) }
23
24static const struct wx_stats wx_gstrings_stats[] = {
25	WX_STAT("rx_dma_pkts", stats.gprc),
26	WX_STAT("tx_dma_pkts", stats.gptc),
27	WX_STAT("rx_dma_bytes", stats.gorc),
28	WX_STAT("tx_dma_bytes", stats.gotc),
29	WX_STAT("rx_total_pkts", stats.tpr),
30	WX_STAT("tx_total_pkts", stats.tpt),
31	WX_STAT("rx_long_length_count", stats.roc),
32	WX_STAT("rx_short_length_count", stats.ruc),
33	WX_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
34	WX_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
35	WX_STAT("os2bmc_tx_by_host", stats.o2bspc),
36	WX_STAT("os2bmc_rx_by_host", stats.b2ogprc),
37	WX_STAT("rx_no_dma_resources", stats.rdmdrop),
38	WX_STAT("tx_busy", tx_busy),
39	WX_STAT("non_eop_descs", non_eop_descs),
40	WX_STAT("tx_restart_queue", restart_queue),
41	WX_STAT("rx_csum_offload_good_count", hw_csum_rx_good),
42	WX_STAT("rx_csum_offload_errors", hw_csum_rx_error),
43	WX_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
44};
45
46/* drivers allocates num_tx_queues and num_rx_queues symmetrically so
47 * we set the num_rx_queues to evaluate to num_tx_queues. This is
48 * used because we do not have a good way to get the max number of
49 * rx queues with CONFIG_RPS disabled.
50 */
51#define WX_NUM_RX_QUEUES netdev->num_tx_queues
52#define WX_NUM_TX_QUEUES netdev->num_tx_queues
53
54#define WX_QUEUE_STATS_LEN ( \
55		(WX_NUM_TX_QUEUES + WX_NUM_RX_QUEUES) * \
56		(sizeof(struct wx_queue_stats) / sizeof(u64)))
57#define WX_GLOBAL_STATS_LEN  ARRAY_SIZE(wx_gstrings_stats)
58#define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN)
59
60int wx_get_sset_count(struct net_device *netdev, int sset)
61{
62	switch (sset) {
63	case ETH_SS_STATS:
64		return WX_STATS_LEN;
65	default:
66		return -EOPNOTSUPP;
67	}
68}
69EXPORT_SYMBOL(wx_get_sset_count);
70
71void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
72{
73	u8 *p = data;
74	int i;
75
76	switch (stringset) {
77	case ETH_SS_STATS:
78		for (i = 0; i < WX_GLOBAL_STATS_LEN; i++)
79			ethtool_puts(&p, wx_gstrings_stats[i].stat_string);
80		for (i = 0; i < netdev->num_tx_queues; i++) {
81			ethtool_sprintf(&p, "tx_queue_%u_packets", i);
82			ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
83		}
84		for (i = 0; i < WX_NUM_RX_QUEUES; i++) {
85			ethtool_sprintf(&p, "rx_queue_%u_packets", i);
86			ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
87		}
88		break;
89	}
90}
91EXPORT_SYMBOL(wx_get_strings);
92
93void wx_get_ethtool_stats(struct net_device *netdev,
94			  struct ethtool_stats *stats, u64 *data)
95{
96	struct wx *wx = netdev_priv(netdev);
97	struct wx_ring *ring;
98	unsigned int start;
99	int i, j;
100	char *p;
101
102	wx_update_stats(wx);
103
104	for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) {
105		p = (char *)wx + wx_gstrings_stats[i].stat_offset;
106		data[i] = (wx_gstrings_stats[i].sizeof_stat ==
107			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
108	}
109
110	for (j = 0; j < netdev->num_tx_queues; j++) {
111		ring = wx->tx_ring[j];
112		if (!ring) {
113			data[i++] = 0;
114			data[i++] = 0;
115			continue;
116		}
117
118		do {
119			start = u64_stats_fetch_begin(&ring->syncp);
120			data[i] = ring->stats.packets;
121			data[i + 1] = ring->stats.bytes;
122		} while (u64_stats_fetch_retry(&ring->syncp, start));
123		i += 2;
124	}
125	for (j = 0; j < WX_NUM_RX_QUEUES; j++) {
126		ring = wx->rx_ring[j];
127		if (!ring) {
128			data[i++] = 0;
129			data[i++] = 0;
130			continue;
131		}
132
133		do {
134			start = u64_stats_fetch_begin(&ring->syncp);
135			data[i] = ring->stats.packets;
136			data[i + 1] = ring->stats.bytes;
137		} while (u64_stats_fetch_retry(&ring->syncp, start));
138		i += 2;
139	}
140}
141EXPORT_SYMBOL(wx_get_ethtool_stats);
142
143void wx_get_mac_stats(struct net_device *netdev,
144		      struct ethtool_eth_mac_stats *mac_stats)
145{
146	struct wx *wx = netdev_priv(netdev);
147	struct wx_hw_stats *hwstats;
148
149	wx_update_stats(wx);
150
151	hwstats = &wx->stats;
152	mac_stats->MulticastFramesXmittedOK = hwstats->mptc;
153	mac_stats->BroadcastFramesXmittedOK = hwstats->bptc;
154	mac_stats->MulticastFramesReceivedOK = hwstats->mprc;
155	mac_stats->BroadcastFramesReceivedOK = hwstats->bprc;
156}
157EXPORT_SYMBOL(wx_get_mac_stats);
158
159void wx_get_pause_stats(struct net_device *netdev,
160			struct ethtool_pause_stats *stats)
161{
162	struct wx *wx = netdev_priv(netdev);
163	struct wx_hw_stats *hwstats;
164
165	wx_update_stats(wx);
166
167	hwstats = &wx->stats;
168	stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc;
169	stats->rx_pause_frames = hwstats->lxonoffrxc;
170}
171EXPORT_SYMBOL(wx_get_pause_stats);
172
173void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
174{
175	struct wx *wx = netdev_priv(netdev);
176
177	strscpy(info->driver, wx->driver_name, sizeof(info->driver));
178	strscpy(info->fw_version, wx->eeprom_id, sizeof(info->fw_version));
179	strscpy(info->bus_info, pci_name(wx->pdev), sizeof(info->bus_info));
180	if (wx->num_tx_queues <= WX_NUM_TX_QUEUES) {
181		info->n_stats = WX_STATS_LEN -
182				   (WX_NUM_TX_QUEUES - wx->num_tx_queues) *
183				   (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2;
184	} else {
185		info->n_stats = WX_STATS_LEN;
186	}
187}
188EXPORT_SYMBOL(wx_get_drvinfo);
189
190int wx_nway_reset(struct net_device *netdev)
191{
192	struct wx *wx = netdev_priv(netdev);
193
194	return phylink_ethtool_nway_reset(wx->phylink);
195}
196EXPORT_SYMBOL(wx_nway_reset);
197
198int wx_get_link_ksettings(struct net_device *netdev,
199			  struct ethtool_link_ksettings *cmd)
200{
201	struct wx *wx = netdev_priv(netdev);
202
203	return phylink_ethtool_ksettings_get(wx->phylink, cmd);
204}
205EXPORT_SYMBOL(wx_get_link_ksettings);
206
207int wx_set_link_ksettings(struct net_device *netdev,
208			  const struct ethtool_link_ksettings *cmd)
209{
210	struct wx *wx = netdev_priv(netdev);
211
212	return phylink_ethtool_ksettings_set(wx->phylink, cmd);
213}
214EXPORT_SYMBOL(wx_set_link_ksettings);
215
216void wx_get_pauseparam(struct net_device *netdev,
217		       struct ethtool_pauseparam *pause)
218{
219	struct wx *wx = netdev_priv(netdev);
220
221	phylink_ethtool_get_pauseparam(wx->phylink, pause);
222}
223EXPORT_SYMBOL(wx_get_pauseparam);
224
225int wx_set_pauseparam(struct net_device *netdev,
226		      struct ethtool_pauseparam *pause)
227{
228	struct wx *wx = netdev_priv(netdev);
229
230	return phylink_ethtool_set_pauseparam(wx->phylink, pause);
231}
232EXPORT_SYMBOL(wx_set_pauseparam);
233
234void wx_get_ringparam(struct net_device *netdev,
235		      struct ethtool_ringparam *ring,
236		      struct kernel_ethtool_ringparam *kernel_ring,
237		      struct netlink_ext_ack *extack)
238{
239	struct wx *wx = netdev_priv(netdev);
240
241	ring->rx_max_pending = WX_MAX_RXD;
242	ring->tx_max_pending = WX_MAX_TXD;
243	ring->rx_mini_max_pending = 0;
244	ring->rx_jumbo_max_pending = 0;
245	ring->rx_pending = wx->rx_ring_count;
246	ring->tx_pending = wx->tx_ring_count;
247	ring->rx_mini_pending = 0;
248	ring->rx_jumbo_pending = 0;
249}
250EXPORT_SYMBOL(wx_get_ringparam);
251
252int wx_get_coalesce(struct net_device *netdev,
253		    struct ethtool_coalesce *ec,
254		    struct kernel_ethtool_coalesce *kernel_coal,
255		    struct netlink_ext_ack *extack)
256{
257	struct wx *wx = netdev_priv(netdev);
258
259	ec->tx_max_coalesced_frames_irq = wx->tx_work_limit;
260	/* only valid if in constant ITR mode */
261	if (wx->rx_itr_setting <= 1)
262		ec->rx_coalesce_usecs = wx->rx_itr_setting;
263	else
264		ec->rx_coalesce_usecs = wx->rx_itr_setting >> 2;
265
266	/* if in mixed tx/rx queues per vector mode, report only rx settings */
267	if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count)
268		return 0;
269
270	/* only valid if in constant ITR mode */
271	if (wx->tx_itr_setting <= 1)
272		ec->tx_coalesce_usecs = wx->tx_itr_setting;
273	else
274		ec->tx_coalesce_usecs = wx->tx_itr_setting >> 2;
275
276	return 0;
277}
278EXPORT_SYMBOL(wx_get_coalesce);
279
280int wx_set_coalesce(struct net_device *netdev,
281		    struct ethtool_coalesce *ec,
282		    struct kernel_ethtool_coalesce *kernel_coal,
283		    struct netlink_ext_ack *extack)
284{
285	struct wx *wx = netdev_priv(netdev);
286	u16 tx_itr_param, rx_itr_param;
287	struct wx_q_vector *q_vector;
288	u16 max_eitr;
289	int i;
290
291	if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count) {
292		/* reject Tx specific changes in case of mixed RxTx vectors */
293		if (ec->tx_coalesce_usecs)
294			return -EOPNOTSUPP;
295	}
296
297	if (ec->tx_max_coalesced_frames_irq)
298		wx->tx_work_limit = ec->tx_max_coalesced_frames_irq;
299
300	if (wx->mac.type == wx_mac_sp)
301		max_eitr = WX_SP_MAX_EITR;
302	else
303		max_eitr = WX_EM_MAX_EITR;
304
305	if ((ec->rx_coalesce_usecs > (max_eitr >> 2)) ||
306	    (ec->tx_coalesce_usecs > (max_eitr >> 2)))
307		return -EINVAL;
308
309	if (ec->rx_coalesce_usecs > 1)
310		wx->rx_itr_setting = ec->rx_coalesce_usecs << 2;
311	else
312		wx->rx_itr_setting = ec->rx_coalesce_usecs;
313
314	if (wx->rx_itr_setting == 1)
315		rx_itr_param = WX_20K_ITR;
316	else
317		rx_itr_param = wx->rx_itr_setting;
318
319	if (ec->tx_coalesce_usecs > 1)
320		wx->tx_itr_setting = ec->tx_coalesce_usecs << 2;
321	else
322		wx->tx_itr_setting = ec->tx_coalesce_usecs;
323
324	if (wx->tx_itr_setting == 1) {
325		if (wx->mac.type == wx_mac_sp)
326			tx_itr_param = WX_12K_ITR;
327		else
328			tx_itr_param = WX_20K_ITR;
329	} else {
330		tx_itr_param = wx->tx_itr_setting;
331	}
332
333	/* mixed Rx/Tx */
334	if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count)
335		wx->tx_itr_setting = wx->rx_itr_setting;
336
337	for (i = 0; i < wx->num_q_vectors; i++) {
338		q_vector = wx->q_vector[i];
339		if (q_vector->tx.count && !q_vector->rx.count)
340			/* tx only */
341			q_vector->itr = tx_itr_param;
342		else
343			/* rx only or mixed */
344			q_vector->itr = rx_itr_param;
345		wx_write_eitr(q_vector);
346	}
347
348	return 0;
349}
350EXPORT_SYMBOL(wx_set_coalesce);
351
352static unsigned int wx_max_channels(struct wx *wx)
353{
354	unsigned int max_combined;
355
356	if (!wx->msix_q_entries) {
357		/* We only support one q_vector without MSI-X */
358		max_combined = 1;
359	} else {
360		/* support up to max allowed queues with RSS */
361		if (wx->mac.type == wx_mac_sp)
362			max_combined = 63;
363		else
364			max_combined = 8;
365	}
366
367	return max_combined;
368}
369
370void wx_get_channels(struct net_device *dev,
371		     struct ethtool_channels *ch)
372{
373	struct wx *wx = netdev_priv(dev);
374
375	/* report maximum channels */
376	ch->max_combined = wx_max_channels(wx);
377
378	/* report info for other vector */
379	if (wx->msix_q_entries) {
380		ch->max_other = 1;
381		ch->other_count = 1;
382	}
383
384	/* record RSS queues */
385	ch->combined_count = wx->ring_feature[RING_F_RSS].indices;
386}
387EXPORT_SYMBOL(wx_get_channels);
388
389int wx_set_channels(struct net_device *dev,
390		    struct ethtool_channels *ch)
391{
392	unsigned int count = ch->combined_count;
393	struct wx *wx = netdev_priv(dev);
394
395	/* verify other_count has not changed */
396	if (ch->other_count != 1)
397		return -EINVAL;
398
399	/* verify the number of channels does not exceed hardware limits */
400	if (count > wx_max_channels(wx))
401		return -EINVAL;
402
403	wx->ring_feature[RING_F_RSS].limit = count;
404
405	return 0;
406}
407EXPORT_SYMBOL(wx_set_channels);
408
409u32 wx_get_msglevel(struct net_device *netdev)
410{
411	struct wx *wx = netdev_priv(netdev);
412
413	return wx->msg_enable;
414}
415EXPORT_SYMBOL(wx_get_msglevel);
416
417void wx_set_msglevel(struct net_device *netdev, u32 data)
418{
419	struct wx *wx = netdev_priv(netdev);
420
421	wx->msg_enable = data;
422}
423EXPORT_SYMBOL(wx_set_msglevel);
424