brintos

brintos / linux-shallow public Read only

0
0
Text · 38.2 KiB · 6ded44b Raw
1336 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2019 Solarflare Communications Inc.5 *6 * This program is free software; you can redistribute it and/or modify it7 * under the terms of the GNU General Public License version 2 as published8 * by the Free Software Foundation, incorporated herein by reference.9 */10#include <linux/module.h>11#include <linux/netdevice.h>12#include "net_driver.h"13#include "mcdi.h"14#include "nic.h"15#include "selftest.h"16#include "rx_common.h"17#include "ethtool_common.h"18#include "mcdi_port_common.h"19 20struct efx_sw_stat_desc {21	const char *name;22	enum {23		EFX_ETHTOOL_STAT_SOURCE_nic,24		EFX_ETHTOOL_STAT_SOURCE_channel,25		EFX_ETHTOOL_STAT_SOURCE_tx_queue26	} source;27	unsigned int offset;28	u64 (*get_stat)(void *field); /* Reader function */29};30 31/* Initialiser for a struct efx_sw_stat_desc with type-checking */32#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \33				get_stat_function) {			\34	.name = #stat_name,						\35	.source = EFX_ETHTOOL_STAT_SOURCE_##source_name,		\36	.offset = ((((field_type *) 0) ==				\37		      &((struct efx_##source_name *)0)->field) ?	\38		    offsetof(struct efx_##source_name, field) :		\39		    offsetof(struct efx_##source_name, field)),		\40	.get_stat = get_stat_function,					\41}42 43static u64 efx_get_uint_stat(void *field)44{45	return *(unsigned int *)field;46}47 48static u64 efx_get_atomic_stat(void *field)49{50	return atomic_read((atomic_t *) field);51}52 53#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field)		\54	EFX_ETHTOOL_STAT(field, nic, field,			\55			 atomic_t, efx_get_atomic_stat)56 57#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field)			\58	EFX_ETHTOOL_STAT(field, channel, n_##field,		\59			 unsigned int, efx_get_uint_stat)60#define EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(field)		\61	EFX_ETHTOOL_STAT(field, channel, field,			\62			 unsigned int, efx_get_uint_stat)63 64#define EFX_ETHTOOL_UINT_TXQ_STAT(field)			\65	EFX_ETHTOOL_STAT(tx_##field, tx_queue, field,		\66			 unsigned int, efx_get_uint_stat)67 68static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {69	EFX_ETHTOOL_UINT_TXQ_STAT(merge_events),70	EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts),71	EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers),72	EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets),73	EFX_ETHTOOL_UINT_TXQ_STAT(tso_fallbacks),74	EFX_ETHTOOL_UINT_TXQ_STAT(pushes),75	EFX_ETHTOOL_UINT_TXQ_STAT(pio_packets),76	EFX_ETHTOOL_UINT_TXQ_STAT(cb_packets),77	EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),78	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),79	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),80	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),81	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_inner_ip_hdr_chksum_err),82	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_inner_tcp_udp_chksum_err),83	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_ip_hdr_chksum_err),84	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_tcp_udp_chksum_err),85	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_eth_crc_err),86	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch),87	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),88	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events),89	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets),90	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_drops),91	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops),92	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx),93	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect),94	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mport_bad),95#ifdef CONFIG_RFS_ACCEL96	EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(rfs_filter_count),97	EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_succeeded),98	EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_failed),99#endif100};101 102#define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc)103 104void efx_ethtool_get_drvinfo(struct net_device *net_dev,105			     struct ethtool_drvinfo *info)106{107	struct efx_nic *efx = efx_netdev_priv(net_dev);108 109	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));110	efx_mcdi_print_fwver(efx, info->fw_version,111			     sizeof(info->fw_version));112	strscpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));113}114 115u32 efx_ethtool_get_msglevel(struct net_device *net_dev)116{117	struct efx_nic *efx = efx_netdev_priv(net_dev);118 119	return efx->msg_enable;120}121 122void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)123{124	struct efx_nic *efx = efx_netdev_priv(net_dev);125 126	efx->msg_enable = msg_enable;127}128 129void efx_ethtool_self_test(struct net_device *net_dev,130			   struct ethtool_test *test, u64 *data)131{132	struct efx_nic *efx = efx_netdev_priv(net_dev);133	struct efx_self_tests *efx_tests;134	bool already_up;135	int rc = -ENOMEM;136 137	efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL);138	if (!efx_tests)139		goto fail;140 141	if (!efx_net_active(efx->state)) {142		rc = -EBUSY;143		goto out;144	}145 146	netif_info(efx, drv, efx->net_dev, "starting %sline testing\n",147		   (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");148 149	/* We need rx buffers and interrupts. */150	already_up = (efx->net_dev->flags & IFF_UP);151	if (!already_up) {152		rc = dev_open(efx->net_dev, NULL);153		if (rc) {154			netif_err(efx, drv, efx->net_dev,155				  "failed opening device.\n");156			goto out;157		}158	}159 160	rc = efx_selftest(efx, efx_tests, test->flags);161 162	if (!already_up)163		dev_close(efx->net_dev);164 165	netif_info(efx, drv, efx->net_dev, "%s %sline self-tests\n",166		   rc == 0 ? "passed" : "failed",167		   (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");168 169out:170	efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data);171	kfree(efx_tests);172fail:173	if (rc)174		test->flags |= ETH_TEST_FL_FAILED;175}176 177void efx_ethtool_get_pauseparam(struct net_device *net_dev,178				struct ethtool_pauseparam *pause)179{180	struct efx_nic *efx = efx_netdev_priv(net_dev);181 182	pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX);183	pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX);184	pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);185}186 187int efx_ethtool_set_pauseparam(struct net_device *net_dev,188			       struct ethtool_pauseparam *pause)189{190	struct efx_nic *efx = efx_netdev_priv(net_dev);191	u8 wanted_fc, old_fc;192	u32 old_adv;193	int rc = 0;194 195	mutex_lock(&efx->mac_lock);196 197	wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |198		     (pause->tx_pause ? EFX_FC_TX : 0) |199		     (pause->autoneg ? EFX_FC_AUTO : 0));200 201	if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {202		netif_dbg(efx, drv, efx->net_dev,203			  "Flow control unsupported: tx ON rx OFF\n");204		rc = -EINVAL;205		goto out;206	}207 208	if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising[0]) {209		netif_dbg(efx, drv, efx->net_dev,210			  "Autonegotiation is disabled\n");211		rc = -EINVAL;212		goto out;213	}214 215	/* Hook for Falcon bug 11482 workaround */216	if (efx->type->prepare_enable_fc_tx &&217	    (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX))218		efx->type->prepare_enable_fc_tx(efx);219 220	old_adv = efx->link_advertising[0];221	old_fc = efx->wanted_fc;222	efx_link_set_wanted_fc(efx, wanted_fc);223	if (efx->link_advertising[0] != old_adv ||224	    (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {225		rc = efx_mcdi_port_reconfigure(efx);226		if (rc) {227			netif_err(efx, drv, efx->net_dev,228				  "Unable to advertise requested flow "229				  "control setting\n");230			goto out;231		}232	}233 234	/* Reconfigure the MAC. The PHY *may* generate a link state change event235	 * if the user just changed the advertised capabilities, but there's no236	 * harm doing this twice */237	efx_mac_reconfigure(efx, false);238 239out:240	mutex_unlock(&efx->mac_lock);241 242	return rc;243}244 245/**246 * efx_fill_test - fill in an individual self-test entry247 * @test_index:		Index of the test248 * @strings:		Ethtool strings, or %NULL249 * @data:		Ethtool test results, or %NULL250 * @test:		Pointer to test result (used only if data != %NULL)251 * @unit_format:	Unit name format (e.g. "chan\%d")252 * @unit_id:		Unit id (e.g. 0 for "chan0")253 * @test_format:	Test name format (e.g. "loopback.\%s.tx.sent")254 * @test_id:		Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent")255 *256 * Fill in an individual self-test entry.257 */258static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,259			  int *test, const char *unit_format, int unit_id,260			  const char *test_format, const char *test_id)261{262	char unit_str[ETH_GSTRING_LEN], test_str[ETH_GSTRING_LEN];263 264	/* Fill data value, if applicable */265	if (data)266		data[test_index] = *test;267 268	/* Fill string, if applicable */269	if (strings) {270		if (strchr(unit_format, '%'))271			snprintf(unit_str, sizeof(unit_str),272				 unit_format, unit_id);273		else274			strcpy(unit_str, unit_format);275		snprintf(test_str, sizeof(test_str), test_format, test_id);276		snprintf(strings + test_index * ETH_GSTRING_LEN,277			 ETH_GSTRING_LEN,278			 "%-6s %-24s", unit_str, test_str);279	}280}281 282#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel283#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->label284#define EFX_LOOPBACK_NAME(_mode, _counter)			\285	"loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode)286 287/**288 * efx_fill_loopback_test - fill in a block of loopback self-test entries289 * @efx:		Efx NIC290 * @lb_tests:		Efx loopback self-test results structure291 * @mode:		Loopback test mode292 * @test_index:		Starting index of the test293 * @strings:		Ethtool strings, or %NULL294 * @data:		Ethtool test results, or %NULL295 *296 * Fill in a block of loopback self-test entries.  Return new test297 * index.298 */299static int efx_fill_loopback_test(struct efx_nic *efx,300				  struct efx_loopback_self_tests *lb_tests,301				  enum efx_loopback_mode mode,302				  unsigned int test_index,303				  u8 *strings, u64 *data)304{305	struct efx_channel *channel =306		efx_get_channel(efx, efx->tx_channel_offset);307	struct efx_tx_queue *tx_queue;308 309	efx_for_each_channel_tx_queue(tx_queue, channel) {310		efx_fill_test(test_index++, strings, data,311			      &lb_tests->tx_sent[tx_queue->label],312			      EFX_TX_QUEUE_NAME(tx_queue),313			      EFX_LOOPBACK_NAME(mode, "tx_sent"));314		efx_fill_test(test_index++, strings, data,315			      &lb_tests->tx_done[tx_queue->label],316			      EFX_TX_QUEUE_NAME(tx_queue),317			      EFX_LOOPBACK_NAME(mode, "tx_done"));318	}319	efx_fill_test(test_index++, strings, data,320		      &lb_tests->rx_good,321		      "rx", 0,322		      EFX_LOOPBACK_NAME(mode, "rx_good"));323	efx_fill_test(test_index++, strings, data,324		      &lb_tests->rx_bad,325		      "rx", 0,326		      EFX_LOOPBACK_NAME(mode, "rx_bad"));327 328	return test_index;329}330 331/**332 * efx_ethtool_fill_self_tests - get self-test details333 * @efx:		Efx NIC334 * @tests:		Efx self-test results structure, or %NULL335 * @strings:		Ethtool strings, or %NULL336 * @data:		Ethtool test results, or %NULL337 *338 * Get self-test number of strings, strings, and/or test results.339 * Return number of strings (== number of test results).340 *341 * The reason for merging these three functions is to make sure that342 * they can never be inconsistent.343 */344int efx_ethtool_fill_self_tests(struct efx_nic *efx,345				struct efx_self_tests *tests,346				u8 *strings, u64 *data)347{348	struct efx_channel *channel;349	unsigned int n = 0, i;350	enum efx_loopback_mode mode;351 352	efx_fill_test(n++, strings, data, &tests->phy_alive,353		      "phy", 0, "alive", NULL);354	efx_fill_test(n++, strings, data, &tests->nvram,355		      "core", 0, "nvram", NULL);356	efx_fill_test(n++, strings, data, &tests->interrupt,357		      "core", 0, "interrupt", NULL);358 359	/* Event queues */360	efx_for_each_channel(channel, efx) {361		efx_fill_test(n++, strings, data,362			      &tests->eventq_dma[channel->channel],363			      EFX_CHANNEL_NAME(channel),364			      "eventq.dma", NULL);365		efx_fill_test(n++, strings, data,366			      &tests->eventq_int[channel->channel],367			      EFX_CHANNEL_NAME(channel),368			      "eventq.int", NULL);369	}370 371	efx_fill_test(n++, strings, data, &tests->memory,372		      "core", 0, "memory", NULL);373	efx_fill_test(n++, strings, data, &tests->registers,374		      "core", 0, "registers", NULL);375 376	for (i = 0; true; ++i) {377		const char *name;378 379		EFX_WARN_ON_PARANOID(i >= EFX_MAX_PHY_TESTS);380		name = efx_mcdi_phy_test_name(efx, i);381		if (name == NULL)382			break;383 384		efx_fill_test(n++, strings, data, &tests->phy_ext[i], "phy", 0, name, NULL);385	}386 387	/* Loopback tests */388	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {389		if (!(efx->loopback_modes & (1 << mode)))390			continue;391		n = efx_fill_loopback_test(efx,392					   &tests->loopback[mode], mode, n,393					   strings, data);394	}395 396	return n;397}398 399static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)400{401	size_t n_stats = 0;402	struct efx_channel *channel;403 404	efx_for_each_channel(channel, efx) {405		if (efx_channel_has_tx_queues(channel)) {406			n_stats++;407			if (strings != NULL) {408				snprintf(strings, ETH_GSTRING_LEN,409					 "tx-%u.tx_packets",410					 channel->tx_queue[0].queue /411					 EFX_MAX_TXQ_PER_CHANNEL);412 413				strings += ETH_GSTRING_LEN;414			}415		}416	}417	efx_for_each_channel(channel, efx) {418		if (efx_channel_has_rx_queue(channel)) {419			n_stats++;420			if (strings != NULL) {421				snprintf(strings, ETH_GSTRING_LEN,422					 "rx-%d.rx_packets", channel->channel);423				strings += ETH_GSTRING_LEN;424			}425		}426	}427	if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) {428		unsigned short xdp;429 430		for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) {431			n_stats++;432			if (strings) {433				snprintf(strings, ETH_GSTRING_LEN,434					 "tx-xdp-cpu-%hu.tx_packets", xdp);435				strings += ETH_GSTRING_LEN;436			}437		}438	}439 440	return n_stats;441}442 443int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set)444{445	struct efx_nic *efx = efx_netdev_priv(net_dev);446 447	switch (string_set) {448	case ETH_SS_STATS:449		return efx->type->describe_stats(efx, NULL) +450		       EFX_ETHTOOL_SW_STAT_COUNT +451		       efx_describe_per_queue_stats(efx, NULL) +452		       efx_ptp_describe_stats(efx, NULL);453	case ETH_SS_TEST:454		return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);455	default:456		return -EINVAL;457	}458}459 460void efx_ethtool_get_strings(struct net_device *net_dev,461			     u32 string_set, u8 *strings)462{463	struct efx_nic *efx = efx_netdev_priv(net_dev);464	int i;465 466	switch (string_set) {467	case ETH_SS_STATS:468		strings += (efx->type->describe_stats(efx, strings) *469			    ETH_GSTRING_LEN);470		for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++)471			strscpy(strings + i * ETH_GSTRING_LEN,472				efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);473		strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;474		strings += (efx_describe_per_queue_stats(efx, strings) *475			    ETH_GSTRING_LEN);476		efx_ptp_describe_stats(efx, strings);477		break;478	case ETH_SS_TEST:479		efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);480		break;481	default:482		/* No other string sets */483		break;484	}485}486 487void efx_ethtool_get_stats(struct net_device *net_dev,488			   struct ethtool_stats *stats,489			   u64 *data)490{491	struct efx_nic *efx = efx_netdev_priv(net_dev);492	const struct efx_sw_stat_desc *stat;493	struct efx_channel *channel;494	struct efx_tx_queue *tx_queue;495	struct efx_rx_queue *rx_queue;496	int i;497 498	spin_lock_bh(&efx->stats_lock);499 500	/* Get NIC statistics */501	data += efx->type->update_stats(efx, data, NULL);502 503	/* Get software statistics */504	for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) {505		stat = &efx_sw_stat_desc[i];506		switch (stat->source) {507		case EFX_ETHTOOL_STAT_SOURCE_nic:508			data[i] = stat->get_stat((void *)efx + stat->offset);509			break;510		case EFX_ETHTOOL_STAT_SOURCE_channel:511			data[i] = 0;512			efx_for_each_channel(channel, efx)513				data[i] += stat->get_stat((void *)channel +514							  stat->offset);515			break;516		case EFX_ETHTOOL_STAT_SOURCE_tx_queue:517			data[i] = 0;518			efx_for_each_channel(channel, efx) {519				efx_for_each_channel_tx_queue(tx_queue, channel)520					data[i] +=521						stat->get_stat((void *)tx_queue522							       + stat->offset);523			}524			break;525		}526	}527	data += EFX_ETHTOOL_SW_STAT_COUNT;528 529	spin_unlock_bh(&efx->stats_lock);530 531	efx_for_each_channel(channel, efx) {532		if (efx_channel_has_tx_queues(channel)) {533			*data = 0;534			efx_for_each_channel_tx_queue(tx_queue, channel) {535				*data += tx_queue->tx_packets;536			}537			data++;538		}539	}540	efx_for_each_channel(channel, efx) {541		if (efx_channel_has_rx_queue(channel)) {542			*data = 0;543			efx_for_each_channel_rx_queue(rx_queue, channel) {544				*data += rx_queue->rx_packets;545			}546			data++;547		}548	}549	if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) {550		int xdp;551 552		for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) {553			data[0] = efx->xdp_tx_queues[xdp]->tx_packets;554			data++;555		}556	}557 558	efx_ptp_update_stats(efx, data);559}560 561/* This must be called with rtnl_lock held. */562int efx_ethtool_get_link_ksettings(struct net_device *net_dev,563				   struct ethtool_link_ksettings *cmd)564{565	struct efx_nic *efx = efx_netdev_priv(net_dev);566	struct efx_link_state *link_state = &efx->link_state;567 568	mutex_lock(&efx->mac_lock);569	efx_mcdi_phy_get_link_ksettings(efx, cmd);570	mutex_unlock(&efx->mac_lock);571 572	/* Both MACs support pause frames (bidirectional and respond-only) */573	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);574	ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);575 576	if (LOOPBACK_INTERNAL(efx)) {577		cmd->base.speed = link_state->speed;578		cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;579	}580 581	return 0;582}583 584/* This must be called with rtnl_lock held. */585int efx_ethtool_set_link_ksettings(struct net_device *net_dev,586				   const struct ethtool_link_ksettings *cmd)587{588	struct efx_nic *efx = efx_netdev_priv(net_dev);589	int rc;590 591	/* GMAC does not support 1000Mbps HD */592	if ((cmd->base.speed == SPEED_1000) &&593	    (cmd->base.duplex != DUPLEX_FULL)) {594		netif_dbg(efx, drv, efx->net_dev,595			  "rejecting unsupported 1000Mbps HD setting\n");596		return -EINVAL;597	}598 599	mutex_lock(&efx->mac_lock);600	rc = efx_mcdi_phy_set_link_ksettings(efx, cmd);601	mutex_unlock(&efx->mac_lock);602	return rc;603}604 605int efx_ethtool_get_fecparam(struct net_device *net_dev,606			     struct ethtool_fecparam *fecparam)607{608	struct efx_nic *efx = efx_netdev_priv(net_dev);609	int rc;610 611	mutex_lock(&efx->mac_lock);612	rc = efx_mcdi_phy_get_fecparam(efx, fecparam);613	mutex_unlock(&efx->mac_lock);614 615	return rc;616}617 618int efx_ethtool_set_fecparam(struct net_device *net_dev,619			     struct ethtool_fecparam *fecparam)620{621	struct efx_nic *efx = efx_netdev_priv(net_dev);622	int rc;623 624	mutex_lock(&efx->mac_lock);625	rc = efx_mcdi_phy_set_fecparam(efx, fecparam);626	mutex_unlock(&efx->mac_lock);627 628	return rc;629}630 631/* MAC address mask including only I/G bit */632static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0};633 634#define IP4_ADDR_FULL_MASK	((__force __be32)~0)635#define IP_PROTO_FULL_MASK	0xFF636#define PORT_FULL_MASK		((__force __be16)~0)637#define ETHER_TYPE_FULL_MASK	((__force __be16)~0)638 639static inline void ip6_fill_mask(__be32 *mask)640{641	mask[0] = mask[1] = mask[2] = mask[3] = ~(__be32)0;642}643 644static int efx_ethtool_get_class_rule(struct efx_nic *efx,645				      struct ethtool_rx_flow_spec *rule,646				      u32 *rss_context)647{648	struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;649	struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;650	struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec;651	struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec;652	struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec;653	struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec;654	struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec;655	struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;656	struct ethhdr *mac_entry = &rule->h_u.ether_spec;657	struct ethhdr *mac_mask = &rule->m_u.ether_spec;658	struct efx_filter_spec spec;659	int rc;660 661	rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL,662					rule->location, &spec);663	if (rc)664		return rc;665 666	if (spec.dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP)667		rule->ring_cookie = RX_CLS_FLOW_DISC;668	else669		rule->ring_cookie = spec.dmaq_id;670 671	if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) &&672	    spec.ether_type == htons(ETH_P_IP) &&673	    (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) &&674	    (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) &&675	    !(spec.match_flags &676	      ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |677		EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |678		EFX_FILTER_MATCH_IP_PROTO |679		EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) {680		rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ?681				   TCP_V4_FLOW : UDP_V4_FLOW);682		if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {683			ip_entry->ip4dst = spec.loc_host[0];684			ip_mask->ip4dst = IP4_ADDR_FULL_MASK;685		}686		if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {687			ip_entry->ip4src = spec.rem_host[0];688			ip_mask->ip4src = IP4_ADDR_FULL_MASK;689		}690		if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) {691			ip_entry->pdst = spec.loc_port;692			ip_mask->pdst = PORT_FULL_MASK;693		}694		if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) {695			ip_entry->psrc = spec.rem_port;696			ip_mask->psrc = PORT_FULL_MASK;697		}698	} else if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) &&699	    spec.ether_type == htons(ETH_P_IPV6) &&700	    (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) &&701	    (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) &&702	    !(spec.match_flags &703	      ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |704		EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |705		EFX_FILTER_MATCH_IP_PROTO |706		EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) {707		rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ?708				   TCP_V6_FLOW : UDP_V6_FLOW);709		if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {710			memcpy(ip6_entry->ip6dst, spec.loc_host,711			       sizeof(ip6_entry->ip6dst));712			ip6_fill_mask(ip6_mask->ip6dst);713		}714		if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {715			memcpy(ip6_entry->ip6src, spec.rem_host,716			       sizeof(ip6_entry->ip6src));717			ip6_fill_mask(ip6_mask->ip6src);718		}719		if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) {720			ip6_entry->pdst = spec.loc_port;721			ip6_mask->pdst = PORT_FULL_MASK;722		}723		if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) {724			ip6_entry->psrc = spec.rem_port;725			ip6_mask->psrc = PORT_FULL_MASK;726		}727	} else if (!(spec.match_flags &728		     ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG |729		       EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE |730		       EFX_FILTER_MATCH_OUTER_VID))) {731		rule->flow_type = ETHER_FLOW;732		if (spec.match_flags &733		    (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {734			ether_addr_copy(mac_entry->h_dest, spec.loc_mac);735			if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)736				eth_broadcast_addr(mac_mask->h_dest);737			else738				ether_addr_copy(mac_mask->h_dest,739						mac_addr_ig_mask);740		}741		if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {742			ether_addr_copy(mac_entry->h_source, spec.rem_mac);743			eth_broadcast_addr(mac_mask->h_source);744		}745		if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {746			mac_entry->h_proto = spec.ether_type;747			mac_mask->h_proto = ETHER_TYPE_FULL_MASK;748		}749	} else if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE &&750		   spec.ether_type == htons(ETH_P_IP) &&751		   !(spec.match_flags &752		     ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |753		       EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |754		       EFX_FILTER_MATCH_IP_PROTO))) {755		rule->flow_type = IPV4_USER_FLOW;756		uip_entry->ip_ver = ETH_RX_NFC_IP4;757		if (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) {758			uip_mask->proto = IP_PROTO_FULL_MASK;759			uip_entry->proto = spec.ip_proto;760		}761		if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {762			uip_entry->ip4dst = spec.loc_host[0];763			uip_mask->ip4dst = IP4_ADDR_FULL_MASK;764		}765		if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {766			uip_entry->ip4src = spec.rem_host[0];767			uip_mask->ip4src = IP4_ADDR_FULL_MASK;768		}769	} else if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE &&770		   spec.ether_type == htons(ETH_P_IPV6) &&771		   !(spec.match_flags &772		     ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |773		       EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |774		       EFX_FILTER_MATCH_IP_PROTO))) {775		rule->flow_type = IPV6_USER_FLOW;776		if (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) {777			uip6_mask->l4_proto = IP_PROTO_FULL_MASK;778			uip6_entry->l4_proto = spec.ip_proto;779		}780		if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {781			memcpy(uip6_entry->ip6dst, spec.loc_host,782			       sizeof(uip6_entry->ip6dst));783			ip6_fill_mask(uip6_mask->ip6dst);784		}785		if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {786			memcpy(uip6_entry->ip6src, spec.rem_host,787			       sizeof(uip6_entry->ip6src));788			ip6_fill_mask(uip6_mask->ip6src);789		}790	} else {791		/* The above should handle all filters that we insert */792		WARN_ON(1);793		return -EINVAL;794	}795 796	if (spec.match_flags & EFX_FILTER_MATCH_OUTER_VID) {797		rule->flow_type |= FLOW_EXT;798		rule->h_ext.vlan_tci = spec.outer_vid;799		rule->m_ext.vlan_tci = htons(0xfff);800	}801 802	if (spec.flags & EFX_FILTER_FLAG_RX_RSS) {803		rule->flow_type |= FLOW_RSS;804		*rss_context = spec.rss_context;805	}806 807	return rc;808}809 810int efx_ethtool_get_rxnfc(struct net_device *net_dev,811			  struct ethtool_rxnfc *info, u32 *rule_locs)812{813	struct efx_nic *efx = efx_netdev_priv(net_dev);814	u32 rss_context = 0;815	s32 rc = 0;816 817	switch (info->cmd) {818	case ETHTOOL_GRXRINGS:819		info->data = efx->n_rx_channels;820		return 0;821 822	case ETHTOOL_GRXFH: {823		struct efx_rss_context_priv *ctx = &efx->rss_context.priv;824		__u64 data;825 826		mutex_lock(&net_dev->ethtool->rss_lock);827		if (info->flow_type & FLOW_RSS && info->rss_context) {828			ctx = efx_find_rss_context_entry(efx, info->rss_context);829			if (!ctx) {830				rc = -ENOENT;831				goto out_unlock;832			}833		}834 835		data = 0;836		if (!efx_rss_active(ctx)) /* No RSS */837			goto out_setdata_unlock;838 839		switch (info->flow_type & ~FLOW_RSS) {840		case UDP_V4_FLOW:841		case UDP_V6_FLOW:842			if (ctx->rx_hash_udp_4tuple)843				data = (RXH_L4_B_0_1 | RXH_L4_B_2_3 |844					RXH_IP_SRC | RXH_IP_DST);845			else846				data = RXH_IP_SRC | RXH_IP_DST;847			break;848		case TCP_V4_FLOW:849		case TCP_V6_FLOW:850			data = (RXH_L4_B_0_1 | RXH_L4_B_2_3 |851				RXH_IP_SRC | RXH_IP_DST);852			break;853		case SCTP_V4_FLOW:854		case SCTP_V6_FLOW:855		case AH_ESP_V4_FLOW:856		case AH_ESP_V6_FLOW:857		case IPV4_FLOW:858		case IPV6_FLOW:859			data = RXH_IP_SRC | RXH_IP_DST;860			break;861		default:862			break;863		}864out_setdata_unlock:865		info->data = data;866out_unlock:867		mutex_unlock(&net_dev->ethtool->rss_lock);868		return rc;869	}870 871	case ETHTOOL_GRXCLSRLCNT:872		info->data = efx_filter_get_rx_id_limit(efx);873		if (info->data == 0)874			return -EOPNOTSUPP;875		info->data |= RX_CLS_LOC_SPECIAL;876		info->rule_cnt =877			efx_filter_count_rx_used(efx, EFX_FILTER_PRI_MANUAL);878		return 0;879 880	case ETHTOOL_GRXCLSRULE:881		if (efx_filter_get_rx_id_limit(efx) == 0)882			return -EOPNOTSUPP;883		rc = efx_ethtool_get_class_rule(efx, &info->fs, &rss_context);884		if (rc < 0)885			return rc;886		if (info->fs.flow_type & FLOW_RSS)887			info->rss_context = rss_context;888		return 0;889 890	case ETHTOOL_GRXCLSRLALL:891		info->data = efx_filter_get_rx_id_limit(efx);892		if (info->data == 0)893			return -EOPNOTSUPP;894		rc = efx_filter_get_rx_ids(efx, EFX_FILTER_PRI_MANUAL,895					   rule_locs, info->rule_cnt);896		if (rc < 0)897			return rc;898		info->rule_cnt = rc;899		return 0;900 901	default:902		return -EOPNOTSUPP;903	}904}905 906static inline bool ip6_mask_is_full(__be32 mask[4])907{908	return !~(mask[0] & mask[1] & mask[2] & mask[3]);909}910 911static inline bool ip6_mask_is_empty(__be32 mask[4])912{913	return !(mask[0] | mask[1] | mask[2] | mask[3]);914}915 916static int efx_ethtool_set_class_rule(struct efx_nic *efx,917				      struct ethtool_rx_flow_spec *rule,918				      u32 rss_context)919{920	struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;921	struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;922	struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec;923	struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec;924	struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec;925	struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec;926	struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec;927	struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;928	u32 flow_type = rule->flow_type & ~(FLOW_EXT | FLOW_RSS);929	struct ethhdr *mac_entry = &rule->h_u.ether_spec;930	struct ethhdr *mac_mask = &rule->m_u.ether_spec;931	enum efx_filter_flags flags = 0;932	struct efx_filter_spec spec;933	int rc;934 935	/* Check that user wants us to choose the location */936	if (rule->location != RX_CLS_LOC_ANY)937		return -EINVAL;938 939	/* Range-check ring_cookie */940	if (rule->ring_cookie >= efx->n_rx_channels &&941	    rule->ring_cookie != RX_CLS_FLOW_DISC)942		return -EINVAL;943 944	/* Check for unsupported extensions */945	if ((rule->flow_type & FLOW_EXT) &&946	    (rule->m_ext.vlan_etype || rule->m_ext.data[0] ||947	     rule->m_ext.data[1]))948		return -EINVAL;949 950	if (efx->rx_scatter)951		flags |= EFX_FILTER_FLAG_RX_SCATTER;952	if (rule->flow_type & FLOW_RSS)953		flags |= EFX_FILTER_FLAG_RX_RSS;954 955	efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, flags,956			   (rule->ring_cookie == RX_CLS_FLOW_DISC) ?957			   EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie);958 959	if (rule->flow_type & FLOW_RSS)960		spec.rss_context = rss_context;961 962	switch (flow_type) {963	case TCP_V4_FLOW:964	case UDP_V4_FLOW:965		spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |966				    EFX_FILTER_MATCH_IP_PROTO);967		spec.ether_type = htons(ETH_P_IP);968		spec.ip_proto = flow_type == TCP_V4_FLOW ? IPPROTO_TCP969							 : IPPROTO_UDP;970		if (ip_mask->ip4dst) {971			if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK)972				return -EINVAL;973			spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;974			spec.loc_host[0] = ip_entry->ip4dst;975		}976		if (ip_mask->ip4src) {977			if (ip_mask->ip4src != IP4_ADDR_FULL_MASK)978				return -EINVAL;979			spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;980			spec.rem_host[0] = ip_entry->ip4src;981		}982		if (ip_mask->pdst) {983			if (ip_mask->pdst != PORT_FULL_MASK)984				return -EINVAL;985			spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT;986			spec.loc_port = ip_entry->pdst;987		}988		if (ip_mask->psrc) {989			if (ip_mask->psrc != PORT_FULL_MASK)990				return -EINVAL;991			spec.match_flags |= EFX_FILTER_MATCH_REM_PORT;992			spec.rem_port = ip_entry->psrc;993		}994		if (ip_mask->tos)995			return -EINVAL;996		break;997 998	case TCP_V6_FLOW:999	case UDP_V6_FLOW:1000		spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |1001				    EFX_FILTER_MATCH_IP_PROTO);1002		spec.ether_type = htons(ETH_P_IPV6);1003		spec.ip_proto = flow_type == TCP_V6_FLOW ? IPPROTO_TCP1004							 : IPPROTO_UDP;1005		if (!ip6_mask_is_empty(ip6_mask->ip6dst)) {1006			if (!ip6_mask_is_full(ip6_mask->ip6dst))1007				return -EINVAL;1008			spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;1009			memcpy(spec.loc_host, ip6_entry->ip6dst, sizeof(spec.loc_host));1010		}1011		if (!ip6_mask_is_empty(ip6_mask->ip6src)) {1012			if (!ip6_mask_is_full(ip6_mask->ip6src))1013				return -EINVAL;1014			spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;1015			memcpy(spec.rem_host, ip6_entry->ip6src, sizeof(spec.rem_host));1016		}1017		if (ip6_mask->pdst) {1018			if (ip6_mask->pdst != PORT_FULL_MASK)1019				return -EINVAL;1020			spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT;1021			spec.loc_port = ip6_entry->pdst;1022		}1023		if (ip6_mask->psrc) {1024			if (ip6_mask->psrc != PORT_FULL_MASK)1025				return -EINVAL;1026			spec.match_flags |= EFX_FILTER_MATCH_REM_PORT;1027			spec.rem_port = ip6_entry->psrc;1028		}1029		if (ip6_mask->tclass)1030			return -EINVAL;1031		break;1032 1033	case IPV4_USER_FLOW:1034		if (uip_mask->l4_4_bytes || uip_mask->tos || uip_mask->ip_ver ||1035		    uip_entry->ip_ver != ETH_RX_NFC_IP4)1036			return -EINVAL;1037		spec.match_flags = EFX_FILTER_MATCH_ETHER_TYPE;1038		spec.ether_type = htons(ETH_P_IP);1039		if (uip_mask->ip4dst) {1040			if (uip_mask->ip4dst != IP4_ADDR_FULL_MASK)1041				return -EINVAL;1042			spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;1043			spec.loc_host[0] = uip_entry->ip4dst;1044		}1045		if (uip_mask->ip4src) {1046			if (uip_mask->ip4src != IP4_ADDR_FULL_MASK)1047				return -EINVAL;1048			spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;1049			spec.rem_host[0] = uip_entry->ip4src;1050		}1051		if (uip_mask->proto) {1052			if (uip_mask->proto != IP_PROTO_FULL_MASK)1053				return -EINVAL;1054			spec.match_flags |= EFX_FILTER_MATCH_IP_PROTO;1055			spec.ip_proto = uip_entry->proto;1056		}1057		break;1058 1059	case IPV6_USER_FLOW:1060		if (uip6_mask->l4_4_bytes || uip6_mask->tclass)1061			return -EINVAL;1062		spec.match_flags = EFX_FILTER_MATCH_ETHER_TYPE;1063		spec.ether_type = htons(ETH_P_IPV6);1064		if (!ip6_mask_is_empty(uip6_mask->ip6dst)) {1065			if (!ip6_mask_is_full(uip6_mask->ip6dst))1066				return -EINVAL;1067			spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;1068			memcpy(spec.loc_host, uip6_entry->ip6dst, sizeof(spec.loc_host));1069		}1070		if (!ip6_mask_is_empty(uip6_mask->ip6src)) {1071			if (!ip6_mask_is_full(uip6_mask->ip6src))1072				return -EINVAL;1073			spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;1074			memcpy(spec.rem_host, uip6_entry->ip6src, sizeof(spec.rem_host));1075		}1076		if (uip6_mask->l4_proto) {1077			if (uip6_mask->l4_proto != IP_PROTO_FULL_MASK)1078				return -EINVAL;1079			spec.match_flags |= EFX_FILTER_MATCH_IP_PROTO;1080			spec.ip_proto = uip6_entry->l4_proto;1081		}1082		break;1083 1084	case ETHER_FLOW:1085		if (!is_zero_ether_addr(mac_mask->h_dest)) {1086			if (ether_addr_equal(mac_mask->h_dest,1087					     mac_addr_ig_mask))1088				spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;1089			else if (is_broadcast_ether_addr(mac_mask->h_dest))1090				spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;1091			else1092				return -EINVAL;1093			ether_addr_copy(spec.loc_mac, mac_entry->h_dest);1094		}1095		if (!is_zero_ether_addr(mac_mask->h_source)) {1096			if (!is_broadcast_ether_addr(mac_mask->h_source))1097				return -EINVAL;1098			spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;1099			ether_addr_copy(spec.rem_mac, mac_entry->h_source);1100		}1101		if (mac_mask->h_proto) {1102			if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)1103				return -EINVAL;1104			spec.match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;1105			spec.ether_type = mac_entry->h_proto;1106		}1107		break;1108 1109	default:1110		return -EINVAL;1111	}1112 1113	if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) {1114		if (rule->m_ext.vlan_tci != htons(0xfff))1115			return -EINVAL;1116		spec.match_flags |= EFX_FILTER_MATCH_OUTER_VID;1117		spec.outer_vid = rule->h_ext.vlan_tci;1118	}1119 1120	rc = efx_filter_insert_filter(efx, &spec, true);1121	if (rc < 0)1122		return rc;1123 1124	rule->location = rc;1125	return 0;1126}1127 1128int efx_ethtool_set_rxnfc(struct net_device *net_dev,1129			  struct ethtool_rxnfc *info)1130{1131	struct efx_nic *efx = efx_netdev_priv(net_dev);1132 1133	if (efx_filter_get_rx_id_limit(efx) == 0)1134		return -EOPNOTSUPP;1135 1136	switch (info->cmd) {1137	case ETHTOOL_SRXCLSRLINS:1138		return efx_ethtool_set_class_rule(efx, &info->fs,1139						  info->rss_context);1140 1141	case ETHTOOL_SRXCLSRLDEL:1142		return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL,1143						 info->fs.location);1144 1145	default:1146		return -EOPNOTSUPP;1147	}1148}1149 1150u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)1151{1152	struct efx_nic *efx = efx_netdev_priv(net_dev);1153 1154	if (efx->n_rx_channels == 1)1155		return 0;1156	return ARRAY_SIZE(efx->rss_context.rx_indir_table);1157}1158 1159u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)1160{1161	struct efx_nic *efx = efx_netdev_priv(net_dev);1162 1163	return efx->type->rx_hash_key_size;1164}1165 1166int efx_ethtool_get_rxfh(struct net_device *net_dev,1167			 struct ethtool_rxfh_param *rxfh)1168{1169	struct efx_nic *efx = efx_netdev_priv(net_dev);1170	int rc;1171 1172	if (rxfh->rss_context) /* core should never call us for these */1173		return -EINVAL;1174 1175	rc = efx->type->rx_pull_rss_config(efx);1176	if (rc)1177		return rc;1178 1179	rxfh->hfunc = ETH_RSS_HASH_TOP;1180	if (rxfh->indir)1181		memcpy(rxfh->indir, efx->rss_context.rx_indir_table,1182		       sizeof(efx->rss_context.rx_indir_table));1183	if (rxfh->key)1184		memcpy(rxfh->key, efx->rss_context.rx_hash_key,1185		       efx->type->rx_hash_key_size);1186	return 0;1187}1188 1189int efx_ethtool_modify_rxfh_context(struct net_device *net_dev,1190				    struct ethtool_rxfh_context *ctx,1191				    const struct ethtool_rxfh_param *rxfh,1192				    struct netlink_ext_ack *extack)1193{1194	struct efx_nic *efx = efx_netdev_priv(net_dev);1195	struct efx_rss_context_priv *priv;1196	const u32 *indir = rxfh->indir;1197	const u8 *key = rxfh->key;1198 1199	if (!efx->type->rx_push_rss_context_config) {1200		NL_SET_ERR_MSG_MOD(extack,1201				   "NIC type does not support custom contexts");1202		return -EOPNOTSUPP;1203	}1204	/* Hash function is Toeplitz, cannot be changed */1205	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&1206	    rxfh->hfunc != ETH_RSS_HASH_TOP) {1207		NL_SET_ERR_MSG_MOD(extack, "Only Toeplitz hash is supported");1208		return -EOPNOTSUPP;1209	}1210 1211	priv = ethtool_rxfh_context_priv(ctx);1212 1213	if (!key)1214		key = ethtool_rxfh_context_key(ctx);1215	if (!indir)1216		indir = ethtool_rxfh_context_indir(ctx);1217 1218	return efx->type->rx_push_rss_context_config(efx, priv, indir, key,1219						     false);1220}1221 1222int efx_ethtool_create_rxfh_context(struct net_device *net_dev,1223				    struct ethtool_rxfh_context *ctx,1224				    const struct ethtool_rxfh_param *rxfh,1225				    struct netlink_ext_ack *extack)1226{1227	struct efx_nic *efx = efx_netdev_priv(net_dev);1228	struct efx_rss_context_priv *priv;1229 1230	priv = ethtool_rxfh_context_priv(ctx);1231 1232	priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;1233	priv->rx_hash_udp_4tuple = false;1234	/* Generate default indir table and/or key if not specified.1235	 * We use ctx as a place to store these; this is fine because1236	 * we're doing a create, so if we fail then the ctx will just1237	 * be deleted.1238	 */1239	if (!rxfh->indir)1240		efx_set_default_rx_indir_table(efx, ethtool_rxfh_context_indir(ctx));1241	if (!rxfh->key)1242		netdev_rss_key_fill(ethtool_rxfh_context_key(ctx),1243				    ctx->key_size);1244	if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE)1245		ctx->hfunc = ETH_RSS_HASH_TOP;1246	if (rxfh->input_xfrm == RXH_XFRM_NO_CHANGE)1247		ctx->input_xfrm = 0;1248	return efx_ethtool_modify_rxfh_context(net_dev, ctx, rxfh, extack);1249}1250 1251int efx_ethtool_remove_rxfh_context(struct net_device *net_dev,1252				    struct ethtool_rxfh_context *ctx,1253				    u32 rss_context,1254				    struct netlink_ext_ack *extack)1255{1256	struct efx_nic *efx = efx_netdev_priv(net_dev);1257	struct efx_rss_context_priv *priv;1258 1259	if (!efx->type->rx_push_rss_context_config) {1260		NL_SET_ERR_MSG_MOD(extack,1261				   "NIC type does not support custom contexts");1262		return -EOPNOTSUPP;1263	}1264 1265	priv = ethtool_rxfh_context_priv(ctx);1266	return efx->type->rx_push_rss_context_config(efx, priv, NULL, NULL,1267						     true);1268}1269 1270int efx_ethtool_set_rxfh(struct net_device *net_dev,1271			 struct ethtool_rxfh_param *rxfh,1272			 struct netlink_ext_ack *extack)1273{1274	struct efx_nic *efx = efx_netdev_priv(net_dev);1275	u32 *indir = rxfh->indir;1276	u8 *key = rxfh->key;1277 1278	/* Hash function is Toeplitz, cannot be changed */1279	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&1280	    rxfh->hfunc != ETH_RSS_HASH_TOP)1281		return -EOPNOTSUPP;1282 1283	/* Custom contexts should use new API */1284	if (WARN_ON_ONCE(rxfh->rss_context))1285		return -EIO;1286 1287	if (!indir && !key)1288		return 0;1289 1290	if (!key)1291		key = efx->rss_context.rx_hash_key;1292	if (!indir)1293		indir = efx->rss_context.rx_indir_table;1294 1295	return efx->type->rx_push_rss_config(efx, true, indir, key);1296}1297 1298int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)1299{1300	struct efx_nic *efx = efx_netdev_priv(net_dev);1301	int rc;1302 1303	rc = efx->type->map_reset_flags(flags);1304	if (rc < 0)1305		return rc;1306 1307	return efx_reset(efx, rc);1308}1309 1310int efx_ethtool_get_module_eeprom(struct net_device *net_dev,1311				  struct ethtool_eeprom *ee,1312				  u8 *data)1313{1314	struct efx_nic *efx = efx_netdev_priv(net_dev);1315	int ret;1316 1317	mutex_lock(&efx->mac_lock);1318	ret = efx_mcdi_phy_get_module_eeprom(efx, ee, data);1319	mutex_unlock(&efx->mac_lock);1320 1321	return ret;1322}1323 1324int efx_ethtool_get_module_info(struct net_device *net_dev,1325				struct ethtool_modinfo *modinfo)1326{1327	struct efx_nic *efx = efx_netdev_priv(net_dev);1328	int ret;1329 1330	mutex_lock(&efx->mac_lock);1331	ret = efx_mcdi_phy_get_module_info(efx, modinfo);1332	mutex_unlock(&efx->mac_lock);1333 1334	return ret;1335}1336