File Index
Files and directories
Sign in
FILE

xgbe-ethtool.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c C
  1// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
  2/*
  3 * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
  4 * Copyright (c) 2014, Synopsys, Inc.
  5 * All rights reserved
  6 */
  7
  8#include <linux/spinlock.h>
  9#include <linux/phy.h>
 10#include <linux/net_tstamp.h>
 11
 12#include "xgbe.h"
 13#include "xgbe-common.h"
 14
 15struct xgbe_stats {
 16	char stat_string[ETH_GSTRING_LEN];
 17	int stat_size;
 18	int stat_offset;
 19};
 20
 21#define XGMAC_MMC_STAT(_string, _var)				\
 22	{ _string,						\
 23	  sizeof_field(struct xgbe_mmc_stats, _var),		\
 24	  offsetof(struct xgbe_prv_data, mmc_stats._var),	\
 25	}
 26
 27#define XGMAC_EXT_STAT(_string, _var)				\
 28	{ _string,						\
 29	  sizeof_field(struct xgbe_ext_stats, _var),		\
 30	  offsetof(struct xgbe_prv_data, ext_stats._var),	\
 31	}
 32
 33static const struct xgbe_stats xgbe_gstring_stats[] = {
 34	XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb),
 35	XGMAC_MMC_STAT("tx_packets", txframecount_gb),
 36	XGMAC_MMC_STAT("tx_unicast_packets", txunicastframes_gb),
 37	XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
 38	XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
 39	XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
 40	XGMAC_EXT_STAT("tx_vxlan_packets", tx_vxlan_packets),
 41	XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets),
 42	XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
 43	XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
 44	XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb),
 45	XGMAC_MMC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb),
 46	XGMAC_MMC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb),
 47	XGMAC_MMC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb),
 48	XGMAC_MMC_STAT("tx_underflow_errors", txunderflowerror),
 49	XGMAC_MMC_STAT("tx_pause_frames", txpauseframes),
 50
 51	XGMAC_MMC_STAT("rx_bytes", rxoctetcount_gb),
 52	XGMAC_MMC_STAT("rx_packets", rxframecount_gb),
 53	XGMAC_MMC_STAT("rx_unicast_packets", rxunicastframes_g),
 54	XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g),
 55	XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g),
 56	XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb),
 57	XGMAC_EXT_STAT("rx_vxlan_packets", rx_vxlan_packets),
 58	XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb),
 59	XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb),
 60	XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb),
 61	XGMAC_MMC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb),
 62	XGMAC_MMC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb),
 63	XGMAC_MMC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb),
 64	XGMAC_MMC_STAT("rx_undersize_packets", rxundersize_g),
 65	XGMAC_MMC_STAT("rx_oversize_packets", rxoversize_g),
 66	XGMAC_MMC_STAT("rx_crc_errors", rxcrcerror),
 67	XGMAC_MMC_STAT("rx_crc_errors_small_packets", rxrunterror),
 68	XGMAC_MMC_STAT("rx_crc_errors_giant_packets", rxjabbererror),
 69	XGMAC_MMC_STAT("rx_length_errors", rxlengtherror),
 70	XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype),
 71	XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
 72	XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
 73	XGMAC_EXT_STAT("rx_csum_errors", rx_csum_errors),
 74	XGMAC_EXT_STAT("rx_vxlan_csum_errors", rx_vxlan_csum_errors),
 75	XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
 76	XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
 77	XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable),
 78};
 79
 80#define XGBE_STATS_COUNT	ARRAY_SIZE(xgbe_gstring_stats)
 81
 82static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
 83{
 84	struct xgbe_prv_data *pdata = netdev_priv(netdev);
 85	int i;
 86
 87	switch (stringset) {
 88	case ETH_SS_TEST:
 89		xgbe_selftest_get_strings(pdata, data);
 90		break;
 91	case ETH_SS_STATS:
 92		for (i = 0; i < XGBE_STATS_COUNT; i++)
 93			ethtool_puts(&data, xgbe_gstring_stats[i].stat_string);
 94
 95		for (i = 0; i < pdata->tx_ring_count; i++) {
 96			ethtool_sprintf(&data, "txq_%u_packets", i);
 97			ethtool_sprintf(&data, "txq_%u_bytes", i);
 98		}
 99
100		for (i = 0; i < pdata->rx_ring_count; i++) {
101			ethtool_sprintf(&data, "rxq_%u_packets", i);
102			ethtool_sprintf(&data, "rxq_%u_bytes", i);
103		}
104
105		break;
106	}
107}
108
109static void xgbe_get_ethtool_stats(struct net_device *netdev,
110				   struct ethtool_stats *stats, u64 *data)
111{
112	struct xgbe_prv_data *pdata = netdev_priv(netdev);
113	u8 *stat;
114	int i;
115
116	pdata->hw_if.read_mmc_stats(pdata);
117	for (i = 0; i < XGBE_STATS_COUNT; i++) {
118		stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset;
119		*data++ = *(u64 *)stat;
120	}
121	for (i = 0; i < pdata->tx_ring_count; i++) {
122		*data++ = pdata->ext_stats.txq_packets[i];
123		*data++ = pdata->ext_stats.txq_bytes[i];
124	}
125	for (i = 0; i < pdata->rx_ring_count; i++) {
126		*data++ = pdata->ext_stats.rxq_packets[i];
127		*data++ = pdata->ext_stats.rxq_bytes[i];
128	}
129}
130
131static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
132{
133	struct xgbe_prv_data *pdata = netdev_priv(netdev);
134	int ret;
135
136	switch (stringset) {
137	case ETH_SS_TEST:
138		ret = xgbe_selftest_get_count(pdata);
139		break;
140	case ETH_SS_STATS:
141		ret = XGBE_STATS_COUNT +
142		      (pdata->tx_ring_count * 2) +
143		      (pdata->rx_ring_count * 2);
144		break;
145
146	default:
147		ret = -EOPNOTSUPP;
148	}
149
150	return ret;
151}
152
153static void xgbe_get_pauseparam(struct net_device *netdev,
154				struct ethtool_pauseparam *pause)
155{
156	struct xgbe_prv_data *pdata = netdev_priv(netdev);
157
158	pause->autoneg = pdata->phy.pause_autoneg;
159	pause->tx_pause = pdata->phy.tx_pause;
160	pause->rx_pause = pdata->phy.rx_pause;
161}
162
163static int xgbe_set_pauseparam(struct net_device *netdev,
164			       struct ethtool_pauseparam *pause)
165{
166	struct xgbe_prv_data *pdata = netdev_priv(netdev);
167	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
168	int ret = 0;
169
170	if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
171		netdev_err(netdev,
172			   "autoneg disabled, pause autoneg not available\n");
173		return -EINVAL;
174	}
175
176	pdata->phy.pause_autoneg = pause->autoneg;
177	pdata->phy.tx_pause = pause->tx_pause;
178	pdata->phy.rx_pause = pause->rx_pause;
179
180	XGBE_CLR_ADV(lks, Pause);
181	XGBE_CLR_ADV(lks, Asym_Pause);
182
183	if (pause->rx_pause) {
184		XGBE_SET_ADV(lks, Pause);
185		XGBE_SET_ADV(lks, Asym_Pause);
186	}
187
188	if (pause->tx_pause) {
189		/* Equivalent to XOR of Asym_Pause */
190		if (XGBE_ADV(lks, Asym_Pause))
191			XGBE_CLR_ADV(lks, Asym_Pause);
192		else
193			XGBE_SET_ADV(lks, Asym_Pause);
194	}
195
196	if (netif_running(netdev))
197		ret = pdata->phy_if.phy_config_aneg(pdata);
198
199	return ret;
200}
201
202static int xgbe_get_link_ksettings(struct net_device *netdev,
203				   struct ethtool_link_ksettings *cmd)
204{
205	struct xgbe_prv_data *pdata = netdev_priv(netdev);
206	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
207
208	cmd->base.phy_address = pdata->phy.address;
209
210	if (netif_carrier_ok(netdev)) {
211		cmd->base.speed = pdata->phy.speed;
212		cmd->base.duplex = pdata->phy.duplex;
213	} else {
214		cmd->base.speed = SPEED_UNKNOWN;
215		cmd->base.duplex = DUPLEX_UNKNOWN;
216	}
217
218	cmd->base.autoneg = pdata->phy.autoneg;
219	cmd->base.port = PORT_NONE;
220
221	XGBE_LM_COPY(cmd, supported, lks, supported);
222	XGBE_LM_COPY(cmd, advertising, lks, advertising);
223	XGBE_LM_COPY(cmd, lp_advertising, lks, lp_advertising);
224
225	return 0;
226}
227
228static int xgbe_set_link_ksettings(struct net_device *netdev,
229				   const struct ethtool_link_ksettings *cmd)
230{
231	struct xgbe_prv_data *pdata = netdev_priv(netdev);
232	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
233	__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
234	u32 speed;
235	int ret;
236
237	speed = cmd->base.speed;
238
239	if (cmd->base.phy_address != pdata->phy.address) {
240		netdev_err(netdev, "invalid phy address %hhu\n",
241			   cmd->base.phy_address);
242		return -EINVAL;
243	}
244
245	if ((cmd->base.autoneg != AUTONEG_ENABLE) &&
246	    (cmd->base.autoneg != AUTONEG_DISABLE)) {
247		netdev_err(netdev, "unsupported autoneg %hhu\n",
248			   cmd->base.autoneg);
249		return -EINVAL;
250	}
251
252	if (cmd->base.autoneg == AUTONEG_DISABLE) {
253		if (!pdata->phy_if.phy_valid_speed(pdata, speed)) {
254			netdev_err(netdev, "unsupported speed %u\n", speed);
255			return -EINVAL;
256		}
257
258		if (cmd->base.duplex != DUPLEX_FULL) {
259			netdev_err(netdev, "unsupported duplex %hhu\n",
260				   cmd->base.duplex);
261			return -EINVAL;
262		}
263	}
264
265	netif_dbg(pdata, link, netdev,
266		  "requested advertisement 0x%*pb, phy supported 0x%*pb\n",
267		  __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising,
268		  __ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported);
269
270	linkmode_and(advertising, cmd->link_modes.advertising,
271		     lks->link_modes.supported);
272
273	if ((cmd->base.autoneg == AUTONEG_ENABLE) &&
274	    bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
275		netdev_err(netdev,
276			   "unsupported requested advertisement\n");
277		return -EINVAL;
278	}
279
280	ret = 0;
281	pdata->phy.autoneg = cmd->base.autoneg;
282	pdata->phy.speed = speed;
283	pdata->phy.duplex = cmd->base.duplex;
284	linkmode_copy(lks->link_modes.advertising, advertising);
285
286	if (cmd->base.autoneg == AUTONEG_ENABLE)
287		XGBE_SET_ADV(lks, Autoneg);
288	else
289		XGBE_CLR_ADV(lks, Autoneg);
290
291	if (netif_running(netdev))
292		ret = pdata->phy_if.phy_config_aneg(pdata);
293
294	return ret;
295}
296
297static void xgbe_get_drvinfo(struct net_device *netdev,
298			     struct ethtool_drvinfo *drvinfo)
299{
300	struct xgbe_prv_data *pdata = netdev_priv(netdev);
301	struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
302
303	strscpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver));
304	strscpy(drvinfo->bus_info, dev_name(pdata->dev),
305		sizeof(drvinfo->bus_info));
306	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d",
307		 XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
308		 XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
309		 XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
310}
311
312static u32 xgbe_get_msglevel(struct net_device *netdev)
313{
314	struct xgbe_prv_data *pdata = netdev_priv(netdev);
315
316	return pdata->msg_enable;
317}
318
319static void xgbe_set_msglevel(struct net_device *netdev, u32 msglevel)
320{
321	struct xgbe_prv_data *pdata = netdev_priv(netdev);
322
323	pdata->msg_enable = msglevel;
324}
325
326static int xgbe_get_coalesce(struct net_device *netdev,
327			     struct ethtool_coalesce *ec,
328			     struct kernel_ethtool_coalesce *kernel_coal,
329			     struct netlink_ext_ack *extack)
330{
331	struct xgbe_prv_data *pdata = netdev_priv(netdev);
332
333	memset(ec, 0, sizeof(struct ethtool_coalesce));
334
335	ec->rx_coalesce_usecs = pdata->rx_usecs;
336	ec->rx_max_coalesced_frames = pdata->rx_frames;
337
338	ec->tx_coalesce_usecs = pdata->tx_usecs;
339	ec->tx_max_coalesced_frames = pdata->tx_frames;
340
341	return 0;
342}
343
344static int xgbe_set_coalesce(struct net_device *netdev,
345			     struct ethtool_coalesce *ec,
346			     struct kernel_ethtool_coalesce *kernel_coal,
347			     struct netlink_ext_ack *extack)
348{
349	struct xgbe_prv_data *pdata = netdev_priv(netdev);
350	struct xgbe_hw_if *hw_if = &pdata->hw_if;
351	unsigned int rx_frames, rx_riwt, rx_usecs;
352	unsigned int tx_frames, tx_usecs;
353	unsigned int jiffy_us = jiffies_to_usecs(1);
354
355	rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs);
356	rx_usecs = ec->rx_coalesce_usecs;
357	rx_frames = ec->rx_max_coalesced_frames;
358
359	/* Use smallest possible value if conversion resulted in zero */
360	if (rx_usecs && !rx_riwt)
361		rx_riwt = 1;
362
363	/* Check the bounds of values for Rx */
364	if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
365		netdev_err(netdev, "rx-usec is limited to %d usecs\n",
366			   hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT));
367		return -EINVAL;
368	}
369	if (rx_frames > pdata->rx_desc_count) {
370		netdev_err(netdev, "rx-frames is limited to %d frames\n",
371			   pdata->rx_desc_count);
372		return -EINVAL;
373	}
374
375	tx_usecs = ec->tx_coalesce_usecs;
376	tx_frames = ec->tx_max_coalesced_frames;
377
378	/* Check the bounds of values for Tx */
379	if (!tx_usecs) {
380		NL_SET_ERR_MSG_FMT_MOD(extack,
381				       "tx-usecs must not be 0");
382		return -EINVAL;
383	}
384	if (tx_usecs > XGMAC_MAX_COAL_TX_TICK) {
385		NL_SET_ERR_MSG_FMT_MOD(extack, "tx-usecs is limited to %d usec",
386				       XGMAC_MAX_COAL_TX_TICK);
387		return -EINVAL;
388	}
389	if (tx_frames > pdata->tx_desc_count) {
390		netdev_err(netdev, "tx-frames is limited to %d frames\n",
391			   pdata->tx_desc_count);
392		return -EINVAL;
393	}
394
395	/* Round tx-usecs to nearest multiple of jiffy granularity */
396	if (tx_usecs % jiffy_us) {
397		tx_usecs = rounddown(tx_usecs, jiffy_us);
398		if (!tx_usecs)
399			tx_usecs = jiffy_us;
400		NL_SET_ERR_MSG_FMT_MOD(extack,
401				       "tx-usecs rounded to %u usec due to jiffy granularity (%u usec)",
402				       tx_usecs, jiffy_us);
403	}
404
405	pdata->rx_riwt = rx_riwt;
406	pdata->rx_usecs = rx_usecs;
407	pdata->rx_frames = rx_frames;
408	hw_if->config_rx_coalesce(pdata);
409
410	pdata->tx_usecs = tx_usecs;
411	pdata->tx_frames = tx_frames;
412	hw_if->config_tx_coalesce(pdata);
413
414	return 0;
415}
416
417static int xgbe_get_rxnfc(struct net_device *netdev,
418			  struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
419{
420	struct xgbe_prv_data *pdata = netdev_priv(netdev);
421
422	switch (rxnfc->cmd) {
423	case ETHTOOL_GRXRINGS:
424		rxnfc->data = pdata->rx_ring_count;
425		break;
426	default:
427		return -EOPNOTSUPP;
428	}
429
430	return 0;
431}
432
433static u32 xgbe_get_rxfh_key_size(struct net_device *netdev)
434{
435	struct xgbe_prv_data *pdata = netdev_priv(netdev);
436
437	return sizeof(pdata->rss_key);
438}
439
440static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
441{
442	struct xgbe_prv_data *pdata = netdev_priv(netdev);
443
444	return ARRAY_SIZE(pdata->rss_table);
445}
446
447static int xgbe_get_rxfh(struct net_device *netdev,
448			 struct ethtool_rxfh_param *rxfh)
449{
450	struct xgbe_prv_data *pdata = netdev_priv(netdev);
451	unsigned int i;
452
453	if (rxfh->indir) {
454		for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
455			rxfh->indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
456							MAC_RSSDR, DMCH);
457	}
458
459	if (rxfh->key)
460		memcpy(rxfh->key, pdata->rss_key, sizeof(pdata->rss_key));
461
462	rxfh->hfunc = ETH_RSS_HASH_TOP;
463
464	return 0;
465}
466
467static int xgbe_set_rxfh(struct net_device *netdev,
468			 struct ethtool_rxfh_param *rxfh,
469			 struct netlink_ext_ack *extack)
470{
471	struct xgbe_prv_data *pdata = netdev_priv(netdev);
472	struct xgbe_hw_if *hw_if = &pdata->hw_if;
473	int ret;
474
475	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
476	    rxfh->hfunc != ETH_RSS_HASH_TOP) {
477		netdev_err(netdev, "unsupported hash function\n");
478		return -EOPNOTSUPP;
479	}
480
481	if (rxfh->indir) {
482		ret = hw_if->set_rss_lookup_table(pdata, rxfh->indir);
483		if (ret)
484			return ret;
485	}
486
487	if (rxfh->key) {
488		ret = hw_if->set_rss_hash_key(pdata, rxfh->key);
489		if (ret)
490			return ret;
491	}
492
493	return 0;
494}
495
496static int xgbe_get_ts_info(struct net_device *netdev,
497			    struct kernel_ethtool_ts_info *ts_info)
498{
499	struct xgbe_prv_data *pdata = netdev_priv(netdev);
500
501	ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
502				   SOF_TIMESTAMPING_TX_HARDWARE |
503				   SOF_TIMESTAMPING_RX_HARDWARE |
504				   SOF_TIMESTAMPING_RAW_HARDWARE;
505
506	if (pdata->ptp_clock)
507		ts_info->phc_index = ptp_clock_index(pdata->ptp_clock);
508
509	ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
510	ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
511			      (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
512			      (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
513			      (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
514			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
515			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
516			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
517			      (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
518			      (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
519			      (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
520			      (1 << HWTSTAMP_FILTER_ALL);
521
522	return 0;
523}
524
525static int xgbe_get_module_info(struct net_device *netdev,
526				struct ethtool_modinfo *modinfo)
527{
528	struct xgbe_prv_data *pdata = netdev_priv(netdev);
529
530	return pdata->phy_if.module_info(pdata, modinfo);
531}
532
533static int xgbe_get_module_eeprom(struct net_device *netdev,
534				  struct ethtool_eeprom *eeprom, u8 *data)
535{
536	struct xgbe_prv_data *pdata = netdev_priv(netdev);
537
538	return pdata->phy_if.module_eeprom(pdata, eeprom, data);
539}
540
541static void
542xgbe_get_ringparam(struct net_device *netdev,
543		   struct ethtool_ringparam *ringparam,
544		   struct kernel_ethtool_ringparam *kernel_ringparam,
545		   struct netlink_ext_ack *extack)
546{
547	struct xgbe_prv_data *pdata = netdev_priv(netdev);
548
549	ringparam->rx_max_pending = XGBE_RX_DESC_CNT_MAX;
550	ringparam->tx_max_pending = XGBE_TX_DESC_CNT_MAX;
551	ringparam->rx_pending = pdata->rx_desc_count;
552	ringparam->tx_pending = pdata->tx_desc_count;
553}
554
555static int xgbe_set_ringparam(struct net_device *netdev,
556			      struct ethtool_ringparam *ringparam,
557			      struct kernel_ethtool_ringparam *kernel_ringparam,
558			      struct netlink_ext_ack *extack)
559{
560	struct xgbe_prv_data *pdata = netdev_priv(netdev);
561	unsigned int rx, tx;
562
563	if (ringparam->rx_mini_pending || ringparam->rx_jumbo_pending) {
564		netdev_err(netdev, "unsupported ring parameter\n");
565		return -EINVAL;
566	}
567
568	if ((ringparam->rx_pending < XGBE_RX_DESC_CNT_MIN) ||
569	    (ringparam->rx_pending > XGBE_RX_DESC_CNT_MAX)) {
570		netdev_err(netdev,
571			   "rx ring parameter must be between %u and %u\n",
572			   XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MAX);
573		return -EINVAL;
574	}
575
576	if ((ringparam->tx_pending < XGBE_TX_DESC_CNT_MIN) ||
577	    (ringparam->tx_pending > XGBE_TX_DESC_CNT_MAX)) {
578		netdev_err(netdev,
579			   "tx ring parameter must be between %u and %u\n",
580			   XGBE_TX_DESC_CNT_MIN, XGBE_TX_DESC_CNT_MAX);
581		return -EINVAL;
582	}
583
584	rx = __rounddown_pow_of_two(ringparam->rx_pending);
585	if (rx != ringparam->rx_pending)
586		netdev_notice(netdev,
587			      "rx ring parameter rounded to power of two: %u\n",
588			      rx);
589
590	tx = __rounddown_pow_of_two(ringparam->tx_pending);
591	if (tx != ringparam->tx_pending)
592		netdev_notice(netdev,
593			      "tx ring parameter rounded to power of two: %u\n",
594			      tx);
595
596	if ((rx == pdata->rx_desc_count) &&
597	    (tx == pdata->tx_desc_count))
598		goto out;
599
600	pdata->rx_desc_count = rx;
601	pdata->tx_desc_count = tx;
602
603	xgbe_restart_dev(pdata);
604
605out:
606	return 0;
607}
608
609static void xgbe_get_channels(struct net_device *netdev,
610			      struct ethtool_channels *channels)
611{
612	struct xgbe_prv_data *pdata = netdev_priv(netdev);
613	unsigned int rx, tx, combined;
614
615	/* Calculate maximums allowed:
616	 *   - Take into account the number of available IRQs
617	 *   - Do not take into account the number of online CPUs so that
618	 *     the user can over-subscribe if desired
619	 *   - Tx is additionally limited by the number of hardware queues
620	 */
621	rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
622	rx = min(rx, pdata->channel_irq_count);
623	tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
624	tx = min(tx, pdata->channel_irq_count);
625	tx = min(tx, pdata->tx_max_q_count);
626
627	combined = min(rx, tx);
628
629	channels->max_combined = combined;
630	channels->max_rx = rx ? rx - 1 : 0;
631	channels->max_tx = tx ? tx - 1 : 0;
632
633	/* Get current settings based on device state */
634	rx = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
635	tx = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
636
637	combined = min(rx, tx);
638	rx -= combined;
639	tx -= combined;
640
641	channels->combined_count = combined;
642	channels->rx_count = rx;
643	channels->tx_count = tx;
644}
645
646static void xgbe_print_set_channels_input(struct net_device *netdev,
647					  struct ethtool_channels *channels)
648{
649	netdev_err(netdev, "channel inputs: combined=%u, rx-only=%u, tx-only=%u\n",
650		   channels->combined_count, channels->rx_count,
651		   channels->tx_count);
652}
653
654static int xgbe_set_channels(struct net_device *netdev,
655			     struct ethtool_channels *channels)
656{
657	struct xgbe_prv_data *pdata = netdev_priv(netdev);
658	unsigned int rx, rx_curr, tx, tx_curr, combined;
659
660	/* Calculate maximums allowed:
661	 *   - Take into account the number of available IRQs
662	 *   - Do not take into account the number of online CPUs so that
663	 *     the user can over-subscribe if desired
664	 *   - Tx is additionally limited by the number of hardware queues
665	 */
666	rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
667	rx = min(rx, pdata->channel_irq_count);
668	tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
669	tx = min(tx, pdata->tx_max_q_count);
670	tx = min(tx, pdata->channel_irq_count);
671
672	combined = min(rx, tx);
673
674	/* Should not be setting other count */
675	if (channels->other_count) {
676		netdev_err(netdev,
677			   "other channel count must be zero\n");
678		return -EINVAL;
679	}
680
681	/* Require at least one Combined (Rx and Tx) channel */
682	if (!channels->combined_count) {
683		netdev_err(netdev,
684			   "at least one combined Rx/Tx channel is required\n");
685		xgbe_print_set_channels_input(netdev, channels);
686		return -EINVAL;
687	}
688
689	/* Check combined channels */
690	if (channels->combined_count > combined) {
691		netdev_err(netdev,
692			   "combined channel count cannot exceed %u\n",
693			   combined);
694		xgbe_print_set_channels_input(netdev, channels);
695		return -EINVAL;
696	}
697
698	/* Can have some Rx-only or Tx-only channels, but not both */
699	if (channels->rx_count && channels->tx_count) {
700		netdev_err(netdev,
701			   "cannot specify both Rx-only and Tx-only channels\n");
702		xgbe_print_set_channels_input(netdev, channels);
703		return -EINVAL;
704	}
705
706	/* Check that we don't exceed the maximum number of channels */
707	if ((channels->combined_count + channels->rx_count) > rx) {
708		netdev_err(netdev,
709			   "total Rx channels (%u) requested exceeds maximum available (%u)\n",
710			   channels->combined_count + channels->rx_count, rx);
711		xgbe_print_set_channels_input(netdev, channels);
712		return -EINVAL;
713	}
714
715	if ((channels->combined_count + channels->tx_count) > tx) {
716		netdev_err(netdev,
717			   "total Tx channels (%u) requested exceeds maximum available (%u)\n",
718			   channels->combined_count + channels->tx_count, tx);
719		xgbe_print_set_channels_input(netdev, channels);
720		return -EINVAL;
721	}
722
723	rx = channels->combined_count + channels->rx_count;
724	tx = channels->combined_count + channels->tx_count;
725
726	rx_curr = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
727	tx_curr = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
728
729	if ((rx == rx_curr) && (tx == tx_curr))
730		goto out;
731
732	pdata->new_rx_ring_count = rx;
733	pdata->new_tx_ring_count = tx;
734
735	xgbe_full_restart_dev(pdata);
736
737out:
738	return 0;
739}
740
741static const struct ethtool_ops xgbe_ethtool_ops = {
742	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
743				     ETHTOOL_COALESCE_MAX_FRAMES,
744	.get_drvinfo = xgbe_get_drvinfo,
745	.get_msglevel = xgbe_get_msglevel,
746	.set_msglevel = xgbe_set_msglevel,
747	.get_link = ethtool_op_get_link,
748	.get_coalesce = xgbe_get_coalesce,
749	.set_coalesce = xgbe_set_coalesce,
750	.get_pauseparam = xgbe_get_pauseparam,
751	.set_pauseparam = xgbe_set_pauseparam,
752	.get_strings = xgbe_get_strings,
753	.get_ethtool_stats = xgbe_get_ethtool_stats,
754	.get_sset_count = xgbe_get_sset_count,
755	.get_rxnfc = xgbe_get_rxnfc,
756	.get_rxfh_key_size = xgbe_get_rxfh_key_size,
757	.get_rxfh_indir_size = xgbe_get_rxfh_indir_size,
758	.get_rxfh = xgbe_get_rxfh,
759	.set_rxfh = xgbe_set_rxfh,
760	.get_ts_info = xgbe_get_ts_info,
761	.get_link_ksettings = xgbe_get_link_ksettings,
762	.set_link_ksettings = xgbe_set_link_ksettings,
763	.get_module_info = xgbe_get_module_info,
764	.get_module_eeprom = xgbe_get_module_eeprom,
765	.get_ringparam = xgbe_get_ringparam,
766	.set_ringparam = xgbe_set_ringparam,
767	.get_channels = xgbe_get_channels,
768	.set_channels = xgbe_set_channels,
769	.self_test = xgbe_selftest_run,
770};
771
772const struct ethtool_ops *xgbe_get_ethtool_ops(void)
773{
774	return &xgbe_ethtool_ops;
775}
~/ Read-only file preview.