brintos

brintos / linux-shallow public Read only

0
0
Text · 32.9 KiB · ba83dbf Raw
1196 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2 3#include <linux/ethtool.h>4#include <linux/linkmode.h>5#include <linux/netdevice.h>6#include <linux/nvme.h>7#include <linux/io.h>8#include <linux/io-64-nonatomic-lo-hi.h>9#include <linux/pci.h>10#include <linux/rtnetlink.h>11#include "funeth.h"12#include "fun_port.h"13#include "funeth_txrx.h"14 15/* Min queue depth. The smallest power-of-2 supporting jumbo frames with 4K16 * pages is 8. Require it for all types of queues though some could work with17 * fewer entries.18 */19#define FUNETH_MIN_QDEPTH 820 21static const char mac_tx_stat_names[][ETH_GSTRING_LEN] = {22	"mac_tx_octets_total",23	"mac_tx_frames_total",24	"mac_tx_vlan_frames_ok",25	"mac_tx_unicast_frames",26	"mac_tx_multicast_frames",27	"mac_tx_broadcast_frames",28	"mac_tx_errors",29	"mac_tx_CBFCPAUSE0",30	"mac_tx_CBFCPAUSE1",31	"mac_tx_CBFCPAUSE2",32	"mac_tx_CBFCPAUSE3",33	"mac_tx_CBFCPAUSE4",34	"mac_tx_CBFCPAUSE5",35	"mac_tx_CBFCPAUSE6",36	"mac_tx_CBFCPAUSE7",37	"mac_tx_CBFCPAUSE8",38	"mac_tx_CBFCPAUSE9",39	"mac_tx_CBFCPAUSE10",40	"mac_tx_CBFCPAUSE11",41	"mac_tx_CBFCPAUSE12",42	"mac_tx_CBFCPAUSE13",43	"mac_tx_CBFCPAUSE14",44	"mac_tx_CBFCPAUSE15",45};46 47static const char mac_rx_stat_names[][ETH_GSTRING_LEN] = {48	"mac_rx_octets_total",49	"mac_rx_frames_total",50	"mac_rx_VLAN_frames_ok",51	"mac_rx_unicast_frames",52	"mac_rx_multicast_frames",53	"mac_rx_broadcast_frames",54	"mac_rx_drop_events",55	"mac_rx_errors",56	"mac_rx_alignment_errors",57	"mac_rx_CBFCPAUSE0",58	"mac_rx_CBFCPAUSE1",59	"mac_rx_CBFCPAUSE2",60	"mac_rx_CBFCPAUSE3",61	"mac_rx_CBFCPAUSE4",62	"mac_rx_CBFCPAUSE5",63	"mac_rx_CBFCPAUSE6",64	"mac_rx_CBFCPAUSE7",65	"mac_rx_CBFCPAUSE8",66	"mac_rx_CBFCPAUSE9",67	"mac_rx_CBFCPAUSE10",68	"mac_rx_CBFCPAUSE11",69	"mac_rx_CBFCPAUSE12",70	"mac_rx_CBFCPAUSE13",71	"mac_rx_CBFCPAUSE14",72	"mac_rx_CBFCPAUSE15",73};74 75static const char * const txq_stat_names[] = {76	"tx_pkts",77	"tx_bytes",78	"tx_cso",79	"tx_tso",80	"tx_encapsulated_tso",81	"tx_uso",82	"tx_more",83	"tx_queue_stops",84	"tx_queue_restarts",85	"tx_mapping_errors",86	"tx_tls_encrypted_packets",87	"tx_tls_encrypted_bytes",88	"tx_tls_ooo",89	"tx_tls_drop_no_sync_data",90};91 92static const char * const xdpq_stat_names[] = {93	"tx_xdp_pkts",94	"tx_xdp_bytes",95	"tx_xdp_full",96	"tx_xdp_mapping_errors",97};98 99static const char * const rxq_stat_names[] = {100	"rx_pkts",101	"rx_bytes",102	"rx_cso",103	"gro_pkts",104	"gro_merged",105	"rx_xdp_tx",106	"rx_xdp_redir",107	"rx_xdp_drops",108	"rx_buffers",109	"rx_page_allocs",110	"rx_drops",111	"rx_budget_exhausted",112	"rx_mapping_errors",113};114 115static const char * const tls_stat_names[] = {116	"tx_tls_ctx",117	"tx_tls_del",118	"tx_tls_resync",119};120 121static void fun_link_modes_to_ethtool(u64 modes,122				      unsigned long *ethtool_modes_map)123{124#define ADD_LINK_MODE(mode) \125	__set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, ethtool_modes_map)126 127	if (modes & FUN_PORT_CAP_AUTONEG)128		ADD_LINK_MODE(Autoneg);129	if (modes & FUN_PORT_CAP_1000_X)130		ADD_LINK_MODE(1000baseX_Full);131	if (modes & FUN_PORT_CAP_10G_R) {132		ADD_LINK_MODE(10000baseCR_Full);133		ADD_LINK_MODE(10000baseSR_Full);134		ADD_LINK_MODE(10000baseLR_Full);135		ADD_LINK_MODE(10000baseER_Full);136	}137	if (modes & FUN_PORT_CAP_25G_R) {138		ADD_LINK_MODE(25000baseCR_Full);139		ADD_LINK_MODE(25000baseSR_Full);140	}141	if (modes & FUN_PORT_CAP_40G_R4) {142		ADD_LINK_MODE(40000baseCR4_Full);143		ADD_LINK_MODE(40000baseSR4_Full);144		ADD_LINK_MODE(40000baseLR4_Full);145	}146	if (modes & FUN_PORT_CAP_50G_R2) {147		ADD_LINK_MODE(50000baseCR2_Full);148		ADD_LINK_MODE(50000baseSR2_Full);149	}150	if (modes & FUN_PORT_CAP_50G_R) {151		ADD_LINK_MODE(50000baseCR_Full);152		ADD_LINK_MODE(50000baseSR_Full);153		ADD_LINK_MODE(50000baseLR_ER_FR_Full);154	}155	if (modes & FUN_PORT_CAP_100G_R4) {156		ADD_LINK_MODE(100000baseCR4_Full);157		ADD_LINK_MODE(100000baseSR4_Full);158		ADD_LINK_MODE(100000baseLR4_ER4_Full);159	}160	if (modes & FUN_PORT_CAP_100G_R2) {161		ADD_LINK_MODE(100000baseCR2_Full);162		ADD_LINK_MODE(100000baseSR2_Full);163		ADD_LINK_MODE(100000baseLR2_ER2_FR2_Full);164	}165	if (modes & FUN_PORT_CAP_FEC_NONE)166		ADD_LINK_MODE(FEC_NONE);167	if (modes & FUN_PORT_CAP_FEC_FC)168		ADD_LINK_MODE(FEC_BASER);169	if (modes & FUN_PORT_CAP_FEC_RS)170		ADD_LINK_MODE(FEC_RS);171	if (modes & FUN_PORT_CAP_RX_PAUSE)172		ADD_LINK_MODE(Pause);173 174#undef ADD_LINK_MODE175}176 177static void set_asym_pause(u64 advertising, struct ethtool_link_ksettings *ks)178{179	bool rx_pause, tx_pause;180 181	rx_pause = advertising & FUN_PORT_CAP_RX_PAUSE;182	tx_pause = advertising & FUN_PORT_CAP_TX_PAUSE;183	if (tx_pause ^ rx_pause)184		ethtool_link_ksettings_add_link_mode(ks, advertising,185						     Asym_Pause);186}187 188static unsigned int fun_port_type(unsigned int xcvr)189{190	if (!xcvr)191		return PORT_NONE;192 193	switch (xcvr & 7) {194	case FUN_XCVR_BASET:195		return PORT_TP;196	case FUN_XCVR_CU:197		return PORT_DA;198	default:199		return PORT_FIBRE;200	}201}202 203static int fun_get_link_ksettings(struct net_device *netdev,204				  struct ethtool_link_ksettings *ks)205{206	const struct funeth_priv *fp = netdev_priv(netdev);207	unsigned int seq, speed, xcvr;208	u64 lp_advertising;209	bool link_up;210 211	ethtool_link_ksettings_zero_link_mode(ks, supported);212	ethtool_link_ksettings_zero_link_mode(ks, advertising);213	ethtool_link_ksettings_zero_link_mode(ks, lp_advertising);214 215	/* Link settings change asynchronously, take a consistent snapshot */216	do {217		seq = read_seqcount_begin(&fp->link_seq);218		link_up = netif_carrier_ok(netdev);219		speed = fp->link_speed;220		xcvr = fp->xcvr_type;221		lp_advertising = fp->lp_advertising;222	} while (read_seqcount_retry(&fp->link_seq, seq));223 224	if (link_up) {225		ks->base.speed = speed;226		ks->base.duplex = DUPLEX_FULL;227		fun_link_modes_to_ethtool(lp_advertising,228					  ks->link_modes.lp_advertising);229	} else {230		ks->base.speed = SPEED_UNKNOWN;231		ks->base.duplex = DUPLEX_UNKNOWN;232	}233 234	ks->base.autoneg = (fp->advertising & FUN_PORT_CAP_AUTONEG) ?235			   AUTONEG_ENABLE : AUTONEG_DISABLE;236	ks->base.port = fun_port_type(xcvr);237 238	fun_link_modes_to_ethtool(fp->port_caps, ks->link_modes.supported);239	if (fp->port_caps & (FUN_PORT_CAP_RX_PAUSE | FUN_PORT_CAP_TX_PAUSE))240		ethtool_link_ksettings_add_link_mode(ks, supported, Asym_Pause);241 242	fun_link_modes_to_ethtool(fp->advertising, ks->link_modes.advertising);243	set_asym_pause(fp->advertising, ks);244	return 0;245}246 247static u64 fun_advert_modes(const struct ethtool_link_ksettings *ks)248{249	u64 modes = 0;250 251#define HAS_MODE(mode) \252	ethtool_link_ksettings_test_link_mode(ks, advertising, mode)253 254	if (HAS_MODE(1000baseX_Full))255		modes |= FUN_PORT_CAP_1000_X;256	if (HAS_MODE(10000baseCR_Full) || HAS_MODE(10000baseSR_Full) ||257	    HAS_MODE(10000baseLR_Full) || HAS_MODE(10000baseER_Full))258		modes |= FUN_PORT_CAP_10G_R;259	if (HAS_MODE(25000baseCR_Full) || HAS_MODE(25000baseSR_Full))260		modes |= FUN_PORT_CAP_25G_R;261	if (HAS_MODE(40000baseCR4_Full) || HAS_MODE(40000baseSR4_Full) ||262	    HAS_MODE(40000baseLR4_Full))263		modes |= FUN_PORT_CAP_40G_R4;264	if (HAS_MODE(50000baseCR2_Full) || HAS_MODE(50000baseSR2_Full))265		modes |= FUN_PORT_CAP_50G_R2;266	if (HAS_MODE(50000baseCR_Full) || HAS_MODE(50000baseSR_Full) ||267	    HAS_MODE(50000baseLR_ER_FR_Full))268		modes |= FUN_PORT_CAP_50G_R;269	if (HAS_MODE(100000baseCR4_Full) || HAS_MODE(100000baseSR4_Full) ||270	    HAS_MODE(100000baseLR4_ER4_Full))271		modes |= FUN_PORT_CAP_100G_R4;272	if (HAS_MODE(100000baseCR2_Full) || HAS_MODE(100000baseSR2_Full) ||273	    HAS_MODE(100000baseLR2_ER2_FR2_Full))274		modes |= FUN_PORT_CAP_100G_R2;275 276	return modes;277#undef HAS_MODE278}279 280static u64 fun_speed_to_link_mode(unsigned int speed)281{282	switch (speed) {283	case SPEED_100000:284		return FUN_PORT_CAP_100G_R4 | FUN_PORT_CAP_100G_R2;285	case SPEED_50000:286		return FUN_PORT_CAP_50G_R | FUN_PORT_CAP_50G_R2;287	case SPEED_40000:288		return FUN_PORT_CAP_40G_R4;289	case SPEED_25000:290		return FUN_PORT_CAP_25G_R;291	case SPEED_10000:292		return FUN_PORT_CAP_10G_R;293	case SPEED_1000:294		return FUN_PORT_CAP_1000_X;295	default:296		return 0;297	}298}299 300static int fun_change_advert(struct funeth_priv *fp, u64 new_advert)301{302	int err;303 304	if (new_advert == fp->advertising)305		return 0;306 307	err = fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT, new_advert);308	if (!err)309		fp->advertising = new_advert;310	return err;311}312 313#define FUN_PORT_CAP_FEC_MASK \314	(FUN_PORT_CAP_FEC_NONE | FUN_PORT_CAP_FEC_FC | FUN_PORT_CAP_FEC_RS)315 316static int fun_set_link_ksettings(struct net_device *netdev,317				  const struct ethtool_link_ksettings *ks)318{319	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {};320	struct funeth_priv *fp = netdev_priv(netdev);321	u64 new_advert;322 323	/* eswitch ports don't support mode changes */324	if (fp->port_caps & FUN_PORT_CAP_VPORT)325		return -EOPNOTSUPP;326 327	if (ks->base.duplex == DUPLEX_HALF)328		return -EINVAL;329	if (ks->base.autoneg == AUTONEG_ENABLE &&330	    !(fp->port_caps & FUN_PORT_CAP_AUTONEG))331		return -EINVAL;332 333	if (ks->base.autoneg == AUTONEG_ENABLE) {334		if (linkmode_empty(ks->link_modes.advertising))335			return -EINVAL;336 337		fun_link_modes_to_ethtool(fp->port_caps, supported);338		if (!linkmode_subset(ks->link_modes.advertising, supported))339			return -EINVAL;340 341		new_advert = fun_advert_modes(ks) | FUN_PORT_CAP_AUTONEG;342	} else {343		new_advert = fun_speed_to_link_mode(ks->base.speed);344		new_advert &= fp->port_caps;345		if (!new_advert)346			return -EINVAL;347	}348	new_advert |= fp->advertising &349		      (FUN_PORT_CAP_PAUSE_MASK | FUN_PORT_CAP_FEC_MASK);350 351	return fun_change_advert(fp, new_advert);352}353 354static void fun_get_pauseparam(struct net_device *netdev,355			       struct ethtool_pauseparam *pause)356{357	const struct funeth_priv *fp = netdev_priv(netdev);358	u8 active_pause = fp->active_fc;359 360	pause->rx_pause = !!(active_pause & FUN_PORT_CAP_RX_PAUSE);361	pause->tx_pause = !!(active_pause & FUN_PORT_CAP_TX_PAUSE);362	pause->autoneg = !!(fp->advertising & FUN_PORT_CAP_AUTONEG);363}364 365static int fun_set_pauseparam(struct net_device *netdev,366			      struct ethtool_pauseparam *pause)367{368	struct funeth_priv *fp = netdev_priv(netdev);369	u64 new_advert;370 371	if (fp->port_caps & FUN_PORT_CAP_VPORT)372		return -EOPNOTSUPP;373	/* Forcing PAUSE settings with AN enabled is unsupported. */374	if (!pause->autoneg && (fp->advertising & FUN_PORT_CAP_AUTONEG))375		return -EOPNOTSUPP;376	if (pause->autoneg && !(fp->advertising & FUN_PORT_CAP_AUTONEG))377		return -EINVAL;378	if (pause->tx_pause && !(fp->port_caps & FUN_PORT_CAP_TX_PAUSE))379		return -EINVAL;380	if (pause->rx_pause && !(fp->port_caps & FUN_PORT_CAP_RX_PAUSE))381		return -EINVAL;382 383	new_advert = fp->advertising & ~FUN_PORT_CAP_PAUSE_MASK;384	if (pause->tx_pause)385		new_advert |= FUN_PORT_CAP_TX_PAUSE;386	if (pause->rx_pause)387		new_advert |= FUN_PORT_CAP_RX_PAUSE;388 389	return fun_change_advert(fp, new_advert);390}391 392static int fun_restart_an(struct net_device *netdev)393{394	struct funeth_priv *fp = netdev_priv(netdev);395 396	if (!(fp->advertising & FUN_PORT_CAP_AUTONEG))397		return -EOPNOTSUPP;398 399	return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT,400				  FUN_PORT_CAP_AUTONEG);401}402 403static int fun_set_phys_id(struct net_device *netdev,404			   enum ethtool_phys_id_state state)405{406	struct funeth_priv *fp = netdev_priv(netdev);407	unsigned int beacon;408 409	if (fp->port_caps & FUN_PORT_CAP_VPORT)410		return -EOPNOTSUPP;411	if (state != ETHTOOL_ID_ACTIVE && state != ETHTOOL_ID_INACTIVE)412		return -EOPNOTSUPP;413 414	beacon = state == ETHTOOL_ID_ACTIVE ? FUN_PORT_LED_BEACON_ON :415					      FUN_PORT_LED_BEACON_OFF;416	return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_LED, beacon);417}418 419static void fun_get_drvinfo(struct net_device *netdev,420			    struct ethtool_drvinfo *info)421{422	const struct funeth_priv *fp = netdev_priv(netdev);423 424	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));425	strscpy(info->bus_info, pci_name(fp->pdev), sizeof(info->bus_info));426}427 428static u32 fun_get_msglevel(struct net_device *netdev)429{430	const struct funeth_priv *fp = netdev_priv(netdev);431 432	return fp->msg_enable;433}434 435static void fun_set_msglevel(struct net_device *netdev, u32 value)436{437	struct funeth_priv *fp = netdev_priv(netdev);438 439	fp->msg_enable = value;440}441 442static int fun_get_regs_len(struct net_device *dev)443{444	return NVME_REG_ACQ + sizeof(u64);445}446 447static void fun_get_regs(struct net_device *dev, struct ethtool_regs *regs,448			 void *buf)449{450	const struct funeth_priv *fp = netdev_priv(dev);451	void __iomem *bar = fp->fdev->bar;452 453	regs->version = 0;454	*(u64 *)(buf + NVME_REG_CAP)   = readq(bar + NVME_REG_CAP);455	*(u32 *)(buf + NVME_REG_VS)    = readl(bar + NVME_REG_VS);456	*(u32 *)(buf + NVME_REG_INTMS) = readl(bar + NVME_REG_INTMS);457	*(u32 *)(buf + NVME_REG_INTMC) = readl(bar + NVME_REG_INTMC);458	*(u32 *)(buf + NVME_REG_CC)    = readl(bar + NVME_REG_CC);459	*(u32 *)(buf + NVME_REG_CSTS)  = readl(bar + NVME_REG_CSTS);460	*(u32 *)(buf + NVME_REG_AQA)   = readl(bar + NVME_REG_AQA);461	*(u64 *)(buf + NVME_REG_ASQ)   = readq(bar + NVME_REG_ASQ);462	*(u64 *)(buf + NVME_REG_ACQ)   = readq(bar + NVME_REG_ACQ);463}464 465static int fun_get_coalesce(struct net_device *netdev,466			    struct ethtool_coalesce *coal,467			    struct kernel_ethtool_coalesce *kcoal,468			    struct netlink_ext_ack *ext_ack)469{470	const struct funeth_priv *fp = netdev_priv(netdev);471 472	coal->rx_coalesce_usecs        = fp->rx_coal_usec;473	coal->rx_max_coalesced_frames  = fp->rx_coal_count;474	coal->use_adaptive_rx_coalesce = !fp->cq_irq_db;475	coal->tx_coalesce_usecs        = fp->tx_coal_usec;476	coal->tx_max_coalesced_frames  = fp->tx_coal_count;477	return 0;478}479 480static int fun_set_coalesce(struct net_device *netdev,481			    struct ethtool_coalesce *coal,482			    struct kernel_ethtool_coalesce *kcoal,483			    struct netlink_ext_ack *ext_ack)484{485	struct funeth_priv *fp = netdev_priv(netdev);486	struct funeth_rxq **rxqs;487	unsigned int i, db_val;488 489	if (coal->rx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||490	    coal->rx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||491	    (coal->rx_coalesce_usecs | coal->rx_max_coalesced_frames) == 0 ||492	    coal->tx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||493	    coal->tx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||494	    (coal->tx_coalesce_usecs | coal->tx_max_coalesced_frames) == 0)495		return -EINVAL;496 497	/* a timer is required if there's any coalescing */498	if ((coal->rx_max_coalesced_frames > 1 && !coal->rx_coalesce_usecs) ||499	    (coal->tx_max_coalesced_frames > 1 && !coal->tx_coalesce_usecs))500		return -EINVAL;501 502	fp->rx_coal_usec  = coal->rx_coalesce_usecs;503	fp->rx_coal_count = coal->rx_max_coalesced_frames;504	fp->tx_coal_usec  = coal->tx_coalesce_usecs;505	fp->tx_coal_count = coal->tx_max_coalesced_frames;506 507	db_val = FUN_IRQ_CQ_DB(fp->rx_coal_usec, fp->rx_coal_count);508	WRITE_ONCE(fp->cq_irq_db, db_val);509 510	rxqs = rtnl_dereference(fp->rxqs);511	if (!rxqs)512		return 0;513 514	for (i = 0; i < netdev->real_num_rx_queues; i++)515		WRITE_ONCE(rxqs[i]->irq_db_val, db_val);516 517	db_val = FUN_IRQ_SQ_DB(fp->tx_coal_usec, fp->tx_coal_count);518	for (i = 0; i < netdev->real_num_tx_queues; i++)519		WRITE_ONCE(fp->txqs[i]->irq_db_val, db_val);520 521	return 0;522}523 524static void fun_get_channels(struct net_device *netdev,525			     struct ethtool_channels *chan)526{527	chan->max_rx   = netdev->num_rx_queues;528	chan->rx_count = netdev->real_num_rx_queues;529 530	chan->max_tx   = netdev->num_tx_queues;531	chan->tx_count = netdev->real_num_tx_queues;532}533 534static int fun_set_channels(struct net_device *netdev,535			    struct ethtool_channels *chan)536{537	if (!chan->tx_count || !chan->rx_count)538		return -EINVAL;539 540	if (chan->tx_count == netdev->real_num_tx_queues &&541	    chan->rx_count == netdev->real_num_rx_queues)542		return 0;543 544	if (netif_running(netdev))545		return fun_change_num_queues(netdev, chan->tx_count,546					     chan->rx_count);547 548	fun_set_ring_count(netdev, chan->tx_count, chan->rx_count);549	return 0;550}551 552static void fun_get_ringparam(struct net_device *netdev,553			      struct ethtool_ringparam *ring,554			      struct kernel_ethtool_ringparam *kring,555			      struct netlink_ext_ack *extack)556{557	const struct funeth_priv *fp = netdev_priv(netdev);558	unsigned int max_depth = fp->fdev->q_depth;559 560	/* We size CQs to be twice the RQ depth so max RQ depth is half the561	 * max queue depth.562	 */563	ring->rx_max_pending = max_depth / 2;564	ring->tx_max_pending = max_depth;565 566	ring->rx_pending = fp->rq_depth;567	ring->tx_pending = fp->sq_depth;568 569	kring->rx_buf_len = PAGE_SIZE;570	kring->cqe_size = FUNETH_CQE_SIZE;571}572 573static int fun_set_ringparam(struct net_device *netdev,574			     struct ethtool_ringparam *ring,575			     struct kernel_ethtool_ringparam *kring,576			     struct netlink_ext_ack *extack)577{578	struct funeth_priv *fp = netdev_priv(netdev);579	int rc;580 581	if (ring->rx_mini_pending || ring->rx_jumbo_pending)582		return -EINVAL;583 584	/* queue depths must be powers-of-2 */585	if (!is_power_of_2(ring->rx_pending) ||586	    !is_power_of_2(ring->tx_pending))587		return -EINVAL;588 589	if (ring->rx_pending < FUNETH_MIN_QDEPTH ||590	    ring->tx_pending < FUNETH_MIN_QDEPTH)591		return -EINVAL;592 593	if (fp->sq_depth == ring->tx_pending &&594	    fp->rq_depth == ring->rx_pending)595		return 0;596 597	if (netif_running(netdev)) {598		struct fun_qset req = {599			.cq_depth = 2 * ring->rx_pending,600			.rq_depth = ring->rx_pending,601			.sq_depth = ring->tx_pending602		};603 604		rc = fun_replace_queues(netdev, &req, extack);605		if (rc)606			return rc;607	}608 609	fp->sq_depth = ring->tx_pending;610	fp->rq_depth = ring->rx_pending;611	fp->cq_depth = 2 * fp->rq_depth;612	return 0;613}614 615static int fun_get_sset_count(struct net_device *dev, int sset)616{617	const struct funeth_priv *fp = netdev_priv(dev);618	int n;619 620	switch (sset) {621	case ETH_SS_STATS:622		n = (dev->real_num_tx_queues + 1) * ARRAY_SIZE(txq_stat_names) +623		    (dev->real_num_rx_queues + 1) * ARRAY_SIZE(rxq_stat_names) +624		    (fp->num_xdpqs + 1) * ARRAY_SIZE(xdpq_stat_names) +625		    ARRAY_SIZE(tls_stat_names);626		if (fp->port_caps & FUN_PORT_CAP_STATS) {627			n += ARRAY_SIZE(mac_tx_stat_names) +628			     ARRAY_SIZE(mac_rx_stat_names);629		}630		return n;631	default:632		break;633	}634	return 0;635}636 637static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)638{639	const struct funeth_priv *fp = netdev_priv(netdev);640	unsigned int i, j;641	u8 *p = data;642 643	switch (sset) {644	case ETH_SS_STATS:645		if (fp->port_caps & FUN_PORT_CAP_STATS) {646			memcpy(p, mac_tx_stat_names, sizeof(mac_tx_stat_names));647			p += sizeof(mac_tx_stat_names);648			memcpy(p, mac_rx_stat_names, sizeof(mac_rx_stat_names));649			p += sizeof(mac_rx_stat_names);650		}651 652		for (i = 0; i < netdev->real_num_tx_queues; i++) {653			for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)654				ethtool_sprintf(&p, "%s[%u]", txq_stat_names[j],655						i);656		}657		for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)658			ethtool_puts(&p, txq_stat_names[j]);659 660		for (i = 0; i < fp->num_xdpqs; i++) {661			for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)662				ethtool_sprintf(&p, "%s[%u]",663						xdpq_stat_names[j], i);664		}665		for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)666			ethtool_puts(&p, xdpq_stat_names[j]);667 668		for (i = 0; i < netdev->real_num_rx_queues; i++) {669			for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)670				ethtool_sprintf(&p, "%s[%u]", rxq_stat_names[j],671						i);672		}673		for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)674			ethtool_puts(&p, rxq_stat_names[j]);675 676		for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++)677			ethtool_puts(&p, tls_stat_names[j]);678		break;679	default:680		break;681	}682}683 684static u64 *get_mac_stats(const struct funeth_priv *fp, u64 *data)685{686#define TX_STAT(s) \687	*data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])688 689	TX_STAT(etherStatsOctets);690	TX_STAT(etherStatsPkts);691	TX_STAT(VLANTransmittedOK);692	TX_STAT(ifOutUcastPkts);693	TX_STAT(ifOutMulticastPkts);694	TX_STAT(ifOutBroadcastPkts);695	TX_STAT(ifOutErrors);696	TX_STAT(CBFCPAUSEFramesTransmitted_0);697	TX_STAT(CBFCPAUSEFramesTransmitted_1);698	TX_STAT(CBFCPAUSEFramesTransmitted_2);699	TX_STAT(CBFCPAUSEFramesTransmitted_3);700	TX_STAT(CBFCPAUSEFramesTransmitted_4);701	TX_STAT(CBFCPAUSEFramesTransmitted_5);702	TX_STAT(CBFCPAUSEFramesTransmitted_6);703	TX_STAT(CBFCPAUSEFramesTransmitted_7);704	TX_STAT(CBFCPAUSEFramesTransmitted_8);705	TX_STAT(CBFCPAUSEFramesTransmitted_9);706	TX_STAT(CBFCPAUSEFramesTransmitted_10);707	TX_STAT(CBFCPAUSEFramesTransmitted_11);708	TX_STAT(CBFCPAUSEFramesTransmitted_12);709	TX_STAT(CBFCPAUSEFramesTransmitted_13);710	TX_STAT(CBFCPAUSEFramesTransmitted_14);711	TX_STAT(CBFCPAUSEFramesTransmitted_15);712 713#define RX_STAT(s) *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_##s])714 715	RX_STAT(etherStatsOctets);716	RX_STAT(etherStatsPkts);717	RX_STAT(VLANReceivedOK);718	RX_STAT(ifInUcastPkts);719	RX_STAT(ifInMulticastPkts);720	RX_STAT(ifInBroadcastPkts);721	RX_STAT(etherStatsDropEvents);722	RX_STAT(ifInErrors);723	RX_STAT(aAlignmentErrors);724	RX_STAT(CBFCPAUSEFramesReceived_0);725	RX_STAT(CBFCPAUSEFramesReceived_1);726	RX_STAT(CBFCPAUSEFramesReceived_2);727	RX_STAT(CBFCPAUSEFramesReceived_3);728	RX_STAT(CBFCPAUSEFramesReceived_4);729	RX_STAT(CBFCPAUSEFramesReceived_5);730	RX_STAT(CBFCPAUSEFramesReceived_6);731	RX_STAT(CBFCPAUSEFramesReceived_7);732	RX_STAT(CBFCPAUSEFramesReceived_8);733	RX_STAT(CBFCPAUSEFramesReceived_9);734	RX_STAT(CBFCPAUSEFramesReceived_10);735	RX_STAT(CBFCPAUSEFramesReceived_11);736	RX_STAT(CBFCPAUSEFramesReceived_12);737	RX_STAT(CBFCPAUSEFramesReceived_13);738	RX_STAT(CBFCPAUSEFramesReceived_14);739	RX_STAT(CBFCPAUSEFramesReceived_15);740 741	return data;742 743#undef TX_STAT744#undef RX_STAT745}746 747static void fun_get_ethtool_stats(struct net_device *netdev,748				  struct ethtool_stats *stats, u64 *data)749{750	const struct funeth_priv *fp = netdev_priv(netdev);751	struct funeth_txq_stats txs;752	struct funeth_rxq_stats rxs;753	struct funeth_txq **xdpqs;754	struct funeth_rxq **rxqs;755	unsigned int i, start;756	u64 *totals, *tot;757 758	if (fp->port_caps & FUN_PORT_CAP_STATS)759		data = get_mac_stats(fp, data);760 761	rxqs = rtnl_dereference(fp->rxqs);762	if (!rxqs)763		return;764 765#define ADD_STAT(cnt) do { \766	*data = (cnt); *tot++ += *data++; \767} while (0)768 769	/* Tx queues */770	totals = data + netdev->real_num_tx_queues * ARRAY_SIZE(txq_stat_names);771 772	for (i = 0; i < netdev->real_num_tx_queues; i++) {773		tot = totals;774 775		FUN_QSTAT_READ(fp->txqs[i], start, txs);776 777		ADD_STAT(txs.tx_pkts);778		ADD_STAT(txs.tx_bytes);779		ADD_STAT(txs.tx_cso);780		ADD_STAT(txs.tx_tso);781		ADD_STAT(txs.tx_encap_tso);782		ADD_STAT(txs.tx_uso);783		ADD_STAT(txs.tx_more);784		ADD_STAT(txs.tx_nstops);785		ADD_STAT(txs.tx_nrestarts);786		ADD_STAT(txs.tx_map_err);787		ADD_STAT(txs.tx_tls_pkts);788		ADD_STAT(txs.tx_tls_bytes);789		ADD_STAT(txs.tx_tls_fallback);790		ADD_STAT(txs.tx_tls_drops);791	}792	data += ARRAY_SIZE(txq_stat_names);793 794	/* XDP Tx queues */795	xdpqs = rtnl_dereference(fp->xdpqs);796	totals = data + fp->num_xdpqs * ARRAY_SIZE(xdpq_stat_names);797 798	for (i = 0; i < fp->num_xdpqs; i++) {799		tot = totals;800 801		FUN_QSTAT_READ(xdpqs[i], start, txs);802 803		ADD_STAT(txs.tx_pkts);804		ADD_STAT(txs.tx_bytes);805		ADD_STAT(txs.tx_xdp_full);806		ADD_STAT(txs.tx_map_err);807	}808	data += ARRAY_SIZE(xdpq_stat_names);809 810	/* Rx queues */811	totals = data + netdev->real_num_rx_queues * ARRAY_SIZE(rxq_stat_names);812 813	for (i = 0; i < netdev->real_num_rx_queues; i++) {814		tot = totals;815 816		FUN_QSTAT_READ(rxqs[i], start, rxs);817 818		ADD_STAT(rxs.rx_pkts);819		ADD_STAT(rxs.rx_bytes);820		ADD_STAT(rxs.rx_cso);821		ADD_STAT(rxs.gro_pkts);822		ADD_STAT(rxs.gro_merged);823		ADD_STAT(rxs.xdp_tx);824		ADD_STAT(rxs.xdp_redir);825		ADD_STAT(rxs.xdp_drops);826		ADD_STAT(rxs.rx_bufs);827		ADD_STAT(rxs.rx_page_alloc);828		ADD_STAT(rxs.rx_mem_drops + rxs.xdp_err);829		ADD_STAT(rxs.rx_budget);830		ADD_STAT(rxs.rx_map_err);831	}832	data += ARRAY_SIZE(rxq_stat_names);833#undef ADD_STAT834 835	*data++ = atomic64_read(&fp->tx_tls_add);836	*data++ = atomic64_read(&fp->tx_tls_del);837	*data++ = atomic64_read(&fp->tx_tls_resync);838}839 840#define RX_STAT(fp, s) be64_to_cpu((fp)->stats[PORT_MAC_RX_##s])841#define TX_STAT(fp, s) \842	be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])843#define FEC_STAT(fp, s) \844	be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + \845				PORT_MAC_TX_STATS_MAX + PORT_MAC_FEC_##s])846 847static void fun_get_pause_stats(struct net_device *netdev,848				struct ethtool_pause_stats *stats)849{850	const struct funeth_priv *fp = netdev_priv(netdev);851 852	if (!(fp->port_caps & FUN_PORT_CAP_STATS))853		return;854 855	stats->tx_pause_frames = TX_STAT(fp, aPAUSEMACCtrlFramesTransmitted);856	stats->rx_pause_frames = RX_STAT(fp, aPAUSEMACCtrlFramesReceived);857}858 859static void fun_get_802_3_stats(struct net_device *netdev,860				struct ethtool_eth_mac_stats *stats)861{862	const struct funeth_priv *fp = netdev_priv(netdev);863 864	if (!(fp->port_caps & FUN_PORT_CAP_STATS))865		return;866 867	stats->FramesTransmittedOK = TX_STAT(fp, aFramesTransmittedOK);868	stats->FramesReceivedOK = RX_STAT(fp, aFramesReceivedOK);869	stats->FrameCheckSequenceErrors = RX_STAT(fp, aFrameCheckSequenceErrors);870	stats->OctetsTransmittedOK = TX_STAT(fp, OctetsTransmittedOK);871	stats->OctetsReceivedOK = RX_STAT(fp, OctetsReceivedOK);872	stats->InRangeLengthErrors = RX_STAT(fp, aInRangeLengthErrors);873	stats->FrameTooLongErrors = RX_STAT(fp, aFrameTooLongErrors);874}875 876static void fun_get_802_3_ctrl_stats(struct net_device *netdev,877				     struct ethtool_eth_ctrl_stats *stats)878{879	const struct funeth_priv *fp = netdev_priv(netdev);880 881	if (!(fp->port_caps & FUN_PORT_CAP_STATS))882		return;883 884	stats->MACControlFramesTransmitted = TX_STAT(fp, MACControlFramesTransmitted);885	stats->MACControlFramesReceived = RX_STAT(fp, MACControlFramesReceived);886}887 888static void fun_get_rmon_stats(struct net_device *netdev,889			       struct ethtool_rmon_stats *stats,890			       const struct ethtool_rmon_hist_range **ranges)891{892	static const struct ethtool_rmon_hist_range rmon_ranges[] = {893		{   64,    64 },894		{   65,   127 },895		{  128,   255 },896		{  256,   511 },897		{  512,  1023 },898		{ 1024,  1518 },899		{ 1519, 32767 },900		{}901	};902 903	const struct funeth_priv *fp = netdev_priv(netdev);904 905	if (!(fp->port_caps & FUN_PORT_CAP_STATS))906		return;907 908	stats->undersize_pkts = RX_STAT(fp, etherStatsUndersizePkts);909	stats->oversize_pkts = RX_STAT(fp, etherStatsOversizePkts);910	stats->fragments = RX_STAT(fp, etherStatsFragments);911	stats->jabbers = RX_STAT(fp, etherStatsJabbers);912 913	stats->hist[0] = RX_STAT(fp, etherStatsPkts64Octets);914	stats->hist[1] = RX_STAT(fp, etherStatsPkts65to127Octets);915	stats->hist[2] = RX_STAT(fp, etherStatsPkts128to255Octets);916	stats->hist[3] = RX_STAT(fp, etherStatsPkts256to511Octets);917	stats->hist[4] = RX_STAT(fp, etherStatsPkts512to1023Octets);918	stats->hist[5] = RX_STAT(fp, etherStatsPkts1024to1518Octets);919	stats->hist[6] = RX_STAT(fp, etherStatsPkts1519toMaxOctets);920 921	stats->hist_tx[0] = TX_STAT(fp, etherStatsPkts64Octets);922	stats->hist_tx[1] = TX_STAT(fp, etherStatsPkts65to127Octets);923	stats->hist_tx[2] = TX_STAT(fp, etherStatsPkts128to255Octets);924	stats->hist_tx[3] = TX_STAT(fp, etherStatsPkts256to511Octets);925	stats->hist_tx[4] = TX_STAT(fp, etherStatsPkts512to1023Octets);926	stats->hist_tx[5] = TX_STAT(fp, etherStatsPkts1024to1518Octets);927	stats->hist_tx[6] = TX_STAT(fp, etherStatsPkts1519toMaxOctets);928 929	*ranges = rmon_ranges;930}931 932static void fun_get_fec_stats(struct net_device *netdev,933			      struct ethtool_fec_stats *stats)934{935	const struct funeth_priv *fp = netdev_priv(netdev);936 937	if (!(fp->port_caps & FUN_PORT_CAP_STATS))938		return;939 940	stats->corrected_blocks.total = FEC_STAT(fp, Correctable);941	stats->uncorrectable_blocks.total = FEC_STAT(fp, Uncorrectable);942}943 944#undef RX_STAT945#undef TX_STAT946#undef FEC_STAT947 948static int fun_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,949			 u32 *rule_locs)950{951	switch (cmd->cmd) {952	case ETHTOOL_GRXRINGS:953		cmd->data = netdev->real_num_rx_queues;954		return 0;955	default:956		break;957	}958	return -EOPNOTSUPP;959}960 961static int fun_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)962{963	return 0;964}965 966static u32 fun_get_rxfh_indir_size(struct net_device *netdev)967{968	const struct funeth_priv *fp = netdev_priv(netdev);969 970	return fp->indir_table_nentries;971}972 973static u32 fun_get_rxfh_key_size(struct net_device *netdev)974{975	const struct funeth_priv *fp = netdev_priv(netdev);976 977	return sizeof(fp->rss_key);978}979 980static int fun_get_rxfh(struct net_device *netdev,981			struct ethtool_rxfh_param *rxfh)982{983	const struct funeth_priv *fp = netdev_priv(netdev);984 985	if (!fp->rss_cfg)986		return -EOPNOTSUPP;987 988	if (rxfh->indir)989		memcpy(rxfh->indir, fp->indir_table,990		       sizeof(u32) * fp->indir_table_nentries);991 992	if (rxfh->key)993		memcpy(rxfh->key, fp->rss_key, sizeof(fp->rss_key));994 995	rxfh->hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ?996			ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32;997 998	return 0;999}1000 1001static int fun_set_rxfh(struct net_device *netdev,1002			struct ethtool_rxfh_param *rxfh,1003			struct netlink_ext_ack *extack)1004{1005	struct funeth_priv *fp = netdev_priv(netdev);1006	const u32 *rss_indir = rxfh->indir ? rxfh->indir : fp->indir_table;1007	const u8 *rss_key = rxfh->key ? rxfh->key : fp->rss_key;1008	enum fun_eth_hash_alg algo;1009 1010	if (!fp->rss_cfg)1011		return -EOPNOTSUPP;1012 1013	if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE)1014		algo = fp->hash_algo;1015	else if (rxfh->hfunc == ETH_RSS_HASH_CRC32)1016		algo = FUN_ETH_RSS_ALG_CRC32;1017	else if (rxfh->hfunc == ETH_RSS_HASH_TOP)1018		algo = FUN_ETH_RSS_ALG_TOEPLITZ;1019	else1020		return -EINVAL;1021 1022	/* If the port is enabled try to reconfigure RSS and keep the new1023	 * settings if successful. If it is down we update the RSS settings1024	 * and apply them at the next UP time.1025	 */1026	if (netif_running(netdev)) {1027		int rc = fun_config_rss(netdev, algo, rss_key, rss_indir,1028					FUN_ADMIN_SUBOP_MODIFY);1029		if (rc)1030			return rc;1031	}1032 1033	fp->hash_algo = algo;1034	if (rxfh->key)1035		memcpy(fp->rss_key, rxfh->key, sizeof(fp->rss_key));1036	if (rxfh->indir)1037		memcpy(fp->indir_table, rxfh->indir,1038		       sizeof(u32) * fp->indir_table_nentries);1039	return 0;1040}1041 1042static int fun_get_ts_info(struct net_device *netdev,1043			   struct kernel_ethtool_ts_info *info)1044{1045	info->so_timestamping = SOF_TIMESTAMPING_RX_HARDWARE |1046				SOF_TIMESTAMPING_TX_SOFTWARE |1047				SOF_TIMESTAMPING_RAW_HARDWARE;1048	info->tx_types = BIT(HWTSTAMP_TX_OFF);1049	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);1050	return 0;1051}1052 1053static unsigned int to_ethtool_fec(unsigned int fun_fec)1054{1055	unsigned int fec = 0;1056 1057	if (fun_fec == FUN_PORT_FEC_NA)1058		fec |= ETHTOOL_FEC_NONE;1059	if (fun_fec & FUN_PORT_FEC_OFF)1060		fec |= ETHTOOL_FEC_OFF;1061	if (fun_fec & FUN_PORT_FEC_RS)1062		fec |= ETHTOOL_FEC_RS;1063	if (fun_fec & FUN_PORT_FEC_FC)1064		fec |= ETHTOOL_FEC_BASER;1065	if (fun_fec & FUN_PORT_FEC_AUTO)1066		fec |= ETHTOOL_FEC_AUTO;1067	return fec;1068}1069 1070static int fun_get_fecparam(struct net_device *netdev,1071			    struct ethtool_fecparam *fec)1072{1073	struct funeth_priv *fp = netdev_priv(netdev);1074	u64 fec_data;1075	int rc;1076 1077	rc = fun_port_read_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, &fec_data);1078	if (rc)1079		return rc;1080 1081	fec->active_fec = to_ethtool_fec(fec_data & 0xff);1082	fec->fec = to_ethtool_fec(fec_data >> 8);1083	return 0;1084}1085 1086static int fun_set_fecparam(struct net_device *netdev,1087			    struct ethtool_fecparam *fec)1088{1089	struct funeth_priv *fp = netdev_priv(netdev);1090	u64 fec_mode;1091 1092	switch (fec->fec) {1093	case ETHTOOL_FEC_AUTO:1094		fec_mode = FUN_PORT_FEC_AUTO;1095		break;1096	case ETHTOOL_FEC_OFF:1097		if (!(fp->port_caps & FUN_PORT_CAP_FEC_NONE))1098			return -EINVAL;1099		fec_mode = FUN_PORT_FEC_OFF;1100		break;1101	case ETHTOOL_FEC_BASER:1102		if (!(fp->port_caps & FUN_PORT_CAP_FEC_FC))1103			return -EINVAL;1104		fec_mode = FUN_PORT_FEC_FC;1105		break;1106	case ETHTOOL_FEC_RS:1107		if (!(fp->port_caps & FUN_PORT_CAP_FEC_RS))1108			return -EINVAL;1109		fec_mode = FUN_PORT_FEC_RS;1110		break;1111	default:1112		return -EINVAL;1113	}1114 1115	return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode);1116}1117 1118static int fun_get_port_module_page(struct net_device *netdev,1119				    const struct ethtool_module_eeprom *req,1120				    struct netlink_ext_ack *extack)1121{1122	union {1123		struct fun_admin_port_req req;1124		struct fun_admin_port_xcvr_read_rsp rsp;1125	} cmd;1126	struct funeth_priv *fp = netdev_priv(netdev);1127	int rc;1128 1129	if (fp->port_caps & FUN_PORT_CAP_VPORT) {1130		NL_SET_ERR_MSG_MOD(extack,1131				   "Specified port is virtual, only physical ports have modules");1132		return -EOPNOTSUPP;1133	}1134 1135	cmd.req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_PORT,1136						    sizeof(cmd.req));1137	cmd.req.u.xcvr_read =1138		FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(0, netdev->dev_port,1139						  req->bank, req->page,1140						  req->offset, req->length,1141						  req->i2c_address);1142	rc = fun_submit_admin_sync_cmd(fp->fdev, &cmd.req.common, &cmd.rsp,1143				       sizeof(cmd.rsp), 0);1144	if (rc)1145		return rc;1146 1147	memcpy(req->data, cmd.rsp.data, req->length);1148	return req->length;1149}1150 1151static const struct ethtool_ops fun_ethtool_ops = {1152	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |1153				     ETHTOOL_COALESCE_MAX_FRAMES,1154	.get_link_ksettings  = fun_get_link_ksettings,1155	.set_link_ksettings  = fun_set_link_ksettings,1156	.set_phys_id         = fun_set_phys_id,1157	.get_drvinfo         = fun_get_drvinfo,1158	.get_msglevel        = fun_get_msglevel,1159	.set_msglevel        = fun_set_msglevel,1160	.get_regs_len        = fun_get_regs_len,1161	.get_regs            = fun_get_regs,1162	.get_link	     = ethtool_op_get_link,1163	.get_coalesce        = fun_get_coalesce,1164	.set_coalesce        = fun_set_coalesce,1165	.get_ts_info         = fun_get_ts_info,1166	.get_ringparam       = fun_get_ringparam,1167	.set_ringparam       = fun_set_ringparam,1168	.get_sset_count      = fun_get_sset_count,1169	.get_strings         = fun_get_strings,1170	.get_ethtool_stats   = fun_get_ethtool_stats,1171	.get_rxnfc	     = fun_get_rxnfc,1172	.set_rxnfc           = fun_set_rxnfc,1173	.get_rxfh_indir_size = fun_get_rxfh_indir_size,1174	.get_rxfh_key_size   = fun_get_rxfh_key_size,1175	.get_rxfh            = fun_get_rxfh,1176	.set_rxfh            = fun_set_rxfh,1177	.get_channels        = fun_get_channels,1178	.set_channels        = fun_set_channels,1179	.get_fecparam	     = fun_get_fecparam,1180	.set_fecparam	     = fun_set_fecparam,1181	.get_pauseparam      = fun_get_pauseparam,1182	.set_pauseparam      = fun_set_pauseparam,1183	.nway_reset          = fun_restart_an,1184	.get_pause_stats     = fun_get_pause_stats,1185	.get_fec_stats       = fun_get_fec_stats,1186	.get_eth_mac_stats   = fun_get_802_3_stats,1187	.get_eth_ctrl_stats  = fun_get_802_3_ctrl_stats,1188	.get_rmon_stats      = fun_get_rmon_stats,1189	.get_module_eeprom_by_page = fun_get_port_module_page,1190};1191 1192void fun_set_ethtool_ops(struct net_device *netdev)1193{1194	netdev->ethtool_ops = &fun_ethtool_ops;1195}1196