18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2018 Solarflare Communications Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2 as published 88c2ecf20Sopenharmony_ci * by the Free Software Foundation, incorporated herein by reference. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "net_driver.h" 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 148c2ecf20Sopenharmony_ci#include <net/gre.h> 158c2ecf20Sopenharmony_ci#include "efx_common.h" 168c2ecf20Sopenharmony_ci#include "efx_channels.h" 178c2ecf20Sopenharmony_ci#include "efx.h" 188c2ecf20Sopenharmony_ci#include "mcdi.h" 198c2ecf20Sopenharmony_ci#include "selftest.h" 208c2ecf20Sopenharmony_ci#include "rx_common.h" 218c2ecf20Sopenharmony_ci#include "tx_common.h" 228c2ecf20Sopenharmony_ci#include "nic.h" 238c2ecf20Sopenharmony_ci#include "mcdi_port_common.h" 248c2ecf20Sopenharmony_ci#include "io.h" 258c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic unsigned int debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 288c2ecf20Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFDOWN | 298c2ecf20Sopenharmony_ci NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | 308c2ecf20Sopenharmony_ci NETIF_MSG_TX_ERR | NETIF_MSG_HW); 318c2ecf20Sopenharmony_cimodule_param(debug, uint, 0); 328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* This is the time (in jiffies) between invocations of the hardware 358c2ecf20Sopenharmony_ci * monitor. 368c2ecf20Sopenharmony_ci * On Falcon-based NICs, this will: 378c2ecf20Sopenharmony_ci * - Check the on-board hardware monitor; 388c2ecf20Sopenharmony_ci * - Poll the link state and reconfigure the hardware as necessary. 398c2ecf20Sopenharmony_ci * On Siena-based NICs for power systems with EEH support, this will give EEH a 408c2ecf20Sopenharmony_ci * chance to start. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic unsigned int efx_monitor_interval = 1 * HZ; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* How often and how many times to poll for a reset while waiting for a 458c2ecf20Sopenharmony_ci * BIST that another function started to complete. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define BIST_WAIT_DELAY_MS 100 488c2ecf20Sopenharmony_ci#define BIST_WAIT_DELAY_COUNT 100 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Default stats update time */ 518c2ecf20Sopenharmony_ci#define STATS_PERIOD_MS_DEFAULT 1000 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciconst unsigned int efx_reset_type_max = RESET_TYPE_MAX; 548c2ecf20Sopenharmony_ciconst char *const efx_reset_type_names[] = { 558c2ecf20Sopenharmony_ci [RESET_TYPE_INVISIBLE] = "INVISIBLE", 568c2ecf20Sopenharmony_ci [RESET_TYPE_ALL] = "ALL", 578c2ecf20Sopenharmony_ci [RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL", 588c2ecf20Sopenharmony_ci [RESET_TYPE_WORLD] = "WORLD", 598c2ecf20Sopenharmony_ci [RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE", 608c2ecf20Sopenharmony_ci [RESET_TYPE_DATAPATH] = "DATAPATH", 618c2ecf20Sopenharmony_ci [RESET_TYPE_MC_BIST] = "MC_BIST", 628c2ecf20Sopenharmony_ci [RESET_TYPE_DISABLE] = "DISABLE", 638c2ecf20Sopenharmony_ci [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", 648c2ecf20Sopenharmony_ci [RESET_TYPE_INT_ERROR] = "INT_ERROR", 658c2ecf20Sopenharmony_ci [RESET_TYPE_DMA_ERROR] = "DMA_ERROR", 668c2ecf20Sopenharmony_ci [RESET_TYPE_TX_SKIP] = "TX_SKIP", 678c2ecf20Sopenharmony_ci [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", 688c2ecf20Sopenharmony_ci [RESET_TYPE_MCDI_TIMEOUT] = "MCDI_TIMEOUT (FLR)", 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define RESET_TYPE(type) \ 728c2ecf20Sopenharmony_ci STRING_TABLE_LOOKUP(type, efx_reset_type) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Loopback mode names (see LOOPBACK_MODE()) */ 758c2ecf20Sopenharmony_ciconst unsigned int efx_loopback_mode_max = LOOPBACK_MAX; 768c2ecf20Sopenharmony_ciconst char *const efx_loopback_mode_names[] = { 778c2ecf20Sopenharmony_ci [LOOPBACK_NONE] = "NONE", 788c2ecf20Sopenharmony_ci [LOOPBACK_DATA] = "DATAPATH", 798c2ecf20Sopenharmony_ci [LOOPBACK_GMAC] = "GMAC", 808c2ecf20Sopenharmony_ci [LOOPBACK_XGMII] = "XGMII", 818c2ecf20Sopenharmony_ci [LOOPBACK_XGXS] = "XGXS", 828c2ecf20Sopenharmony_ci [LOOPBACK_XAUI] = "XAUI", 838c2ecf20Sopenharmony_ci [LOOPBACK_GMII] = "GMII", 848c2ecf20Sopenharmony_ci [LOOPBACK_SGMII] = "SGMII", 858c2ecf20Sopenharmony_ci [LOOPBACK_XGBR] = "XGBR", 868c2ecf20Sopenharmony_ci [LOOPBACK_XFI] = "XFI", 878c2ecf20Sopenharmony_ci [LOOPBACK_XAUI_FAR] = "XAUI_FAR", 888c2ecf20Sopenharmony_ci [LOOPBACK_GMII_FAR] = "GMII_FAR", 898c2ecf20Sopenharmony_ci [LOOPBACK_SGMII_FAR] = "SGMII_FAR", 908c2ecf20Sopenharmony_ci [LOOPBACK_XFI_FAR] = "XFI_FAR", 918c2ecf20Sopenharmony_ci [LOOPBACK_GPHY] = "GPHY", 928c2ecf20Sopenharmony_ci [LOOPBACK_PHYXS] = "PHYXS", 938c2ecf20Sopenharmony_ci [LOOPBACK_PCS] = "PCS", 948c2ecf20Sopenharmony_ci [LOOPBACK_PMAPMD] = "PMA/PMD", 958c2ecf20Sopenharmony_ci [LOOPBACK_XPORT] = "XPORT", 968c2ecf20Sopenharmony_ci [LOOPBACK_XGMII_WS] = "XGMII_WS", 978c2ecf20Sopenharmony_ci [LOOPBACK_XAUI_WS] = "XAUI_WS", 988c2ecf20Sopenharmony_ci [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", 998c2ecf20Sopenharmony_ci [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", 1008c2ecf20Sopenharmony_ci [LOOPBACK_GMII_WS] = "GMII_WS", 1018c2ecf20Sopenharmony_ci [LOOPBACK_XFI_WS] = "XFI_WS", 1028c2ecf20Sopenharmony_ci [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", 1038c2ecf20Sopenharmony_ci [LOOPBACK_PHYXS_WS] = "PHYXS_WS", 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Reset workqueue. If any NIC has a hardware failure then a reset will be 1078c2ecf20Sopenharmony_ci * queued onto this work queue. This is not a per-nic work queue, because 1088c2ecf20Sopenharmony_ci * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic struct workqueue_struct *reset_workqueue; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint efx_create_reset_workqueue(void) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci reset_workqueue = create_singlethread_workqueue("sfc_reset"); 1158c2ecf20Sopenharmony_ci if (!reset_workqueue) { 1168c2ecf20Sopenharmony_ci printk(KERN_ERR "Failed to create reset workqueue\n"); 1178c2ecf20Sopenharmony_ci return -ENOMEM; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid efx_queue_reset_work(struct efx_nic *efx) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci queue_work(reset_workqueue, &efx->reset_work); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_civoid efx_flush_reset_workqueue(struct efx_nic *efx) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci cancel_work_sync(&efx->reset_work); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_civoid efx_destroy_reset_workqueue(void) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci if (reset_workqueue) { 1368c2ecf20Sopenharmony_ci destroy_workqueue(reset_workqueue); 1378c2ecf20Sopenharmony_ci reset_workqueue = NULL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* We assume that efx->type->reconfigure_mac will always try to sync RX 1428c2ecf20Sopenharmony_ci * filters and therefore needs to read-lock the filter table against freeing 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_civoid efx_mac_reconfigure(struct efx_nic *efx, bool mtu_only) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (efx->type->reconfigure_mac) { 1478c2ecf20Sopenharmony_ci down_read(&efx->filter_sem); 1488c2ecf20Sopenharmony_ci efx->type->reconfigure_mac(efx, mtu_only); 1498c2ecf20Sopenharmony_ci up_read(&efx->filter_sem); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* Asynchronous work item for changing MAC promiscuity and multicast 1548c2ecf20Sopenharmony_ci * hash. Avoid a drain/rx_ingress enable by reconfiguring the current 1558c2ecf20Sopenharmony_ci * MAC directly. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic void efx_mac_work(struct work_struct *data) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 1628c2ecf20Sopenharmony_ci if (efx->port_enabled) 1638c2ecf20Sopenharmony_ci efx_mac_reconfigure(efx, false); 1648c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint efx_set_mac_address(struct net_device *net_dev, void *data) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 1708c2ecf20Sopenharmony_ci struct sockaddr *addr = data; 1718c2ecf20Sopenharmony_ci u8 *new_addr = addr->sa_data; 1728c2ecf20Sopenharmony_ci u8 old_addr[6]; 1738c2ecf20Sopenharmony_ci int rc; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(new_addr)) { 1768c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 1778c2ecf20Sopenharmony_ci "invalid ethernet MAC address requested: %pM\n", 1788c2ecf20Sopenharmony_ci new_addr); 1798c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* save old address */ 1838c2ecf20Sopenharmony_ci ether_addr_copy(old_addr, net_dev->dev_addr); 1848c2ecf20Sopenharmony_ci ether_addr_copy(net_dev->dev_addr, new_addr); 1858c2ecf20Sopenharmony_ci if (efx->type->set_mac_address) { 1868c2ecf20Sopenharmony_ci rc = efx->type->set_mac_address(efx); 1878c2ecf20Sopenharmony_ci if (rc) { 1888c2ecf20Sopenharmony_ci ether_addr_copy(net_dev->dev_addr, old_addr); 1898c2ecf20Sopenharmony_ci return rc; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Reconfigure the MAC */ 1948c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 1958c2ecf20Sopenharmony_ci efx_mac_reconfigure(efx, false); 1968c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* Context: netif_addr_lock held, BHs disabled. */ 2028c2ecf20Sopenharmony_civoid efx_set_rx_mode(struct net_device *net_dev) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (efx->port_enabled) 2078c2ecf20Sopenharmony_ci queue_work(efx->workqueue, &efx->mac_work); 2088c2ecf20Sopenharmony_ci /* Otherwise efx_start_port() will do this */ 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciint efx_set_features(struct net_device *net_dev, netdev_features_t data) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 2148c2ecf20Sopenharmony_ci int rc; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* If disabling RX n-tuple filtering, clear existing filters */ 2178c2ecf20Sopenharmony_ci if (net_dev->features & ~data & NETIF_F_NTUPLE) { 2188c2ecf20Sopenharmony_ci rc = efx->type->filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); 2198c2ecf20Sopenharmony_ci if (rc) 2208c2ecf20Sopenharmony_ci return rc; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* If Rx VLAN filter is changed, update filters via mac_reconfigure. 2248c2ecf20Sopenharmony_ci * If rx-fcs is changed, mac_reconfigure updates that too. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci if ((net_dev->features ^ data) & (NETIF_F_HW_VLAN_CTAG_FILTER | 2278c2ecf20Sopenharmony_ci NETIF_F_RXFCS)) { 2288c2ecf20Sopenharmony_ci /* efx_set_rx_mode() will schedule MAC work to update filters 2298c2ecf20Sopenharmony_ci * when a new features are finally set in net_dev. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci efx_set_rx_mode(net_dev); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* This ensures that the kernel is kept informed (via 2388c2ecf20Sopenharmony_ci * netif_carrier_on/off) of the link status, and also maintains the 2398c2ecf20Sopenharmony_ci * link status's stop on the port's TX queue. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_civoid efx_link_status_changed(struct efx_nic *efx) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct efx_link_state *link_state = &efx->link_state; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure 2468c2ecf20Sopenharmony_ci * that no events are triggered between unregister_netdev() and the 2478c2ecf20Sopenharmony_ci * driver unloading. A more general condition is that NETDEV_CHANGE 2488c2ecf20Sopenharmony_ci * can only be generated between NETDEV_UP and NETDEV_DOWN 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci if (!netif_running(efx->net_dev)) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (link_state->up != netif_carrier_ok(efx->net_dev)) { 2548c2ecf20Sopenharmony_ci efx->n_link_state_changes++; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (link_state->up) 2578c2ecf20Sopenharmony_ci netif_carrier_on(efx->net_dev); 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci netif_carrier_off(efx->net_dev); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Status message for kernel log */ 2638c2ecf20Sopenharmony_ci if (link_state->up) 2648c2ecf20Sopenharmony_ci netif_info(efx, link, efx->net_dev, 2658c2ecf20Sopenharmony_ci "link up at %uMbps %s-duplex (MTU %d)\n", 2668c2ecf20Sopenharmony_ci link_state->speed, link_state->fd ? "full" : "half", 2678c2ecf20Sopenharmony_ci efx->net_dev->mtu); 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci netif_info(efx, link, efx->net_dev, "link down\n"); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ciunsigned int efx_xdp_max_mtu(struct efx_nic *efx) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci /* The maximum MTU that we can fit in a single page, allowing for 2758c2ecf20Sopenharmony_ci * framing, overhead and XDP headroom + tailroom. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci int overhead = EFX_MAX_FRAME_LEN(0) + sizeof(struct efx_rx_page_state) + 2788c2ecf20Sopenharmony_ci efx->rx_prefix_size + efx->type->rx_buffer_padding + 2798c2ecf20Sopenharmony_ci efx->rx_ip_align + EFX_XDP_HEADROOM + EFX_XDP_TAILROOM; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return PAGE_SIZE - overhead; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* Context: process, rtnl_lock() held. */ 2858c2ecf20Sopenharmony_ciint efx_change_mtu(struct net_device *net_dev, int new_mtu) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 2888c2ecf20Sopenharmony_ci int rc; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci rc = efx_check_disabled(efx); 2918c2ecf20Sopenharmony_ci if (rc) 2928c2ecf20Sopenharmony_ci return rc; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (rtnl_dereference(efx->xdp_prog) && 2958c2ecf20Sopenharmony_ci new_mtu > efx_xdp_max_mtu(efx)) { 2968c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 2978c2ecf20Sopenharmony_ci "Requested MTU of %d too big for XDP (max: %d)\n", 2988c2ecf20Sopenharmony_ci new_mtu, efx_xdp_max_mtu(efx)); 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci efx_device_detach_sync(efx); 3058c2ecf20Sopenharmony_ci efx_stop_all(efx); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 3088c2ecf20Sopenharmony_ci net_dev->mtu = new_mtu; 3098c2ecf20Sopenharmony_ci efx_mac_reconfigure(efx, true); 3108c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci efx_start_all(efx); 3138c2ecf20Sopenharmony_ci efx_device_attach_if_not_resetting(efx); 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/************************************************************************** 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * Hardware monitor 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci **************************************************************************/ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* Run periodically off the general workqueue */ 3248c2ecf20Sopenharmony_cistatic void efx_monitor(struct work_struct *data) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct efx_nic *efx = container_of(data, struct efx_nic, 3278c2ecf20Sopenharmony_ci monitor_work.work); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci netif_vdbg(efx, timer, efx->net_dev, 3308c2ecf20Sopenharmony_ci "hardware monitor executing on CPU %d\n", 3318c2ecf20Sopenharmony_ci raw_smp_processor_id()); 3328c2ecf20Sopenharmony_ci BUG_ON(efx->type->monitor == NULL); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* If the mac_lock is already held then it is likely a port 3358c2ecf20Sopenharmony_ci * reconfiguration is already in place, which will likely do 3368c2ecf20Sopenharmony_ci * most of the work of monitor() anyway. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (mutex_trylock(&efx->mac_lock)) { 3398c2ecf20Sopenharmony_ci if (efx->port_enabled && efx->type->monitor) 3408c2ecf20Sopenharmony_ci efx->type->monitor(efx); 3418c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci efx_start_monitor(efx); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_civoid efx_start_monitor(struct efx_nic *efx) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci if (efx->type->monitor) 3508c2ecf20Sopenharmony_ci queue_delayed_work(efx->workqueue, &efx->monitor_work, 3518c2ecf20Sopenharmony_ci efx_monitor_interval); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/************************************************************************** 3558c2ecf20Sopenharmony_ci * 3568c2ecf20Sopenharmony_ci * Event queue processing 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci *************************************************************************/ 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* Channels are shutdown and reinitialised whilst the NIC is running 3618c2ecf20Sopenharmony_ci * to propagate configuration changes (mtu, checksum offload), or 3628c2ecf20Sopenharmony_ci * to clear hardware error conditions 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic void efx_start_datapath(struct efx_nic *efx) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci netdev_features_t old_features = efx->net_dev->features; 3678c2ecf20Sopenharmony_ci bool old_rx_scatter = efx->rx_scatter; 3688c2ecf20Sopenharmony_ci size_t rx_buf_len; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Calculate the rx buffer allocation parameters required to 3718c2ecf20Sopenharmony_ci * support the current MTU, including padding for header 3728c2ecf20Sopenharmony_ci * alignment and overruns. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci efx->rx_dma_len = (efx->rx_prefix_size + 3758c2ecf20Sopenharmony_ci EFX_MAX_FRAME_LEN(efx->net_dev->mtu) + 3768c2ecf20Sopenharmony_ci efx->type->rx_buffer_padding); 3778c2ecf20Sopenharmony_ci rx_buf_len = (sizeof(struct efx_rx_page_state) + EFX_XDP_HEADROOM + 3788c2ecf20Sopenharmony_ci efx->rx_ip_align + efx->rx_dma_len + EFX_XDP_TAILROOM); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (rx_buf_len <= PAGE_SIZE) { 3818c2ecf20Sopenharmony_ci efx->rx_scatter = efx->type->always_rx_scatter; 3828c2ecf20Sopenharmony_ci efx->rx_buffer_order = 0; 3838c2ecf20Sopenharmony_ci } else if (efx->type->can_rx_scatter) { 3848c2ecf20Sopenharmony_ci BUILD_BUG_ON(EFX_RX_USR_BUF_SIZE % L1_CACHE_BYTES); 3858c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct efx_rx_page_state) + 3868c2ecf20Sopenharmony_ci 2 * ALIGN(NET_IP_ALIGN + EFX_RX_USR_BUF_SIZE, 3878c2ecf20Sopenharmony_ci EFX_RX_BUF_ALIGNMENT) > 3888c2ecf20Sopenharmony_ci PAGE_SIZE); 3898c2ecf20Sopenharmony_ci efx->rx_scatter = true; 3908c2ecf20Sopenharmony_ci efx->rx_dma_len = EFX_RX_USR_BUF_SIZE; 3918c2ecf20Sopenharmony_ci efx->rx_buffer_order = 0; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci efx->rx_scatter = false; 3948c2ecf20Sopenharmony_ci efx->rx_buffer_order = get_order(rx_buf_len); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci efx_rx_config_page_split(efx); 3988c2ecf20Sopenharmony_ci if (efx->rx_buffer_order) 3998c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 4008c2ecf20Sopenharmony_ci "RX buf len=%u; page order=%u batch=%u\n", 4018c2ecf20Sopenharmony_ci efx->rx_dma_len, efx->rx_buffer_order, 4028c2ecf20Sopenharmony_ci efx->rx_pages_per_batch); 4038c2ecf20Sopenharmony_ci else 4048c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 4058c2ecf20Sopenharmony_ci "RX buf len=%u step=%u bpp=%u; page batch=%u\n", 4068c2ecf20Sopenharmony_ci efx->rx_dma_len, efx->rx_page_buf_step, 4078c2ecf20Sopenharmony_ci efx->rx_bufs_per_page, efx->rx_pages_per_batch); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Restore previously fixed features in hw_features and remove 4108c2ecf20Sopenharmony_ci * features which are fixed now 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci efx->net_dev->hw_features |= efx->net_dev->features; 4138c2ecf20Sopenharmony_ci efx->net_dev->hw_features &= ~efx->fixed_features; 4148c2ecf20Sopenharmony_ci efx->net_dev->features |= efx->fixed_features; 4158c2ecf20Sopenharmony_ci if (efx->net_dev->features != old_features) 4168c2ecf20Sopenharmony_ci netdev_features_change(efx->net_dev); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* RX filters may also have scatter-enabled flags */ 4198c2ecf20Sopenharmony_ci if ((efx->rx_scatter != old_rx_scatter) && 4208c2ecf20Sopenharmony_ci efx->type->filter_update_rx_scatter) 4218c2ecf20Sopenharmony_ci efx->type->filter_update_rx_scatter(efx); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* We must keep at least one descriptor in a TX ring empty. 4248c2ecf20Sopenharmony_ci * We could avoid this when the queue size does not exactly 4258c2ecf20Sopenharmony_ci * match the hardware ring size, but it's not that important. 4268c2ecf20Sopenharmony_ci * Therefore we stop the queue when one more skb might fill 4278c2ecf20Sopenharmony_ci * the ring completely. We wake it when half way back to 4288c2ecf20Sopenharmony_ci * empty. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci efx->txq_stop_thresh = efx->txq_entries - efx_tx_max_skb_descs(efx); 4318c2ecf20Sopenharmony_ci efx->txq_wake_thresh = efx->txq_stop_thresh / 2; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Initialise the channels */ 4348c2ecf20Sopenharmony_ci efx_start_channels(efx); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci efx_ptp_start_datapath(efx); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (netif_device_present(efx->net_dev)) 4398c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(efx->net_dev); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void efx_stop_datapath(struct efx_nic *efx) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 4458c2ecf20Sopenharmony_ci BUG_ON(efx->port_enabled); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci efx_ptp_stop_datapath(efx); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci efx_stop_channels(efx); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/************************************************************************** 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * Port handling 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci **************************************************************************/ 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* Equivalent to efx_link_set_advertising with all-zeroes, except does not 4598c2ecf20Sopenharmony_ci * force the Autoneg bit on. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_civoid efx_link_clear_advertising(struct efx_nic *efx) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci bitmap_zero(efx->link_advertising, __ETHTOOL_LINK_MODE_MASK_NBITS); 4648c2ecf20Sopenharmony_ci efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_civoid efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci efx->wanted_fc = wanted_fc; 4708c2ecf20Sopenharmony_ci if (efx->link_advertising[0]) { 4718c2ecf20Sopenharmony_ci if (wanted_fc & EFX_FC_RX) 4728c2ecf20Sopenharmony_ci efx->link_advertising[0] |= (ADVERTISED_Pause | 4738c2ecf20Sopenharmony_ci ADVERTISED_Asym_Pause); 4748c2ecf20Sopenharmony_ci else 4758c2ecf20Sopenharmony_ci efx->link_advertising[0] &= ~(ADVERTISED_Pause | 4768c2ecf20Sopenharmony_ci ADVERTISED_Asym_Pause); 4778c2ecf20Sopenharmony_ci if (wanted_fc & EFX_FC_TX) 4788c2ecf20Sopenharmony_ci efx->link_advertising[0] ^= ADVERTISED_Asym_Pause; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void efx_start_port(struct efx_nic *efx) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci netif_dbg(efx, ifup, efx->net_dev, "start port\n"); 4858c2ecf20Sopenharmony_ci BUG_ON(efx->port_enabled); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 4888c2ecf20Sopenharmony_ci efx->port_enabled = true; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* Ensure MAC ingress/egress is enabled */ 4918c2ecf20Sopenharmony_ci efx_mac_reconfigure(efx, false); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/* Cancel work for MAC reconfiguration, periodic hardware monitoring 4978c2ecf20Sopenharmony_ci * and the async self-test, wait for them to finish and prevent them 4988c2ecf20Sopenharmony_ci * being scheduled again. This doesn't cover online resets, which 4998c2ecf20Sopenharmony_ci * should only be cancelled when removing the device. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_cistatic void efx_stop_port(struct efx_nic *efx) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci netif_dbg(efx, ifdown, efx->net_dev, "stop port\n"); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 5088c2ecf20Sopenharmony_ci efx->port_enabled = false; 5098c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Serialise against efx_set_multicast_list() */ 5128c2ecf20Sopenharmony_ci netif_addr_lock_bh(efx->net_dev); 5138c2ecf20Sopenharmony_ci netif_addr_unlock_bh(efx->net_dev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&efx->monitor_work); 5168c2ecf20Sopenharmony_ci efx_selftest_async_cancel(efx); 5178c2ecf20Sopenharmony_ci cancel_work_sync(&efx->mac_work); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* If the interface is supposed to be running but is not, start 5218c2ecf20Sopenharmony_ci * the hardware and software data path, regular activity for the port 5228c2ecf20Sopenharmony_ci * (MAC statistics, link polling, etc.) and schedule the port to be 5238c2ecf20Sopenharmony_ci * reconfigured. Interrupts must already be enabled. This function 5248c2ecf20Sopenharmony_ci * is safe to call multiple times, so long as the NIC is not disabled. 5258c2ecf20Sopenharmony_ci * Requires the RTNL lock. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_civoid efx_start_all(struct efx_nic *efx) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 5308c2ecf20Sopenharmony_ci BUG_ON(efx->state == STATE_DISABLED); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Check that it is appropriate to restart the interface. All 5338c2ecf20Sopenharmony_ci * of these flags are safe to read under just the rtnl lock 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci if (efx->port_enabled || !netif_running(efx->net_dev) || 5368c2ecf20Sopenharmony_ci efx->reset_pending) 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci efx_start_port(efx); 5408c2ecf20Sopenharmony_ci efx_start_datapath(efx); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Start the hardware monitor if there is one */ 5438c2ecf20Sopenharmony_ci efx_start_monitor(efx); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci efx_selftest_async_start(efx); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Link state detection is normally event-driven; we have 5488c2ecf20Sopenharmony_ci * to poll now because we could have missed a change 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 5518c2ecf20Sopenharmony_ci if (efx_mcdi_phy_poll(efx)) 5528c2ecf20Sopenharmony_ci efx_link_status_changed(efx); 5538c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (efx->type->start_stats) { 5568c2ecf20Sopenharmony_ci efx->type->start_stats(efx); 5578c2ecf20Sopenharmony_ci efx->type->pull_stats(efx); 5588c2ecf20Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 5598c2ecf20Sopenharmony_ci efx->type->update_stats(efx, NULL, NULL); 5608c2ecf20Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci/* Quiesce the hardware and software data path, and regular activity 5658c2ecf20Sopenharmony_ci * for the port without bringing the link down. Safe to call multiple 5668c2ecf20Sopenharmony_ci * times with the NIC in almost any state, but interrupts should be 5678c2ecf20Sopenharmony_ci * enabled. Requires the RTNL lock. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_civoid efx_stop_all(struct efx_nic *efx) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* port_enabled can be read safely under the rtnl lock */ 5748c2ecf20Sopenharmony_ci if (!efx->port_enabled) 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (efx->type->update_stats) { 5788c2ecf20Sopenharmony_ci /* update stats before we go down so we can accurately count 5798c2ecf20Sopenharmony_ci * rx_nodesc_drops 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci efx->type->pull_stats(efx); 5828c2ecf20Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 5838c2ecf20Sopenharmony_ci efx->type->update_stats(efx, NULL, NULL); 5848c2ecf20Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 5858c2ecf20Sopenharmony_ci efx->type->stop_stats(efx); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci efx_stop_port(efx); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Stop the kernel transmit interface. This is only valid if 5918c2ecf20Sopenharmony_ci * the device is stopped or detached; otherwise the watchdog 5928c2ecf20Sopenharmony_ci * may fire immediately. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci WARN_ON(netif_running(efx->net_dev) && 5958c2ecf20Sopenharmony_ci netif_device_present(efx->net_dev)); 5968c2ecf20Sopenharmony_ci netif_tx_disable(efx->net_dev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci efx_stop_datapath(efx); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* Context: process, dev_base_lock or RTNL held, non-blocking. */ 6028c2ecf20Sopenharmony_civoid efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 6078c2ecf20Sopenharmony_ci efx_nic_update_stats_atomic(efx, NULL, stats); 6088c2ecf20Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* Push loopback/power/transmit disable settings to the PHY, and reconfigure 6128c2ecf20Sopenharmony_ci * the MAC appropriately. All other PHY configuration changes are pushed 6138c2ecf20Sopenharmony_ci * through phy_op->set_settings(), and pushed asynchronously to the MAC 6148c2ecf20Sopenharmony_ci * through efx_monitor(). 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * Callers must hold the mac_lock 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ciint __efx_reconfigure_port(struct efx_nic *efx) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci enum efx_phy_mode phy_mode; 6218c2ecf20Sopenharmony_ci int rc = 0; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* Disable PHY transmit in mac level loopbacks */ 6268c2ecf20Sopenharmony_ci phy_mode = efx->phy_mode; 6278c2ecf20Sopenharmony_ci if (LOOPBACK_INTERNAL(efx)) 6288c2ecf20Sopenharmony_ci efx->phy_mode |= PHY_MODE_TX_DISABLED; 6298c2ecf20Sopenharmony_ci else 6308c2ecf20Sopenharmony_ci efx->phy_mode &= ~PHY_MODE_TX_DISABLED; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (efx->type->reconfigure_port) 6338c2ecf20Sopenharmony_ci rc = efx->type->reconfigure_port(efx); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (rc) 6368c2ecf20Sopenharmony_ci efx->phy_mode = phy_mode; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return rc; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/* Reinitialise the MAC to pick up new PHY settings, even if the port is 6428c2ecf20Sopenharmony_ci * disabled. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ciint efx_reconfigure_port(struct efx_nic *efx) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci int rc; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 6518c2ecf20Sopenharmony_ci rc = __efx_reconfigure_port(efx); 6528c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return rc; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/************************************************************************** 6588c2ecf20Sopenharmony_ci * 6598c2ecf20Sopenharmony_ci * Device reset and suspend 6608c2ecf20Sopenharmony_ci * 6618c2ecf20Sopenharmony_ci **************************************************************************/ 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void efx_wait_for_bist_end(struct efx_nic *efx) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci int i; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci for (i = 0; i < BIST_WAIT_DELAY_COUNT; ++i) { 6688c2ecf20Sopenharmony_ci if (efx_mcdi_poll_reboot(efx)) 6698c2ecf20Sopenharmony_ci goto out; 6708c2ecf20Sopenharmony_ci msleep(BIST_WAIT_DELAY_MS); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "Warning: No MC reboot after BIST mode\n"); 6748c2ecf20Sopenharmony_ciout: 6758c2ecf20Sopenharmony_ci /* Either way unset the BIST flag. If we found no reboot we probably 6768c2ecf20Sopenharmony_ci * won't recover, but we should try. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci efx->mc_bist_for_other_fn = false; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/* Try recovery mechanisms. 6828c2ecf20Sopenharmony_ci * For now only EEH is supported. 6838c2ecf20Sopenharmony_ci * Returns 0 if the recovery mechanisms are unsuccessful. 6848c2ecf20Sopenharmony_ci * Returns a non-zero value otherwise. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ciint efx_try_recovery(struct efx_nic *efx) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci#ifdef CONFIG_EEH 6898c2ecf20Sopenharmony_ci /* A PCI error can occur and not be seen by EEH because nothing 6908c2ecf20Sopenharmony_ci * happens on the PCI bus. In this case the driver may fail and 6918c2ecf20Sopenharmony_ci * schedule a 'recover or reset', leading to this recovery handler. 6928c2ecf20Sopenharmony_ci * Manually call the eeh failure check function. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci struct eeh_dev *eehdev = pci_dev_to_eeh_dev(efx->pci_dev); 6958c2ecf20Sopenharmony_ci if (eeh_dev_check_failure(eehdev)) { 6968c2ecf20Sopenharmony_ci /* The EEH mechanisms will handle the error and reset the 6978c2ecf20Sopenharmony_ci * device if necessary. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci return 1; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci#endif 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* Tears down the entire software state and most of the hardware state 7068c2ecf20Sopenharmony_ci * before reset. 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_civoid efx_reset_down(struct efx_nic *efx, enum reset_type method) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (method == RESET_TYPE_MCDI_TIMEOUT) 7138c2ecf20Sopenharmony_ci efx->type->prepare_flr(efx); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci efx_stop_all(efx); 7168c2ecf20Sopenharmony_ci efx_disable_interrupts(efx); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci mutex_lock(&efx->mac_lock); 7198c2ecf20Sopenharmony_ci down_write(&efx->filter_sem); 7208c2ecf20Sopenharmony_ci mutex_lock(&efx->rss_lock); 7218c2ecf20Sopenharmony_ci efx->type->fini(efx); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/* Context: netif_tx_lock held, BHs disabled. */ 7258c2ecf20Sopenharmony_civoid efx_watchdog(struct net_device *net_dev, unsigned int txqueue) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci netif_err(efx, tx_err, efx->net_dev, 7308c2ecf20Sopenharmony_ci "TX stuck with port_enabled=%d: resetting channels\n", 7318c2ecf20Sopenharmony_ci efx->port_enabled); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci/* This function will always ensure that the locks acquired in 7378c2ecf20Sopenharmony_ci * efx_reset_down() are released. A failure return code indicates 7388c2ecf20Sopenharmony_ci * that we were unable to reinitialise the hardware, and the 7398c2ecf20Sopenharmony_ci * driver should be disabled. If ok is false, then the rx and tx 7408c2ecf20Sopenharmony_ci * engines are not restarted, pending a RESET_DISABLE. 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ciint efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int rc; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (method == RESET_TYPE_MCDI_TIMEOUT) 7498c2ecf20Sopenharmony_ci efx->type->finish_flr(efx); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Ensure that SRAM is initialised even if we're disabling the device */ 7528c2ecf20Sopenharmony_ci rc = efx->type->init(efx); 7538c2ecf20Sopenharmony_ci if (rc) { 7548c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n"); 7558c2ecf20Sopenharmony_ci goto fail; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (!ok) 7598c2ecf20Sopenharmony_ci goto fail; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (efx->port_initialized && method != RESET_TYPE_INVISIBLE && 7628c2ecf20Sopenharmony_ci method != RESET_TYPE_DATAPATH) { 7638c2ecf20Sopenharmony_ci rc = efx_mcdi_port_reconfigure(efx); 7648c2ecf20Sopenharmony_ci if (rc && rc != -EPERM) 7658c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 7668c2ecf20Sopenharmony_ci "could not restore PHY settings\n"); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci rc = efx_enable_interrupts(efx); 7708c2ecf20Sopenharmony_ci if (rc) 7718c2ecf20Sopenharmony_ci goto fail; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_SRIOV 7748c2ecf20Sopenharmony_ci rc = efx->type->vswitching_restore(efx); 7758c2ecf20Sopenharmony_ci if (rc) /* not fatal; the PF will still work fine */ 7768c2ecf20Sopenharmony_ci netif_warn(efx, probe, efx->net_dev, 7778c2ecf20Sopenharmony_ci "failed to restore vswitching rc=%d;" 7788c2ecf20Sopenharmony_ci " VFs may not function\n", rc); 7798c2ecf20Sopenharmony_ci#endif 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (efx->type->rx_restore_rss_contexts) 7828c2ecf20Sopenharmony_ci efx->type->rx_restore_rss_contexts(efx); 7838c2ecf20Sopenharmony_ci mutex_unlock(&efx->rss_lock); 7848c2ecf20Sopenharmony_ci efx->type->filter_table_restore(efx); 7858c2ecf20Sopenharmony_ci up_write(&efx->filter_sem); 7868c2ecf20Sopenharmony_ci if (efx->type->sriov_reset) 7878c2ecf20Sopenharmony_ci efx->type->sriov_reset(efx); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci efx_start_all(efx); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (efx->type->udp_tnl_push_ports) 7948c2ecf20Sopenharmony_ci efx->type->udp_tnl_push_ports(efx); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cifail: 7998c2ecf20Sopenharmony_ci efx->port_initialized = false; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci mutex_unlock(&efx->rss_lock); 8028c2ecf20Sopenharmony_ci up_write(&efx->filter_sem); 8038c2ecf20Sopenharmony_ci mutex_unlock(&efx->mac_lock); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return rc; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/* Reset the NIC using the specified method. Note that the reset may 8098c2ecf20Sopenharmony_ci * fail, in which case the card will be left in an unusable state. 8108c2ecf20Sopenharmony_ci * 8118c2ecf20Sopenharmony_ci * Caller must hold the rtnl_lock. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ciint efx_reset(struct efx_nic *efx, enum reset_type method) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci int rc, rc2 = 0; 8168c2ecf20Sopenharmony_ci bool disabled; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", 8198c2ecf20Sopenharmony_ci RESET_TYPE(method)); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci efx_device_detach_sync(efx); 8228c2ecf20Sopenharmony_ci /* efx_reset_down() grabs locks that prevent recovery on EF100. 8238c2ecf20Sopenharmony_ci * EF100 reset is handled in the efx_nic_type callback below. 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci if (efx_nic_rev(efx) != EFX_REV_EF100) 8268c2ecf20Sopenharmony_ci efx_reset_down(efx, method); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci rc = efx->type->reset(efx, method); 8298c2ecf20Sopenharmony_ci if (rc) { 8308c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "failed to reset hardware\n"); 8318c2ecf20Sopenharmony_ci goto out; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Clear flags for the scopes we covered. We assume the NIC and 8358c2ecf20Sopenharmony_ci * driver are now quiescent so that there is no race here. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_ci if (method < RESET_TYPE_MAX_METHOD) 8388c2ecf20Sopenharmony_ci efx->reset_pending &= -(1 << (method + 1)); 8398c2ecf20Sopenharmony_ci else /* it doesn't fit into the well-ordered scope hierarchy */ 8408c2ecf20Sopenharmony_ci __clear_bit(method, &efx->reset_pending); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Reinitialise bus-mastering, which may have been turned off before 8438c2ecf20Sopenharmony_ci * the reset was scheduled. This is still appropriate, even in the 8448c2ecf20Sopenharmony_ci * RESET_TYPE_DISABLE since this driver generally assumes the hardware 8458c2ecf20Sopenharmony_ci * can respond to requests. 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ci pci_set_master(efx->pci_dev); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ciout: 8508c2ecf20Sopenharmony_ci /* Leave device stopped if necessary */ 8518c2ecf20Sopenharmony_ci disabled = rc || 8528c2ecf20Sopenharmony_ci method == RESET_TYPE_DISABLE || 8538c2ecf20Sopenharmony_ci method == RESET_TYPE_RECOVER_OR_DISABLE; 8548c2ecf20Sopenharmony_ci if (efx_nic_rev(efx) != EFX_REV_EF100) 8558c2ecf20Sopenharmony_ci rc2 = efx_reset_up(efx, method, !disabled); 8568c2ecf20Sopenharmony_ci if (rc2) { 8578c2ecf20Sopenharmony_ci disabled = true; 8588c2ecf20Sopenharmony_ci if (!rc) 8598c2ecf20Sopenharmony_ci rc = rc2; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (disabled) { 8638c2ecf20Sopenharmony_ci dev_close(efx->net_dev); 8648c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "has been disabled\n"); 8658c2ecf20Sopenharmony_ci efx->state = STATE_DISABLED; 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "reset complete\n"); 8688c2ecf20Sopenharmony_ci efx_device_attach_if_not_resetting(efx); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci return rc; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci/* The worker thread exists so that code that cannot sleep can 8748c2ecf20Sopenharmony_ci * schedule a reset for later. 8758c2ecf20Sopenharmony_ci */ 8768c2ecf20Sopenharmony_cistatic void efx_reset_work(struct work_struct *data) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); 8798c2ecf20Sopenharmony_ci unsigned long pending; 8808c2ecf20Sopenharmony_ci enum reset_type method; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci pending = READ_ONCE(efx->reset_pending); 8838c2ecf20Sopenharmony_ci method = fls(pending) - 1; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (method == RESET_TYPE_MC_BIST) 8868c2ecf20Sopenharmony_ci efx_wait_for_bist_end(efx); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if ((method == RESET_TYPE_RECOVER_OR_DISABLE || 8898c2ecf20Sopenharmony_ci method == RESET_TYPE_RECOVER_OR_ALL) && 8908c2ecf20Sopenharmony_ci efx_try_recovery(efx)) 8918c2ecf20Sopenharmony_ci return; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (!pending) 8948c2ecf20Sopenharmony_ci return; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci rtnl_lock(); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* We checked the state in efx_schedule_reset() but it may 8998c2ecf20Sopenharmony_ci * have changed by now. Now that we have the RTNL lock, 9008c2ecf20Sopenharmony_ci * it cannot change again. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci if (efx_net_active(efx->state)) 9038c2ecf20Sopenharmony_ci (void)efx_reset(efx, method); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci rtnl_unlock(); 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_civoid efx_schedule_reset(struct efx_nic *efx, enum reset_type type) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci enum reset_type method; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (efx_recovering(efx->state)) { 9138c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 9148c2ecf20Sopenharmony_ci "recovering: skip scheduling %s reset\n", 9158c2ecf20Sopenharmony_ci RESET_TYPE(type)); 9168c2ecf20Sopenharmony_ci return; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci switch (type) { 9208c2ecf20Sopenharmony_ci case RESET_TYPE_INVISIBLE: 9218c2ecf20Sopenharmony_ci case RESET_TYPE_ALL: 9228c2ecf20Sopenharmony_ci case RESET_TYPE_RECOVER_OR_ALL: 9238c2ecf20Sopenharmony_ci case RESET_TYPE_WORLD: 9248c2ecf20Sopenharmony_ci case RESET_TYPE_DISABLE: 9258c2ecf20Sopenharmony_ci case RESET_TYPE_RECOVER_OR_DISABLE: 9268c2ecf20Sopenharmony_ci case RESET_TYPE_DATAPATH: 9278c2ecf20Sopenharmony_ci case RESET_TYPE_MC_BIST: 9288c2ecf20Sopenharmony_ci case RESET_TYPE_MCDI_TIMEOUT: 9298c2ecf20Sopenharmony_ci method = type; 9308c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", 9318c2ecf20Sopenharmony_ci RESET_TYPE(method)); 9328c2ecf20Sopenharmony_ci break; 9338c2ecf20Sopenharmony_ci default: 9348c2ecf20Sopenharmony_ci method = efx->type->map_reset_reason(type); 9358c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 9368c2ecf20Sopenharmony_ci "scheduling %s reset for %s\n", 9378c2ecf20Sopenharmony_ci RESET_TYPE(method), RESET_TYPE(type)); 9388c2ecf20Sopenharmony_ci break; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci set_bit(method, &efx->reset_pending); 9428c2ecf20Sopenharmony_ci smp_mb(); /* ensure we change reset_pending before checking state */ 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* If we're not READY then just leave the flags set as the cue 9458c2ecf20Sopenharmony_ci * to abort probing or reschedule the reset later. 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_ci if (!efx_net_active(READ_ONCE(efx->state))) 9488c2ecf20Sopenharmony_ci return; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* efx_process_channel() will no longer read events once a 9518c2ecf20Sopenharmony_ci * reset is scheduled. So switch back to poll'd MCDI completions. 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci efx_mcdi_mode_poll(efx); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci efx_queue_reset_work(efx); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci/************************************************************************** 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * Dummy NIC operations 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Can be used for some unimplemented operations 9638c2ecf20Sopenharmony_ci * Needed so all function pointers are valid and do not have to be tested 9648c2ecf20Sopenharmony_ci * before use 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci **************************************************************************/ 9678c2ecf20Sopenharmony_ciint efx_port_dummy_op_int(struct efx_nic *efx) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_civoid efx_port_dummy_op_void(struct efx_nic *efx) {} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/************************************************************************** 9748c2ecf20Sopenharmony_ci * 9758c2ecf20Sopenharmony_ci * Data housekeeping 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci **************************************************************************/ 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/* This zeroes out and then fills in the invariants in a struct 9808c2ecf20Sopenharmony_ci * efx_nic (including all sub-structures). 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_ciint efx_init_struct(struct efx_nic *efx, 9838c2ecf20Sopenharmony_ci struct pci_dev *pci_dev, struct net_device *net_dev) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci int rc = -ENOMEM; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Initialise common structures */ 9888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&efx->node); 9898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&efx->secondary_list); 9908c2ecf20Sopenharmony_ci spin_lock_init(&efx->biu_lock); 9918c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_MTD 9928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&efx->mtd_list); 9938c2ecf20Sopenharmony_ci#endif 9948c2ecf20Sopenharmony_ci INIT_WORK(&efx->reset_work, efx_reset_work); 9958c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); 9968c2ecf20Sopenharmony_ci efx_selftest_async_init(efx); 9978c2ecf20Sopenharmony_ci efx->pci_dev = pci_dev; 9988c2ecf20Sopenharmony_ci efx->msg_enable = debug; 9998c2ecf20Sopenharmony_ci efx->state = STATE_UNINIT; 10008c2ecf20Sopenharmony_ci strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci efx->net_dev = net_dev; 10038c2ecf20Sopenharmony_ci efx->rx_prefix_size = efx->type->rx_prefix_size; 10048c2ecf20Sopenharmony_ci efx->rx_ip_align = 10058c2ecf20Sopenharmony_ci NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0; 10068c2ecf20Sopenharmony_ci efx->rx_packet_hash_offset = 10078c2ecf20Sopenharmony_ci efx->type->rx_hash_offset - efx->type->rx_prefix_size; 10088c2ecf20Sopenharmony_ci efx->rx_packet_ts_offset = 10098c2ecf20Sopenharmony_ci efx->type->rx_ts_offset - efx->type->rx_prefix_size; 10108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&efx->rss_context.list); 10118c2ecf20Sopenharmony_ci efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 10128c2ecf20Sopenharmony_ci mutex_init(&efx->rss_lock); 10138c2ecf20Sopenharmony_ci efx->vport_id = EVB_PORT_ID_ASSIGNED; 10148c2ecf20Sopenharmony_ci spin_lock_init(&efx->stats_lock); 10158c2ecf20Sopenharmony_ci efx->vi_stride = EFX_DEFAULT_VI_STRIDE; 10168c2ecf20Sopenharmony_ci efx->num_mac_stats = MC_CMD_MAC_NSTATS; 10178c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_MAC_NSTATS - 1 != MC_CMD_MAC_GENERATION_END); 10188c2ecf20Sopenharmony_ci mutex_init(&efx->mac_lock); 10198c2ecf20Sopenharmony_ci init_rwsem(&efx->filter_sem); 10208c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 10218c2ecf20Sopenharmony_ci mutex_init(&efx->rps_mutex); 10228c2ecf20Sopenharmony_ci spin_lock_init(&efx->rps_hash_lock); 10238c2ecf20Sopenharmony_ci /* Failure to allocate is not fatal, but may degrade ARFS performance */ 10248c2ecf20Sopenharmony_ci efx->rps_hash_table = kcalloc(EFX_ARFS_HASH_TABLE_SIZE, 10258c2ecf20Sopenharmony_ci sizeof(*efx->rps_hash_table), GFP_KERNEL); 10268c2ecf20Sopenharmony_ci#endif 10278c2ecf20Sopenharmony_ci efx->mdio.dev = net_dev; 10288c2ecf20Sopenharmony_ci INIT_WORK(&efx->mac_work, efx_mac_work); 10298c2ecf20Sopenharmony_ci init_waitqueue_head(&efx->flush_wq); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci efx->tx_queues_per_channel = 1; 10328c2ecf20Sopenharmony_ci efx->rxq_entries = EFX_DEFAULT_DMAQ_SIZE; 10338c2ecf20Sopenharmony_ci efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci efx->mem_bar = UINT_MAX; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci rc = efx_init_channels(efx); 10388c2ecf20Sopenharmony_ci if (rc) 10398c2ecf20Sopenharmony_ci goto fail; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Would be good to use the net_dev name, but we're too early */ 10428c2ecf20Sopenharmony_ci snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s", 10438c2ecf20Sopenharmony_ci pci_name(pci_dev)); 10448c2ecf20Sopenharmony_ci efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); 10458c2ecf20Sopenharmony_ci if (!efx->workqueue) { 10468c2ecf20Sopenharmony_ci rc = -ENOMEM; 10478c2ecf20Sopenharmony_ci goto fail; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci return 0; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cifail: 10538c2ecf20Sopenharmony_ci efx_fini_struct(efx); 10548c2ecf20Sopenharmony_ci return rc; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_civoid efx_fini_struct(struct efx_nic *efx) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 10608c2ecf20Sopenharmony_ci kfree(efx->rps_hash_table); 10618c2ecf20Sopenharmony_ci#endif 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci efx_fini_channels(efx); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci kfree(efx->vpd_sn); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (efx->workqueue) { 10688c2ecf20Sopenharmony_ci destroy_workqueue(efx->workqueue); 10698c2ecf20Sopenharmony_ci efx->workqueue = NULL; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci/* This configures the PCI device to enable I/O and DMA. */ 10748c2ecf20Sopenharmony_ciint efx_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask, 10758c2ecf20Sopenharmony_ci unsigned int mem_map_size) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci struct pci_dev *pci_dev = efx->pci_dev; 10788c2ecf20Sopenharmony_ci int rc; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci efx->mem_bar = UINT_MAX; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "initialising I/O bar=%d\n", bar); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci rc = pci_enable_device(pci_dev); 10858c2ecf20Sopenharmony_ci if (rc) { 10868c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 10878c2ecf20Sopenharmony_ci "failed to enable PCI device\n"); 10888c2ecf20Sopenharmony_ci goto fail1; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci pci_set_master(pci_dev); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask); 10948c2ecf20Sopenharmony_ci if (rc) { 10958c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 10968c2ecf20Sopenharmony_ci "could not find a suitable DMA mask\n"); 10978c2ecf20Sopenharmony_ci goto fail2; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 11008c2ecf20Sopenharmony_ci "using DMA mask %llx\n", (unsigned long long)dma_mask); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci efx->membase_phys = pci_resource_start(efx->pci_dev, bar); 11038c2ecf20Sopenharmony_ci if (!efx->membase_phys) { 11048c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 11058c2ecf20Sopenharmony_ci "ERROR: No BAR%d mapping from the BIOS. " 11068c2ecf20Sopenharmony_ci "Try pci=realloc on the kernel command line\n", bar); 11078c2ecf20Sopenharmony_ci rc = -ENODEV; 11088c2ecf20Sopenharmony_ci goto fail3; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci rc = pci_request_region(pci_dev, bar, "sfc"); 11128c2ecf20Sopenharmony_ci if (rc) { 11138c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 11148c2ecf20Sopenharmony_ci "request for memory BAR[%d] failed\n", bar); 11158c2ecf20Sopenharmony_ci rc = -EIO; 11168c2ecf20Sopenharmony_ci goto fail3; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci efx->mem_bar = bar; 11198c2ecf20Sopenharmony_ci efx->membase = ioremap(efx->membase_phys, mem_map_size); 11208c2ecf20Sopenharmony_ci if (!efx->membase) { 11218c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 11228c2ecf20Sopenharmony_ci "could not map memory BAR[%d] at %llx+%x\n", bar, 11238c2ecf20Sopenharmony_ci (unsigned long long)efx->membase_phys, mem_map_size); 11248c2ecf20Sopenharmony_ci rc = -ENOMEM; 11258c2ecf20Sopenharmony_ci goto fail4; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 11288c2ecf20Sopenharmony_ci "memory BAR[%d] at %llx+%x (virtual %p)\n", bar, 11298c2ecf20Sopenharmony_ci (unsigned long long)efx->membase_phys, mem_map_size, 11308c2ecf20Sopenharmony_ci efx->membase); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci return 0; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cifail4: 11358c2ecf20Sopenharmony_ci pci_release_region(efx->pci_dev, bar); 11368c2ecf20Sopenharmony_cifail3: 11378c2ecf20Sopenharmony_ci efx->membase_phys = 0; 11388c2ecf20Sopenharmony_cifail2: 11398c2ecf20Sopenharmony_ci pci_disable_device(efx->pci_dev); 11408c2ecf20Sopenharmony_cifail1: 11418c2ecf20Sopenharmony_ci return rc; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_civoid efx_fini_io(struct efx_nic *efx) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n"); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (efx->membase) { 11498c2ecf20Sopenharmony_ci iounmap(efx->membase); 11508c2ecf20Sopenharmony_ci efx->membase = NULL; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (efx->membase_phys) { 11548c2ecf20Sopenharmony_ci pci_release_region(efx->pci_dev, efx->mem_bar); 11558c2ecf20Sopenharmony_ci efx->membase_phys = 0; 11568c2ecf20Sopenharmony_ci efx->mem_bar = UINT_MAX; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Don't disable bus-mastering if VFs are assigned */ 11608c2ecf20Sopenharmony_ci if (!pci_vfs_assigned(efx->pci_dev)) 11618c2ecf20Sopenharmony_ci pci_disable_device(efx->pci_dev); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_MCDI_LOGGING 11658c2ecf20Sopenharmony_cistatic ssize_t show_mcdi_log(struct device *dev, struct device_attribute *attr, 11668c2ecf20Sopenharmony_ci char *buf) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci struct efx_nic *efx = dev_get_drvdata(dev); 11698c2ecf20Sopenharmony_ci struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", mcdi->logging_enabled); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic ssize_t set_mcdi_log(struct device *dev, struct device_attribute *attr, 11758c2ecf20Sopenharmony_ci const char *buf, size_t count) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci struct efx_nic *efx = dev_get_drvdata(dev); 11788c2ecf20Sopenharmony_ci struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 11798c2ecf20Sopenharmony_ci bool enable = count > 0 && *buf != '0'; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci mcdi->logging_enabled = enable; 11828c2ecf20Sopenharmony_ci return count; 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mcdi_logging, 0644, show_mcdi_log, set_mcdi_log); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_civoid efx_init_mcdi_logging(struct efx_nic *efx) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci int rc = device_create_file(&efx->pci_dev->dev, &dev_attr_mcdi_logging); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (rc) { 11928c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 11938c2ecf20Sopenharmony_ci "failed to init net dev attributes\n"); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_civoid efx_fini_mcdi_logging(struct efx_nic *efx) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci device_remove_file(&efx->pci_dev->dev, &dev_attr_mcdi_logging); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci#endif 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci/* A PCI error affecting this device was detected. 12048c2ecf20Sopenharmony_ci * At this point MMIO and DMA may be disabled. 12058c2ecf20Sopenharmony_ci * Stop the software path and request a slot reset. 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_cistatic pci_ers_result_t efx_io_error_detected(struct pci_dev *pdev, 12088c2ecf20Sopenharmony_ci pci_channel_state_t state) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 12118c2ecf20Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pdev); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) 12148c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci rtnl_lock(); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (efx->state != STATE_DISABLED) { 12198c2ecf20Sopenharmony_ci efx->state = efx_recover(efx->state); 12208c2ecf20Sopenharmony_ci efx->reset_pending = 0; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci efx_device_detach_sync(efx); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci efx_stop_all(efx); 12258c2ecf20Sopenharmony_ci efx_disable_interrupts(efx); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci status = PCI_ERS_RESULT_NEED_RESET; 12288c2ecf20Sopenharmony_ci } else { 12298c2ecf20Sopenharmony_ci /* If the interface is disabled we don't want to do anything 12308c2ecf20Sopenharmony_ci * with it. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci status = PCI_ERS_RESULT_RECOVERED; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci rtnl_unlock(); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci pci_disable_device(pdev); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci return status; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/* Fake a successful reset, which will be performed later in efx_io_resume. */ 12438c2ecf20Sopenharmony_cistatic pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev) 12448c2ecf20Sopenharmony_ci{ 12458c2ecf20Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pdev); 12468c2ecf20Sopenharmony_ci pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 12498c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 12508c2ecf20Sopenharmony_ci "Cannot re-enable PCI device after reset.\n"); 12518c2ecf20Sopenharmony_ci status = PCI_ERS_RESULT_DISCONNECT; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci return status; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci/* Perform the actual reset and resume I/O operations. */ 12588c2ecf20Sopenharmony_cistatic void efx_io_resume(struct pci_dev *pdev) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pdev); 12618c2ecf20Sopenharmony_ci int rc; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci rtnl_lock(); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (efx->state == STATE_DISABLED) 12668c2ecf20Sopenharmony_ci goto out; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci rc = efx_reset(efx, RESET_TYPE_ALL); 12698c2ecf20Sopenharmony_ci if (rc) { 12708c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 12718c2ecf20Sopenharmony_ci "efx_reset failed after PCI error (%d)\n", rc); 12728c2ecf20Sopenharmony_ci } else { 12738c2ecf20Sopenharmony_ci efx->state = efx_recovered(efx->state); 12748c2ecf20Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 12758c2ecf20Sopenharmony_ci "Done resetting and resuming IO after PCI error.\n"); 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ciout: 12798c2ecf20Sopenharmony_ci rtnl_unlock(); 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci/* For simplicity and reliability, we always require a slot reset and try to 12838c2ecf20Sopenharmony_ci * reset the hardware when a pci error affecting the device is detected. 12848c2ecf20Sopenharmony_ci * We leave both the link_reset and mmio_enabled callback unimplemented: 12858c2ecf20Sopenharmony_ci * with our request for slot reset the mmio_enabled callback will never be 12868c2ecf20Sopenharmony_ci * called, and the link_reset callback is not used by AER or EEH mechanisms. 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_ciconst struct pci_error_handlers efx_err_handlers = { 12898c2ecf20Sopenharmony_ci .error_detected = efx_io_error_detected, 12908c2ecf20Sopenharmony_ci .slot_reset = efx_io_slot_reset, 12918c2ecf20Sopenharmony_ci .resume = efx_io_resume, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci/* Determine whether the NIC will be able to handle TX offloads for a given 12958c2ecf20Sopenharmony_ci * encapsulated packet. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_cistatic bool efx_can_encap_offloads(struct efx_nic *efx, struct sk_buff *skb) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct gre_base_hdr *greh; 13008c2ecf20Sopenharmony_ci __be16 dst_port; 13018c2ecf20Sopenharmony_ci u8 ipproto; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Does the NIC support encap offloads? 13048c2ecf20Sopenharmony_ci * If not, we should never get here, because we shouldn't have 13058c2ecf20Sopenharmony_ci * advertised encap offload feature flags in the first place. 13068c2ecf20Sopenharmony_ci */ 13078c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!efx->type->udp_tnl_has_port)) 13088c2ecf20Sopenharmony_ci return false; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* Determine encapsulation protocol in use */ 13118c2ecf20Sopenharmony_ci switch (skb->protocol) { 13128c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 13138c2ecf20Sopenharmony_ci ipproto = ip_hdr(skb)->protocol; 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 13168c2ecf20Sopenharmony_ci /* If there are extension headers, this will cause us to 13178c2ecf20Sopenharmony_ci * think we can't offload something that we maybe could have. 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_ci ipproto = ipv6_hdr(skb)->nexthdr; 13208c2ecf20Sopenharmony_ci break; 13218c2ecf20Sopenharmony_ci default: 13228c2ecf20Sopenharmony_ci /* Not IP, so can't offload it */ 13238c2ecf20Sopenharmony_ci return false; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci switch (ipproto) { 13268c2ecf20Sopenharmony_ci case IPPROTO_GRE: 13278c2ecf20Sopenharmony_ci /* We support NVGRE but not IP over GRE or random gretaps. 13288c2ecf20Sopenharmony_ci * Specifically, the NIC will accept GRE as encapsulated if 13298c2ecf20Sopenharmony_ci * the inner protocol is Ethernet, but only handle it 13308c2ecf20Sopenharmony_ci * correctly if the GRE header is 8 bytes long. Moreover, 13318c2ecf20Sopenharmony_ci * it will not update the Checksum or Sequence Number fields 13328c2ecf20Sopenharmony_ci * if they are present. (The Routing Present flag, 13338c2ecf20Sopenharmony_ci * GRE_ROUTING, cannot be set else the header would be more 13348c2ecf20Sopenharmony_ci * than 8 bytes long; so we don't have to worry about it.) 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci if (skb->inner_protocol_type != ENCAP_TYPE_ETHER) 13378c2ecf20Sopenharmony_ci return false; 13388c2ecf20Sopenharmony_ci if (ntohs(skb->inner_protocol) != ETH_P_TEB) 13398c2ecf20Sopenharmony_ci return false; 13408c2ecf20Sopenharmony_ci if (skb_inner_mac_header(skb) - skb_transport_header(skb) != 8) 13418c2ecf20Sopenharmony_ci return false; 13428c2ecf20Sopenharmony_ci greh = (struct gre_base_hdr *)skb_transport_header(skb); 13438c2ecf20Sopenharmony_ci return !(greh->flags & (GRE_CSUM | GRE_SEQ)); 13448c2ecf20Sopenharmony_ci case IPPROTO_UDP: 13458c2ecf20Sopenharmony_ci /* If the port is registered for a UDP tunnel, we assume the 13468c2ecf20Sopenharmony_ci * packet is for that tunnel, and the NIC will handle it as 13478c2ecf20Sopenharmony_ci * such. If not, the NIC won't know what to do with it. 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci dst_port = udp_hdr(skb)->dest; 13508c2ecf20Sopenharmony_ci return efx->type->udp_tnl_has_port(efx, dst_port); 13518c2ecf20Sopenharmony_ci default: 13528c2ecf20Sopenharmony_ci return false; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci} 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cinetdev_features_t efx_features_check(struct sk_buff *skb, struct net_device *dev, 13578c2ecf20Sopenharmony_ci netdev_features_t features) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(dev); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (skb->encapsulation) { 13628c2ecf20Sopenharmony_ci if (features & NETIF_F_GSO_MASK) 13638c2ecf20Sopenharmony_ci /* Hardware can only do TSO with at most 208 bytes 13648c2ecf20Sopenharmony_ci * of headers. 13658c2ecf20Sopenharmony_ci */ 13668c2ecf20Sopenharmony_ci if (skb_inner_transport_offset(skb) > 13678c2ecf20Sopenharmony_ci EFX_TSO2_MAX_HDRLEN) 13688c2ecf20Sopenharmony_ci features &= ~(NETIF_F_GSO_MASK); 13698c2ecf20Sopenharmony_ci if (features & (NETIF_F_GSO_MASK | NETIF_F_CSUM_MASK)) 13708c2ecf20Sopenharmony_ci if (!efx_can_encap_offloads(efx, skb)) 13718c2ecf20Sopenharmony_ci features &= ~(NETIF_F_GSO_MASK | 13728c2ecf20Sopenharmony_ci NETIF_F_CSUM_MASK); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci return features; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ciint efx_get_phys_port_id(struct net_device *net_dev, 13788c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (efx->type->get_phys_port_id) 13838c2ecf20Sopenharmony_ci return efx->type->get_phys_port_id(efx, ppid); 13848c2ecf20Sopenharmony_ci else 13858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ciint efx_get_phys_port_name(struct net_device *net_dev, char *name, size_t len) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (snprintf(name, len, "p%u", efx->port_num) >= len) 13938c2ecf20Sopenharmony_ci return -EINVAL; 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci} 1396