18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 58c2ecf20Sopenharmony_ci * Copyright 2006-2013 Solarflare Communications Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 108c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 118c2ecf20Sopenharmony_ci#include <linux/in.h> 128c2ecf20Sopenharmony_ci#include "net_driver.h" 138c2ecf20Sopenharmony_ci#include "workarounds.h" 148c2ecf20Sopenharmony_ci#include "selftest.h" 158c2ecf20Sopenharmony_ci#include "efx.h" 168c2ecf20Sopenharmony_ci#include "filter.h" 178c2ecf20Sopenharmony_ci#include "nic.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct ef4_sw_stat_desc { 208c2ecf20Sopenharmony_ci const char *name; 218c2ecf20Sopenharmony_ci enum { 228c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT_SOURCE_nic, 238c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT_SOURCE_channel, 248c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT_SOURCE_tx_queue 258c2ecf20Sopenharmony_ci } source; 268c2ecf20Sopenharmony_ci unsigned offset; 278c2ecf20Sopenharmony_ci u64(*get_stat) (void *field); /* Reader function */ 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Initialiser for a struct ef4_sw_stat_desc with type-checking */ 318c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_STAT(stat_name, source_name, field, field_type, \ 328c2ecf20Sopenharmony_ci get_stat_function) { \ 338c2ecf20Sopenharmony_ci .name = #stat_name, \ 348c2ecf20Sopenharmony_ci .source = EF4_ETHTOOL_STAT_SOURCE_##source_name, \ 358c2ecf20Sopenharmony_ci .offset = ((((field_type *) 0) == \ 368c2ecf20Sopenharmony_ci &((struct ef4_##source_name *)0)->field) ? \ 378c2ecf20Sopenharmony_ci offsetof(struct ef4_##source_name, field) : \ 388c2ecf20Sopenharmony_ci offsetof(struct ef4_##source_name, field)), \ 398c2ecf20Sopenharmony_ci .get_stat = get_stat_function, \ 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic u64 ef4_get_uint_stat(void *field) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return *(unsigned int *)field; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic u64 ef4_get_atomic_stat(void *field) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return atomic_read((atomic_t *) field); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \ 538c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT(field, nic, field, \ 548c2ecf20Sopenharmony_ci atomic_t, ef4_get_atomic_stat) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_UINT_CHANNEL_STAT(field) \ 578c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT(field, channel, n_##field, \ 588c2ecf20Sopenharmony_ci unsigned int, ef4_get_uint_stat) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_UINT_TXQ_STAT(field) \ 618c2ecf20Sopenharmony_ci EF4_ETHTOOL_STAT(tx_##field, tx_queue, field, \ 628c2ecf20Sopenharmony_ci unsigned int, ef4_get_uint_stat) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct ef4_sw_stat_desc ef4_sw_stat_desc[] = { 658c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_TXQ_STAT(merge_events), 668c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_TXQ_STAT(pushes), 678c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_TXQ_STAT(cb_packets), 688c2ecf20Sopenharmony_ci EF4_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), 698c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), 708c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), 718c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), 728c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), 738c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), 748c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events), 758c2ecf20Sopenharmony_ci EF4_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets), 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(ef4_sw_stat_desc) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define EF4_ETHTOOL_EEPROM_MAGIC 0xEFAB 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/************************************************************************** 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Ethtool operations 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci ************************************************************************** 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Identify device by flashing LEDs */ 908c2ecf20Sopenharmony_cistatic int ef4_ethtool_phys_id(struct net_device *net_dev, 918c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 948c2ecf20Sopenharmony_ci enum ef4_led_mode mode = EF4_LED_DEFAULT; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci switch (state) { 978c2ecf20Sopenharmony_ci case ETHTOOL_ID_ON: 988c2ecf20Sopenharmony_ci mode = EF4_LED_ON; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case ETHTOOL_ID_OFF: 1018c2ecf20Sopenharmony_ci mode = EF4_LED_OFF; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 1048c2ecf20Sopenharmony_ci mode = EF4_LED_DEFAULT; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 1078c2ecf20Sopenharmony_ci return 1; /* cycle on/off once per second */ 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci efx->type->set_id_led(efx, mode); 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* This must be called with rtnl_lock held. */ 1158c2ecf20Sopenharmony_cistatic int 1168c2ecf20Sopenharmony_cief4_ethtool_get_link_ksettings(struct net_device *net_dev, 1178c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1208c2ecf20Sopenharmony_ci struct ef4_link_state *link_state = &efx->link_state; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 1238c2ecf20Sopenharmony_ci efx->phy_op->get_link_ksettings(efx, cmd); 1248c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Both MACs support pause frames (bidirectional and respond-only) */ 1278c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); 1288c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (LOOPBACK_INTERNAL(efx)) { 1318c2ecf20Sopenharmony_ci cmd->base.speed = link_state->speed; 1328c2ecf20Sopenharmony_ci cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* This must be called with rtnl_lock held. */ 1398c2ecf20Sopenharmony_cistatic int 1408c2ecf20Sopenharmony_cief4_ethtool_set_link_ksettings(struct net_device *net_dev, 1418c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1448c2ecf20Sopenharmony_ci int rc; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* GMAC does not support 1000Mbps HD */ 1478c2ecf20Sopenharmony_ci if ((cmd->base.speed == SPEED_1000) && 1488c2ecf20Sopenharmony_ci (cmd->base.duplex != DUPLEX_FULL)) { 1498c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 1508c2ecf20Sopenharmony_ci "rejecting unsupported 1000Mbps HD setting\n"); 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 1558c2ecf20Sopenharmony_ci rc = efx->phy_op->set_link_ksettings(efx, cmd); 1568c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 1578c2ecf20Sopenharmony_ci return rc; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_drvinfo(struct net_device *net_dev, 1618c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 1668c2ecf20Sopenharmony_ci strlcpy(info->version, EF4_DRIVER_VERSION, sizeof(info->version)); 1678c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_regs_len(struct net_device *net_dev) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return ef4_nic_get_regs_len(netdev_priv(net_dev)); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_regs(struct net_device *net_dev, 1768c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *buf) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci regs->version = efx->type->revision; 1818c2ecf20Sopenharmony_ci ef4_nic_get_regs(efx, buf); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic u32 ef4_ethtool_get_msglevel(struct net_device *net_dev) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1878c2ecf20Sopenharmony_ci return efx->msg_enable; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void ef4_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 1938c2ecf20Sopenharmony_ci efx->msg_enable = msg_enable; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * ef4_fill_test - fill in an individual self-test entry 1988c2ecf20Sopenharmony_ci * @test_index: Index of the test 1998c2ecf20Sopenharmony_ci * @strings: Ethtool strings, or %NULL 2008c2ecf20Sopenharmony_ci * @data: Ethtool test results, or %NULL 2018c2ecf20Sopenharmony_ci * @test: Pointer to test result (used only if data != %NULL) 2028c2ecf20Sopenharmony_ci * @unit_format: Unit name format (e.g. "chan\%d") 2038c2ecf20Sopenharmony_ci * @unit_id: Unit id (e.g. 0 for "chan0") 2048c2ecf20Sopenharmony_ci * @test_format: Test name format (e.g. "loopback.\%s.tx.sent") 2058c2ecf20Sopenharmony_ci * @test_id: Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent") 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Fill in an individual self-test entry. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic void ef4_fill_test(unsigned int test_index, u8 *strings, u64 *data, 2108c2ecf20Sopenharmony_ci int *test, const char *unit_format, int unit_id, 2118c2ecf20Sopenharmony_ci const char *test_format, const char *test_id) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci char unit_str[ETH_GSTRING_LEN], test_str[ETH_GSTRING_LEN]; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Fill data value, if applicable */ 2168c2ecf20Sopenharmony_ci if (data) 2178c2ecf20Sopenharmony_ci data[test_index] = *test; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Fill string, if applicable */ 2208c2ecf20Sopenharmony_ci if (strings) { 2218c2ecf20Sopenharmony_ci if (strchr(unit_format, '%')) 2228c2ecf20Sopenharmony_ci snprintf(unit_str, sizeof(unit_str), 2238c2ecf20Sopenharmony_ci unit_format, unit_id); 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci strcpy(unit_str, unit_format); 2268c2ecf20Sopenharmony_ci snprintf(test_str, sizeof(test_str), test_format, test_id); 2278c2ecf20Sopenharmony_ci snprintf(strings + test_index * ETH_GSTRING_LEN, 2288c2ecf20Sopenharmony_ci ETH_GSTRING_LEN, 2298c2ecf20Sopenharmony_ci "%-6s %-24s", unit_str, test_str); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define EF4_CHANNEL_NAME(_channel) "chan%d", _channel->channel 2348c2ecf20Sopenharmony_ci#define EF4_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue 2358c2ecf20Sopenharmony_ci#define EF4_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue 2368c2ecf20Sopenharmony_ci#define EF4_LOOPBACK_NAME(_mode, _counter) \ 2378c2ecf20Sopenharmony_ci "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, ef4_loopback_mode) 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * ef4_fill_loopback_test - fill in a block of loopback self-test entries 2418c2ecf20Sopenharmony_ci * @efx: Efx NIC 2428c2ecf20Sopenharmony_ci * @lb_tests: Efx loopback self-test results structure 2438c2ecf20Sopenharmony_ci * @mode: Loopback test mode 2448c2ecf20Sopenharmony_ci * @test_index: Starting index of the test 2458c2ecf20Sopenharmony_ci * @strings: Ethtool strings, or %NULL 2468c2ecf20Sopenharmony_ci * @data: Ethtool test results, or %NULL 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Fill in a block of loopback self-test entries. Return new test 2498c2ecf20Sopenharmony_ci * index. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic int ef4_fill_loopback_test(struct ef4_nic *efx, 2528c2ecf20Sopenharmony_ci struct ef4_loopback_self_tests *lb_tests, 2538c2ecf20Sopenharmony_ci enum ef4_loopback_mode mode, 2548c2ecf20Sopenharmony_ci unsigned int test_index, 2558c2ecf20Sopenharmony_ci u8 *strings, u64 *data) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ef4_channel *channel = 2588c2ecf20Sopenharmony_ci ef4_get_channel(efx, efx->tx_channel_offset); 2598c2ecf20Sopenharmony_ci struct ef4_tx_queue *tx_queue; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 2628c2ecf20Sopenharmony_ci ef4_fill_test(test_index++, strings, data, 2638c2ecf20Sopenharmony_ci &lb_tests->tx_sent[tx_queue->queue], 2648c2ecf20Sopenharmony_ci EF4_TX_QUEUE_NAME(tx_queue), 2658c2ecf20Sopenharmony_ci EF4_LOOPBACK_NAME(mode, "tx_sent")); 2668c2ecf20Sopenharmony_ci ef4_fill_test(test_index++, strings, data, 2678c2ecf20Sopenharmony_ci &lb_tests->tx_done[tx_queue->queue], 2688c2ecf20Sopenharmony_ci EF4_TX_QUEUE_NAME(tx_queue), 2698c2ecf20Sopenharmony_ci EF4_LOOPBACK_NAME(mode, "tx_done")); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci ef4_fill_test(test_index++, strings, data, 2728c2ecf20Sopenharmony_ci &lb_tests->rx_good, 2738c2ecf20Sopenharmony_ci "rx", 0, 2748c2ecf20Sopenharmony_ci EF4_LOOPBACK_NAME(mode, "rx_good")); 2758c2ecf20Sopenharmony_ci ef4_fill_test(test_index++, strings, data, 2768c2ecf20Sopenharmony_ci &lb_tests->rx_bad, 2778c2ecf20Sopenharmony_ci "rx", 0, 2788c2ecf20Sopenharmony_ci EF4_LOOPBACK_NAME(mode, "rx_bad")); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return test_index; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/** 2848c2ecf20Sopenharmony_ci * ef4_ethtool_fill_self_tests - get self-test details 2858c2ecf20Sopenharmony_ci * @efx: Efx NIC 2868c2ecf20Sopenharmony_ci * @tests: Efx self-test results structure, or %NULL 2878c2ecf20Sopenharmony_ci * @strings: Ethtool strings, or %NULL 2888c2ecf20Sopenharmony_ci * @data: Ethtool test results, or %NULL 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * Get self-test number of strings, strings, and/or test results. 2918c2ecf20Sopenharmony_ci * Return number of strings (== number of test results). 2928c2ecf20Sopenharmony_ci * 2938c2ecf20Sopenharmony_ci * The reason for merging these three functions is to make sure that 2948c2ecf20Sopenharmony_ci * they can never be inconsistent. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_cistatic int ef4_ethtool_fill_self_tests(struct ef4_nic *efx, 2978c2ecf20Sopenharmony_ci struct ef4_self_tests *tests, 2988c2ecf20Sopenharmony_ci u8 *strings, u64 *data) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct ef4_channel *channel; 3018c2ecf20Sopenharmony_ci unsigned int n = 0, i; 3028c2ecf20Sopenharmony_ci enum ef4_loopback_mode mode; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->phy_alive, 3058c2ecf20Sopenharmony_ci "phy", 0, "alive", NULL); 3068c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->nvram, 3078c2ecf20Sopenharmony_ci "core", 0, "nvram", NULL); 3088c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->interrupt, 3098c2ecf20Sopenharmony_ci "core", 0, "interrupt", NULL); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Event queues */ 3128c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 3138c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, 3148c2ecf20Sopenharmony_ci &tests->eventq_dma[channel->channel], 3158c2ecf20Sopenharmony_ci EF4_CHANNEL_NAME(channel), 3168c2ecf20Sopenharmony_ci "eventq.dma", NULL); 3178c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, 3188c2ecf20Sopenharmony_ci &tests->eventq_int[channel->channel], 3198c2ecf20Sopenharmony_ci EF4_CHANNEL_NAME(channel), 3208c2ecf20Sopenharmony_ci "eventq.int", NULL); 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->memory, 3248c2ecf20Sopenharmony_ci "core", 0, "memory", NULL); 3258c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->registers, 3268c2ecf20Sopenharmony_ci "core", 0, "registers", NULL); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (efx->phy_op->run_tests != NULL) { 3298c2ecf20Sopenharmony_ci EF4_BUG_ON_PARANOID(efx->phy_op->test_name == NULL); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci for (i = 0; true; ++i) { 3328c2ecf20Sopenharmony_ci const char *name; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci EF4_BUG_ON_PARANOID(i >= EF4_MAX_PHY_TESTS); 3358c2ecf20Sopenharmony_ci name = efx->phy_op->test_name(efx, i); 3368c2ecf20Sopenharmony_ci if (name == NULL) 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ef4_fill_test(n++, strings, data, &tests->phy_ext[i], 3408c2ecf20Sopenharmony_ci "phy", 0, name, NULL); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Loopback tests */ 3458c2ecf20Sopenharmony_ci for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { 3468c2ecf20Sopenharmony_ci if (!(efx->loopback_modes & (1 << mode))) 3478c2ecf20Sopenharmony_ci continue; 3488c2ecf20Sopenharmony_ci n = ef4_fill_loopback_test(efx, 3498c2ecf20Sopenharmony_ci &tests->loopback[mode], mode, n, 3508c2ecf20Sopenharmony_ci strings, data); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return n; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 *strings) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci size_t n_stats = 0; 3598c2ecf20Sopenharmony_ci struct ef4_channel *channel; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 3628c2ecf20Sopenharmony_ci if (ef4_channel_has_tx_queues(channel)) { 3638c2ecf20Sopenharmony_ci n_stats++; 3648c2ecf20Sopenharmony_ci if (strings != NULL) { 3658c2ecf20Sopenharmony_ci snprintf(strings, ETH_GSTRING_LEN, 3668c2ecf20Sopenharmony_ci "tx-%u.tx_packets", 3678c2ecf20Sopenharmony_ci channel->tx_queue[0].queue / 3688c2ecf20Sopenharmony_ci EF4_TXQ_TYPES); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 3758c2ecf20Sopenharmony_ci if (ef4_channel_has_rx_queue(channel)) { 3768c2ecf20Sopenharmony_ci n_stats++; 3778c2ecf20Sopenharmony_ci if (strings != NULL) { 3788c2ecf20Sopenharmony_ci snprintf(strings, ETH_GSTRING_LEN, 3798c2ecf20Sopenharmony_ci "rx-%d.rx_packets", channel->channel); 3808c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci return n_stats; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_sset_count(struct net_device *net_dev, 3888c2ecf20Sopenharmony_ci int string_set) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci switch (string_set) { 3938c2ecf20Sopenharmony_ci case ETH_SS_STATS: 3948c2ecf20Sopenharmony_ci return efx->type->describe_stats(efx, NULL) + 3958c2ecf20Sopenharmony_ci EF4_ETHTOOL_SW_STAT_COUNT + 3968c2ecf20Sopenharmony_ci ef4_describe_per_queue_stats(efx, NULL); 3978c2ecf20Sopenharmony_ci case ETH_SS_TEST: 3988c2ecf20Sopenharmony_ci return ef4_ethtool_fill_self_tests(efx, NULL, NULL, NULL); 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_strings(struct net_device *net_dev, 4058c2ecf20Sopenharmony_ci u32 string_set, u8 *strings) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 4088c2ecf20Sopenharmony_ci int i; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci switch (string_set) { 4118c2ecf20Sopenharmony_ci case ETH_SS_STATS: 4128c2ecf20Sopenharmony_ci strings += (efx->type->describe_stats(efx, strings) * 4138c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 4148c2ecf20Sopenharmony_ci for (i = 0; i < EF4_ETHTOOL_SW_STAT_COUNT; i++) 4158c2ecf20Sopenharmony_ci strlcpy(strings + i * ETH_GSTRING_LEN, 4168c2ecf20Sopenharmony_ci ef4_sw_stat_desc[i].name, ETH_GSTRING_LEN); 4178c2ecf20Sopenharmony_ci strings += EF4_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; 4188c2ecf20Sopenharmony_ci strings += (ef4_describe_per_queue_stats(efx, strings) * 4198c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci case ETH_SS_TEST: 4228c2ecf20Sopenharmony_ci ef4_ethtool_fill_self_tests(efx, NULL, strings, NULL); 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci default: 4258c2ecf20Sopenharmony_ci /* No other string sets */ 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_stats(struct net_device *net_dev, 4318c2ecf20Sopenharmony_ci struct ethtool_stats *stats, 4328c2ecf20Sopenharmony_ci u64 *data) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 4358c2ecf20Sopenharmony_ci const struct ef4_sw_stat_desc *stat; 4368c2ecf20Sopenharmony_ci struct ef4_channel *channel; 4378c2ecf20Sopenharmony_ci struct ef4_tx_queue *tx_queue; 4388c2ecf20Sopenharmony_ci struct ef4_rx_queue *rx_queue; 4398c2ecf20Sopenharmony_ci int i; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Get NIC statistics */ 4448c2ecf20Sopenharmony_ci data += efx->type->update_stats(efx, data, NULL); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Get software statistics */ 4478c2ecf20Sopenharmony_ci for (i = 0; i < EF4_ETHTOOL_SW_STAT_COUNT; i++) { 4488c2ecf20Sopenharmony_ci stat = &ef4_sw_stat_desc[i]; 4498c2ecf20Sopenharmony_ci switch (stat->source) { 4508c2ecf20Sopenharmony_ci case EF4_ETHTOOL_STAT_SOURCE_nic: 4518c2ecf20Sopenharmony_ci data[i] = stat->get_stat((void *)efx + stat->offset); 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci case EF4_ETHTOOL_STAT_SOURCE_channel: 4548c2ecf20Sopenharmony_ci data[i] = 0; 4558c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) 4568c2ecf20Sopenharmony_ci data[i] += stat->get_stat((void *)channel + 4578c2ecf20Sopenharmony_ci stat->offset); 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci case EF4_ETHTOOL_STAT_SOURCE_tx_queue: 4608c2ecf20Sopenharmony_ci data[i] = 0; 4618c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 4628c2ecf20Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) 4638c2ecf20Sopenharmony_ci data[i] += 4648c2ecf20Sopenharmony_ci stat->get_stat((void *)tx_queue 4658c2ecf20Sopenharmony_ci + stat->offset); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci data += EF4_ETHTOOL_SW_STAT_COUNT; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 4758c2ecf20Sopenharmony_ci if (ef4_channel_has_tx_queues(channel)) { 4768c2ecf20Sopenharmony_ci *data = 0; 4778c2ecf20Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 4788c2ecf20Sopenharmony_ci *data += tx_queue->tx_packets; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci data++; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) { 4848c2ecf20Sopenharmony_ci if (ef4_channel_has_rx_queue(channel)) { 4858c2ecf20Sopenharmony_ci *data = 0; 4868c2ecf20Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) { 4878c2ecf20Sopenharmony_ci *data += rx_queue->rx_packets; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci data++; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void ef4_ethtool_self_test(struct net_device *net_dev, 4958c2ecf20Sopenharmony_ci struct ethtool_test *test, u64 *data) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 4988c2ecf20Sopenharmony_ci struct ef4_self_tests *ef4_tests; 4998c2ecf20Sopenharmony_ci bool already_up; 5008c2ecf20Sopenharmony_ci int rc = -ENOMEM; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ef4_tests = kzalloc(sizeof(*ef4_tests), GFP_KERNEL); 5038c2ecf20Sopenharmony_ci if (!ef4_tests) 5048c2ecf20Sopenharmony_ci goto fail; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (efx->state != STATE_READY) { 5078c2ecf20Sopenharmony_ci rc = -EBUSY; 5088c2ecf20Sopenharmony_ci goto out; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "starting %sline testing\n", 5128c2ecf20Sopenharmony_ci (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* We need rx buffers and interrupts. */ 5158c2ecf20Sopenharmony_ci already_up = (efx->net_dev->flags & IFF_UP); 5168c2ecf20Sopenharmony_ci if (!already_up) { 5178c2ecf20Sopenharmony_ci rc = dev_open(efx->net_dev, NULL); 5188c2ecf20Sopenharmony_ci if (rc) { 5198c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 5208c2ecf20Sopenharmony_ci "failed opening device.\n"); 5218c2ecf20Sopenharmony_ci goto out; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci rc = ef4_selftest(efx, ef4_tests, test->flags); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (!already_up) 5288c2ecf20Sopenharmony_ci dev_close(efx->net_dev); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "%s %sline self-tests\n", 5318c2ecf20Sopenharmony_ci rc == 0 ? "passed" : "failed", 5328c2ecf20Sopenharmony_ci (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciout: 5358c2ecf20Sopenharmony_ci ef4_ethtool_fill_self_tests(efx, ef4_tests, NULL, data); 5368c2ecf20Sopenharmony_ci kfree(ef4_tests); 5378c2ecf20Sopenharmony_cifail: 5388c2ecf20Sopenharmony_ci if (rc) 5398c2ecf20Sopenharmony_ci test->flags |= ETH_TEST_FL_FAILED; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* Restart autonegotiation */ 5438c2ecf20Sopenharmony_cistatic int ef4_ethtool_nway_reset(struct net_device *net_dev) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return mdio45_nway_restart(&efx->mdio); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci/* 5518c2ecf20Sopenharmony_ci * Each channel has a single IRQ and moderation timer, started by any 5528c2ecf20Sopenharmony_ci * completion (or other event). Unless the module parameter 5538c2ecf20Sopenharmony_ci * separate_tx_channels is set, IRQs and moderation are therefore 5548c2ecf20Sopenharmony_ci * shared between RX and TX completions. In this case, when RX IRQ 5558c2ecf20Sopenharmony_ci * moderation is explicitly changed then TX IRQ moderation is 5568c2ecf20Sopenharmony_ci * automatically changed too, but otherwise we fail if the two values 5578c2ecf20Sopenharmony_ci * are requested to be different. 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * The hardware does not support a limit on the number of completions 5608c2ecf20Sopenharmony_ci * before an IRQ, so we do not use the max_frames fields. We should 5618c2ecf20Sopenharmony_ci * report and require that max_frames == (usecs != 0), but this would 5628c2ecf20Sopenharmony_ci * invalidate existing user documentation. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * The hardware does not have distinct settings for interrupt 5658c2ecf20Sopenharmony_ci * moderation while the previous IRQ is being handled, so we should 5668c2ecf20Sopenharmony_ci * not use the 'irq' fields. However, an earlier developer 5678c2ecf20Sopenharmony_ci * misunderstood the meaning of the 'irq' fields and the driver did 5688c2ecf20Sopenharmony_ci * not support the standard fields. To avoid invalidating existing 5698c2ecf20Sopenharmony_ci * user documentation, we report and accept changes through either the 5708c2ecf20Sopenharmony_ci * standard or 'irq' fields. If both are changed at the same time, we 5718c2ecf20Sopenharmony_ci * prefer the standard field. 5728c2ecf20Sopenharmony_ci * 5738c2ecf20Sopenharmony_ci * We implement adaptive IRQ moderation, but use a different algorithm 5748c2ecf20Sopenharmony_ci * from that assumed in the definition of struct ethtool_coalesce. 5758c2ecf20Sopenharmony_ci * Therefore we do not use any of the adaptive moderation parameters 5768c2ecf20Sopenharmony_ci * in it. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_coalesce(struct net_device *net_dev, 5808c2ecf20Sopenharmony_ci struct ethtool_coalesce *coalesce) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 5838c2ecf20Sopenharmony_ci unsigned int tx_usecs, rx_usecs; 5848c2ecf20Sopenharmony_ci bool rx_adaptive; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci ef4_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci coalesce->tx_coalesce_usecs = tx_usecs; 5898c2ecf20Sopenharmony_ci coalesce->tx_coalesce_usecs_irq = tx_usecs; 5908c2ecf20Sopenharmony_ci coalesce->rx_coalesce_usecs = rx_usecs; 5918c2ecf20Sopenharmony_ci coalesce->rx_coalesce_usecs_irq = rx_usecs; 5928c2ecf20Sopenharmony_ci coalesce->use_adaptive_rx_coalesce = rx_adaptive; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_coalesce(struct net_device *net_dev, 5988c2ecf20Sopenharmony_ci struct ethtool_coalesce *coalesce) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 6018c2ecf20Sopenharmony_ci struct ef4_channel *channel; 6028c2ecf20Sopenharmony_ci unsigned int tx_usecs, rx_usecs; 6038c2ecf20Sopenharmony_ci bool adaptive, rx_may_override_tx; 6048c2ecf20Sopenharmony_ci int rc; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci ef4_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (coalesce->rx_coalesce_usecs != rx_usecs) 6098c2ecf20Sopenharmony_ci rx_usecs = coalesce->rx_coalesce_usecs; 6108c2ecf20Sopenharmony_ci else 6118c2ecf20Sopenharmony_ci rx_usecs = coalesce->rx_coalesce_usecs_irq; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci adaptive = coalesce->use_adaptive_rx_coalesce; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* If channels are shared, TX IRQ moderation can be quietly 6168c2ecf20Sopenharmony_ci * overridden unless it is changed from its old value. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs && 6198c2ecf20Sopenharmony_ci coalesce->tx_coalesce_usecs_irq == tx_usecs); 6208c2ecf20Sopenharmony_ci if (coalesce->tx_coalesce_usecs != tx_usecs) 6218c2ecf20Sopenharmony_ci tx_usecs = coalesce->tx_coalesce_usecs; 6228c2ecf20Sopenharmony_ci else 6238c2ecf20Sopenharmony_ci tx_usecs = coalesce->tx_coalesce_usecs_irq; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci rc = ef4_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive, 6268c2ecf20Sopenharmony_ci rx_may_override_tx); 6278c2ecf20Sopenharmony_ci if (rc != 0) 6288c2ecf20Sopenharmony_ci return rc; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ef4_for_each_channel(channel, efx) 6318c2ecf20Sopenharmony_ci efx->type->push_irq_moderation(channel); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_ringparam(struct net_device *net_dev, 6378c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ring->rx_max_pending = EF4_MAX_DMAQ_SIZE; 6428c2ecf20Sopenharmony_ci ring->tx_max_pending = EF4_MAX_DMAQ_SIZE; 6438c2ecf20Sopenharmony_ci ring->rx_pending = efx->rxq_entries; 6448c2ecf20Sopenharmony_ci ring->tx_pending = efx->txq_entries; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_ringparam(struct net_device *net_dev, 6488c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 6518c2ecf20Sopenharmony_ci u32 txq_entries; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (ring->rx_mini_pending || ring->rx_jumbo_pending || 6548c2ecf20Sopenharmony_ci ring->rx_pending > EF4_MAX_DMAQ_SIZE || 6558c2ecf20Sopenharmony_ci ring->tx_pending > EF4_MAX_DMAQ_SIZE) 6568c2ecf20Sopenharmony_ci return -EINVAL; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (ring->rx_pending < EF4_RXQ_MIN_ENT) { 6598c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 6608c2ecf20Sopenharmony_ci "RX queues cannot be smaller than %u\n", 6618c2ecf20Sopenharmony_ci EF4_RXQ_MIN_ENT); 6628c2ecf20Sopenharmony_ci return -EINVAL; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci txq_entries = max(ring->tx_pending, EF4_TXQ_MIN_ENT(efx)); 6668c2ecf20Sopenharmony_ci if (txq_entries != ring->tx_pending) 6678c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 6688c2ecf20Sopenharmony_ci "increasing TX queue size to minimum of %u\n", 6698c2ecf20Sopenharmony_ci txq_entries); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return ef4_realloc_channels(efx, ring->rx_pending, txq_entries); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_pauseparam(struct net_device *net_dev, 6758c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 6788c2ecf20Sopenharmony_ci u8 wanted_fc, old_fc; 6798c2ecf20Sopenharmony_ci u32 old_adv; 6808c2ecf20Sopenharmony_ci int rc = 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci wanted_fc = ((pause->rx_pause ? EF4_FC_RX : 0) | 6858c2ecf20Sopenharmony_ci (pause->tx_pause ? EF4_FC_TX : 0) | 6868c2ecf20Sopenharmony_ci (pause->autoneg ? EF4_FC_AUTO : 0)); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if ((wanted_fc & EF4_FC_TX) && !(wanted_fc & EF4_FC_RX)) { 6898c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 6908c2ecf20Sopenharmony_ci "Flow control unsupported: tx ON rx OFF\n"); 6918c2ecf20Sopenharmony_ci rc = -EINVAL; 6928c2ecf20Sopenharmony_ci goto out; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if ((wanted_fc & EF4_FC_AUTO) && !efx->link_advertising) { 6968c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 6978c2ecf20Sopenharmony_ci "Autonegotiation is disabled\n"); 6988c2ecf20Sopenharmony_ci rc = -EINVAL; 6998c2ecf20Sopenharmony_ci goto out; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* Hook for Falcon bug 11482 workaround */ 7038c2ecf20Sopenharmony_ci if (efx->type->prepare_enable_fc_tx && 7048c2ecf20Sopenharmony_ci (wanted_fc & EF4_FC_TX) && !(efx->wanted_fc & EF4_FC_TX)) 7058c2ecf20Sopenharmony_ci efx->type->prepare_enable_fc_tx(efx); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci old_adv = efx->link_advertising; 7088c2ecf20Sopenharmony_ci old_fc = efx->wanted_fc; 7098c2ecf20Sopenharmony_ci ef4_link_set_wanted_fc(efx, wanted_fc); 7108c2ecf20Sopenharmony_ci if (efx->link_advertising != old_adv || 7118c2ecf20Sopenharmony_ci (efx->wanted_fc ^ old_fc) & EF4_FC_AUTO) { 7128c2ecf20Sopenharmony_ci rc = efx->phy_op->reconfigure(efx); 7138c2ecf20Sopenharmony_ci if (rc) { 7148c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 7158c2ecf20Sopenharmony_ci "Unable to advertise requested flow " 7168c2ecf20Sopenharmony_ci "control setting\n"); 7178c2ecf20Sopenharmony_ci goto out; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Reconfigure the MAC. The PHY *may* generate a link state change event 7228c2ecf20Sopenharmony_ci * if the user just changed the advertised capabilities, but there's no 7238c2ecf20Sopenharmony_ci * harm doing this twice */ 7248c2ecf20Sopenharmony_ci ef4_mac_reconfigure(efx); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ciout: 7278c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return rc; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_pauseparam(struct net_device *net_dev, 7338c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci pause->rx_pause = !!(efx->wanted_fc & EF4_FC_RX); 7388c2ecf20Sopenharmony_ci pause->tx_pause = !!(efx->wanted_fc & EF4_FC_TX); 7398c2ecf20Sopenharmony_ci pause->autoneg = !!(efx->wanted_fc & EF4_FC_AUTO); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic void ef4_ethtool_get_wol(struct net_device *net_dev, 7438c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 7468c2ecf20Sopenharmony_ci return efx->type->get_wol(efx, wol); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_wol(struct net_device *net_dev, 7518c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 7548c2ecf20Sopenharmony_ci return efx->type->set_wol(efx, wol->wolopts); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int ef4_ethtool_reset(struct net_device *net_dev, u32 *flags) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 7608c2ecf20Sopenharmony_ci int rc; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci rc = efx->type->map_reset_flags(flags); 7638c2ecf20Sopenharmony_ci if (rc < 0) 7648c2ecf20Sopenharmony_ci return rc; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return ef4_reset(efx, rc); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/* MAC address mask including only I/G bit */ 7708c2ecf20Sopenharmony_cistatic const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0}; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci#define IP4_ADDR_FULL_MASK ((__force __be32)~0) 7738c2ecf20Sopenharmony_ci#define IP_PROTO_FULL_MASK 0xFF 7748c2ecf20Sopenharmony_ci#define PORT_FULL_MASK ((__force __be16)~0) 7758c2ecf20Sopenharmony_ci#define ETHER_TYPE_FULL_MASK ((__force __be16)~0) 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic inline void ip6_fill_mask(__be32 *mask) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci mask[0] = mask[1] = mask[2] = mask[3] = ~(__be32)0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_class_rule(struct ef4_nic *efx, 7838c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *rule) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 7868c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; 7878c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; 7888c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; 7898c2ecf20Sopenharmony_ci struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; 7908c2ecf20Sopenharmony_ci struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; 7918c2ecf20Sopenharmony_ci struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; 7928c2ecf20Sopenharmony_ci struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec; 7938c2ecf20Sopenharmony_ci struct ethhdr *mac_entry = &rule->h_u.ether_spec; 7948c2ecf20Sopenharmony_ci struct ethhdr *mac_mask = &rule->m_u.ether_spec; 7958c2ecf20Sopenharmony_ci struct ef4_filter_spec spec; 7968c2ecf20Sopenharmony_ci int rc; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci rc = ef4_filter_get_filter_safe(efx, EF4_FILTER_PRI_MANUAL, 7998c2ecf20Sopenharmony_ci rule->location, &spec); 8008c2ecf20Sopenharmony_ci if (rc) 8018c2ecf20Sopenharmony_ci return rc; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (spec.dmaq_id == EF4_FILTER_RX_DMAQ_ID_DROP) 8048c2ecf20Sopenharmony_ci rule->ring_cookie = RX_CLS_FLOW_DISC; 8058c2ecf20Sopenharmony_ci else 8068c2ecf20Sopenharmony_ci rule->ring_cookie = spec.dmaq_id; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if ((spec.match_flags & EF4_FILTER_MATCH_ETHER_TYPE) && 8098c2ecf20Sopenharmony_ci spec.ether_type == htons(ETH_P_IP) && 8108c2ecf20Sopenharmony_ci (spec.match_flags & EF4_FILTER_MATCH_IP_PROTO) && 8118c2ecf20Sopenharmony_ci (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && 8128c2ecf20Sopenharmony_ci !(spec.match_flags & 8138c2ecf20Sopenharmony_ci ~(EF4_FILTER_MATCH_ETHER_TYPE | EF4_FILTER_MATCH_OUTER_VID | 8148c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_REM_HOST | 8158c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO | 8168c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_PORT | EF4_FILTER_MATCH_REM_PORT))) { 8178c2ecf20Sopenharmony_ci rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? 8188c2ecf20Sopenharmony_ci TCP_V4_FLOW : UDP_V4_FLOW); 8198c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_HOST) { 8208c2ecf20Sopenharmony_ci ip_entry->ip4dst = spec.loc_host[0]; 8218c2ecf20Sopenharmony_ci ip_mask->ip4dst = IP4_ADDR_FULL_MASK; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_HOST) { 8248c2ecf20Sopenharmony_ci ip_entry->ip4src = spec.rem_host[0]; 8258c2ecf20Sopenharmony_ci ip_mask->ip4src = IP4_ADDR_FULL_MASK; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_PORT) { 8288c2ecf20Sopenharmony_ci ip_entry->pdst = spec.loc_port; 8298c2ecf20Sopenharmony_ci ip_mask->pdst = PORT_FULL_MASK; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_PORT) { 8328c2ecf20Sopenharmony_ci ip_entry->psrc = spec.rem_port; 8338c2ecf20Sopenharmony_ci ip_mask->psrc = PORT_FULL_MASK; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci } else if ((spec.match_flags & EF4_FILTER_MATCH_ETHER_TYPE) && 8368c2ecf20Sopenharmony_ci spec.ether_type == htons(ETH_P_IPV6) && 8378c2ecf20Sopenharmony_ci (spec.match_flags & EF4_FILTER_MATCH_IP_PROTO) && 8388c2ecf20Sopenharmony_ci (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && 8398c2ecf20Sopenharmony_ci !(spec.match_flags & 8408c2ecf20Sopenharmony_ci ~(EF4_FILTER_MATCH_ETHER_TYPE | EF4_FILTER_MATCH_OUTER_VID | 8418c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_REM_HOST | 8428c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO | 8438c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_PORT | EF4_FILTER_MATCH_REM_PORT))) { 8448c2ecf20Sopenharmony_ci rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? 8458c2ecf20Sopenharmony_ci TCP_V6_FLOW : UDP_V6_FLOW); 8468c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_HOST) { 8478c2ecf20Sopenharmony_ci memcpy(ip6_entry->ip6dst, spec.loc_host, 8488c2ecf20Sopenharmony_ci sizeof(ip6_entry->ip6dst)); 8498c2ecf20Sopenharmony_ci ip6_fill_mask(ip6_mask->ip6dst); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_HOST) { 8528c2ecf20Sopenharmony_ci memcpy(ip6_entry->ip6src, spec.rem_host, 8538c2ecf20Sopenharmony_ci sizeof(ip6_entry->ip6src)); 8548c2ecf20Sopenharmony_ci ip6_fill_mask(ip6_mask->ip6src); 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_PORT) { 8578c2ecf20Sopenharmony_ci ip6_entry->pdst = spec.loc_port; 8588c2ecf20Sopenharmony_ci ip6_mask->pdst = PORT_FULL_MASK; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_PORT) { 8618c2ecf20Sopenharmony_ci ip6_entry->psrc = spec.rem_port; 8628c2ecf20Sopenharmony_ci ip6_mask->psrc = PORT_FULL_MASK; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci } else if (!(spec.match_flags & 8658c2ecf20Sopenharmony_ci ~(EF4_FILTER_MATCH_LOC_MAC | EF4_FILTER_MATCH_LOC_MAC_IG | 8668c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_REM_MAC | EF4_FILTER_MATCH_ETHER_TYPE | 8678c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_OUTER_VID))) { 8688c2ecf20Sopenharmony_ci rule->flow_type = ETHER_FLOW; 8698c2ecf20Sopenharmony_ci if (spec.match_flags & 8708c2ecf20Sopenharmony_ci (EF4_FILTER_MATCH_LOC_MAC | EF4_FILTER_MATCH_LOC_MAC_IG)) { 8718c2ecf20Sopenharmony_ci ether_addr_copy(mac_entry->h_dest, spec.loc_mac); 8728c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_MAC) 8738c2ecf20Sopenharmony_ci eth_broadcast_addr(mac_mask->h_dest); 8748c2ecf20Sopenharmony_ci else 8758c2ecf20Sopenharmony_ci ether_addr_copy(mac_mask->h_dest, 8768c2ecf20Sopenharmony_ci mac_addr_ig_mask); 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_MAC) { 8798c2ecf20Sopenharmony_ci ether_addr_copy(mac_entry->h_source, spec.rem_mac); 8808c2ecf20Sopenharmony_ci eth_broadcast_addr(mac_mask->h_source); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_ETHER_TYPE) { 8838c2ecf20Sopenharmony_ci mac_entry->h_proto = spec.ether_type; 8848c2ecf20Sopenharmony_ci mac_mask->h_proto = ETHER_TYPE_FULL_MASK; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } else if (spec.match_flags & EF4_FILTER_MATCH_ETHER_TYPE && 8878c2ecf20Sopenharmony_ci spec.ether_type == htons(ETH_P_IP) && 8888c2ecf20Sopenharmony_ci !(spec.match_flags & 8898c2ecf20Sopenharmony_ci ~(EF4_FILTER_MATCH_ETHER_TYPE | EF4_FILTER_MATCH_OUTER_VID | 8908c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_REM_HOST | 8918c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO))) { 8928c2ecf20Sopenharmony_ci rule->flow_type = IPV4_USER_FLOW; 8938c2ecf20Sopenharmony_ci uip_entry->ip_ver = ETH_RX_NFC_IP4; 8948c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_IP_PROTO) { 8958c2ecf20Sopenharmony_ci uip_mask->proto = IP_PROTO_FULL_MASK; 8968c2ecf20Sopenharmony_ci uip_entry->proto = spec.ip_proto; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_HOST) { 8998c2ecf20Sopenharmony_ci uip_entry->ip4dst = spec.loc_host[0]; 9008c2ecf20Sopenharmony_ci uip_mask->ip4dst = IP4_ADDR_FULL_MASK; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_HOST) { 9038c2ecf20Sopenharmony_ci uip_entry->ip4src = spec.rem_host[0]; 9048c2ecf20Sopenharmony_ci uip_mask->ip4src = IP4_ADDR_FULL_MASK; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci } else if (spec.match_flags & EF4_FILTER_MATCH_ETHER_TYPE && 9078c2ecf20Sopenharmony_ci spec.ether_type == htons(ETH_P_IPV6) && 9088c2ecf20Sopenharmony_ci !(spec.match_flags & 9098c2ecf20Sopenharmony_ci ~(EF4_FILTER_MATCH_ETHER_TYPE | EF4_FILTER_MATCH_OUTER_VID | 9108c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_REM_HOST | 9118c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO))) { 9128c2ecf20Sopenharmony_ci rule->flow_type = IPV6_USER_FLOW; 9138c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_IP_PROTO) { 9148c2ecf20Sopenharmony_ci uip6_mask->l4_proto = IP_PROTO_FULL_MASK; 9158c2ecf20Sopenharmony_ci uip6_entry->l4_proto = spec.ip_proto; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_LOC_HOST) { 9188c2ecf20Sopenharmony_ci memcpy(uip6_entry->ip6dst, spec.loc_host, 9198c2ecf20Sopenharmony_ci sizeof(uip6_entry->ip6dst)); 9208c2ecf20Sopenharmony_ci ip6_fill_mask(uip6_mask->ip6dst); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_REM_HOST) { 9238c2ecf20Sopenharmony_ci memcpy(uip6_entry->ip6src, spec.rem_host, 9248c2ecf20Sopenharmony_ci sizeof(uip6_entry->ip6src)); 9258c2ecf20Sopenharmony_ci ip6_fill_mask(uip6_mask->ip6src); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci } else { 9288c2ecf20Sopenharmony_ci /* The above should handle all filters that we insert */ 9298c2ecf20Sopenharmony_ci WARN_ON(1); 9308c2ecf20Sopenharmony_ci return -EINVAL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (spec.match_flags & EF4_FILTER_MATCH_OUTER_VID) { 9348c2ecf20Sopenharmony_ci rule->flow_type |= FLOW_EXT; 9358c2ecf20Sopenharmony_ci rule->h_ext.vlan_tci = spec.outer_vid; 9368c2ecf20Sopenharmony_ci rule->m_ext.vlan_tci = htons(0xfff); 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return rc; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic int 9438c2ecf20Sopenharmony_cief4_ethtool_get_rxnfc(struct net_device *net_dev, 9448c2ecf20Sopenharmony_ci struct ethtool_rxnfc *info, u32 *rule_locs) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci switch (info->cmd) { 9498c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 9508c2ecf20Sopenharmony_ci info->data = efx->n_rx_channels; 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: { 9548c2ecf20Sopenharmony_ci unsigned min_revision = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci info->data = 0; 9578c2ecf20Sopenharmony_ci switch (info->flow_type) { 9588c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 9598c2ecf20Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 9608c2ecf20Sopenharmony_ci fallthrough; 9618c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 9628c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 9638c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 9648c2ecf20Sopenharmony_ci case IPV4_FLOW: 9658c2ecf20Sopenharmony_ci info->data |= RXH_IP_SRC | RXH_IP_DST; 9668c2ecf20Sopenharmony_ci min_revision = EF4_REV_FALCON_B0; 9678c2ecf20Sopenharmony_ci break; 9688c2ecf20Sopenharmony_ci default: 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci if (ef4_nic_rev(efx) < min_revision) 9728c2ecf20Sopenharmony_ci info->data = 0; 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 9778c2ecf20Sopenharmony_ci info->data = ef4_filter_get_rx_id_limit(efx); 9788c2ecf20Sopenharmony_ci if (info->data == 0) 9798c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9808c2ecf20Sopenharmony_ci info->data |= RX_CLS_LOC_SPECIAL; 9818c2ecf20Sopenharmony_ci info->rule_cnt = 9828c2ecf20Sopenharmony_ci ef4_filter_count_rx_used(efx, EF4_FILTER_PRI_MANUAL); 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 9868c2ecf20Sopenharmony_ci if (ef4_filter_get_rx_id_limit(efx) == 0) 9878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9888c2ecf20Sopenharmony_ci return ef4_ethtool_get_class_rule(efx, &info->fs); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: { 9918c2ecf20Sopenharmony_ci s32 rc; 9928c2ecf20Sopenharmony_ci info->data = ef4_filter_get_rx_id_limit(efx); 9938c2ecf20Sopenharmony_ci if (info->data == 0) 9948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9958c2ecf20Sopenharmony_ci rc = ef4_filter_get_rx_ids(efx, EF4_FILTER_PRI_MANUAL, 9968c2ecf20Sopenharmony_ci rule_locs, info->rule_cnt); 9978c2ecf20Sopenharmony_ci if (rc < 0) 9988c2ecf20Sopenharmony_ci return rc; 9998c2ecf20Sopenharmony_ci info->rule_cnt = rc; 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci default: 10048c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic inline bool ip6_mask_is_full(__be32 mask[4]) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci return !~(mask[0] & mask[1] & mask[2] & mask[3]); 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic inline bool ip6_mask_is_empty(__be32 mask[4]) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci return !(mask[0] | mask[1] | mask[2] | mask[3]); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_class_rule(struct ef4_nic *efx, 10198c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *rule) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 10228c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; 10238c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; 10248c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; 10258c2ecf20Sopenharmony_ci struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; 10268c2ecf20Sopenharmony_ci struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; 10278c2ecf20Sopenharmony_ci struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; 10288c2ecf20Sopenharmony_ci struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec; 10298c2ecf20Sopenharmony_ci struct ethhdr *mac_entry = &rule->h_u.ether_spec; 10308c2ecf20Sopenharmony_ci struct ethhdr *mac_mask = &rule->m_u.ether_spec; 10318c2ecf20Sopenharmony_ci struct ef4_filter_spec spec; 10328c2ecf20Sopenharmony_ci int rc; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Check that user wants us to choose the location */ 10358c2ecf20Sopenharmony_ci if (rule->location != RX_CLS_LOC_ANY) 10368c2ecf20Sopenharmony_ci return -EINVAL; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Range-check ring_cookie */ 10398c2ecf20Sopenharmony_ci if (rule->ring_cookie >= efx->n_rx_channels && 10408c2ecf20Sopenharmony_ci rule->ring_cookie != RX_CLS_FLOW_DISC) 10418c2ecf20Sopenharmony_ci return -EINVAL; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Check for unsupported extensions */ 10448c2ecf20Sopenharmony_ci if ((rule->flow_type & FLOW_EXT) && 10458c2ecf20Sopenharmony_ci (rule->m_ext.vlan_etype || rule->m_ext.data[0] || 10468c2ecf20Sopenharmony_ci rule->m_ext.data[1])) 10478c2ecf20Sopenharmony_ci return -EINVAL; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci ef4_filter_init_rx(&spec, EF4_FILTER_PRI_MANUAL, 10508c2ecf20Sopenharmony_ci efx->rx_scatter ? EF4_FILTER_FLAG_RX_SCATTER : 0, 10518c2ecf20Sopenharmony_ci (rule->ring_cookie == RX_CLS_FLOW_DISC) ? 10528c2ecf20Sopenharmony_ci EF4_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci switch (rule->flow_type & ~FLOW_EXT) { 10558c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 10568c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 10578c2ecf20Sopenharmony_ci spec.match_flags = (EF4_FILTER_MATCH_ETHER_TYPE | 10588c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO); 10598c2ecf20Sopenharmony_ci spec.ether_type = htons(ETH_P_IP); 10608c2ecf20Sopenharmony_ci spec.ip_proto = ((rule->flow_type & ~FLOW_EXT) == TCP_V4_FLOW ? 10618c2ecf20Sopenharmony_ci IPPROTO_TCP : IPPROTO_UDP); 10628c2ecf20Sopenharmony_ci if (ip_mask->ip4dst) { 10638c2ecf20Sopenharmony_ci if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK) 10648c2ecf20Sopenharmony_ci return -EINVAL; 10658c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_HOST; 10668c2ecf20Sopenharmony_ci spec.loc_host[0] = ip_entry->ip4dst; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci if (ip_mask->ip4src) { 10698c2ecf20Sopenharmony_ci if (ip_mask->ip4src != IP4_ADDR_FULL_MASK) 10708c2ecf20Sopenharmony_ci return -EINVAL; 10718c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_HOST; 10728c2ecf20Sopenharmony_ci spec.rem_host[0] = ip_entry->ip4src; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci if (ip_mask->pdst) { 10758c2ecf20Sopenharmony_ci if (ip_mask->pdst != PORT_FULL_MASK) 10768c2ecf20Sopenharmony_ci return -EINVAL; 10778c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_PORT; 10788c2ecf20Sopenharmony_ci spec.loc_port = ip_entry->pdst; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci if (ip_mask->psrc) { 10818c2ecf20Sopenharmony_ci if (ip_mask->psrc != PORT_FULL_MASK) 10828c2ecf20Sopenharmony_ci return -EINVAL; 10838c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_PORT; 10848c2ecf20Sopenharmony_ci spec.rem_port = ip_entry->psrc; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci if (ip_mask->tos) 10878c2ecf20Sopenharmony_ci return -EINVAL; 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 10918c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 10928c2ecf20Sopenharmony_ci spec.match_flags = (EF4_FILTER_MATCH_ETHER_TYPE | 10938c2ecf20Sopenharmony_ci EF4_FILTER_MATCH_IP_PROTO); 10948c2ecf20Sopenharmony_ci spec.ether_type = htons(ETH_P_IPV6); 10958c2ecf20Sopenharmony_ci spec.ip_proto = ((rule->flow_type & ~FLOW_EXT) == TCP_V6_FLOW ? 10968c2ecf20Sopenharmony_ci IPPROTO_TCP : IPPROTO_UDP); 10978c2ecf20Sopenharmony_ci if (!ip6_mask_is_empty(ip6_mask->ip6dst)) { 10988c2ecf20Sopenharmony_ci if (!ip6_mask_is_full(ip6_mask->ip6dst)) 10998c2ecf20Sopenharmony_ci return -EINVAL; 11008c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_HOST; 11018c2ecf20Sopenharmony_ci memcpy(spec.loc_host, ip6_entry->ip6dst, sizeof(spec.loc_host)); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci if (!ip6_mask_is_empty(ip6_mask->ip6src)) { 11048c2ecf20Sopenharmony_ci if (!ip6_mask_is_full(ip6_mask->ip6src)) 11058c2ecf20Sopenharmony_ci return -EINVAL; 11068c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_HOST; 11078c2ecf20Sopenharmony_ci memcpy(spec.rem_host, ip6_entry->ip6src, sizeof(spec.rem_host)); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci if (ip6_mask->pdst) { 11108c2ecf20Sopenharmony_ci if (ip6_mask->pdst != PORT_FULL_MASK) 11118c2ecf20Sopenharmony_ci return -EINVAL; 11128c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_PORT; 11138c2ecf20Sopenharmony_ci spec.loc_port = ip6_entry->pdst; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci if (ip6_mask->psrc) { 11168c2ecf20Sopenharmony_ci if (ip6_mask->psrc != PORT_FULL_MASK) 11178c2ecf20Sopenharmony_ci return -EINVAL; 11188c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_PORT; 11198c2ecf20Sopenharmony_ci spec.rem_port = ip6_entry->psrc; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci if (ip6_mask->tclass) 11228c2ecf20Sopenharmony_ci return -EINVAL; 11238c2ecf20Sopenharmony_ci break; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci case IPV4_USER_FLOW: 11268c2ecf20Sopenharmony_ci if (uip_mask->l4_4_bytes || uip_mask->tos || uip_mask->ip_ver || 11278c2ecf20Sopenharmony_ci uip_entry->ip_ver != ETH_RX_NFC_IP4) 11288c2ecf20Sopenharmony_ci return -EINVAL; 11298c2ecf20Sopenharmony_ci spec.match_flags = EF4_FILTER_MATCH_ETHER_TYPE; 11308c2ecf20Sopenharmony_ci spec.ether_type = htons(ETH_P_IP); 11318c2ecf20Sopenharmony_ci if (uip_mask->ip4dst) { 11328c2ecf20Sopenharmony_ci if (uip_mask->ip4dst != IP4_ADDR_FULL_MASK) 11338c2ecf20Sopenharmony_ci return -EINVAL; 11348c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_HOST; 11358c2ecf20Sopenharmony_ci spec.loc_host[0] = uip_entry->ip4dst; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci if (uip_mask->ip4src) { 11388c2ecf20Sopenharmony_ci if (uip_mask->ip4src != IP4_ADDR_FULL_MASK) 11398c2ecf20Sopenharmony_ci return -EINVAL; 11408c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_HOST; 11418c2ecf20Sopenharmony_ci spec.rem_host[0] = uip_entry->ip4src; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci if (uip_mask->proto) { 11448c2ecf20Sopenharmony_ci if (uip_mask->proto != IP_PROTO_FULL_MASK) 11458c2ecf20Sopenharmony_ci return -EINVAL; 11468c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_IP_PROTO; 11478c2ecf20Sopenharmony_ci spec.ip_proto = uip_entry->proto; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci break; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci case IPV6_USER_FLOW: 11528c2ecf20Sopenharmony_ci if (uip6_mask->l4_4_bytes || uip6_mask->tclass) 11538c2ecf20Sopenharmony_ci return -EINVAL; 11548c2ecf20Sopenharmony_ci spec.match_flags = EF4_FILTER_MATCH_ETHER_TYPE; 11558c2ecf20Sopenharmony_ci spec.ether_type = htons(ETH_P_IPV6); 11568c2ecf20Sopenharmony_ci if (!ip6_mask_is_empty(uip6_mask->ip6dst)) { 11578c2ecf20Sopenharmony_ci if (!ip6_mask_is_full(uip6_mask->ip6dst)) 11588c2ecf20Sopenharmony_ci return -EINVAL; 11598c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_HOST; 11608c2ecf20Sopenharmony_ci memcpy(spec.loc_host, uip6_entry->ip6dst, sizeof(spec.loc_host)); 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci if (!ip6_mask_is_empty(uip6_mask->ip6src)) { 11638c2ecf20Sopenharmony_ci if (!ip6_mask_is_full(uip6_mask->ip6src)) 11648c2ecf20Sopenharmony_ci return -EINVAL; 11658c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_HOST; 11668c2ecf20Sopenharmony_ci memcpy(spec.rem_host, uip6_entry->ip6src, sizeof(spec.rem_host)); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci if (uip6_mask->l4_proto) { 11698c2ecf20Sopenharmony_ci if (uip6_mask->l4_proto != IP_PROTO_FULL_MASK) 11708c2ecf20Sopenharmony_ci return -EINVAL; 11718c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_IP_PROTO; 11728c2ecf20Sopenharmony_ci spec.ip_proto = uip6_entry->l4_proto; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci case ETHER_FLOW: 11778c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(mac_mask->h_dest)) { 11788c2ecf20Sopenharmony_ci if (ether_addr_equal(mac_mask->h_dest, 11798c2ecf20Sopenharmony_ci mac_addr_ig_mask)) 11808c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_MAC_IG; 11818c2ecf20Sopenharmony_ci else if (is_broadcast_ether_addr(mac_mask->h_dest)) 11828c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_LOC_MAC; 11838c2ecf20Sopenharmony_ci else 11848c2ecf20Sopenharmony_ci return -EINVAL; 11858c2ecf20Sopenharmony_ci ether_addr_copy(spec.loc_mac, mac_entry->h_dest); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(mac_mask->h_source)) { 11888c2ecf20Sopenharmony_ci if (!is_broadcast_ether_addr(mac_mask->h_source)) 11898c2ecf20Sopenharmony_ci return -EINVAL; 11908c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_REM_MAC; 11918c2ecf20Sopenharmony_ci ether_addr_copy(spec.rem_mac, mac_entry->h_source); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci if (mac_mask->h_proto) { 11948c2ecf20Sopenharmony_ci if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK) 11958c2ecf20Sopenharmony_ci return -EINVAL; 11968c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_ETHER_TYPE; 11978c2ecf20Sopenharmony_ci spec.ether_type = mac_entry->h_proto; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci break; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci default: 12028c2ecf20Sopenharmony_ci return -EINVAL; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) { 12068c2ecf20Sopenharmony_ci if (rule->m_ext.vlan_tci != htons(0xfff)) 12078c2ecf20Sopenharmony_ci return -EINVAL; 12088c2ecf20Sopenharmony_ci spec.match_flags |= EF4_FILTER_MATCH_OUTER_VID; 12098c2ecf20Sopenharmony_ci spec.outer_vid = rule->h_ext.vlan_tci; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci rc = ef4_filter_insert_filter(efx, &spec, true); 12138c2ecf20Sopenharmony_ci if (rc < 0) 12148c2ecf20Sopenharmony_ci return rc; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci rule->location = rc; 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_rxnfc(struct net_device *net_dev, 12218c2ecf20Sopenharmony_ci struct ethtool_rxnfc *info) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (ef4_filter_get_rx_id_limit(efx) == 0) 12268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci switch (info->cmd) { 12298c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 12308c2ecf20Sopenharmony_ci return ef4_ethtool_set_class_rule(efx, &info->fs); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 12338c2ecf20Sopenharmony_ci return ef4_filter_remove_id_safe(efx, EF4_FILTER_PRI_MANUAL, 12348c2ecf20Sopenharmony_ci info->fs.location); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci default: 12378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic u32 ef4_ethtool_get_rxfh_indir_size(struct net_device *net_dev) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return ((ef4_nic_rev(efx) < EF4_REV_FALCON_B0 || 12468c2ecf20Sopenharmony_ci efx->n_rx_channels == 1) ? 12478c2ecf20Sopenharmony_ci 0 : ARRAY_SIZE(efx->rx_indir_table)); 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key, 12518c2ecf20Sopenharmony_ci u8 *hfunc) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (hfunc) 12568c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 12578c2ecf20Sopenharmony_ci if (indir) 12588c2ecf20Sopenharmony_ci memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic int ef4_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir, 12638c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* We do not allow change in unsupported parameters */ 12688c2ecf20Sopenharmony_ci if (key || 12698c2ecf20Sopenharmony_ci (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) 12708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12718c2ecf20Sopenharmony_ci if (!indir) 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci return efx->type->rx_push_rss_config(efx, true, indir); 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_module_eeprom(struct net_device *net_dev, 12788c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, 12798c2ecf20Sopenharmony_ci u8 *data) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12828c2ecf20Sopenharmony_ci int ret; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (!efx->phy_op || !efx->phy_op->get_module_eeprom) 12858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 12888c2ecf20Sopenharmony_ci ret = efx->phy_op->get_module_eeprom(efx, ee, data); 12898c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return ret; 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic int ef4_ethtool_get_module_info(struct net_device *net_dev, 12958c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 12988c2ecf20Sopenharmony_ci int ret; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (!efx->phy_op || !efx->phy_op->get_module_info) 13018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 13048c2ecf20Sopenharmony_ci ret = efx->phy_op->get_module_info(efx, modinfo); 13058c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci return ret; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ciconst struct ethtool_ops ef4_ethtool_ops = { 13118c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 13128c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USECS_IRQ | 13138c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 13148c2ecf20Sopenharmony_ci .get_drvinfo = ef4_ethtool_get_drvinfo, 13158c2ecf20Sopenharmony_ci .get_regs_len = ef4_ethtool_get_regs_len, 13168c2ecf20Sopenharmony_ci .get_regs = ef4_ethtool_get_regs, 13178c2ecf20Sopenharmony_ci .get_msglevel = ef4_ethtool_get_msglevel, 13188c2ecf20Sopenharmony_ci .set_msglevel = ef4_ethtool_set_msglevel, 13198c2ecf20Sopenharmony_ci .nway_reset = ef4_ethtool_nway_reset, 13208c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 13218c2ecf20Sopenharmony_ci .get_coalesce = ef4_ethtool_get_coalesce, 13228c2ecf20Sopenharmony_ci .set_coalesce = ef4_ethtool_set_coalesce, 13238c2ecf20Sopenharmony_ci .get_ringparam = ef4_ethtool_get_ringparam, 13248c2ecf20Sopenharmony_ci .set_ringparam = ef4_ethtool_set_ringparam, 13258c2ecf20Sopenharmony_ci .get_pauseparam = ef4_ethtool_get_pauseparam, 13268c2ecf20Sopenharmony_ci .set_pauseparam = ef4_ethtool_set_pauseparam, 13278c2ecf20Sopenharmony_ci .get_sset_count = ef4_ethtool_get_sset_count, 13288c2ecf20Sopenharmony_ci .self_test = ef4_ethtool_self_test, 13298c2ecf20Sopenharmony_ci .get_strings = ef4_ethtool_get_strings, 13308c2ecf20Sopenharmony_ci .set_phys_id = ef4_ethtool_phys_id, 13318c2ecf20Sopenharmony_ci .get_ethtool_stats = ef4_ethtool_get_stats, 13328c2ecf20Sopenharmony_ci .get_wol = ef4_ethtool_get_wol, 13338c2ecf20Sopenharmony_ci .set_wol = ef4_ethtool_set_wol, 13348c2ecf20Sopenharmony_ci .reset = ef4_ethtool_reset, 13358c2ecf20Sopenharmony_ci .get_rxnfc = ef4_ethtool_get_rxnfc, 13368c2ecf20Sopenharmony_ci .set_rxnfc = ef4_ethtool_set_rxnfc, 13378c2ecf20Sopenharmony_ci .get_rxfh_indir_size = ef4_ethtool_get_rxfh_indir_size, 13388c2ecf20Sopenharmony_ci .get_rxfh = ef4_ethtool_get_rxfh, 13398c2ecf20Sopenharmony_ci .set_rxfh = ef4_ethtool_set_rxfh, 13408c2ecf20Sopenharmony_ci .get_module_info = ef4_ethtool_get_module_info, 13418c2ecf20Sopenharmony_ci .get_module_eeprom = ef4_ethtool_get_module_eeprom, 13428c2ecf20Sopenharmony_ci .get_link_ksettings = ef4_ethtool_get_link_ksettings, 13438c2ecf20Sopenharmony_ci .set_link_ksettings = ef4_ethtool_set_link_ksettings, 13448c2ecf20Sopenharmony_ci}; 1345