Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */
  3
  4#include "tsnep.h"
  5
  6static const char tsnep_stats_strings[][ETH_GSTRING_LEN] = {
  7	"rx_packets",
  8	"rx_bytes",
  9	"rx_dropped",
 10	"rx_multicast",
 11	"rx_alloc_failed",
 12	"rx_phy_errors",
 13	"rx_forwarded_phy_errors",
 14	"rx_invalid_frame_errors",
 15	"tx_packets",
 16	"tx_bytes",
 17	"tx_dropped",
 18};
 19
 20struct tsnep_stats {
 21	u64 rx_packets;
 22	u64 rx_bytes;
 23	u64 rx_dropped;
 24	u64 rx_multicast;
 25	u64 rx_alloc_failed;
 26	u64 rx_phy_errors;
 27	u64 rx_forwarded_phy_errors;
 28	u64 rx_invalid_frame_errors;
 29	u64 tx_packets;
 30	u64 tx_bytes;
 31	u64 tx_dropped;
 32};
 33
 34#define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64))
 35
 36static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = {
 37	"rx_%d_packets",
 38	"rx_%d_bytes",
 39	"rx_%d_dropped",
 40	"rx_%d_multicast",
 41	"rx_%d_alloc_failed",
 42	"rx_%d_no_descriptor_errors",
 43	"rx_%d_buffer_too_small_errors",
 44	"rx_%d_fifo_overflow_errors",
 45	"rx_%d_invalid_frame_errors",
 46};
 47
 48struct tsnep_rx_queue_stats {
 49	u64 rx_packets;
 50	u64 rx_bytes;
 51	u64 rx_dropped;
 52	u64 rx_multicast;
 53	u64 rx_alloc_failed;
 54	u64 rx_no_descriptor_errors;
 55	u64 rx_buffer_too_small_errors;
 56	u64 rx_fifo_overflow_errors;
 57	u64 rx_invalid_frame_errors;
 58};
 59
 60#define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \
 61				    sizeof(u64))
 62
 63static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
 64	"tx_%d_packets",
 65	"tx_%d_bytes",
 66	"tx_%d_dropped",
 67};
 68
 69struct tsnep_tx_queue_stats {
 70	u64 tx_packets;
 71	u64 tx_bytes;
 72	u64 tx_dropped;
 73};
 74
 75#define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \
 76				    sizeof(u64))
 77
 78static void tsnep_ethtool_get_drvinfo(struct net_device *netdev,
 79				      struct ethtool_drvinfo *drvinfo)
 80{
 81	struct tsnep_adapter *adapter = netdev_priv(netdev);
 82
 83	strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver));
 84	strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev),
 85		sizeof(drvinfo->bus_info));
 86}
 87
 88static int tsnep_ethtool_get_regs_len(struct net_device *netdev)
 89{
 90	struct tsnep_adapter *adapter = netdev_priv(netdev);
 91	int len;
 92	int num_additional_queues;
 93
 94	len = TSNEP_MAC_SIZE;
 95
 96	/* first queue pair is within TSNEP_MAC_SIZE, only queues additional to
 97	 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE
 98	 */
 99	num_additional_queues =
100		max(adapter->num_tx_queues, adapter->num_rx_queues) - 1;
101	len += TSNEP_QUEUE_SIZE * num_additional_queues;
102
103	return len;
104}
105
106static void tsnep_ethtool_get_regs(struct net_device *netdev,
107				   struct ethtool_regs *regs,
108				   void *p)
109{
110	struct tsnep_adapter *adapter = netdev_priv(netdev);
111
112	regs->version = 1;
113
114	memcpy_fromio(p, adapter->addr, regs->len);
115}
116
117static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev)
118{
119	struct tsnep_adapter *adapter = netdev_priv(netdev);
120
121	return adapter->msg_enable;
122}
123
124static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data)
125{
126	struct tsnep_adapter *adapter = netdev_priv(netdev);
127
128	adapter->msg_enable = data;
129}
130
131static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset,
132				      u8 *data)
133{
134	struct tsnep_adapter *adapter = netdev_priv(netdev);
135	int rx_count = adapter->num_rx_queues;
136	int tx_count = adapter->num_tx_queues;
137	int i, j;
138
139	switch (stringset) {
140	case ETH_SS_STATS:
141		memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings));
142		data += sizeof(tsnep_stats_strings);
143
144		for (i = 0; i < rx_count; i++) {
145			for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) {
146				snprintf(data, ETH_GSTRING_LEN,
147					 tsnep_rx_queue_stats_strings[j], i);
148				data += ETH_GSTRING_LEN;
149			}
150		}
151
152		for (i = 0; i < tx_count; i++) {
153			for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) {
154				snprintf(data, ETH_GSTRING_LEN,
155					 tsnep_tx_queue_stats_strings[j], i);
156				data += ETH_GSTRING_LEN;
157			}
158		}
159		break;
160	case ETH_SS_TEST:
161		tsnep_ethtool_get_test_strings(data);
162		break;
163	}
164}
165
166static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev,
167					    struct ethtool_stats *stats,
168					    u64 *data)
169{
170	struct tsnep_adapter *adapter = netdev_priv(netdev);
171	int rx_count = adapter->num_rx_queues;
172	int tx_count = adapter->num_tx_queues;
173	struct tsnep_stats tsnep_stats;
174	struct tsnep_rx_queue_stats tsnep_rx_queue_stats;
175	struct tsnep_tx_queue_stats tsnep_tx_queue_stats;
176	u32 reg;
177	int i;
178
179	memset(&tsnep_stats, 0, sizeof(tsnep_stats));
180	for (i = 0; i < adapter->num_rx_queues; i++) {
181		tsnep_stats.rx_packets += adapter->rx[i].packets;
182		tsnep_stats.rx_bytes += adapter->rx[i].bytes;
183		tsnep_stats.rx_dropped += adapter->rx[i].dropped;
184		tsnep_stats.rx_multicast += adapter->rx[i].multicast;
185		tsnep_stats.rx_alloc_failed += adapter->rx[i].alloc_failed;
186	}
187	reg = ioread32(adapter->addr + ECM_STAT);
188	tsnep_stats.rx_phy_errors =
189		(reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT;
190	tsnep_stats.rx_forwarded_phy_errors =
191		(reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT;
192	tsnep_stats.rx_invalid_frame_errors =
193		(reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT;
194	for (i = 0; i < adapter->num_tx_queues; i++) {
195		tsnep_stats.tx_packets += adapter->tx[i].packets;
196		tsnep_stats.tx_bytes += adapter->tx[i].bytes;
197		tsnep_stats.tx_dropped += adapter->tx[i].dropped;
198	}
199	memcpy(data, &tsnep_stats, sizeof(tsnep_stats));
200	data += TSNEP_STATS_COUNT;
201
202	for (i = 0; i < rx_count; i++) {
203		memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats));
204		tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets;
205		tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes;
206		tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped;
207		tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast;
208		tsnep_rx_queue_stats.rx_alloc_failed =
209			adapter->rx[i].alloc_failed;
210		reg = ioread32(adapter->addr + TSNEP_QUEUE(i) +
211			       TSNEP_RX_STATISTIC);
212		tsnep_rx_queue_stats.rx_no_descriptor_errors =
213			(reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >>
214			TSNEP_RX_STATISTIC_NO_DESC_SHIFT;
215		tsnep_rx_queue_stats.rx_buffer_too_small_errors =
216			(reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >>
217			TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT;
218		tsnep_rx_queue_stats.rx_fifo_overflow_errors =
219			(reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >>
220			TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT;
221		tsnep_rx_queue_stats.rx_invalid_frame_errors =
222			(reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >>
223			TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT;
224		memcpy(data, &tsnep_rx_queue_stats,
225		       sizeof(tsnep_rx_queue_stats));
226		data += TSNEP_RX_QUEUE_STATS_COUNT;
227	}
228
229	for (i = 0; i < tx_count; i++) {
230		memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats));
231		tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets;
232		tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes;
233		tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped;
234		memcpy(data, &tsnep_tx_queue_stats,
235		       sizeof(tsnep_tx_queue_stats));
236		data += TSNEP_TX_QUEUE_STATS_COUNT;
237	}
238}
239
240static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset)
241{
242	struct tsnep_adapter *adapter = netdev_priv(netdev);
243	int rx_count;
244	int tx_count;
245
246	switch (sset) {
247	case ETH_SS_STATS:
248		rx_count = adapter->num_rx_queues;
249		tx_count = adapter->num_tx_queues;
250		return TSNEP_STATS_COUNT +
251		       TSNEP_RX_QUEUE_STATS_COUNT * rx_count +
252		       TSNEP_TX_QUEUE_STATS_COUNT * tx_count;
253	case ETH_SS_TEST:
254		return tsnep_ethtool_get_test_count();
255	default:
256		return -EOPNOTSUPP;
257	}
258}
259
260static int tsnep_ethtool_get_rxnfc(struct net_device *netdev,
261				   struct ethtool_rxnfc *cmd, u32 *rule_locs)
262{
263	struct tsnep_adapter *adapter = netdev_priv(netdev);
264
265	switch (cmd->cmd) {
266	case ETHTOOL_GRXRINGS:
267		cmd->data = adapter->num_rx_queues;
268		return 0;
269	case ETHTOOL_GRXCLSRLCNT:
270		cmd->rule_cnt = adapter->rxnfc_count;
271		cmd->data = adapter->rxnfc_max;
272		cmd->data |= RX_CLS_LOC_SPECIAL;
273		return 0;
274	case ETHTOOL_GRXCLSRULE:
275		return tsnep_rxnfc_get_rule(adapter, cmd);
276	case ETHTOOL_GRXCLSRLALL:
277		return tsnep_rxnfc_get_all(adapter, cmd, rule_locs);
278	default:
279		return -EOPNOTSUPP;
280	}
281}
282
283static int tsnep_ethtool_set_rxnfc(struct net_device *netdev,
284				   struct ethtool_rxnfc *cmd)
285{
286	struct tsnep_adapter *adapter = netdev_priv(netdev);
287
288	switch (cmd->cmd) {
289	case ETHTOOL_SRXCLSRLINS:
290		return tsnep_rxnfc_add_rule(adapter, cmd);
291	case ETHTOOL_SRXCLSRLDEL:
292		return tsnep_rxnfc_del_rule(adapter, cmd);
293	default:
294		return -EOPNOTSUPP;
295	}
296}
297
298static void tsnep_ethtool_get_channels(struct net_device *netdev,
299				       struct ethtool_channels *ch)
300{
301	struct tsnep_adapter *adapter = netdev_priv(netdev);
302
303	ch->max_combined = adapter->num_queues;
304	ch->combined_count = adapter->num_queues;
 
 
305}
306
307static int tsnep_ethtool_get_ts_info(struct net_device *netdev,
308				     struct kernel_ethtool_ts_info *info)
309{
310	struct tsnep_adapter *adapter = netdev_priv(netdev);
311
312	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
 
 
313				SOF_TIMESTAMPING_TX_HARDWARE |
314				SOF_TIMESTAMPING_RX_HARDWARE |
315				SOF_TIMESTAMPING_RAW_HARDWARE;
316
317	if (adapter->ptp_clock)
318		info->phc_index = ptp_clock_index(adapter->ptp_clock);
 
 
319
320	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
321			 BIT(HWTSTAMP_TX_ON);
322	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
323			   BIT(HWTSTAMP_FILTER_ALL);
324
325	return 0;
326}
327
328static struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter,
329						   int index)
330{
331	int i;
332
333	for (i = 0; i < adapter->num_queues; i++) {
334		if (adapter->queue[i].tx) {
335			if (index == 0)
336				return &adapter->queue[i];
337
338			index--;
339		}
340	}
341
342	return NULL;
343}
344
345static struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter,
346						   int index)
347{
348	int i;
349
350	for (i = 0; i < adapter->num_queues; i++) {
351		if (adapter->queue[i].rx) {
352			if (index == 0)
353				return &adapter->queue[i];
354
355			index--;
356		}
357	}
358
359	return NULL;
360}
361
362static int tsnep_ethtool_get_coalesce(struct net_device *netdev,
363				      struct ethtool_coalesce *ec,
364				      struct kernel_ethtool_coalesce *kernel_coal,
365				      struct netlink_ext_ack *extack)
366{
367	struct tsnep_adapter *adapter = netdev_priv(netdev);
368	struct tsnep_queue *queue;
369
370	queue = tsnep_get_queue_with_rx(adapter, 0);
371	if (queue)
372		ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
373
374	queue = tsnep_get_queue_with_tx(adapter, 0);
375	if (queue)
376		ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
377
378	return 0;
379}
380
381static int tsnep_ethtool_set_coalesce(struct net_device *netdev,
382				      struct ethtool_coalesce *ec,
383				      struct kernel_ethtool_coalesce *kernel_coal,
384				      struct netlink_ext_ack *extack)
385{
386	struct tsnep_adapter *adapter = netdev_priv(netdev);
387	int i;
388	int retval;
389
390	for (i = 0; i < adapter->num_queues; i++) {
391		/* RX coalesce has priority for queues with TX and RX */
392		if (adapter->queue[i].rx)
393			retval = tsnep_set_irq_coalesce(&adapter->queue[i],
394							ec->rx_coalesce_usecs);
395		else
396			retval = tsnep_set_irq_coalesce(&adapter->queue[i],
397							ec->tx_coalesce_usecs);
398		if (retval != 0)
399			return retval;
400	}
401
402	return 0;
403}
404
405static int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev,
406						u32 queue,
407						struct ethtool_coalesce *ec)
408{
409	struct tsnep_adapter *adapter = netdev_priv(netdev);
410	struct tsnep_queue *queue_with_rx;
411	struct tsnep_queue *queue_with_tx;
412
413	if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
414		return -EINVAL;
415
416	queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
417	if (queue_with_rx)
418		ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx);
419
420	queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
421	if (queue_with_tx)
422		ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx);
423
424	return 0;
425}
426
427static int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev,
428						u32 queue,
429						struct ethtool_coalesce *ec)
430{
431	struct tsnep_adapter *adapter = netdev_priv(netdev);
432	struct tsnep_queue *queue_with_rx;
433	struct tsnep_queue *queue_with_tx;
434	int retval;
435
436	if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
437		return -EINVAL;
438
439	queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
440	if (queue_with_rx) {
441		retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs);
442		if (retval != 0)
443			return retval;
444	}
445
446	/* RX coalesce has priority for queues with TX and RX */
447	queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
448	if (queue_with_tx && !queue_with_tx->rx) {
449		retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs);
450		if (retval != 0)
451			return retval;
452	}
453
454	return 0;
455}
456
457const struct ethtool_ops tsnep_ethtool_ops = {
458	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
459	.get_drvinfo = tsnep_ethtool_get_drvinfo,
460	.get_regs_len = tsnep_ethtool_get_regs_len,
461	.get_regs = tsnep_ethtool_get_regs,
462	.get_msglevel = tsnep_ethtool_get_msglevel,
463	.set_msglevel = tsnep_ethtool_set_msglevel,
464	.nway_reset = phy_ethtool_nway_reset,
465	.get_link = ethtool_op_get_link,
466	.self_test = tsnep_ethtool_self_test,
467	.get_strings = tsnep_ethtool_get_strings,
468	.get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
469	.get_sset_count = tsnep_ethtool_get_sset_count,
470	.get_rxnfc = tsnep_ethtool_get_rxnfc,
471	.set_rxnfc = tsnep_ethtool_set_rxnfc,
472	.get_channels = tsnep_ethtool_get_channels,
473	.get_ts_info = tsnep_ethtool_get_ts_info,
474	.get_coalesce = tsnep_ethtool_get_coalesce,
475	.set_coalesce = tsnep_ethtool_set_coalesce,
476	.get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce,
477	.set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce,
478	.get_link_ksettings = phy_ethtool_get_link_ksettings,
479	.set_link_ksettings = phy_ethtool_set_link_ksettings,
480};
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */
  3
  4#include "tsnep.h"
  5
  6static const char tsnep_stats_strings[][ETH_GSTRING_LEN] = {
  7	"rx_packets",
  8	"rx_bytes",
  9	"rx_dropped",
 10	"rx_multicast",
 11	"rx_alloc_failed",
 12	"rx_phy_errors",
 13	"rx_forwarded_phy_errors",
 14	"rx_invalid_frame_errors",
 15	"tx_packets",
 16	"tx_bytes",
 17	"tx_dropped",
 18};
 19
 20struct tsnep_stats {
 21	u64 rx_packets;
 22	u64 rx_bytes;
 23	u64 rx_dropped;
 24	u64 rx_multicast;
 25	u64 rx_alloc_failed;
 26	u64 rx_phy_errors;
 27	u64 rx_forwarded_phy_errors;
 28	u64 rx_invalid_frame_errors;
 29	u64 tx_packets;
 30	u64 tx_bytes;
 31	u64 tx_dropped;
 32};
 33
 34#define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64))
 35
 36static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = {
 37	"rx_%d_packets",
 38	"rx_%d_bytes",
 39	"rx_%d_dropped",
 40	"rx_%d_multicast",
 41	"rx_%d_alloc_failed",
 42	"rx_%d_no_descriptor_errors",
 43	"rx_%d_buffer_too_small_errors",
 44	"rx_%d_fifo_overflow_errors",
 45	"rx_%d_invalid_frame_errors",
 46};
 47
 48struct tsnep_rx_queue_stats {
 49	u64 rx_packets;
 50	u64 rx_bytes;
 51	u64 rx_dropped;
 52	u64 rx_multicast;
 53	u64 rx_alloc_failed;
 54	u64 rx_no_descriptor_errors;
 55	u64 rx_buffer_too_small_errors;
 56	u64 rx_fifo_overflow_errors;
 57	u64 rx_invalid_frame_errors;
 58};
 59
 60#define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \
 61				    sizeof(u64))
 62
 63static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
 64	"tx_%d_packets",
 65	"tx_%d_bytes",
 66	"tx_%d_dropped",
 67};
 68
 69struct tsnep_tx_queue_stats {
 70	u64 tx_packets;
 71	u64 tx_bytes;
 72	u64 tx_dropped;
 73};
 74
 75#define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \
 76				    sizeof(u64))
 77
 78static void tsnep_ethtool_get_drvinfo(struct net_device *netdev,
 79				      struct ethtool_drvinfo *drvinfo)
 80{
 81	struct tsnep_adapter *adapter = netdev_priv(netdev);
 82
 83	strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver));
 84	strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev),
 85		sizeof(drvinfo->bus_info));
 86}
 87
 88static int tsnep_ethtool_get_regs_len(struct net_device *netdev)
 89{
 90	struct tsnep_adapter *adapter = netdev_priv(netdev);
 91	int len;
 92	int num_additional_queues;
 93
 94	len = TSNEP_MAC_SIZE;
 95
 96	/* first queue pair is within TSNEP_MAC_SIZE, only queues additional to
 97	 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE
 98	 */
 99	num_additional_queues =
100		max(adapter->num_tx_queues, adapter->num_rx_queues) - 1;
101	len += TSNEP_QUEUE_SIZE * num_additional_queues;
102
103	return len;
104}
105
106static void tsnep_ethtool_get_regs(struct net_device *netdev,
107				   struct ethtool_regs *regs,
108				   void *p)
109{
110	struct tsnep_adapter *adapter = netdev_priv(netdev);
111
112	regs->version = 1;
113
114	memcpy_fromio(p, adapter->addr, regs->len);
115}
116
117static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev)
118{
119	struct tsnep_adapter *adapter = netdev_priv(netdev);
120
121	return adapter->msg_enable;
122}
123
124static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data)
125{
126	struct tsnep_adapter *adapter = netdev_priv(netdev);
127
128	adapter->msg_enable = data;
129}
130
131static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset,
132				      u8 *data)
133{
134	struct tsnep_adapter *adapter = netdev_priv(netdev);
135	int rx_count = adapter->num_rx_queues;
136	int tx_count = adapter->num_tx_queues;
137	int i, j;
138
139	switch (stringset) {
140	case ETH_SS_STATS:
141		memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings));
142		data += sizeof(tsnep_stats_strings);
143
144		for (i = 0; i < rx_count; i++) {
145			for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) {
146				snprintf(data, ETH_GSTRING_LEN,
147					 tsnep_rx_queue_stats_strings[j], i);
148				data += ETH_GSTRING_LEN;
149			}
150		}
151
152		for (i = 0; i < tx_count; i++) {
153			for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) {
154				snprintf(data, ETH_GSTRING_LEN,
155					 tsnep_tx_queue_stats_strings[j], i);
156				data += ETH_GSTRING_LEN;
157			}
158		}
159		break;
160	case ETH_SS_TEST:
161		tsnep_ethtool_get_test_strings(data);
162		break;
163	}
164}
165
166static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev,
167					    struct ethtool_stats *stats,
168					    u64 *data)
169{
170	struct tsnep_adapter *adapter = netdev_priv(netdev);
171	int rx_count = adapter->num_rx_queues;
172	int tx_count = adapter->num_tx_queues;
173	struct tsnep_stats tsnep_stats;
174	struct tsnep_rx_queue_stats tsnep_rx_queue_stats;
175	struct tsnep_tx_queue_stats tsnep_tx_queue_stats;
176	u32 reg;
177	int i;
178
179	memset(&tsnep_stats, 0, sizeof(tsnep_stats));
180	for (i = 0; i < adapter->num_rx_queues; i++) {
181		tsnep_stats.rx_packets += adapter->rx[i].packets;
182		tsnep_stats.rx_bytes += adapter->rx[i].bytes;
183		tsnep_stats.rx_dropped += adapter->rx[i].dropped;
184		tsnep_stats.rx_multicast += adapter->rx[i].multicast;
185		tsnep_stats.rx_alloc_failed += adapter->rx[i].alloc_failed;
186	}
187	reg = ioread32(adapter->addr + ECM_STAT);
188	tsnep_stats.rx_phy_errors =
189		(reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT;
190	tsnep_stats.rx_forwarded_phy_errors =
191		(reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT;
192	tsnep_stats.rx_invalid_frame_errors =
193		(reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT;
194	for (i = 0; i < adapter->num_tx_queues; i++) {
195		tsnep_stats.tx_packets += adapter->tx[i].packets;
196		tsnep_stats.tx_bytes += adapter->tx[i].bytes;
197		tsnep_stats.tx_dropped += adapter->tx[i].dropped;
198	}
199	memcpy(data, &tsnep_stats, sizeof(tsnep_stats));
200	data += TSNEP_STATS_COUNT;
201
202	for (i = 0; i < rx_count; i++) {
203		memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats));
204		tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets;
205		tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes;
206		tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped;
207		tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast;
208		tsnep_rx_queue_stats.rx_alloc_failed =
209			adapter->rx[i].alloc_failed;
210		reg = ioread32(adapter->addr + TSNEP_QUEUE(i) +
211			       TSNEP_RX_STATISTIC);
212		tsnep_rx_queue_stats.rx_no_descriptor_errors =
213			(reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >>
214			TSNEP_RX_STATISTIC_NO_DESC_SHIFT;
215		tsnep_rx_queue_stats.rx_buffer_too_small_errors =
216			(reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >>
217			TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT;
218		tsnep_rx_queue_stats.rx_fifo_overflow_errors =
219			(reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >>
220			TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT;
221		tsnep_rx_queue_stats.rx_invalid_frame_errors =
222			(reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >>
223			TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT;
224		memcpy(data, &tsnep_rx_queue_stats,
225		       sizeof(tsnep_rx_queue_stats));
226		data += TSNEP_RX_QUEUE_STATS_COUNT;
227	}
228
229	for (i = 0; i < tx_count; i++) {
230		memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats));
231		tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets;
232		tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes;
233		tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped;
234		memcpy(data, &tsnep_tx_queue_stats,
235		       sizeof(tsnep_tx_queue_stats));
236		data += TSNEP_TX_QUEUE_STATS_COUNT;
237	}
238}
239
240static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset)
241{
242	struct tsnep_adapter *adapter = netdev_priv(netdev);
243	int rx_count;
244	int tx_count;
245
246	switch (sset) {
247	case ETH_SS_STATS:
248		rx_count = adapter->num_rx_queues;
249		tx_count = adapter->num_tx_queues;
250		return TSNEP_STATS_COUNT +
251		       TSNEP_RX_QUEUE_STATS_COUNT * rx_count +
252		       TSNEP_TX_QUEUE_STATS_COUNT * tx_count;
253	case ETH_SS_TEST:
254		return tsnep_ethtool_get_test_count();
255	default:
256		return -EOPNOTSUPP;
257	}
258}
259
260static int tsnep_ethtool_get_rxnfc(struct net_device *netdev,
261				   struct ethtool_rxnfc *cmd, u32 *rule_locs)
262{
263	struct tsnep_adapter *adapter = netdev_priv(netdev);
264
265	switch (cmd->cmd) {
266	case ETHTOOL_GRXRINGS:
267		cmd->data = adapter->num_rx_queues;
268		return 0;
269	case ETHTOOL_GRXCLSRLCNT:
270		cmd->rule_cnt = adapter->rxnfc_count;
271		cmd->data = adapter->rxnfc_max;
272		cmd->data |= RX_CLS_LOC_SPECIAL;
273		return 0;
274	case ETHTOOL_GRXCLSRULE:
275		return tsnep_rxnfc_get_rule(adapter, cmd);
276	case ETHTOOL_GRXCLSRLALL:
277		return tsnep_rxnfc_get_all(adapter, cmd, rule_locs);
278	default:
279		return -EOPNOTSUPP;
280	}
281}
282
283static int tsnep_ethtool_set_rxnfc(struct net_device *netdev,
284				   struct ethtool_rxnfc *cmd)
285{
286	struct tsnep_adapter *adapter = netdev_priv(netdev);
287
288	switch (cmd->cmd) {
289	case ETHTOOL_SRXCLSRLINS:
290		return tsnep_rxnfc_add_rule(adapter, cmd);
291	case ETHTOOL_SRXCLSRLDEL:
292		return tsnep_rxnfc_del_rule(adapter, cmd);
293	default:
294		return -EOPNOTSUPP;
295	}
296}
297
298static void tsnep_ethtool_get_channels(struct net_device *netdev,
299				       struct ethtool_channels *ch)
300{
301	struct tsnep_adapter *adapter = netdev_priv(netdev);
302
303	ch->max_rx = adapter->num_rx_queues;
304	ch->max_tx = adapter->num_tx_queues;
305	ch->rx_count = adapter->num_rx_queues;
306	ch->tx_count = adapter->num_tx_queues;
307}
308
309static int tsnep_ethtool_get_ts_info(struct net_device *netdev,
310				     struct ethtool_ts_info *info)
311{
312	struct tsnep_adapter *adapter = netdev_priv(netdev);
313
314	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
315				SOF_TIMESTAMPING_RX_SOFTWARE |
316				SOF_TIMESTAMPING_SOFTWARE |
317				SOF_TIMESTAMPING_TX_HARDWARE |
318				SOF_TIMESTAMPING_RX_HARDWARE |
319				SOF_TIMESTAMPING_RAW_HARDWARE;
320
321	if (adapter->ptp_clock)
322		info->phc_index = ptp_clock_index(adapter->ptp_clock);
323	else
324		info->phc_index = -1;
325
326	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
327			 BIT(HWTSTAMP_TX_ON);
328	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
329			   BIT(HWTSTAMP_FILTER_ALL);
330
331	return 0;
332}
333
334static struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter,
335						   int index)
336{
337	int i;
338
339	for (i = 0; i < adapter->num_queues; i++) {
340		if (adapter->queue[i].tx) {
341			if (index == 0)
342				return &adapter->queue[i];
343
344			index--;
345		}
346	}
347
348	return NULL;
349}
350
351static struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter,
352						   int index)
353{
354	int i;
355
356	for (i = 0; i < adapter->num_queues; i++) {
357		if (adapter->queue[i].rx) {
358			if (index == 0)
359				return &adapter->queue[i];
360
361			index--;
362		}
363	}
364
365	return NULL;
366}
367
368static int tsnep_ethtool_get_coalesce(struct net_device *netdev,
369				      struct ethtool_coalesce *ec,
370				      struct kernel_ethtool_coalesce *kernel_coal,
371				      struct netlink_ext_ack *extack)
372{
373	struct tsnep_adapter *adapter = netdev_priv(netdev);
374	struct tsnep_queue *queue;
375
376	queue = tsnep_get_queue_with_rx(adapter, 0);
377	if (queue)
378		ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
379
380	queue = tsnep_get_queue_with_tx(adapter, 0);
381	if (queue)
382		ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
383
384	return 0;
385}
386
387static int tsnep_ethtool_set_coalesce(struct net_device *netdev,
388				      struct ethtool_coalesce *ec,
389				      struct kernel_ethtool_coalesce *kernel_coal,
390				      struct netlink_ext_ack *extack)
391{
392	struct tsnep_adapter *adapter = netdev_priv(netdev);
393	int i;
394	int retval;
395
396	for (i = 0; i < adapter->num_queues; i++) {
397		/* RX coalesce has priority for queues with TX and RX */
398		if (adapter->queue[i].rx)
399			retval = tsnep_set_irq_coalesce(&adapter->queue[i],
400							ec->rx_coalesce_usecs);
401		else
402			retval = tsnep_set_irq_coalesce(&adapter->queue[i],
403							ec->tx_coalesce_usecs);
404		if (retval != 0)
405			return retval;
406	}
407
408	return 0;
409}
410
411static int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev,
412						u32 queue,
413						struct ethtool_coalesce *ec)
414{
415	struct tsnep_adapter *adapter = netdev_priv(netdev);
416	struct tsnep_queue *queue_with_rx;
417	struct tsnep_queue *queue_with_tx;
418
419	if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
420		return -EINVAL;
421
422	queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
423	if (queue_with_rx)
424		ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx);
425
426	queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
427	if (queue_with_tx)
428		ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx);
429
430	return 0;
431}
432
433static int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev,
434						u32 queue,
435						struct ethtool_coalesce *ec)
436{
437	struct tsnep_adapter *adapter = netdev_priv(netdev);
438	struct tsnep_queue *queue_with_rx;
439	struct tsnep_queue *queue_with_tx;
440	int retval;
441
442	if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
443		return -EINVAL;
444
445	queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
446	if (queue_with_rx) {
447		retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs);
448		if (retval != 0)
449			return retval;
450	}
451
452	/* RX coalesce has priority for queues with TX and RX */
453	queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
454	if (queue_with_tx && !queue_with_tx->rx) {
455		retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs);
456		if (retval != 0)
457			return retval;
458	}
459
460	return 0;
461}
462
463const struct ethtool_ops tsnep_ethtool_ops = {
464	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
465	.get_drvinfo = tsnep_ethtool_get_drvinfo,
466	.get_regs_len = tsnep_ethtool_get_regs_len,
467	.get_regs = tsnep_ethtool_get_regs,
468	.get_msglevel = tsnep_ethtool_get_msglevel,
469	.set_msglevel = tsnep_ethtool_set_msglevel,
470	.nway_reset = phy_ethtool_nway_reset,
471	.get_link = ethtool_op_get_link,
472	.self_test = tsnep_ethtool_self_test,
473	.get_strings = tsnep_ethtool_get_strings,
474	.get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
475	.get_sset_count = tsnep_ethtool_get_sset_count,
476	.get_rxnfc = tsnep_ethtool_get_rxnfc,
477	.set_rxnfc = tsnep_ethtool_set_rxnfc,
478	.get_channels = tsnep_ethtool_get_channels,
479	.get_ts_info = tsnep_ethtool_get_ts_info,
480	.get_coalesce = tsnep_ethtool_get_coalesce,
481	.set_coalesce = tsnep_ethtool_set_coalesce,
482	.get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce,
483	.set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce,
484	.get_link_ksettings = phy_ethtool_get_link_ksettings,
485	.set_link_ksettings = phy_ethtool_set_link_ksettings,
486};