brintos

brintos / linux-shallow public Read only

0
0
Text · 19.5 KiB · f7986f2 Raw
744 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright 2013 Cisco Systems, Inc.  All rights reserved.3 4#include <linux/netdevice.h>5#include <linux/ethtool.h>6#include <linux/net_tstamp.h>7 8#include "enic_res.h"9#include "enic.h"10#include "enic_dev.h"11#include "enic_clsf.h"12#include "vnic_rss.h"13#include "vnic_stats.h"14 15struct enic_stat {16	char name[ETH_GSTRING_LEN];17	unsigned int index;18};19 20#define ENIC_TX_STAT(stat) { \21	.name = #stat, \22	.index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \23}24 25#define ENIC_RX_STAT(stat) { \26	.name = #stat, \27	.index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \28}29 30#define ENIC_GEN_STAT(stat) { \31	.name = #stat, \32	.index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\33}34 35#define ENIC_PER_RQ_STAT(stat) { \36	.name = "rq[%d]_"#stat, \37	.index = offsetof(struct enic_rq_stats, stat) / sizeof(u64) \38}39 40#define ENIC_PER_WQ_STAT(stat) { \41	.name = "wq[%d]_"#stat, \42	.index = offsetof(struct enic_wq_stats, stat) / sizeof(u64) \43}44 45static const struct enic_stat enic_per_rq_stats[] = {46	ENIC_PER_RQ_STAT(l4_rss_hash),47	ENIC_PER_RQ_STAT(l3_rss_hash),48	ENIC_PER_RQ_STAT(csum_unnecessary_encap),49	ENIC_PER_RQ_STAT(vlan_stripped),50	ENIC_PER_RQ_STAT(napi_complete),51	ENIC_PER_RQ_STAT(napi_repoll),52	ENIC_PER_RQ_STAT(no_skb),53	ENIC_PER_RQ_STAT(desc_skip),54};55 56#define NUM_ENIC_PER_RQ_STATS   ARRAY_SIZE(enic_per_rq_stats)57 58static const struct enic_stat enic_per_wq_stats[] = {59	ENIC_PER_WQ_STAT(encap_tso),60	ENIC_PER_WQ_STAT(encap_csum),61	ENIC_PER_WQ_STAT(add_vlan),62	ENIC_PER_WQ_STAT(cq_work),63	ENIC_PER_WQ_STAT(cq_bytes),64	ENIC_PER_WQ_STAT(null_pkt),65	ENIC_PER_WQ_STAT(skb_linear_fail),66	ENIC_PER_WQ_STAT(desc_full_awake),67};68 69#define NUM_ENIC_PER_WQ_STATS   ARRAY_SIZE(enic_per_wq_stats)70static const struct enic_stat enic_tx_stats[] = {71	ENIC_TX_STAT(tx_frames_ok),72	ENIC_TX_STAT(tx_unicast_frames_ok),73	ENIC_TX_STAT(tx_multicast_frames_ok),74	ENIC_TX_STAT(tx_broadcast_frames_ok),75	ENIC_TX_STAT(tx_bytes_ok),76	ENIC_TX_STAT(tx_unicast_bytes_ok),77	ENIC_TX_STAT(tx_multicast_bytes_ok),78	ENIC_TX_STAT(tx_broadcast_bytes_ok),79	ENIC_TX_STAT(tx_drops),80	ENIC_TX_STAT(tx_errors),81	ENIC_TX_STAT(tx_tso),82};83 84#define NUM_ENIC_TX_STATS	ARRAY_SIZE(enic_tx_stats)85 86static const struct enic_stat enic_rx_stats[] = {87	ENIC_RX_STAT(rx_frames_ok),88	ENIC_RX_STAT(rx_frames_total),89	ENIC_RX_STAT(rx_unicast_frames_ok),90	ENIC_RX_STAT(rx_multicast_frames_ok),91	ENIC_RX_STAT(rx_broadcast_frames_ok),92	ENIC_RX_STAT(rx_bytes_ok),93	ENIC_RX_STAT(rx_unicast_bytes_ok),94	ENIC_RX_STAT(rx_multicast_bytes_ok),95	ENIC_RX_STAT(rx_broadcast_bytes_ok),96	ENIC_RX_STAT(rx_drop),97	ENIC_RX_STAT(rx_no_bufs),98	ENIC_RX_STAT(rx_errors),99	ENIC_RX_STAT(rx_rss),100	ENIC_RX_STAT(rx_crc_errors),101	ENIC_RX_STAT(rx_frames_64),102	ENIC_RX_STAT(rx_frames_127),103	ENIC_RX_STAT(rx_frames_255),104	ENIC_RX_STAT(rx_frames_511),105	ENIC_RX_STAT(rx_frames_1023),106	ENIC_RX_STAT(rx_frames_1518),107	ENIC_RX_STAT(rx_frames_to_max),108};109 110#define NUM_ENIC_RX_STATS	ARRAY_SIZE(enic_rx_stats)111 112static const struct enic_stat enic_gen_stats[] = {113	ENIC_GEN_STAT(dma_map_error),114};115 116#define NUM_ENIC_GEN_STATS	ARRAY_SIZE(enic_gen_stats)117 118static void enic_intr_coal_set_rx(struct enic *enic, u32 timer)119{120	int i;121	int intr;122 123	for (i = 0; i < enic->rq_count; i++) {124		intr = enic_msix_rq_intr(enic, i);125		vnic_intr_coalescing_timer_set(&enic->intr[intr], timer);126	}127}128 129static int enic_get_ksettings(struct net_device *netdev,130			      struct ethtool_link_ksettings *ecmd)131{132	struct enic *enic = netdev_priv(netdev);133	struct ethtool_link_settings *base = &ecmd->base;134 135	ethtool_link_ksettings_add_link_mode(ecmd, supported,136					     10000baseT_Full);137	ethtool_link_ksettings_add_link_mode(ecmd, supported, FIBRE);138	ethtool_link_ksettings_add_link_mode(ecmd, advertising,139					     10000baseT_Full);140	ethtool_link_ksettings_add_link_mode(ecmd, advertising, FIBRE);141	base->port = PORT_FIBRE;142 143	if (netif_carrier_ok(netdev)) {144		base->speed = vnic_dev_port_speed(enic->vdev);145		base->duplex = DUPLEX_FULL;146	} else {147		base->speed = SPEED_UNKNOWN;148		base->duplex = DUPLEX_UNKNOWN;149	}150 151	base->autoneg = AUTONEG_DISABLE;152 153	return 0;154}155 156static void enic_get_drvinfo(struct net_device *netdev,157	struct ethtool_drvinfo *drvinfo)158{159	struct enic *enic = netdev_priv(netdev);160	struct vnic_devcmd_fw_info *fw_info;161	int err;162 163	err = enic_dev_fw_info(enic, &fw_info);164	/* return only when dma_alloc_coherent fails in vnic_dev_fw_info165	 * For other failures, like devcmd failure, we return previously166	 * recorded info.167	 */168	if (err == -ENOMEM)169		return;170 171	strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));172	strscpy(drvinfo->fw_version, fw_info->fw_version,173		sizeof(drvinfo->fw_version));174	strscpy(drvinfo->bus_info, pci_name(enic->pdev),175		sizeof(drvinfo->bus_info));176}177 178static void enic_get_strings(struct net_device *netdev, u32 stringset,179	u8 *data)180{181	struct enic *enic = netdev_priv(netdev);182	unsigned int i;183	unsigned int j;184 185	switch (stringset) {186	case ETH_SS_STATS:187		for (i = 0; i < NUM_ENIC_TX_STATS; i++) {188			memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);189			data += ETH_GSTRING_LEN;190		}191		for (i = 0; i < NUM_ENIC_RX_STATS; i++) {192			memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);193			data += ETH_GSTRING_LEN;194		}195		for (i = 0; i < NUM_ENIC_GEN_STATS; i++) {196			memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN);197			data += ETH_GSTRING_LEN;198		}199		for (i = 0; i < enic->rq_count; i++) {200			for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) {201				snprintf(data, ETH_GSTRING_LEN,202					 enic_per_rq_stats[j].name, i);203				data += ETH_GSTRING_LEN;204			}205		}206		for (i = 0; i < enic->wq_count; i++) {207			for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) {208				snprintf(data, ETH_GSTRING_LEN,209					 enic_per_wq_stats[j].name, i);210				data += ETH_GSTRING_LEN;211			}212		}213		break;214	}215}216 217static void enic_get_ringparam(struct net_device *netdev,218			       struct ethtool_ringparam *ring,219			       struct kernel_ethtool_ringparam *kernel_ring,220			       struct netlink_ext_ack *extack)221{222	struct enic *enic = netdev_priv(netdev);223	struct vnic_enet_config *c = &enic->config;224 225	ring->rx_max_pending = ENIC_MAX_RQ_DESCS;226	ring->rx_pending = c->rq_desc_count;227	ring->tx_max_pending = ENIC_MAX_WQ_DESCS;228	ring->tx_pending = c->wq_desc_count;229}230 231static int enic_set_ringparam(struct net_device *netdev,232			      struct ethtool_ringparam *ring,233			      struct kernel_ethtool_ringparam *kernel_ring,234			      struct netlink_ext_ack *extack)235{236	struct enic *enic = netdev_priv(netdev);237	struct vnic_enet_config *c = &enic->config;238	int running = netif_running(netdev);239	unsigned int rx_pending;240	unsigned int tx_pending;241	int err = 0;242 243	if (ring->rx_mini_max_pending || ring->rx_mini_pending) {244		netdev_info(netdev,245			    "modifying mini ring params is not supported");246		return -EINVAL;247	}248	if (ring->rx_jumbo_max_pending || ring->rx_jumbo_pending) {249		netdev_info(netdev,250			    "modifying jumbo ring params is not supported");251		return -EINVAL;252	}253	rx_pending = c->rq_desc_count;254	tx_pending = c->wq_desc_count;255	if (ring->rx_pending > ENIC_MAX_RQ_DESCS ||256	    ring->rx_pending < ENIC_MIN_RQ_DESCS) {257		netdev_info(netdev, "rx pending (%u) not in range [%u,%u]",258			    ring->rx_pending, ENIC_MIN_RQ_DESCS,259			    ENIC_MAX_RQ_DESCS);260		return -EINVAL;261	}262	if (ring->tx_pending > ENIC_MAX_WQ_DESCS ||263	    ring->tx_pending < ENIC_MIN_WQ_DESCS) {264		netdev_info(netdev, "tx pending (%u) not in range [%u,%u]",265			    ring->tx_pending, ENIC_MIN_WQ_DESCS,266			    ENIC_MAX_WQ_DESCS);267		return -EINVAL;268	}269	if (running)270		dev_close(netdev);271	c->rq_desc_count =272		ring->rx_pending & 0xffffffe0; /* must be aligned to groups of 32 */273	c->wq_desc_count =274		ring->tx_pending & 0xffffffe0; /* must be aligned to groups of 32 */275	enic_free_vnic_resources(enic);276	err = enic_alloc_vnic_resources(enic);277	if (err) {278		netdev_err(netdev,279			   "Failed to alloc vNIC resources, aborting\n");280		enic_free_vnic_resources(enic);281		goto err_out;282	}283	enic_init_vnic_resources(enic);284	if (running) {285		err = dev_open(netdev, NULL);286		if (err)287			goto err_out;288	}289	return 0;290err_out:291	c->rq_desc_count = rx_pending;292	c->wq_desc_count = tx_pending;293	return err;294}295 296static int enic_get_sset_count(struct net_device *netdev, int sset)297{298	struct enic *enic = netdev_priv(netdev);299	unsigned int n_per_rq_stats;300	unsigned int n_per_wq_stats;301	unsigned int n_stats;302 303	switch (sset) {304	case ETH_SS_STATS:305		n_per_rq_stats = NUM_ENIC_PER_RQ_STATS * enic->rq_count;306		n_per_wq_stats = NUM_ENIC_PER_WQ_STATS * enic->wq_count;307		n_stats = NUM_ENIC_TX_STATS + NUM_ENIC_RX_STATS +308			NUM_ENIC_GEN_STATS +309			n_per_rq_stats + n_per_wq_stats;310		return n_stats;311	default:312		return -EOPNOTSUPP;313	}314}315 316static void enic_get_ethtool_stats(struct net_device *netdev,317	struct ethtool_stats *stats, u64 *data)318{319	struct enic *enic = netdev_priv(netdev);320	struct vnic_stats *vstats;321	unsigned int i;322	unsigned int j;323	int err;324 325	err = enic_dev_stats_dump(enic, &vstats);326	/* return only when dma_alloc_coherent fails in vnic_dev_stats_dump327	 * For other failures, like devcmd failure, we return previously328	 * recorded stats.329	 */330	if (err == -ENOMEM)331		return;332 333	for (i = 0; i < NUM_ENIC_TX_STATS; i++)334		*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];335	for (i = 0; i < NUM_ENIC_RX_STATS; i++)336		*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index];337	for (i = 0; i < NUM_ENIC_GEN_STATS; i++)338		*(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index];339	for (i = 0; i < enic->rq_count; i++) {340		struct enic_rq_stats *rqstats = &enic->rq_stats[i];341		int index;342 343		for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) {344			index = enic_per_rq_stats[j].index;345			*(data++) = ((u64 *)rqstats)[index];346		}347	}348	for (i = 0; i < enic->wq_count; i++) {349		struct enic_wq_stats *wqstats = &enic->wq_stats[i];350		int index;351 352		for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) {353			index = enic_per_wq_stats[j].index;354			*(data++) = ((u64 *)wqstats)[index];355		}356	}357}358 359static u32 enic_get_msglevel(struct net_device *netdev)360{361	struct enic *enic = netdev_priv(netdev);362	return enic->msg_enable;363}364 365static void enic_set_msglevel(struct net_device *netdev, u32 value)366{367	struct enic *enic = netdev_priv(netdev);368	enic->msg_enable = value;369}370 371static int enic_get_coalesce(struct net_device *netdev,372			     struct ethtool_coalesce *ecmd,373			     struct kernel_ethtool_coalesce *kernel_coal,374			     struct netlink_ext_ack *extack)375{376	struct enic *enic = netdev_priv(netdev);377	struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;378 379	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)380		ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;381	ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;382	if (rxcoal->use_adaptive_rx_coalesce)383		ecmd->use_adaptive_rx_coalesce = 1;384	ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start;385	ecmd->rx_coalesce_usecs_high = rxcoal->range_end;386 387	return 0;388}389 390static int enic_coalesce_valid(struct enic *enic,391			       struct ethtool_coalesce *ec)392{393	u32 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev);394	u32 rx_coalesce_usecs_high = min_t(u32, coalesce_usecs_max,395					   ec->rx_coalesce_usecs_high);396	u32 rx_coalesce_usecs_low = min_t(u32, coalesce_usecs_max,397					  ec->rx_coalesce_usecs_low);398 399	if ((vnic_dev_get_intr_mode(enic->vdev) != VNIC_DEV_INTR_MODE_MSIX) &&400	    ec->tx_coalesce_usecs)401		return -EINVAL;402 403	if ((ec->tx_coalesce_usecs > coalesce_usecs_max)	||404	    (ec->rx_coalesce_usecs > coalesce_usecs_max)	||405	    (ec->rx_coalesce_usecs_low > coalesce_usecs_max)	||406	    (ec->rx_coalesce_usecs_high > coalesce_usecs_max))407		netdev_info(enic->netdev, "ethtool_set_coalesce: adaptor supports max coalesce value of %d. Setting max value.\n",408			    coalesce_usecs_max);409 410	if (ec->rx_coalesce_usecs_high &&411	    (rx_coalesce_usecs_high <412	     rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF))413		return -EINVAL;414 415	return 0;416}417 418static int enic_set_coalesce(struct net_device *netdev,419			     struct ethtool_coalesce *ecmd,420			     struct kernel_ethtool_coalesce *kernel_coal,421			     struct netlink_ext_ack *extack)422{423	struct enic *enic = netdev_priv(netdev);424	u32 tx_coalesce_usecs;425	u32 rx_coalesce_usecs;426	u32 rx_coalesce_usecs_low;427	u32 rx_coalesce_usecs_high;428	u32 coalesce_usecs_max;429	unsigned int i, intr;430	int ret;431	struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;432 433	ret = enic_coalesce_valid(enic, ecmd);434	if (ret)435		return ret;436	coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev);437	tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,438				  coalesce_usecs_max);439	rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,440				  coalesce_usecs_max);441 442	rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low,443				      coalesce_usecs_max);444	rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high,445				       coalesce_usecs_max);446 447	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) {448		for (i = 0; i < enic->wq_count; i++) {449			intr = enic_msix_wq_intr(enic, i);450			vnic_intr_coalescing_timer_set(&enic->intr[intr],451						       tx_coalesce_usecs);452		}453		enic->tx_coalesce_usecs = tx_coalesce_usecs;454	}455	rxcoal->use_adaptive_rx_coalesce = !!ecmd->use_adaptive_rx_coalesce;456	if (!rxcoal->use_adaptive_rx_coalesce)457		enic_intr_coal_set_rx(enic, rx_coalesce_usecs);458	if (ecmd->rx_coalesce_usecs_high) {459		rxcoal->range_end = rx_coalesce_usecs_high;460		rxcoal->small_pkt_range_start = rx_coalesce_usecs_low;461		rxcoal->large_pkt_range_start = rx_coalesce_usecs_low +462						ENIC_AIC_LARGE_PKT_DIFF;463	}464 465	enic->rx_coalesce_usecs = rx_coalesce_usecs;466 467	return 0;468}469 470static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd,471			    u32 *rule_locs)472{473	int j, ret = 0, cnt = 0;474 475	cmd->data = enic->rfs_h.max - enic->rfs_h.free;476	for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) {477		struct hlist_head *hhead;478		struct hlist_node *tmp;479		struct enic_rfs_fltr_node *n;480 481		hhead = &enic->rfs_h.ht_head[j];482		hlist_for_each_entry_safe(n, tmp, hhead, node) {483			if (cnt == cmd->rule_cnt)484				return -EMSGSIZE;485			rule_locs[cnt] = n->fltr_id;486			cnt++;487		}488	}489	cmd->rule_cnt = cnt;490 491	return ret;492}493 494static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)495{496	struct ethtool_rx_flow_spec *fsp =497				(struct ethtool_rx_flow_spec *)&cmd->fs;498	struct enic_rfs_fltr_node *n;499 500	n = htbl_fltr_search(enic, (u16)fsp->location);501	if (!n)502		return -EINVAL;503	switch (n->keys.basic.ip_proto) {504	case IPPROTO_TCP:505		fsp->flow_type = TCP_V4_FLOW;506		break;507	case IPPROTO_UDP:508		fsp->flow_type = UDP_V4_FLOW;509		break;510	default:511		return -EINVAL;512	}513 514	fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys);515	fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0;516 517	fsp->h_u.tcp_ip4_spec.ip4dst = flow_get_u32_dst(&n->keys);518	fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0;519 520	fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src;521	fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0;522 523	fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.dst;524	fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0;525 526	fsp->ring_cookie = n->rq_id;527 528	return 0;529}530 531static int enic_get_rx_flow_hash(struct enic *enic, struct ethtool_rxnfc *cmd)532{533	u8 rss_hash_type = 0;534	cmd->data = 0;535 536	spin_lock_bh(&enic->devcmd_lock);537	(void)vnic_dev_capable_rss_hash_type(enic->vdev, &rss_hash_type);538	spin_unlock_bh(&enic->devcmd_lock);539	switch (cmd->flow_type) {540	case TCP_V6_FLOW:541	case TCP_V4_FLOW:542		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3 |543			     RXH_IP_SRC | RXH_IP_DST;544		break;545	case UDP_V6_FLOW:546		cmd->data |= RXH_IP_SRC | RXH_IP_DST;547		if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV6)548			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;549		break;550	case UDP_V4_FLOW:551		cmd->data |= RXH_IP_SRC | RXH_IP_DST;552		if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV4)553			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;554		break;555	case SCTP_V4_FLOW:556	case AH_ESP_V4_FLOW:557	case AH_V4_FLOW:558	case ESP_V4_FLOW:559	case SCTP_V6_FLOW:560	case AH_ESP_V6_FLOW:561	case AH_V6_FLOW:562	case ESP_V6_FLOW:563	case IPV4_FLOW:564	case IPV6_FLOW:565		cmd->data |= RXH_IP_SRC | RXH_IP_DST;566		break;567	default:568		return -EINVAL;569	}570 571	return 0;572}573 574static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,575			  u32 *rule_locs)576{577	struct enic *enic = netdev_priv(dev);578	int ret = 0;579 580	switch (cmd->cmd) {581	case ETHTOOL_GRXRINGS:582		cmd->data = enic->rq_count;583		break;584	case ETHTOOL_GRXCLSRLCNT:585		spin_lock_bh(&enic->rfs_h.lock);586		cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free;587		cmd->data = enic->rfs_h.max;588		spin_unlock_bh(&enic->rfs_h.lock);589		break;590	case ETHTOOL_GRXCLSRLALL:591		spin_lock_bh(&enic->rfs_h.lock);592		ret = enic_grxclsrlall(enic, cmd, rule_locs);593		spin_unlock_bh(&enic->rfs_h.lock);594		break;595	case ETHTOOL_GRXCLSRULE:596		spin_lock_bh(&enic->rfs_h.lock);597		ret = enic_grxclsrule(enic, cmd);598		spin_unlock_bh(&enic->rfs_h.lock);599		break;600	case ETHTOOL_GRXFH:601		ret = enic_get_rx_flow_hash(enic, cmd);602		break;603	default:604		ret = -EOPNOTSUPP;605		break;606	}607 608	return ret;609}610 611static int enic_get_tunable(struct net_device *dev,612			    const struct ethtool_tunable *tuna, void *data)613{614	struct enic *enic = netdev_priv(dev);615	int ret = 0;616 617	switch (tuna->id) {618	case ETHTOOL_RX_COPYBREAK:619		*(u32 *)data = enic->rx_copybreak;620		break;621	default:622		ret = -EINVAL;623		break;624	}625 626	return ret;627}628 629static int enic_set_tunable(struct net_device *dev,630			    const struct ethtool_tunable *tuna,631			    const void *data)632{633	struct enic *enic = netdev_priv(dev);634	int ret = 0;635 636	switch (tuna->id) {637	case ETHTOOL_RX_COPYBREAK:638		enic->rx_copybreak = *(u32 *)data;639		break;640	default:641		ret = -EINVAL;642		break;643	}644 645	return ret;646}647 648static u32 enic_get_rxfh_key_size(struct net_device *netdev)649{650	return ENIC_RSS_LEN;651}652 653static int enic_get_rxfh(struct net_device *netdev,654			 struct ethtool_rxfh_param *rxfh)655{656	struct enic *enic = netdev_priv(netdev);657 658	if (rxfh->key)659		memcpy(rxfh->key, enic->rss_key, ENIC_RSS_LEN);660 661	rxfh->hfunc = ETH_RSS_HASH_TOP;662 663	return 0;664}665 666static int enic_set_rxfh(struct net_device *netdev,667			 struct ethtool_rxfh_param *rxfh,668			 struct netlink_ext_ack *extack)669{670	struct enic *enic = netdev_priv(netdev);671 672	if (rxfh->indir ||673	    (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&674	     rxfh->hfunc != ETH_RSS_HASH_TOP))675		return -EINVAL;676 677	if (rxfh->key)678		memcpy(enic->rss_key, rxfh->key, ENIC_RSS_LEN);679 680	return __enic_set_rsskey(enic);681}682 683static int enic_get_ts_info(struct net_device *netdev,684			    struct kernel_ethtool_ts_info *info)685{686	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE;687 688	return 0;689}690 691static void enic_get_channels(struct net_device *netdev,692			      struct ethtool_channels *channels)693{694	struct enic *enic = netdev_priv(netdev);695 696	switch (vnic_dev_get_intr_mode(enic->vdev)) {697	case VNIC_DEV_INTR_MODE_MSIX:698		channels->max_rx = ENIC_RQ_MAX;699		channels->max_tx = ENIC_WQ_MAX;700		channels->rx_count = enic->rq_count;701		channels->tx_count = enic->wq_count;702		break;703	case VNIC_DEV_INTR_MODE_MSI:704	case VNIC_DEV_INTR_MODE_INTX:705		channels->max_combined = 1;706		channels->combined_count = 1;707		break;708	default:709		break;710	}711}712 713static const struct ethtool_ops enic_ethtool_ops = {714	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |715				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX |716				     ETHTOOL_COALESCE_RX_USECS_LOW |717				     ETHTOOL_COALESCE_RX_USECS_HIGH,718	.get_drvinfo = enic_get_drvinfo,719	.get_msglevel = enic_get_msglevel,720	.set_msglevel = enic_set_msglevel,721	.get_link = ethtool_op_get_link,722	.get_strings = enic_get_strings,723	.get_ringparam = enic_get_ringparam,724	.set_ringparam = enic_set_ringparam,725	.get_sset_count = enic_get_sset_count,726	.get_ethtool_stats = enic_get_ethtool_stats,727	.get_coalesce = enic_get_coalesce,728	.set_coalesce = enic_set_coalesce,729	.get_rxnfc = enic_get_rxnfc,730	.get_tunable = enic_get_tunable,731	.set_tunable = enic_set_tunable,732	.get_rxfh_key_size = enic_get_rxfh_key_size,733	.get_rxfh = enic_get_rxfh,734	.set_rxfh = enic_set_rxfh,735	.get_link_ksettings = enic_get_ksettings,736	.get_ts_info = enic_get_ts_info,737	.get_channels = enic_get_channels,738};739 740void enic_set_ethtool_ops(struct net_device *netdev)741{742	netdev->ethtool_ops = &enic_ethtool_ops;743}744