cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

funeth_ethtool.c (32635B)


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