1// SPDX-License-Identifier: GPL-2.0-only
2/* Atlantic Network Driver
3 *
4 * Copyright (C) 2014-2019 aQuantia Corporation
5 * Copyright (C) 2019-2020 Marvell International Ltd.
6 */
7
8/* File aq_ethtool.c: Definition of ethertool related functions. */
9
10#include "aq_ethtool.h"
11#include "aq_nic.h"
12#include "aq_vec.h"
13#include "aq_ptp.h"
14#include "aq_filters.h"
15#include "aq_macsec.h"
16#include "aq_main.h"
17
18#include <linux/ptp_clock_kernel.h>
19
20static void aq_ethtool_get_regs(struct net_device *ndev,
21				struct ethtool_regs *regs, void *p)
22{
23	struct aq_nic_s *aq_nic = netdev_priv(ndev);
24	u32 regs_count;
25
26	regs_count = aq_nic_get_regs_count(aq_nic);
27
28	memset(p, 0, regs_count * sizeof(u32));
29	aq_nic_get_regs(aq_nic, regs, p);
30}
31
32static int aq_ethtool_get_regs_len(struct net_device *ndev)
33{
34	struct aq_nic_s *aq_nic = netdev_priv(ndev);
35	u32 regs_count;
36
37	regs_count = aq_nic_get_regs_count(aq_nic);
38
39	return regs_count * sizeof(u32);
40}
41
42static u32 aq_ethtool_get_link(struct net_device *ndev)
43{
44	return ethtool_op_get_link(ndev);
45}
46
47static int aq_ethtool_get_link_ksettings(struct net_device *ndev,
48					 struct ethtool_link_ksettings *cmd)
49{
50	struct aq_nic_s *aq_nic = netdev_priv(ndev);
51
52	aq_nic_get_link_ksettings(aq_nic, cmd);
53	cmd->base.speed = netif_carrier_ok(ndev) ?
54				aq_nic_get_link_speed(aq_nic) : 0U;
55
56	return 0;
57}
58
59static int
60aq_ethtool_set_link_ksettings(struct net_device *ndev,
61			      const struct ethtool_link_ksettings *cmd)
62{
63	struct aq_nic_s *aq_nic = netdev_priv(ndev);
64
65	return aq_nic_set_link_ksettings(aq_nic, cmd);
66}
67
68static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
69	"InPackets",
70	"InUCast",
71	"InMCast",
72	"InBCast",
73	"InErrors",
74	"OutPackets",
75	"OutUCast",
76	"OutMCast",
77	"OutBCast",
78	"InUCastOctets",
79	"OutUCastOctets",
80	"InMCastOctets",
81	"OutMCastOctets",
82	"InBCastOctets",
83	"OutBCastOctets",
84	"InOctets",
85	"OutOctets",
86	"InPacketsDma",
87	"OutPacketsDma",
88	"InOctetsDma",
89	"OutOctetsDma",
90	"InDroppedDma",
91};
92
93static const char * const aq_ethtool_queue_rx_stat_names[] = {
94	"%sQueue[%d] InPackets",
95	"%sQueue[%d] InJumboPackets",
96	"%sQueue[%d] InLroPackets",
97	"%sQueue[%d] InErrors",
98	"%sQueue[%d] AllocFails",
99	"%sQueue[%d] SkbAllocFails",
100	"%sQueue[%d] Polls",
101};
102
103static const char * const aq_ethtool_queue_tx_stat_names[] = {
104	"%sQueue[%d] OutPackets",
105	"%sQueue[%d] Restarts",
106};
107
108#if IS_ENABLED(CONFIG_MACSEC)
109static const char aq_macsec_stat_names[][ETH_GSTRING_LEN] = {
110	"MACSec InCtlPackets",
111	"MACSec InTaggedMissPackets",
112	"MACSec InUntaggedMissPackets",
113	"MACSec InNotagPackets",
114	"MACSec InUntaggedPackets",
115	"MACSec InBadTagPackets",
116	"MACSec InNoSciPackets",
117	"MACSec InUnknownSciPackets",
118	"MACSec InCtrlPortPassPackets",
119	"MACSec InUnctrlPortPassPackets",
120	"MACSec InCtrlPortFailPackets",
121	"MACSec InUnctrlPortFailPackets",
122	"MACSec InTooLongPackets",
123	"MACSec InIgpocCtlPackets",
124	"MACSec InEccErrorPackets",
125	"MACSec InUnctrlHitDropRedir",
126	"MACSec OutCtlPackets",
127	"MACSec OutUnknownSaPackets",
128	"MACSec OutUntaggedPackets",
129	"MACSec OutTooLong",
130	"MACSec OutEccErrorPackets",
131	"MACSec OutUnctrlHitDropRedir",
132};
133
134static const char * const aq_macsec_txsc_stat_names[] = {
135	"MACSecTXSC%d ProtectedPkts",
136	"MACSecTXSC%d EncryptedPkts",
137	"MACSecTXSC%d ProtectedOctets",
138	"MACSecTXSC%d EncryptedOctets",
139};
140
141static const char * const aq_macsec_txsa_stat_names[] = {
142	"MACSecTXSC%dSA%d HitDropRedirect",
143	"MACSecTXSC%dSA%d Protected2Pkts",
144	"MACSecTXSC%dSA%d ProtectedPkts",
145	"MACSecTXSC%dSA%d EncryptedPkts",
146};
147
148static const char * const aq_macsec_rxsa_stat_names[] = {
149	"MACSecRXSC%dSA%d UntaggedHitPkts",
150	"MACSecRXSC%dSA%d CtrlHitDrpRedir",
151	"MACSecRXSC%dSA%d NotUsingSa",
152	"MACSecRXSC%dSA%d UnusedSa",
153	"MACSecRXSC%dSA%d NotValidPkts",
154	"MACSecRXSC%dSA%d InvalidPkts",
155	"MACSecRXSC%dSA%d OkPkts",
156	"MACSecRXSC%dSA%d LatePkts",
157	"MACSecRXSC%dSA%d DelayedPkts",
158	"MACSecRXSC%dSA%d UncheckedPkts",
159	"MACSecRXSC%dSA%d ValidatedOctets",
160	"MACSecRXSC%dSA%d DecryptedOctets",
161};
162#endif
163
164static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {
165	"DMASystemLoopback",
166	"PKTSystemLoopback",
167	"DMANetworkLoopback",
168	"PHYInternalLoopback",
169	"PHYExternalLoopback",
170};
171
172static u32 aq_ethtool_n_stats(struct net_device *ndev)
173{
174	const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
175	const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
176	struct aq_nic_s *nic = netdev_priv(ndev);
177	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(nic);
178	u32 n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
179		      (rx_stat_cnt + tx_stat_cnt) * cfg->vecs * cfg->tcs;
180
181#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
182	n_stats += rx_stat_cnt * aq_ptp_get_ring_cnt(nic, ATL_RING_RX) +
183		   tx_stat_cnt * aq_ptp_get_ring_cnt(nic, ATL_RING_TX);
184#endif
185
186#if IS_ENABLED(CONFIG_MACSEC)
187	if (nic->macsec_cfg) {
188		n_stats += ARRAY_SIZE(aq_macsec_stat_names) +
189			   ARRAY_SIZE(aq_macsec_txsc_stat_names) *
190				   aq_macsec_tx_sc_cnt(nic) +
191			   ARRAY_SIZE(aq_macsec_txsa_stat_names) *
192				   aq_macsec_tx_sa_cnt(nic) +
193			   ARRAY_SIZE(aq_macsec_rxsa_stat_names) *
194				   aq_macsec_rx_sa_cnt(nic);
195	}
196#endif
197
198	return n_stats;
199}
200
201static void aq_ethtool_stats(struct net_device *ndev,
202			     struct ethtool_stats *stats, u64 *data)
203{
204	struct aq_nic_s *aq_nic = netdev_priv(ndev);
205
206	memset(data, 0, aq_ethtool_n_stats(ndev) * sizeof(u64));
207	data = aq_nic_get_stats(aq_nic, data);
208#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
209	data = aq_ptp_get_stats(aq_nic, data);
210#endif
211#if IS_ENABLED(CONFIG_MACSEC)
212	data = aq_macsec_get_stats(aq_nic, data);
213#endif
214}
215
216static void aq_ethtool_get_drvinfo(struct net_device *ndev,
217				   struct ethtool_drvinfo *drvinfo)
218{
219	struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
220	struct aq_nic_s *aq_nic = netdev_priv(ndev);
221	u32 firmware_version;
222	u32 regs_count;
223
224	firmware_version = aq_nic_get_fw_version(aq_nic);
225	regs_count = aq_nic_get_regs_count(aq_nic);
226
227	strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver));
228
229	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
230		 "%u.%u.%u", firmware_version >> 24,
231		 (firmware_version >> 16) & 0xFFU, firmware_version & 0xFFFFU);
232
233	strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "",
234		sizeof(drvinfo->bus_info));
235	drvinfo->n_stats = aq_ethtool_n_stats(ndev);
236	drvinfo->testinfo_len = 0;
237	drvinfo->regdump_len = regs_count;
238	drvinfo->eedump_len = 0;
239}
240
241static void aq_ethtool_get_strings(struct net_device *ndev,
242				   u32 stringset, u8 *data)
243{
244	struct aq_nic_s *nic = netdev_priv(ndev);
245	struct aq_nic_cfg_s *cfg;
246	u8 *p = data;
247	int i, si;
248#if IS_ENABLED(CONFIG_MACSEC)
249	int sa;
250#endif
251
252	cfg = aq_nic_get_cfg(nic);
253
254	switch (stringset) {
255	case ETH_SS_STATS: {
256		const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
257		const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
258		char tc_string[8];
259		int tc;
260
261		memset(tc_string, 0, sizeof(tc_string));
262		memcpy(p, aq_ethtool_stat_names,
263		       sizeof(aq_ethtool_stat_names));
264		p = p + sizeof(aq_ethtool_stat_names);
265
266		for (tc = 0; tc < cfg->tcs; tc++) {
267			if (cfg->is_qos)
268				snprintf(tc_string, 8, "TC%d ", tc);
269
270			for (i = 0; i < cfg->vecs; i++) {
271				for (si = 0; si < rx_stat_cnt; si++) {
272					snprintf(p, ETH_GSTRING_LEN,
273					     aq_ethtool_queue_rx_stat_names[si],
274					     tc_string,
275					     AQ_NIC_CFG_TCVEC2RING(cfg, tc, i));
276					p += ETH_GSTRING_LEN;
277				}
278				for (si = 0; si < tx_stat_cnt; si++) {
279					snprintf(p, ETH_GSTRING_LEN,
280					     aq_ethtool_queue_tx_stat_names[si],
281					     tc_string,
282					     AQ_NIC_CFG_TCVEC2RING(cfg, tc, i));
283					p += ETH_GSTRING_LEN;
284				}
285			}
286		}
287#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
288		if (nic->aq_ptp) {
289			const int rx_ring_cnt = aq_ptp_get_ring_cnt(nic, ATL_RING_RX);
290			const int tx_ring_cnt = aq_ptp_get_ring_cnt(nic, ATL_RING_TX);
291			unsigned int ptp_ring_idx =
292				aq_ptp_ring_idx(nic->aq_nic_cfg.tc_mode);
293
294			snprintf(tc_string, 8, "PTP ");
295
296			for (i = 0; i < max(rx_ring_cnt, tx_ring_cnt); i++) {
297				for (si = 0; si < rx_stat_cnt; si++) {
298					snprintf(p, ETH_GSTRING_LEN,
299						 aq_ethtool_queue_rx_stat_names[si],
300						 tc_string,
301						 i ? PTP_HWST_RING_IDX : ptp_ring_idx);
302					p += ETH_GSTRING_LEN;
303				}
304				if (i >= tx_ring_cnt)
305					continue;
306				for (si = 0; si < tx_stat_cnt; si++) {
307					snprintf(p, ETH_GSTRING_LEN,
308						 aq_ethtool_queue_tx_stat_names[si],
309						 tc_string,
310						 i ? PTP_HWST_RING_IDX : ptp_ring_idx);
311					p += ETH_GSTRING_LEN;
312				}
313			}
314		}
315#endif
316#if IS_ENABLED(CONFIG_MACSEC)
317		if (!nic->macsec_cfg)
318			break;
319
320		memcpy(p, aq_macsec_stat_names, sizeof(aq_macsec_stat_names));
321		p = p + sizeof(aq_macsec_stat_names);
322		for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
323			struct aq_macsec_txsc *aq_txsc;
324
325			if (!(test_bit(i, &nic->macsec_cfg->txsc_idx_busy)))
326				continue;
327
328			for (si = 0;
329				si < ARRAY_SIZE(aq_macsec_txsc_stat_names);
330				si++) {
331				snprintf(p, ETH_GSTRING_LEN,
332					 aq_macsec_txsc_stat_names[si], i);
333				p += ETH_GSTRING_LEN;
334			}
335			aq_txsc = &nic->macsec_cfg->aq_txsc[i];
336			for (sa = 0; sa < MACSEC_NUM_AN; sa++) {
337				if (!(test_bit(sa, &aq_txsc->tx_sa_idx_busy)))
338					continue;
339				for (si = 0;
340				     si < ARRAY_SIZE(aq_macsec_txsa_stat_names);
341				     si++) {
342					snprintf(p, ETH_GSTRING_LEN,
343						 aq_macsec_txsa_stat_names[si],
344						 i, sa);
345					p += ETH_GSTRING_LEN;
346				}
347			}
348		}
349		for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
350			struct aq_macsec_rxsc *aq_rxsc;
351
352			if (!(test_bit(i, &nic->macsec_cfg->rxsc_idx_busy)))
353				continue;
354
355			aq_rxsc = &nic->macsec_cfg->aq_rxsc[i];
356			for (sa = 0; sa < MACSEC_NUM_AN; sa++) {
357				if (!(test_bit(sa, &aq_rxsc->rx_sa_idx_busy)))
358					continue;
359				for (si = 0;
360				     si < ARRAY_SIZE(aq_macsec_rxsa_stat_names);
361				     si++) {
362					snprintf(p, ETH_GSTRING_LEN,
363						 aq_macsec_rxsa_stat_names[si],
364						 i, sa);
365					p += ETH_GSTRING_LEN;
366				}
367			}
368		}
369#endif
370		break;
371	}
372	case ETH_SS_PRIV_FLAGS:
373		memcpy(p, aq_ethtool_priv_flag_names,
374		       sizeof(aq_ethtool_priv_flag_names));
375		break;
376	}
377}
378
379static int aq_ethtool_set_phys_id(struct net_device *ndev,
380				  enum ethtool_phys_id_state state)
381{
382	struct aq_nic_s *aq_nic = netdev_priv(ndev);
383	struct aq_hw_s *hw = aq_nic->aq_hw;
384	int ret = 0;
385
386	if (!aq_nic->aq_fw_ops->led_control)
387		return -EOPNOTSUPP;
388
389	mutex_lock(&aq_nic->fwreq_mutex);
390
391	switch (state) {
392	case ETHTOOL_ID_ACTIVE:
393		ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_BLINK |
394				 AQ_HW_LED_BLINK << 2 | AQ_HW_LED_BLINK << 4);
395		break;
396	case ETHTOOL_ID_INACTIVE:
397		ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_DEFAULT);
398		break;
399	default:
400		break;
401	}
402
403	mutex_unlock(&aq_nic->fwreq_mutex);
404
405	return ret;
406}
407
408static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
409{
410	int ret = 0;
411
412	switch (stringset) {
413	case ETH_SS_STATS:
414		ret = aq_ethtool_n_stats(ndev);
415		break;
416	case ETH_SS_PRIV_FLAGS:
417		ret = ARRAY_SIZE(aq_ethtool_priv_flag_names);
418		break;
419	default:
420		ret = -EOPNOTSUPP;
421	}
422
423	return ret;
424}
425
426static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev)
427{
428	return AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
429}
430
431static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev)
432{
433	struct aq_nic_s *aq_nic = netdev_priv(ndev);
434	struct aq_nic_cfg_s *cfg;
435
436	cfg = aq_nic_get_cfg(aq_nic);
437
438	return sizeof(cfg->aq_rss.hash_secret_key);
439}
440
441static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
442			      u8 *hfunc)
443{
444	struct aq_nic_s *aq_nic = netdev_priv(ndev);
445	struct aq_nic_cfg_s *cfg;
446	unsigned int i = 0U;
447
448	cfg = aq_nic_get_cfg(aq_nic);
449
450	if (hfunc)
451		*hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
452	if (indir) {
453		for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++)
454			indir[i] = cfg->aq_rss.indirection_table[i];
455	}
456	if (key)
457		memcpy(key, cfg->aq_rss.hash_secret_key,
458		       sizeof(cfg->aq_rss.hash_secret_key));
459
460	return 0;
461}
462
463static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir,
464			      const u8 *key, const u8 hfunc)
465{
466	struct aq_nic_s *aq_nic = netdev_priv(netdev);
467	struct aq_nic_cfg_s *cfg;
468	unsigned int i = 0U;
469	u32 rss_entries;
470	int err = 0;
471
472	cfg = aq_nic_get_cfg(aq_nic);
473	rss_entries = cfg->aq_rss.indirection_table_size;
474
475	/* We do not allow change in unsupported parameters */
476	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
477		return -EOPNOTSUPP;
478	/* Fill out the redirection table */
479	if (indir)
480		for (i = 0; i < rss_entries; i++)
481			cfg->aq_rss.indirection_table[i] = indir[i];
482
483	/* Fill out the rss hash key */
484	if (key) {
485		memcpy(cfg->aq_rss.hash_secret_key, key,
486		       sizeof(cfg->aq_rss.hash_secret_key));
487		err = aq_nic->aq_hw_ops->hw_rss_hash_set(aq_nic->aq_hw,
488			&cfg->aq_rss);
489		if (err)
490			return err;
491	}
492
493	err = aq_nic->aq_hw_ops->hw_rss_set(aq_nic->aq_hw, &cfg->aq_rss);
494
495	return err;
496}
497
498static int aq_ethtool_get_rxnfc(struct net_device *ndev,
499				struct ethtool_rxnfc *cmd,
500				u32 *rule_locs)
501{
502	struct aq_nic_s *aq_nic = netdev_priv(ndev);
503	struct aq_nic_cfg_s *cfg;
504	int err = 0;
505
506	cfg = aq_nic_get_cfg(aq_nic);
507
508	switch (cmd->cmd) {
509	case ETHTOOL_GRXRINGS:
510		cmd->data = cfg->vecs;
511		break;
512	case ETHTOOL_GRXCLSRLCNT:
513		cmd->rule_cnt = aq_get_rxnfc_count_all_rules(aq_nic);
514		break;
515	case ETHTOOL_GRXCLSRULE:
516		err = aq_get_rxnfc_rule(aq_nic, cmd);
517		break;
518	case ETHTOOL_GRXCLSRLALL:
519		err = aq_get_rxnfc_all_rules(aq_nic, cmd, rule_locs);
520		break;
521	default:
522		err = -EOPNOTSUPP;
523		break;
524	}
525
526	return err;
527}
528
529static int aq_ethtool_set_rxnfc(struct net_device *ndev,
530				struct ethtool_rxnfc *cmd)
531{
532	struct aq_nic_s *aq_nic = netdev_priv(ndev);
533	int err = 0;
534
535	switch (cmd->cmd) {
536	case ETHTOOL_SRXCLSRLINS:
537		err = aq_add_rxnfc_rule(aq_nic, cmd);
538		break;
539	case ETHTOOL_SRXCLSRLDEL:
540		err = aq_del_rxnfc_rule(aq_nic, cmd);
541		break;
542	default:
543		err = -EOPNOTSUPP;
544		break;
545	}
546
547	return err;
548}
549
550static int aq_ethtool_get_coalesce(struct net_device *ndev,
551				   struct ethtool_coalesce *coal)
552{
553	struct aq_nic_s *aq_nic = netdev_priv(ndev);
554	struct aq_nic_cfg_s *cfg;
555
556	cfg = aq_nic_get_cfg(aq_nic);
557
558	if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON ||
559	    cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) {
560		coal->rx_coalesce_usecs = cfg->rx_itr;
561		coal->tx_coalesce_usecs = cfg->tx_itr;
562		coal->rx_max_coalesced_frames = 0;
563		coal->tx_max_coalesced_frames = 0;
564	} else {
565		coal->rx_coalesce_usecs = 0;
566		coal->tx_coalesce_usecs = 0;
567		coal->rx_max_coalesced_frames = 1;
568		coal->tx_max_coalesced_frames = 1;
569	}
570
571	return 0;
572}
573
574static int aq_ethtool_set_coalesce(struct net_device *ndev,
575				   struct ethtool_coalesce *coal)
576{
577	struct aq_nic_s *aq_nic = netdev_priv(ndev);
578	struct aq_nic_cfg_s *cfg;
579
580	cfg = aq_nic_get_cfg(aq_nic);
581
582	/* Atlantic only supports timing based coalescing
583	 */
584	if (coal->rx_max_coalesced_frames > 1 ||
585	    coal->tx_max_coalesced_frames > 1)
586		return -EOPNOTSUPP;
587
588	/* We do not support frame counting. Check this
589	 */
590	if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs))
591		return -EOPNOTSUPP;
592	if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs))
593		return -EOPNOTSUPP;
594
595	if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX ||
596	    coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX)
597		return -EINVAL;
598
599	cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON;
600
601	cfg->rx_itr = coal->rx_coalesce_usecs;
602	cfg->tx_itr = coal->tx_coalesce_usecs;
603
604	return aq_nic_update_interrupt_moderation_settings(aq_nic);
605}
606
607static void aq_ethtool_get_wol(struct net_device *ndev,
608			       struct ethtool_wolinfo *wol)
609{
610	struct aq_nic_s *aq_nic = netdev_priv(ndev);
611	struct aq_nic_cfg_s *cfg;
612
613	cfg = aq_nic_get_cfg(aq_nic);
614
615	wol->supported = AQ_NIC_WOL_MODES;
616	wol->wolopts = cfg->wol;
617}
618
619static int aq_ethtool_set_wol(struct net_device *ndev,
620			      struct ethtool_wolinfo *wol)
621{
622	struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
623	struct aq_nic_s *aq_nic = netdev_priv(ndev);
624	struct aq_nic_cfg_s *cfg;
625	int err = 0;
626
627	cfg = aq_nic_get_cfg(aq_nic);
628
629	if (wol->wolopts & ~AQ_NIC_WOL_MODES)
630		return -EOPNOTSUPP;
631
632	cfg->wol = wol->wolopts;
633
634	err = device_set_wakeup_enable(&pdev->dev, !!cfg->wol);
635
636	return err;
637}
638
639static int aq_ethtool_get_ts_info(struct net_device *ndev,
640				  struct ethtool_ts_info *info)
641{
642	struct aq_nic_s *aq_nic = netdev_priv(ndev);
643
644	ethtool_op_get_ts_info(ndev, info);
645
646	if (!aq_nic->aq_ptp)
647		return 0;
648
649	info->so_timestamping |=
650		SOF_TIMESTAMPING_TX_HARDWARE |
651		SOF_TIMESTAMPING_RX_HARDWARE |
652		SOF_TIMESTAMPING_RAW_HARDWARE;
653
654	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
655			 BIT(HWTSTAMP_TX_ON);
656
657	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
658
659	info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
660			    BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
661			    BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
662
663#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
664	info->phc_index = ptp_clock_index(aq_ptp_get_ptp_clock(aq_nic->aq_ptp));
665#endif
666
667	return 0;
668}
669
670static u32 eee_mask_to_ethtool_mask(u32 speed)
671{
672	u32 rate = 0;
673
674	if (speed & AQ_NIC_RATE_EEE_10G)
675		rate |= SUPPORTED_10000baseT_Full;
676
677	if (speed & AQ_NIC_RATE_EEE_1G)
678		rate |= SUPPORTED_1000baseT_Full;
679
680	if (speed & AQ_NIC_RATE_EEE_100M)
681		rate |= SUPPORTED_100baseT_Full;
682
683	return rate;
684}
685
686static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
687{
688	struct aq_nic_s *aq_nic = netdev_priv(ndev);
689	u32 rate, supported_rates;
690	int err = 0;
691
692	if (!aq_nic->aq_fw_ops->get_eee_rate)
693		return -EOPNOTSUPP;
694
695	mutex_lock(&aq_nic->fwreq_mutex);
696	err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
697					      &supported_rates);
698	mutex_unlock(&aq_nic->fwreq_mutex);
699	if (err < 0)
700		return err;
701
702	eee->supported = eee_mask_to_ethtool_mask(supported_rates);
703
704	if (aq_nic->aq_nic_cfg.eee_speeds)
705		eee->advertised = eee->supported;
706
707	eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
708
709	eee->eee_enabled = !!eee->advertised;
710
711	eee->tx_lpi_enabled = eee->eee_enabled;
712	if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK)
713		eee->eee_active = true;
714
715	return 0;
716}
717
718static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
719{
720	struct aq_nic_s *aq_nic = netdev_priv(ndev);
721	u32 rate, supported_rates;
722	struct aq_nic_cfg_s *cfg;
723	int err = 0;
724
725	cfg = aq_nic_get_cfg(aq_nic);
726
727	if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
728		     !aq_nic->aq_fw_ops->set_eee_rate))
729		return -EOPNOTSUPP;
730
731	mutex_lock(&aq_nic->fwreq_mutex);
732	err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
733					      &supported_rates);
734	mutex_unlock(&aq_nic->fwreq_mutex);
735	if (err < 0)
736		return err;
737
738	if (eee->eee_enabled) {
739		rate = supported_rates;
740		cfg->eee_speeds = rate;
741	} else {
742		rate = 0;
743		cfg->eee_speeds = 0;
744	}
745
746	mutex_lock(&aq_nic->fwreq_mutex);
747	err = aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
748	mutex_unlock(&aq_nic->fwreq_mutex);
749
750	return err;
751}
752
753static int aq_ethtool_nway_reset(struct net_device *ndev)
754{
755	struct aq_nic_s *aq_nic = netdev_priv(ndev);
756	int err = 0;
757
758	if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
759		return -EOPNOTSUPP;
760
761	if (netif_running(ndev)) {
762		mutex_lock(&aq_nic->fwreq_mutex);
763		err = aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
764		mutex_unlock(&aq_nic->fwreq_mutex);
765	}
766
767	return err;
768}
769
770static void aq_ethtool_get_pauseparam(struct net_device *ndev,
771				      struct ethtool_pauseparam *pause)
772{
773	struct aq_nic_s *aq_nic = netdev_priv(ndev);
774	int fc = aq_nic->aq_nic_cfg.fc.req;
775
776	pause->autoneg = 0;
777
778	pause->rx_pause = !!(fc & AQ_NIC_FC_RX);
779	pause->tx_pause = !!(fc & AQ_NIC_FC_TX);
780}
781
782static int aq_ethtool_set_pauseparam(struct net_device *ndev,
783				     struct ethtool_pauseparam *pause)
784{
785	struct aq_nic_s *aq_nic = netdev_priv(ndev);
786	int err = 0;
787
788	if (!aq_nic->aq_fw_ops->set_flow_control)
789		return -EOPNOTSUPP;
790
791	if (pause->autoneg == AUTONEG_ENABLE)
792		return -EOPNOTSUPP;
793
794	if (pause->rx_pause)
795		aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_RX;
796	else
797		aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_RX;
798
799	if (pause->tx_pause)
800		aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_TX;
801	else
802		aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_TX;
803
804	mutex_lock(&aq_nic->fwreq_mutex);
805	err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
806	mutex_unlock(&aq_nic->fwreq_mutex);
807
808	return err;
809}
810
811static void aq_get_ringparam(struct net_device *ndev,
812			     struct ethtool_ringparam *ring)
813{
814	struct aq_nic_s *aq_nic = netdev_priv(ndev);
815	struct aq_nic_cfg_s *cfg;
816
817	cfg = aq_nic_get_cfg(aq_nic);
818
819	ring->rx_pending = cfg->rxds;
820	ring->tx_pending = cfg->txds;
821
822	ring->rx_max_pending = cfg->aq_hw_caps->rxds_max;
823	ring->tx_max_pending = cfg->aq_hw_caps->txds_max;
824}
825
826static int aq_set_ringparam(struct net_device *ndev,
827			    struct ethtool_ringparam *ring)
828{
829	struct aq_nic_s *aq_nic = netdev_priv(ndev);
830	const struct aq_hw_caps_s *hw_caps;
831	bool ndev_running = false;
832	struct aq_nic_cfg_s *cfg;
833	int err = 0;
834
835	cfg = aq_nic_get_cfg(aq_nic);
836	hw_caps = cfg->aq_hw_caps;
837
838	if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
839		err = -EOPNOTSUPP;
840		goto err_exit;
841	}
842
843	if (netif_running(ndev)) {
844		ndev_running = true;
845		aq_ndev_close(ndev);
846	}
847
848	cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
849	cfg->rxds = min(cfg->rxds, hw_caps->rxds_max);
850	cfg->rxds = ALIGN(cfg->rxds, AQ_HW_RXD_MULTIPLE);
851
852	cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
853	cfg->txds = min(cfg->txds, hw_caps->txds_max);
854	cfg->txds = ALIGN(cfg->txds, AQ_HW_TXD_MULTIPLE);
855
856	err = aq_nic_realloc_vectors(aq_nic);
857	if (err)
858		goto err_exit;
859
860	if (ndev_running)
861		err = aq_ndev_open(ndev);
862
863err_exit:
864	return err;
865}
866
867static u32 aq_get_msg_level(struct net_device *ndev)
868{
869	struct aq_nic_s *aq_nic = netdev_priv(ndev);
870
871	return aq_nic->msg_enable;
872}
873
874static void aq_set_msg_level(struct net_device *ndev, u32 data)
875{
876	struct aq_nic_s *aq_nic = netdev_priv(ndev);
877
878	aq_nic->msg_enable = data;
879}
880
881static u32 aq_ethtool_get_priv_flags(struct net_device *ndev)
882{
883	struct aq_nic_s *aq_nic = netdev_priv(ndev);
884
885	return aq_nic->aq_nic_cfg.priv_flags;
886}
887
888static int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags)
889{
890	struct aq_nic_s *aq_nic = netdev_priv(ndev);
891	struct aq_nic_cfg_s *cfg;
892	u32 priv_flags;
893	int ret = 0;
894
895	cfg = aq_nic_get_cfg(aq_nic);
896	priv_flags = cfg->priv_flags;
897
898	if (flags & ~AQ_PRIV_FLAGS_MASK)
899		return -EOPNOTSUPP;
900
901	if (hweight32((flags | priv_flags) & AQ_HW_LOOPBACK_MASK) > 1) {
902		netdev_info(ndev, "Can't enable more than one loopback simultaneously\n");
903		return -EINVAL;
904	}
905
906	cfg->priv_flags = flags;
907
908	if ((priv_flags ^ flags) & BIT(AQ_HW_LOOPBACK_DMA_NET)) {
909		if (netif_running(ndev)) {
910			dev_close(ndev);
911
912			dev_open(ndev, NULL);
913		}
914	} else if ((priv_flags ^ flags) & AQ_HW_LOOPBACK_MASK) {
915		ret = aq_nic_set_loopback(aq_nic);
916	}
917
918	return ret;
919}
920
921static int aq_ethtool_get_phy_tunable(struct net_device *ndev,
922				      const struct ethtool_tunable *tuna, void *data)
923{
924	struct aq_nic_s *aq_nic = netdev_priv(ndev);
925
926	switch (tuna->id) {
927	case ETHTOOL_PHY_EDPD: {
928		u16 *val = data;
929
930		*val = aq_nic->aq_nic_cfg.is_media_detect ? AQ_HW_MEDIA_DETECT_CNT : 0;
931		break;
932	}
933	case ETHTOOL_PHY_DOWNSHIFT: {
934		u8 *val = data;
935
936		*val = (u8)aq_nic->aq_nic_cfg.downshift_counter;
937		break;
938	}
939	default:
940		return -EOPNOTSUPP;
941	}
942
943	return 0;
944}
945
946static int aq_ethtool_set_phy_tunable(struct net_device *ndev,
947				      const struct ethtool_tunable *tuna, const void *data)
948{
949	int err = -EOPNOTSUPP;
950	struct aq_nic_s *aq_nic = netdev_priv(ndev);
951
952	switch (tuna->id) {
953	case ETHTOOL_PHY_EDPD: {
954		const u16 *val = data;
955
956		err = aq_nic_set_media_detect(aq_nic, *val);
957		break;
958	}
959	case ETHTOOL_PHY_DOWNSHIFT: {
960		const u8 *val = data;
961
962		err = aq_nic_set_downshift(aq_nic, *val);
963		break;
964	}
965	default:
966		break;
967	}
968
969	return err;
970}
971
972const struct ethtool_ops aq_ethtool_ops = {
973	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
974				     ETHTOOL_COALESCE_MAX_FRAMES,
975	.get_link            = aq_ethtool_get_link,
976	.get_regs_len        = aq_ethtool_get_regs_len,
977	.get_regs            = aq_ethtool_get_regs,
978	.get_drvinfo         = aq_ethtool_get_drvinfo,
979	.get_strings         = aq_ethtool_get_strings,
980	.set_phys_id         = aq_ethtool_set_phys_id,
981	.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
982	.get_wol             = aq_ethtool_get_wol,
983	.set_wol             = aq_ethtool_set_wol,
984	.nway_reset          = aq_ethtool_nway_reset,
985	.get_ringparam       = aq_get_ringparam,
986	.set_ringparam       = aq_set_ringparam,
987	.get_eee             = aq_ethtool_get_eee,
988	.set_eee             = aq_ethtool_set_eee,
989	.get_pauseparam      = aq_ethtool_get_pauseparam,
990	.set_pauseparam      = aq_ethtool_set_pauseparam,
991	.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
992	.get_rxfh            = aq_ethtool_get_rss,
993	.set_rxfh            = aq_ethtool_set_rss,
994	.get_rxnfc           = aq_ethtool_get_rxnfc,
995	.set_rxnfc           = aq_ethtool_set_rxnfc,
996	.get_msglevel        = aq_get_msg_level,
997	.set_msglevel        = aq_set_msg_level,
998	.get_sset_count      = aq_ethtool_get_sset_count,
999	.get_ethtool_stats   = aq_ethtool_stats,
1000	.get_priv_flags      = aq_ethtool_get_priv_flags,
1001	.set_priv_flags      = aq_ethtool_set_priv_flags,
1002	.get_link_ksettings  = aq_ethtool_get_link_ksettings,
1003	.set_link_ksettings  = aq_ethtool_set_link_ksettings,
1004	.get_coalesce	     = aq_ethtool_get_coalesce,
1005	.set_coalesce	     = aq_ethtool_set_coalesce,
1006	.get_ts_info         = aq_ethtool_get_ts_info,
1007	.get_phy_tunable     = aq_ethtool_get_phy_tunable,
1008	.set_phy_tunable     = aq_ethtool_set_phy_tunable,
1009};
1010