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 * Copyright 2019-2020 Xilinx Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 88c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2 as published 98c2ecf20Sopenharmony_ci * by the Free Software Foundation, incorporated herein by reference. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "ef100_nic.h" 138c2ecf20Sopenharmony_ci#include "efx_common.h" 148c2ecf20Sopenharmony_ci#include "efx_channels.h" 158c2ecf20Sopenharmony_ci#include "io.h" 168c2ecf20Sopenharmony_ci#include "selftest.h" 178c2ecf20Sopenharmony_ci#include "ef100_regs.h" 188c2ecf20Sopenharmony_ci#include "mcdi.h" 198c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 208c2ecf20Sopenharmony_ci#include "mcdi_port_common.h" 218c2ecf20Sopenharmony_ci#include "mcdi_functions.h" 228c2ecf20Sopenharmony_ci#include "mcdi_filters.h" 238c2ecf20Sopenharmony_ci#include "ef100_rx.h" 248c2ecf20Sopenharmony_ci#include "ef100_tx.h" 258c2ecf20Sopenharmony_ci#include "ef100_netdev.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define EF100_MAX_VIS 4096 288c2ecf20Sopenharmony_ci#define EF100_NUM_MCDI_BUFFERS 1 298c2ecf20Sopenharmony_ci#define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define EF100_RESET_PORT ((ETH_RESET_MAC | ETH_RESET_PHY) << ETH_RESET_SHARED_SHIFT) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* MCDI 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic u8 *ef100_mcdi_buf(struct efx_nic *efx, u8 bufid, dma_addr_t *dma_addr) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (dma_addr) 408c2ecf20Sopenharmony_ci *dma_addr = nic_data->mcdi_buf.dma_addr + 418c2ecf20Sopenharmony_ci bufid * ALIGN(MCDI_BUF_LEN, 256); 428c2ecf20Sopenharmony_ci return nic_data->mcdi_buf.addr + bufid * ALIGN(MCDI_BUF_LEN, 256); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int ef100_get_warm_boot_count(struct efx_nic *efx) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci efx_dword_t reg; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci efx_readd(efx, ®, efx_reg(efx, ER_GZ_MC_SFT_STATUS)); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) == 0xffffffff) { 528c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "Hardware unavailable\n"); 538c2ecf20Sopenharmony_ci efx->state = STATE_DISABLED; 548c2ecf20Sopenharmony_ci return -ENETDOWN; 558c2ecf20Sopenharmony_ci } else { 568c2ecf20Sopenharmony_ci return EFX_DWORD_FIELD(reg, EFX_WORD_1) == 0xb007 ? 578c2ecf20Sopenharmony_ci EFX_DWORD_FIELD(reg, EFX_WORD_0) : -EIO; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void ef100_mcdi_request(struct efx_nic *efx, 628c2ecf20Sopenharmony_ci const efx_dword_t *hdr, size_t hdr_len, 638c2ecf20Sopenharmony_ci const efx_dword_t *sdu, size_t sdu_len) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 668c2ecf20Sopenharmony_ci u8 *pdu = ef100_mcdi_buf(efx, 0, &dma_addr); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci memcpy(pdu, hdr, hdr_len); 698c2ecf20Sopenharmony_ci memcpy(pdu + hdr_len, sdu, sdu_len); 708c2ecf20Sopenharmony_ci wmb(); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* The hardware provides 'low' and 'high' (doorbell) registers 738c2ecf20Sopenharmony_ci * for passing the 64-bit address of an MCDI request to 748c2ecf20Sopenharmony_ci * firmware. However the dwords are swapped by firmware. The 758c2ecf20Sopenharmony_ci * least significant bits of the doorbell are then 0 for all 768c2ecf20Sopenharmony_ci * MCDI requests due to alignment. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci _efx_writed(efx, cpu_to_le32((u64)dma_addr >> 32), efx_reg(efx, ER_GZ_MC_DB_LWRD)); 798c2ecf20Sopenharmony_ci _efx_writed(efx, cpu_to_le32((u32)dma_addr), efx_reg(efx, ER_GZ_MC_DB_HWRD)); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic bool ef100_mcdi_poll_response(struct efx_nic *efx) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci const efx_dword_t hdr = 858c2ecf20Sopenharmony_ci *(const efx_dword_t *)(ef100_mcdi_buf(efx, 0, NULL)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci rmb(); 888c2ecf20Sopenharmony_ci return EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void ef100_mcdi_read_response(struct efx_nic *efx, 928c2ecf20Sopenharmony_ci efx_dword_t *outbuf, size_t offset, 938c2ecf20Sopenharmony_ci size_t outlen) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci const u8 *pdu = ef100_mcdi_buf(efx, 0, NULL); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci memcpy(outbuf, pdu + offset, outlen); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int ef100_mcdi_poll_reboot(struct efx_nic *efx) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 1038c2ecf20Sopenharmony_ci int rc; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci rc = ef100_get_warm_boot_count(efx); 1068c2ecf20Sopenharmony_ci if (rc < 0) { 1078c2ecf20Sopenharmony_ci /* The firmware is presumably in the process of 1088c2ecf20Sopenharmony_ci * rebooting. However, we are supposed to report each 1098c2ecf20Sopenharmony_ci * reboot just once, so we must only do that once we 1108c2ecf20Sopenharmony_ci * can read and store the updated warm boot count. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (rc == nic_data->warm_boot_count) 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci nic_data->warm_boot_count = rc; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return -EIO; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void ef100_mcdi_reboot_detected(struct efx_nic *efx) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* MCDI calls 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN); 1328c2ecf20Sopenharmony_ci size_t outlen; 1338c2ecf20Sopenharmony_ci int rc; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_GET_MAC_ADDRESSES_IN_LEN != 0); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_GET_MAC_ADDRESSES, NULL, 0, 1388c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 1398c2ecf20Sopenharmony_ci if (rc) 1408c2ecf20Sopenharmony_ci return rc; 1418c2ecf20Sopenharmony_ci if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) 1428c2ecf20Sopenharmony_ci return -EIO; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ether_addr_copy(mac_address, 1458c2ecf20Sopenharmony_ci MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE)); 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int efx_ef100_init_datapath_caps(struct efx_nic *efx) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V7_OUT_LEN); 1528c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 1538c2ecf20Sopenharmony_ci u8 vi_window_mode; 1548c2ecf20Sopenharmony_ci size_t outlen; 1558c2ecf20Sopenharmony_ci int rc; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_GET_CAPABILITIES_IN_LEN != 0); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_GET_CAPABILITIES, NULL, 0, 1608c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 1618c2ecf20Sopenharmony_ci if (rc) 1628c2ecf20Sopenharmony_ci return rc; 1638c2ecf20Sopenharmony_ci if (outlen < MC_CMD_GET_CAPABILITIES_V4_OUT_LEN) { 1648c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 1658c2ecf20Sopenharmony_ci "unable to read datapath firmware capabilities\n"); 1668c2ecf20Sopenharmony_ci return -EIO; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci nic_data->datapath_caps = MCDI_DWORD(outbuf, 1708c2ecf20Sopenharmony_ci GET_CAPABILITIES_OUT_FLAGS1); 1718c2ecf20Sopenharmony_ci nic_data->datapath_caps2 = MCDI_DWORD(outbuf, 1728c2ecf20Sopenharmony_ci GET_CAPABILITIES_V2_OUT_FLAGS2); 1738c2ecf20Sopenharmony_ci if (outlen < MC_CMD_GET_CAPABILITIES_V7_OUT_LEN) 1748c2ecf20Sopenharmony_ci nic_data->datapath_caps3 = 0; 1758c2ecf20Sopenharmony_ci else 1768c2ecf20Sopenharmony_ci nic_data->datapath_caps3 = MCDI_DWORD(outbuf, 1778c2ecf20Sopenharmony_ci GET_CAPABILITIES_V7_OUT_FLAGS3); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci vi_window_mode = MCDI_BYTE(outbuf, 1808c2ecf20Sopenharmony_ci GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE); 1818c2ecf20Sopenharmony_ci rc = efx_mcdi_window_mode_to_stride(efx, vi_window_mode); 1828c2ecf20Sopenharmony_ci if (rc) 1838c2ecf20Sopenharmony_ci return rc; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (efx_ef100_has_cap(nic_data->datapath_caps2, TX_TSO_V3)) 1868c2ecf20Sopenharmony_ci efx->net_dev->features |= NETIF_F_TSO | NETIF_F_TSO6; 1878c2ecf20Sopenharmony_ci efx->num_mac_stats = MCDI_WORD(outbuf, 1888c2ecf20Sopenharmony_ci GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS); 1898c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 1908c2ecf20Sopenharmony_ci "firmware reports num_mac_stats = %u\n", 1918c2ecf20Sopenharmony_ci efx->num_mac_stats); 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* Event handling 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic int ef100_ev_probe(struct efx_channel *channel) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci /* Allocate an extra descriptor for the QMDA status completion entry */ 2008c2ecf20Sopenharmony_ci return efx_nic_alloc_buffer(channel->efx, &channel->eventq.buf, 2018c2ecf20Sopenharmony_ci (channel->eventq_mask + 2) * 2028c2ecf20Sopenharmony_ci sizeof(efx_qword_t), 2038c2ecf20Sopenharmony_ci GFP_KERNEL); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int ef100_ev_init(struct efx_channel *channel) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = channel->efx->nic_data; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* initial phase is 0 */ 2118c2ecf20Sopenharmony_ci clear_bit(channel->channel, nic_data->evq_phases); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return efx_mcdi_ev_init(channel, false, false); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void ef100_ev_read_ack(struct efx_channel *channel) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci efx_dword_t evq_prime; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci EFX_POPULATE_DWORD_2(evq_prime, 2218c2ecf20Sopenharmony_ci ERF_GZ_EVQ_ID, channel->channel, 2228c2ecf20Sopenharmony_ci ERF_GZ_IDX, channel->eventq_read_ptr & 2238c2ecf20Sopenharmony_ci channel->eventq_mask); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci efx_writed(channel->efx, &evq_prime, 2268c2ecf20Sopenharmony_ci efx_reg(channel->efx, ER_GZ_EVQ_INT_PRIME)); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int ef100_ev_process(struct efx_channel *channel, int quota) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct efx_nic *efx = channel->efx; 2328c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data; 2338c2ecf20Sopenharmony_ci bool evq_phase, old_evq_phase; 2348c2ecf20Sopenharmony_ci unsigned int read_ptr; 2358c2ecf20Sopenharmony_ci efx_qword_t *p_event; 2368c2ecf20Sopenharmony_ci int spent = 0; 2378c2ecf20Sopenharmony_ci bool ev_phase; 2388c2ecf20Sopenharmony_ci int ev_type; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (unlikely(!channel->enabled)) 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci nic_data = efx->nic_data; 2448c2ecf20Sopenharmony_ci evq_phase = test_bit(channel->channel, nic_data->evq_phases); 2458c2ecf20Sopenharmony_ci old_evq_phase = evq_phase; 2468c2ecf20Sopenharmony_ci read_ptr = channel->eventq_read_ptr; 2478c2ecf20Sopenharmony_ci BUILD_BUG_ON(ESF_GZ_EV_RXPKTS_PHASE_LBN != ESF_GZ_EV_TXCMPL_PHASE_LBN); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci while (spent < quota) { 2508c2ecf20Sopenharmony_ci p_event = efx_event(channel, read_ptr); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ev_phase = !!EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_RXPKTS_PHASE); 2538c2ecf20Sopenharmony_ci if (ev_phase != evq_phase) 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci netif_vdbg(efx, drv, efx->net_dev, 2578c2ecf20Sopenharmony_ci "processing event on %d " EFX_QWORD_FMT "\n", 2588c2ecf20Sopenharmony_ci channel->channel, EFX_QWORD_VAL(*p_event)); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ev_type = EFX_QWORD_FIELD(*p_event, ESF_GZ_E_TYPE); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci switch (ev_type) { 2638c2ecf20Sopenharmony_ci case ESE_GZ_EF100_EV_RX_PKTS: 2648c2ecf20Sopenharmony_ci efx_ef100_ev_rx(channel, p_event); 2658c2ecf20Sopenharmony_ci ++spent; 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci case ESE_GZ_EF100_EV_MCDI: 2688c2ecf20Sopenharmony_ci efx_mcdi_process_event(channel, p_event); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case ESE_GZ_EF100_EV_TX_COMPLETION: 2718c2ecf20Sopenharmony_ci ef100_ev_tx(channel, p_event); 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case ESE_GZ_EF100_EV_DRIVER: 2748c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, 2758c2ecf20Sopenharmony_ci "Driver initiated event " EFX_QWORD_FMT "\n", 2768c2ecf20Sopenharmony_ci EFX_QWORD_VAL(*p_event)); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci default: 2798c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, 2808c2ecf20Sopenharmony_ci "Unhandled event " EFX_QWORD_FMT "\n", 2818c2ecf20Sopenharmony_ci EFX_QWORD_VAL(*p_event)); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ++read_ptr; 2858c2ecf20Sopenharmony_ci if ((read_ptr & channel->eventq_mask) == 0) 2868c2ecf20Sopenharmony_ci evq_phase = !evq_phase; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci channel->eventq_read_ptr = read_ptr; 2908c2ecf20Sopenharmony_ci if (evq_phase != old_evq_phase) 2918c2ecf20Sopenharmony_ci change_bit(channel->channel, nic_data->evq_phases); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return spent; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic irqreturn_t ef100_msi_interrupt(int irq, void *dev_id) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct efx_msi_context *context = dev_id; 2998c2ecf20Sopenharmony_ci struct efx_nic *efx = context->efx; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci netif_vdbg(efx, intr, efx->net_dev, 3028c2ecf20Sopenharmony_ci "IRQ %d on CPU %d\n", irq, raw_smp_processor_id()); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (likely(READ_ONCE(efx->irq_soft_enabled))) { 3058c2ecf20Sopenharmony_ci /* Note test interrupts */ 3068c2ecf20Sopenharmony_ci if (context->index == efx->irq_level) 3078c2ecf20Sopenharmony_ci efx->last_irq_cpu = raw_smp_processor_id(); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Schedule processing of the channel */ 3108c2ecf20Sopenharmony_ci efx_schedule_channel_irq(efx->channel[context->index]); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int ef100_phy_probe(struct efx_nic *efx) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct efx_mcdi_phy_data *phy_data; 3198c2ecf20Sopenharmony_ci int rc; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Probe for the PHY */ 3228c2ecf20Sopenharmony_ci efx->phy_data = kzalloc(sizeof(struct efx_mcdi_phy_data), GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (!efx->phy_data) 3248c2ecf20Sopenharmony_ci return -ENOMEM; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci rc = efx_mcdi_get_phy_cfg(efx, efx->phy_data); 3278c2ecf20Sopenharmony_ci if (rc) 3288c2ecf20Sopenharmony_ci return rc; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Populate driver and ethtool settings */ 3318c2ecf20Sopenharmony_ci phy_data = efx->phy_data; 3328c2ecf20Sopenharmony_ci mcdi_to_ethtool_linkset(phy_data->media, phy_data->supported_cap, 3338c2ecf20Sopenharmony_ci efx->link_advertising); 3348c2ecf20Sopenharmony_ci efx->fec_config = mcdi_fec_caps_to_ethtool(phy_data->supported_cap, 3358c2ecf20Sopenharmony_ci false); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Default to Autonegotiated flow control if the PHY supports it */ 3388c2ecf20Sopenharmony_ci efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; 3398c2ecf20Sopenharmony_ci if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 3408c2ecf20Sopenharmony_ci efx->wanted_fc |= EFX_FC_AUTO; 3418c2ecf20Sopenharmony_ci efx_link_set_wanted_fc(efx, efx->wanted_fc); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Push settings to the PHY. Failure is not fatal, the user can try to 3448c2ecf20Sopenharmony_ci * fix it using ethtool. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci rc = efx_mcdi_port_reconfigure(efx); 3478c2ecf20Sopenharmony_ci if (rc && rc != -EPERM) 3488c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 3498c2ecf20Sopenharmony_ci "could not initialise PHY settings\n"); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int ef100_filter_table_probe(struct efx_nic *efx) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci return efx_mcdi_filter_table_probe(efx, true); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int ef100_filter_table_up(struct efx_nic *efx) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci int rc; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci rc = efx_mcdi_filter_add_vlan(efx, EFX_FILTER_VID_UNSPEC); 3648c2ecf20Sopenharmony_ci if (rc) { 3658c2ecf20Sopenharmony_ci efx_mcdi_filter_table_down(efx); 3668c2ecf20Sopenharmony_ci return rc; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci rc = efx_mcdi_filter_add_vlan(efx, 0); 3708c2ecf20Sopenharmony_ci if (rc) { 3718c2ecf20Sopenharmony_ci efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC); 3728c2ecf20Sopenharmony_ci efx_mcdi_filter_table_down(efx); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return rc; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic void ef100_filter_table_down(struct efx_nic *efx) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci efx_mcdi_filter_del_vlan(efx, 0); 3818c2ecf20Sopenharmony_ci efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC); 3828c2ecf20Sopenharmony_ci efx_mcdi_filter_table_down(efx); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/* Other 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic int ef100_reconfigure_mac(struct efx_nic *efx, bool mtu_only) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci efx_mcdi_filter_sync_rx_mode(efx); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (mtu_only && efx_has_cap(efx, SET_MAC_ENHANCED)) 3948c2ecf20Sopenharmony_ci return efx_mcdi_set_mtu(efx); 3958c2ecf20Sopenharmony_ci return efx_mcdi_set_mac(efx); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic enum reset_type ef100_map_reset_reason(enum reset_type reason) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci if (reason == RESET_TYPE_TX_WATCHDOG) 4018c2ecf20Sopenharmony_ci return reason; 4028c2ecf20Sopenharmony_ci return RESET_TYPE_DISABLE; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int ef100_map_reset_flags(u32 *flags) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci /* Only perform a RESET_TYPE_ALL because we don't support MC_REBOOTs */ 4088c2ecf20Sopenharmony_ci if ((*flags & EF100_RESET_PORT)) { 4098c2ecf20Sopenharmony_ci *flags &= ~EF100_RESET_PORT; 4108c2ecf20Sopenharmony_ci return RESET_TYPE_ALL; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci if (*flags & ETH_RESET_MGMT) { 4138c2ecf20Sopenharmony_ci *flags &= ~ETH_RESET_MGMT; 4148c2ecf20Sopenharmony_ci return RESET_TYPE_DISABLE; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int ef100_reset(struct efx_nic *efx, enum reset_type reset_type) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int rc; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci dev_close(efx->net_dev); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (reset_type == RESET_TYPE_TX_WATCHDOG) { 4278c2ecf20Sopenharmony_ci netif_device_attach(efx->net_dev); 4288c2ecf20Sopenharmony_ci __clear_bit(reset_type, &efx->reset_pending); 4298c2ecf20Sopenharmony_ci rc = dev_open(efx->net_dev, NULL); 4308c2ecf20Sopenharmony_ci } else if (reset_type == RESET_TYPE_ALL) { 4318c2ecf20Sopenharmony_ci rc = efx_mcdi_reset(efx, reset_type); 4328c2ecf20Sopenharmony_ci if (rc) 4338c2ecf20Sopenharmony_ci return rc; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci netif_device_attach(efx->net_dev); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci rc = dev_open(efx->net_dev, NULL); 4388c2ecf20Sopenharmony_ci } else { 4398c2ecf20Sopenharmony_ci rc = 1; /* Leave the device closed */ 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return rc; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void ef100_common_stat_mask(unsigned long *mask) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_packets, mask); 4478c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_packets, mask); 4488c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_bytes, mask); 4498c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_bytes, mask); 4508c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_multicast, mask); 4518c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_bad, mask); 4528c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_align_error, mask); 4538c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_overflow, mask); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void ef100_ethtool_stat_mask(unsigned long *mask) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_pause, mask); 4598c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_unicast, mask); 4608c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_multicast, mask); 4618c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_broadcast, mask); 4628c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_lt64, mask); 4638c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_64, mask); 4648c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_65_to_127, mask); 4658c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_128_to_255, mask); 4668c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_256_to_511, mask); 4678c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_512_to_1023, mask); 4688c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_1024_to_15xx, mask); 4698c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_tx_15xx_to_jumbo, mask); 4708c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_good, mask); 4718c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_pause, mask); 4728c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_unicast, mask); 4738c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_broadcast, mask); 4748c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_lt64, mask); 4758c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_64, mask); 4768c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_65_to_127, mask); 4778c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_128_to_255, mask); 4788c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_256_to_511, mask); 4798c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_512_to_1023, mask); 4808c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_1024_to_15xx, mask); 4818c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_15xx_to_jumbo, mask); 4828c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_gtjumbo, mask); 4838c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_bad_gtjumbo, mask); 4848c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_length_error, mask); 4858c2ecf20Sopenharmony_ci __set_bit(EF100_STAT_port_rx_nodesc_drops, mask); 4868c2ecf20Sopenharmony_ci __set_bit(GENERIC_STAT_rx_nodesc_trunc, mask); 4878c2ecf20Sopenharmony_ci __set_bit(GENERIC_STAT_rx_noskb_drops, mask); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci#define EF100_DMA_STAT(ext_name, mcdi_name) \ 4918c2ecf20Sopenharmony_ci [EF100_STAT_ ## ext_name] = \ 4928c2ecf20Sopenharmony_ci { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic const struct efx_hw_stat_desc ef100_stat_desc[EF100_STAT_COUNT] = { 4958c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_bytes, TX_BYTES), 4968c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_packets, TX_PKTS), 4978c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_pause, TX_PAUSE_PKTS), 4988c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_unicast, TX_UNICAST_PKTS), 4998c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_multicast, TX_MULTICAST_PKTS), 5008c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_broadcast, TX_BROADCAST_PKTS), 5018c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_lt64, TX_LT64_PKTS), 5028c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_64, TX_64_PKTS), 5038c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_65_to_127, TX_65_TO_127_PKTS), 5048c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_128_to_255, TX_128_TO_255_PKTS), 5058c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_256_to_511, TX_256_TO_511_PKTS), 5068c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_512_to_1023, TX_512_TO_1023_PKTS), 5078c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_1024_to_15xx, TX_1024_TO_15XX_PKTS), 5088c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS), 5098c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_bytes, RX_BYTES), 5108c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_packets, RX_PKTS), 5118c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_good, RX_GOOD_PKTS), 5128c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_bad, RX_BAD_FCS_PKTS), 5138c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_pause, RX_PAUSE_PKTS), 5148c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_unicast, RX_UNICAST_PKTS), 5158c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_multicast, RX_MULTICAST_PKTS), 5168c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_broadcast, RX_BROADCAST_PKTS), 5178c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_lt64, RX_UNDERSIZE_PKTS), 5188c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_64, RX_64_PKTS), 5198c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_65_to_127, RX_65_TO_127_PKTS), 5208c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_128_to_255, RX_128_TO_255_PKTS), 5218c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_256_to_511, RX_256_TO_511_PKTS), 5228c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_512_to_1023, RX_512_TO_1023_PKTS), 5238c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_1024_to_15xx, RX_1024_TO_15XX_PKTS), 5248c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS), 5258c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_gtjumbo, RX_GTJUMBO_PKTS), 5268c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_bad_gtjumbo, RX_JABBER_PKTS), 5278c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_align_error, RX_ALIGN_ERROR_PKTS), 5288c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_length_error, RX_LENGTH_ERROR_PKTS), 5298c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_overflow, RX_OVERFLOW_PKTS), 5308c2ecf20Sopenharmony_ci EF100_DMA_STAT(port_rx_nodesc_drops, RX_NODESC_DROPS), 5318c2ecf20Sopenharmony_ci EFX_GENERIC_SW_STAT(rx_nodesc_trunc), 5328c2ecf20Sopenharmony_ci EFX_GENERIC_SW_STAT(rx_noskb_drops), 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic size_t ef100_describe_stats(struct efx_nic *efx, u8 *names) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ef100_ethtool_stat_mask(mask); 5408c2ecf20Sopenharmony_ci return efx_nic_describe_stats(ef100_stat_desc, EF100_STAT_COUNT, 5418c2ecf20Sopenharmony_ci mask, names); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic size_t ef100_update_stats_common(struct efx_nic *efx, u64 *full_stats, 5458c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *core_stats) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 5488c2ecf20Sopenharmony_ci DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; 5498c2ecf20Sopenharmony_ci size_t stats_count = 0, index; 5508c2ecf20Sopenharmony_ci u64 *stats = nic_data->stats; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ef100_ethtool_stat_mask(mask); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (full_stats) { 5558c2ecf20Sopenharmony_ci for_each_set_bit(index, mask, EF100_STAT_COUNT) { 5568c2ecf20Sopenharmony_ci if (ef100_stat_desc[index].name) { 5578c2ecf20Sopenharmony_ci *full_stats++ = stats[index]; 5588c2ecf20Sopenharmony_ci ++stats_count; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!core_stats) 5648c2ecf20Sopenharmony_ci return stats_count; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci core_stats->rx_packets = stats[EF100_STAT_port_rx_packets]; 5678c2ecf20Sopenharmony_ci core_stats->tx_packets = stats[EF100_STAT_port_tx_packets]; 5688c2ecf20Sopenharmony_ci core_stats->rx_bytes = stats[EF100_STAT_port_rx_bytes]; 5698c2ecf20Sopenharmony_ci core_stats->tx_bytes = stats[EF100_STAT_port_tx_bytes]; 5708c2ecf20Sopenharmony_ci core_stats->rx_dropped = stats[EF100_STAT_port_rx_nodesc_drops] + 5718c2ecf20Sopenharmony_ci stats[GENERIC_STAT_rx_nodesc_trunc] + 5728c2ecf20Sopenharmony_ci stats[GENERIC_STAT_rx_noskb_drops]; 5738c2ecf20Sopenharmony_ci core_stats->multicast = stats[EF100_STAT_port_rx_multicast]; 5748c2ecf20Sopenharmony_ci core_stats->rx_length_errors = 5758c2ecf20Sopenharmony_ci stats[EF100_STAT_port_rx_gtjumbo] + 5768c2ecf20Sopenharmony_ci stats[EF100_STAT_port_rx_length_error]; 5778c2ecf20Sopenharmony_ci core_stats->rx_crc_errors = stats[EF100_STAT_port_rx_bad]; 5788c2ecf20Sopenharmony_ci core_stats->rx_frame_errors = 5798c2ecf20Sopenharmony_ci stats[EF100_STAT_port_rx_align_error]; 5808c2ecf20Sopenharmony_ci core_stats->rx_fifo_errors = stats[EF100_STAT_port_rx_overflow]; 5818c2ecf20Sopenharmony_ci core_stats->rx_errors = (core_stats->rx_length_errors + 5828c2ecf20Sopenharmony_ci core_stats->rx_crc_errors + 5838c2ecf20Sopenharmony_ci core_stats->rx_frame_errors); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return stats_count; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic size_t ef100_update_stats(struct efx_nic *efx, 5898c2ecf20Sopenharmony_ci u64 *full_stats, 5908c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *core_stats) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci __le64 *mc_stats = kmalloc(array_size(efx->num_mac_stats, sizeof(__le64)), GFP_ATOMIC); 5938c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 5948c2ecf20Sopenharmony_ci DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; 5958c2ecf20Sopenharmony_ci u64 *stats = nic_data->stats; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci ef100_common_stat_mask(mask); 5988c2ecf20Sopenharmony_ci ef100_ethtool_stat_mask(mask); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (!mc_stats) 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci efx_nic_copy_stats(efx, mc_stats); 6048c2ecf20Sopenharmony_ci efx_nic_update_stats(ef100_stat_desc, EF100_STAT_COUNT, mask, 6058c2ecf20Sopenharmony_ci stats, mc_stats, false); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci kfree(mc_stats); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return ef100_update_stats_common(efx, full_stats, core_stats); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int efx_ef100_get_phys_port_id(struct efx_nic *efx, 6138c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(nic_data->port_id)) 6188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ppid->id_len = ETH_ALEN; 6218c2ecf20Sopenharmony_ci memcpy(ppid->id, nic_data->port_id, ppid->id_len); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int efx_ef100_irq_test_generate(struct efx_nic *efx) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_TRIGGER_INTERRUPT_IN_LEN); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_TRIGGER_INTERRUPT_OUT_LEN != 0); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, TRIGGER_INTERRUPT_IN_INTR_LEVEL, efx->irq_level); 6338c2ecf20Sopenharmony_ci return efx_mcdi_rpc_quiet(efx, MC_CMD_TRIGGER_INTERRUPT, 6348c2ecf20Sopenharmony_ci inbuf, sizeof(inbuf), NULL, 0, NULL); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci#define EFX_EF100_TEST 1 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic void efx_ef100_ev_test_generate(struct efx_channel *channel) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_DRIVER_EVENT_IN_LEN); 6428c2ecf20Sopenharmony_ci struct efx_nic *efx = channel->efx; 6438c2ecf20Sopenharmony_ci efx_qword_t event; 6448c2ecf20Sopenharmony_ci int rc; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci EFX_POPULATE_QWORD_2(event, 6478c2ecf20Sopenharmony_ci ESF_GZ_E_TYPE, ESE_GZ_EF100_EV_DRIVER, 6488c2ecf20Sopenharmony_ci ESF_GZ_DRIVER_DATA, EFX_EF100_TEST); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, DRIVER_EVENT_IN_EVQ, channel->channel); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* MCDI_SET_QWORD is not appropriate here since EFX_POPULATE_* has 6538c2ecf20Sopenharmony_ci * already swapped the data to little-endian order. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci memcpy(MCDI_PTR(inbuf, DRIVER_EVENT_IN_DATA), &event.u64[0], 6568c2ecf20Sopenharmony_ci sizeof(efx_qword_t)); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_DRIVER_EVENT, inbuf, sizeof(inbuf), 6598c2ecf20Sopenharmony_ci NULL, 0, NULL); 6608c2ecf20Sopenharmony_ci if (rc && (rc != -ENETDOWN)) 6618c2ecf20Sopenharmony_ci goto fail; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cifail: 6668c2ecf20Sopenharmony_ci WARN_ON(true); 6678c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic unsigned int ef100_check_caps(const struct efx_nic *efx, 6718c2ecf20Sopenharmony_ci u8 flag, u32 offset) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci const struct ef100_nic_data *nic_data = efx->nic_data; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci switch (offset) { 6768c2ecf20Sopenharmony_ci case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS1_OFST: 6778c2ecf20Sopenharmony_ci return nic_data->datapath_caps & BIT_ULL(flag); 6788c2ecf20Sopenharmony_ci case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS2_OFST: 6798c2ecf20Sopenharmony_ci return nic_data->datapath_caps2 & BIT_ULL(flag); 6808c2ecf20Sopenharmony_ci case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS3_OFST: 6818c2ecf20Sopenharmony_ci return nic_data->datapath_caps3 & BIT_ULL(flag); 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* NIC level access functions 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci#define EF100_OFFLOAD_FEATURES (NETIF_F_HW_CSUM | NETIF_F_RXCSUM | \ 6908c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_NTUPLE | \ 6918c2ecf20Sopenharmony_ci NETIF_F_RXHASH | NETIF_F_RXFCS | NETIF_F_TSO_ECN | NETIF_F_RXALL | \ 6928c2ecf20Sopenharmony_ci NETIF_F_TSO_MANGLEID | NETIF_F_HW_VLAN_CTAG_TX) 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ciconst struct efx_nic_type ef100_pf_nic_type = { 6958c2ecf20Sopenharmony_ci .revision = EFX_REV_EF100, 6968c2ecf20Sopenharmony_ci .is_vf = false, 6978c2ecf20Sopenharmony_ci .probe = ef100_probe_pf, 6988c2ecf20Sopenharmony_ci .offload_features = EF100_OFFLOAD_FEATURES, 6998c2ecf20Sopenharmony_ci .mcdi_max_ver = 2, 7008c2ecf20Sopenharmony_ci .mcdi_request = ef100_mcdi_request, 7018c2ecf20Sopenharmony_ci .mcdi_poll_response = ef100_mcdi_poll_response, 7028c2ecf20Sopenharmony_ci .mcdi_read_response = ef100_mcdi_read_response, 7038c2ecf20Sopenharmony_ci .mcdi_poll_reboot = ef100_mcdi_poll_reboot, 7048c2ecf20Sopenharmony_ci .mcdi_reboot_detected = ef100_mcdi_reboot_detected, 7058c2ecf20Sopenharmony_ci .irq_enable_master = efx_port_dummy_op_void, 7068c2ecf20Sopenharmony_ci .irq_test_generate = efx_ef100_irq_test_generate, 7078c2ecf20Sopenharmony_ci .irq_disable_non_ev = efx_port_dummy_op_void, 7088c2ecf20Sopenharmony_ci .push_irq_moderation = efx_channel_dummy_op_void, 7098c2ecf20Sopenharmony_ci .min_interrupt_mode = EFX_INT_MODE_MSIX, 7108c2ecf20Sopenharmony_ci .map_reset_reason = ef100_map_reset_reason, 7118c2ecf20Sopenharmony_ci .map_reset_flags = ef100_map_reset_flags, 7128c2ecf20Sopenharmony_ci .reset = ef100_reset, 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci .check_caps = ef100_check_caps, 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci .ev_probe = ef100_ev_probe, 7178c2ecf20Sopenharmony_ci .ev_init = ef100_ev_init, 7188c2ecf20Sopenharmony_ci .ev_fini = efx_mcdi_ev_fini, 7198c2ecf20Sopenharmony_ci .ev_remove = efx_mcdi_ev_remove, 7208c2ecf20Sopenharmony_ci .irq_handle_msi = ef100_msi_interrupt, 7218c2ecf20Sopenharmony_ci .ev_process = ef100_ev_process, 7228c2ecf20Sopenharmony_ci .ev_read_ack = ef100_ev_read_ack, 7238c2ecf20Sopenharmony_ci .ev_test_generate = efx_ef100_ev_test_generate, 7248c2ecf20Sopenharmony_ci .tx_probe = ef100_tx_probe, 7258c2ecf20Sopenharmony_ci .tx_init = ef100_tx_init, 7268c2ecf20Sopenharmony_ci .tx_write = ef100_tx_write, 7278c2ecf20Sopenharmony_ci .tx_enqueue = ef100_enqueue_skb, 7288c2ecf20Sopenharmony_ci .rx_probe = efx_mcdi_rx_probe, 7298c2ecf20Sopenharmony_ci .rx_init = efx_mcdi_rx_init, 7308c2ecf20Sopenharmony_ci .rx_remove = efx_mcdi_rx_remove, 7318c2ecf20Sopenharmony_ci .rx_write = ef100_rx_write, 7328c2ecf20Sopenharmony_ci .rx_packet = __ef100_rx_packet, 7338c2ecf20Sopenharmony_ci .rx_buf_hash_valid = ef100_rx_buf_hash_valid, 7348c2ecf20Sopenharmony_ci .fini_dmaq = efx_fini_dmaq, 7358c2ecf20Sopenharmony_ci .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS, 7368c2ecf20Sopenharmony_ci .filter_table_probe = ef100_filter_table_up, 7378c2ecf20Sopenharmony_ci .filter_table_restore = efx_mcdi_filter_table_restore, 7388c2ecf20Sopenharmony_ci .filter_table_remove = ef100_filter_table_down, 7398c2ecf20Sopenharmony_ci .filter_insert = efx_mcdi_filter_insert, 7408c2ecf20Sopenharmony_ci .filter_remove_safe = efx_mcdi_filter_remove_safe, 7418c2ecf20Sopenharmony_ci .filter_get_safe = efx_mcdi_filter_get_safe, 7428c2ecf20Sopenharmony_ci .filter_clear_rx = efx_mcdi_filter_clear_rx, 7438c2ecf20Sopenharmony_ci .filter_count_rx_used = efx_mcdi_filter_count_rx_used, 7448c2ecf20Sopenharmony_ci .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit, 7458c2ecf20Sopenharmony_ci .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids, 7468c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 7478c2ecf20Sopenharmony_ci .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one, 7488c2ecf20Sopenharmony_ci#endif 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci .get_phys_port_id = efx_ef100_get_phys_port_id, 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN, 7538c2ecf20Sopenharmony_ci .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8, 7548c2ecf20Sopenharmony_ci .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8, 7558c2ecf20Sopenharmony_ci .rx_hash_key_size = 40, 7568c2ecf20Sopenharmony_ci .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, 7578c2ecf20Sopenharmony_ci .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config, 7588c2ecf20Sopenharmony_ci .rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_config, 7598c2ecf20Sopenharmony_ci .rx_pull_rss_context_config = efx_mcdi_rx_pull_rss_context_config, 7608c2ecf20Sopenharmony_ci .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts, 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci .reconfigure_mac = ef100_reconfigure_mac, 7638c2ecf20Sopenharmony_ci .reconfigure_port = efx_mcdi_port_reconfigure, 7648c2ecf20Sopenharmony_ci .test_nvram = efx_new_mcdi_nvram_test_all, 7658c2ecf20Sopenharmony_ci .describe_stats = ef100_describe_stats, 7668c2ecf20Sopenharmony_ci .start_stats = efx_mcdi_mac_start_stats, 7678c2ecf20Sopenharmony_ci .update_stats = ef100_update_stats, 7688c2ecf20Sopenharmony_ci .pull_stats = efx_mcdi_mac_pull_stats, 7698c2ecf20Sopenharmony_ci .stop_stats = efx_mcdi_mac_stop_stats, 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Per-type bar/size configuration not used on ef100. Location of 7728c2ecf20Sopenharmony_ci * registers is defined by extended capabilities. 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci .mem_bar = NULL, 7758c2ecf20Sopenharmony_ci .mem_map_size = NULL, 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci}; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ciconst struct efx_nic_type ef100_vf_nic_type = { 7808c2ecf20Sopenharmony_ci .revision = EFX_REV_EF100, 7818c2ecf20Sopenharmony_ci .is_vf = true, 7828c2ecf20Sopenharmony_ci .probe = ef100_probe_vf, 7838c2ecf20Sopenharmony_ci .offload_features = EF100_OFFLOAD_FEATURES, 7848c2ecf20Sopenharmony_ci .mcdi_max_ver = 2, 7858c2ecf20Sopenharmony_ci .mcdi_request = ef100_mcdi_request, 7868c2ecf20Sopenharmony_ci .mcdi_poll_response = ef100_mcdi_poll_response, 7878c2ecf20Sopenharmony_ci .mcdi_read_response = ef100_mcdi_read_response, 7888c2ecf20Sopenharmony_ci .mcdi_poll_reboot = ef100_mcdi_poll_reboot, 7898c2ecf20Sopenharmony_ci .mcdi_reboot_detected = ef100_mcdi_reboot_detected, 7908c2ecf20Sopenharmony_ci .irq_enable_master = efx_port_dummy_op_void, 7918c2ecf20Sopenharmony_ci .irq_test_generate = efx_ef100_irq_test_generate, 7928c2ecf20Sopenharmony_ci .irq_disable_non_ev = efx_port_dummy_op_void, 7938c2ecf20Sopenharmony_ci .push_irq_moderation = efx_channel_dummy_op_void, 7948c2ecf20Sopenharmony_ci .min_interrupt_mode = EFX_INT_MODE_MSIX, 7958c2ecf20Sopenharmony_ci .map_reset_reason = ef100_map_reset_reason, 7968c2ecf20Sopenharmony_ci .map_reset_flags = ef100_map_reset_flags, 7978c2ecf20Sopenharmony_ci .reset = ef100_reset, 7988c2ecf20Sopenharmony_ci .check_caps = ef100_check_caps, 7998c2ecf20Sopenharmony_ci .ev_probe = ef100_ev_probe, 8008c2ecf20Sopenharmony_ci .ev_init = ef100_ev_init, 8018c2ecf20Sopenharmony_ci .ev_fini = efx_mcdi_ev_fini, 8028c2ecf20Sopenharmony_ci .ev_remove = efx_mcdi_ev_remove, 8038c2ecf20Sopenharmony_ci .irq_handle_msi = ef100_msi_interrupt, 8048c2ecf20Sopenharmony_ci .ev_process = ef100_ev_process, 8058c2ecf20Sopenharmony_ci .ev_read_ack = ef100_ev_read_ack, 8068c2ecf20Sopenharmony_ci .ev_test_generate = efx_ef100_ev_test_generate, 8078c2ecf20Sopenharmony_ci .tx_probe = ef100_tx_probe, 8088c2ecf20Sopenharmony_ci .tx_init = ef100_tx_init, 8098c2ecf20Sopenharmony_ci .tx_write = ef100_tx_write, 8108c2ecf20Sopenharmony_ci .tx_enqueue = ef100_enqueue_skb, 8118c2ecf20Sopenharmony_ci .rx_probe = efx_mcdi_rx_probe, 8128c2ecf20Sopenharmony_ci .rx_init = efx_mcdi_rx_init, 8138c2ecf20Sopenharmony_ci .rx_remove = efx_mcdi_rx_remove, 8148c2ecf20Sopenharmony_ci .rx_write = ef100_rx_write, 8158c2ecf20Sopenharmony_ci .rx_packet = __ef100_rx_packet, 8168c2ecf20Sopenharmony_ci .rx_buf_hash_valid = ef100_rx_buf_hash_valid, 8178c2ecf20Sopenharmony_ci .fini_dmaq = efx_fini_dmaq, 8188c2ecf20Sopenharmony_ci .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS, 8198c2ecf20Sopenharmony_ci .filter_table_probe = ef100_filter_table_up, 8208c2ecf20Sopenharmony_ci .filter_table_restore = efx_mcdi_filter_table_restore, 8218c2ecf20Sopenharmony_ci .filter_table_remove = ef100_filter_table_down, 8228c2ecf20Sopenharmony_ci .filter_insert = efx_mcdi_filter_insert, 8238c2ecf20Sopenharmony_ci .filter_remove_safe = efx_mcdi_filter_remove_safe, 8248c2ecf20Sopenharmony_ci .filter_get_safe = efx_mcdi_filter_get_safe, 8258c2ecf20Sopenharmony_ci .filter_clear_rx = efx_mcdi_filter_clear_rx, 8268c2ecf20Sopenharmony_ci .filter_count_rx_used = efx_mcdi_filter_count_rx_used, 8278c2ecf20Sopenharmony_ci .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit, 8288c2ecf20Sopenharmony_ci .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids, 8298c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 8308c2ecf20Sopenharmony_ci .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one, 8318c2ecf20Sopenharmony_ci#endif 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN, 8348c2ecf20Sopenharmony_ci .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8, 8358c2ecf20Sopenharmony_ci .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8, 8368c2ecf20Sopenharmony_ci .rx_hash_key_size = 40, 8378c2ecf20Sopenharmony_ci .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, 8388c2ecf20Sopenharmony_ci .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config, 8398c2ecf20Sopenharmony_ci .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts, 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci .reconfigure_mac = ef100_reconfigure_mac, 8428c2ecf20Sopenharmony_ci .test_nvram = efx_new_mcdi_nvram_test_all, 8438c2ecf20Sopenharmony_ci .describe_stats = ef100_describe_stats, 8448c2ecf20Sopenharmony_ci .start_stats = efx_mcdi_mac_start_stats, 8458c2ecf20Sopenharmony_ci .update_stats = ef100_update_stats, 8468c2ecf20Sopenharmony_ci .pull_stats = efx_mcdi_mac_pull_stats, 8478c2ecf20Sopenharmony_ci .stop_stats = efx_mcdi_mac_stop_stats, 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci .mem_bar = NULL, 8508c2ecf20Sopenharmony_ci .mem_map_size = NULL, 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci}; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic int compare_versions(const char *a, const char *b) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci int a_major, a_minor, a_point, a_patch; 8578c2ecf20Sopenharmony_ci int b_major, b_minor, b_point, b_patch; 8588c2ecf20Sopenharmony_ci int a_matched, b_matched; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci a_matched = sscanf(a, "%d.%d.%d.%d", &a_major, &a_minor, &a_point, &a_patch); 8618c2ecf20Sopenharmony_ci b_matched = sscanf(b, "%d.%d.%d.%d", &b_major, &b_minor, &b_point, &b_patch); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (a_matched == 4 && b_matched != 4) 8648c2ecf20Sopenharmony_ci return +1; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (a_matched != 4 && b_matched == 4) 8678c2ecf20Sopenharmony_ci return -1; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (a_matched != 4 && b_matched != 4) 8708c2ecf20Sopenharmony_ci return 0; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (a_major != b_major) 8738c2ecf20Sopenharmony_ci return a_major - b_major; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (a_minor != b_minor) 8768c2ecf20Sopenharmony_ci return a_minor - b_minor; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (a_point != b_point) 8798c2ecf20Sopenharmony_ci return a_point - b_point; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return a_patch - b_patch; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cienum ef100_tlv_state_machine { 8858c2ecf20Sopenharmony_ci EF100_TLV_TYPE, 8868c2ecf20Sopenharmony_ci EF100_TLV_TYPE_CONT, 8878c2ecf20Sopenharmony_ci EF100_TLV_LENGTH, 8888c2ecf20Sopenharmony_ci EF100_TLV_VALUE 8898c2ecf20Sopenharmony_ci}; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistruct ef100_tlv_state { 8928c2ecf20Sopenharmony_ci enum ef100_tlv_state_machine state; 8938c2ecf20Sopenharmony_ci u64 value; 8948c2ecf20Sopenharmony_ci u32 value_offset; 8958c2ecf20Sopenharmony_ci u16 type; 8968c2ecf20Sopenharmony_ci u8 len; 8978c2ecf20Sopenharmony_ci}; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int ef100_tlv_feed(struct ef100_tlv_state *state, u8 byte) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci switch (state->state) { 9028c2ecf20Sopenharmony_ci case EF100_TLV_TYPE: 9038c2ecf20Sopenharmony_ci state->type = byte & 0x7f; 9048c2ecf20Sopenharmony_ci state->state = (byte & 0x80) ? EF100_TLV_TYPE_CONT 9058c2ecf20Sopenharmony_ci : EF100_TLV_LENGTH; 9068c2ecf20Sopenharmony_ci /* Clear ready to read in a new entry */ 9078c2ecf20Sopenharmony_ci state->value = 0; 9088c2ecf20Sopenharmony_ci state->value_offset = 0; 9098c2ecf20Sopenharmony_ci return 0; 9108c2ecf20Sopenharmony_ci case EF100_TLV_TYPE_CONT: 9118c2ecf20Sopenharmony_ci state->type |= byte << 7; 9128c2ecf20Sopenharmony_ci state->state = EF100_TLV_LENGTH; 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci case EF100_TLV_LENGTH: 9158c2ecf20Sopenharmony_ci state->len = byte; 9168c2ecf20Sopenharmony_ci /* We only handle TLVs that fit in a u64 */ 9178c2ecf20Sopenharmony_ci if (state->len > sizeof(state->value)) 9188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9198c2ecf20Sopenharmony_ci /* len may be zero, implying a value of zero */ 9208c2ecf20Sopenharmony_ci state->state = state->len ? EF100_TLV_VALUE : EF100_TLV_TYPE; 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci case EF100_TLV_VALUE: 9238c2ecf20Sopenharmony_ci state->value |= ((u64)byte) << (state->value_offset * 8); 9248c2ecf20Sopenharmony_ci state->value_offset++; 9258c2ecf20Sopenharmony_ci if (state->value_offset >= state->len) 9268c2ecf20Sopenharmony_ci state->state = EF100_TLV_TYPE; 9278c2ecf20Sopenharmony_ci return 0; 9288c2ecf20Sopenharmony_ci default: /* state machine error, can't happen */ 9298c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 9308c2ecf20Sopenharmony_ci return -EIO; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic int ef100_process_design_param(struct efx_nic *efx, 9358c2ecf20Sopenharmony_ci const struct ef100_tlv_state *reader) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci switch (reader->type) { 9408c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_PAD: /* padding, skip it */ 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_PARTIAL_TSTAMP_SUB_NANO_BITS: 9438c2ecf20Sopenharmony_ci /* Driver doesn't support timestamping yet, so we don't care */ 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_EVQ_UNSOL_CREDIT_SEQ_BITS: 9468c2ecf20Sopenharmony_ci /* Driver doesn't support unsolicited-event credits yet, so 9478c2ecf20Sopenharmony_ci * we don't care 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci return 0; 9508c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_NMMU_GROUP_SIZE: 9518c2ecf20Sopenharmony_ci /* Driver doesn't manage the NMMU (so we don't care) */ 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_RX_L4_CSUM_PROTOCOLS: 9548c2ecf20Sopenharmony_ci /* Driver uses CHECKSUM_COMPLETE, so we don't care about 9558c2ecf20Sopenharmony_ci * protocol checksum validation 9568c2ecf20Sopenharmony_ci */ 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN: 9598c2ecf20Sopenharmony_ci nic_data->tso_max_hdr_len = min_t(u64, reader->value, 0xffff); 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS: 9628c2ecf20Sopenharmony_ci /* We always put HDR_NUM_SEGS=1 in our TSO descriptors */ 9638c2ecf20Sopenharmony_ci if (!reader->value) { 9648c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 9658c2ecf20Sopenharmony_ci "TSO_MAX_HDR_NUM_SEGS < 1\n"); 9668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY: 9708c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TXQ_SIZE_GRANULARITY: 9718c2ecf20Sopenharmony_ci /* Our TXQ and RXQ sizes are always power-of-two and thus divisible by 9728c2ecf20Sopenharmony_ci * EFX_MIN_DMAQ_SIZE, so we just need to check that 9738c2ecf20Sopenharmony_ci * EFX_MIN_DMAQ_SIZE is divisible by GRANULARITY. 9748c2ecf20Sopenharmony_ci * This is very unlikely to fail. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_ci if (!reader->value || reader->value > EFX_MIN_DMAQ_SIZE || 9778c2ecf20Sopenharmony_ci EFX_MIN_DMAQ_SIZE % (u32)reader->value) { 9788c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 9798c2ecf20Sopenharmony_ci "%s size granularity is %llu, can't guarantee safety\n", 9808c2ecf20Sopenharmony_ci reader->type == ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY ? "RXQ" : "TXQ", 9818c2ecf20Sopenharmony_ci reader->value); 9828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci return 0; 9858c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN: 9868c2ecf20Sopenharmony_ci nic_data->tso_max_payload_len = min_t(u64, reader->value, GSO_MAX_SIZE); 9878c2ecf20Sopenharmony_ci efx->net_dev->gso_max_size = nic_data->tso_max_payload_len; 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS: 9908c2ecf20Sopenharmony_ci nic_data->tso_max_payload_num_segs = min_t(u64, reader->value, 0xffff); 9918c2ecf20Sopenharmony_ci efx->net_dev->gso_max_segs = nic_data->tso_max_payload_num_segs; 9928c2ecf20Sopenharmony_ci return 0; 9938c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES: 9948c2ecf20Sopenharmony_ci nic_data->tso_max_frames = min_t(u64, reader->value, 0xffff); 9958c2ecf20Sopenharmony_ci return 0; 9968c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_COMPAT: 9978c2ecf20Sopenharmony_ci if (reader->value) { 9988c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 9998c2ecf20Sopenharmony_ci "DP_COMPAT has unknown bits %#llx, driver not compatible with this hw\n", 10008c2ecf20Sopenharmony_ci reader->value); 10018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_MEM2MEM_MAX_LEN: 10058c2ecf20Sopenharmony_ci /* Driver doesn't use mem2mem transfers */ 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_EVQ_TIMER_TICK_NANOS: 10088c2ecf20Sopenharmony_ci /* Driver doesn't currently use EVQ_TIMER */ 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_NMMU_PAGE_SIZES: 10118c2ecf20Sopenharmony_ci /* Driver doesn't manage the NMMU (so we don't care) */ 10128c2ecf20Sopenharmony_ci return 0; 10138c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_VI_STRIDES: 10148c2ecf20Sopenharmony_ci /* We never try to set the VI stride, and we don't rely on 10158c2ecf20Sopenharmony_ci * being able to find VIs past VI 0 until after we've learned 10168c2ecf20Sopenharmony_ci * the current stride from MC_CMD_GET_CAPABILITIES. 10178c2ecf20Sopenharmony_ci * So the value of this shouldn't matter. 10188c2ecf20Sopenharmony_ci */ 10198c2ecf20Sopenharmony_ci if (reader->value != ESE_EF100_DP_GZ_VI_STRIDES_DEFAULT) 10208c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 10218c2ecf20Sopenharmony_ci "NIC has other than default VI_STRIDES (mask " 10228c2ecf20Sopenharmony_ci "%#llx), early probing might use wrong one\n", 10238c2ecf20Sopenharmony_ci reader->value); 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci case ESE_EF100_DP_GZ_RX_MAX_RUNT: 10268c2ecf20Sopenharmony_ci /* Driver doesn't look at L2_STATUS:LEN_ERR bit, so we don't 10278c2ecf20Sopenharmony_ci * care whether it indicates runt or overlength for any given 10288c2ecf20Sopenharmony_ci * packet, so we don't care about this parameter. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci default: 10328c2ecf20Sopenharmony_ci /* Host interface says "Drivers should ignore design parameters 10338c2ecf20Sopenharmony_ci * that they do not recognise." 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 10368c2ecf20Sopenharmony_ci "Ignoring unrecognised design parameter %u\n", 10378c2ecf20Sopenharmony_ci reader->type); 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic int ef100_check_design_params(struct efx_nic *efx) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct ef100_tlv_state reader = {}; 10458c2ecf20Sopenharmony_ci u32 total_len, offset = 0; 10468c2ecf20Sopenharmony_ci efx_dword_t reg; 10478c2ecf20Sopenharmony_ci int rc = 0, i; 10488c2ecf20Sopenharmony_ci u32 data; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci efx_readd(efx, ®, ER_GZ_PARAMS_TLV_LEN); 10518c2ecf20Sopenharmony_ci total_len = EFX_DWORD_FIELD(reg, EFX_DWORD_0); 10528c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "%u bytes of design parameters\n", 10538c2ecf20Sopenharmony_ci total_len); 10548c2ecf20Sopenharmony_ci while (offset < total_len) { 10558c2ecf20Sopenharmony_ci efx_readd(efx, ®, ER_GZ_PARAMS_TLV + offset); 10568c2ecf20Sopenharmony_ci data = EFX_DWORD_FIELD(reg, EFX_DWORD_0); 10578c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(data); i++) { 10588c2ecf20Sopenharmony_ci rc = ef100_tlv_feed(&reader, data); 10598c2ecf20Sopenharmony_ci /* Got a complete value? */ 10608c2ecf20Sopenharmony_ci if (!rc && reader.state == EF100_TLV_TYPE) 10618c2ecf20Sopenharmony_ci rc = ef100_process_design_param(efx, &reader); 10628c2ecf20Sopenharmony_ci if (rc) 10638c2ecf20Sopenharmony_ci goto out; 10648c2ecf20Sopenharmony_ci data >>= 8; 10658c2ecf20Sopenharmony_ci offset++; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci /* Check we didn't end halfway through a TLV entry, which could either 10698c2ecf20Sopenharmony_ci * mean that the TLV stream is truncated or just that it's corrupted 10708c2ecf20Sopenharmony_ci * and our state machine is out of sync. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci if (reader.state != EF100_TLV_TYPE) { 10738c2ecf20Sopenharmony_ci if (reader.state == EF100_TLV_TYPE_CONT) 10748c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 10758c2ecf20Sopenharmony_ci "truncated design parameter (incomplete type %u)\n", 10768c2ecf20Sopenharmony_ci reader.type); 10778c2ecf20Sopenharmony_ci else 10788c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 10798c2ecf20Sopenharmony_ci "truncated design parameter %u\n", 10808c2ecf20Sopenharmony_ci reader.type); 10818c2ecf20Sopenharmony_ci rc = -EIO; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ciout: 10848c2ecf20Sopenharmony_ci return rc; 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci/* NIC probe and remove 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_cistatic int ef100_probe_main(struct efx_nic *efx) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci unsigned int bar_size = resource_size(&efx->pci_dev->resource[efx->mem_bar]); 10928c2ecf20Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 10938c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data; 10948c2ecf20Sopenharmony_ci char fw_version[32]; 10958c2ecf20Sopenharmony_ci int i, rc; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (WARN_ON(bar_size == 0)) 10988c2ecf20Sopenharmony_ci return -EIO; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); 11018c2ecf20Sopenharmony_ci if (!nic_data) 11028c2ecf20Sopenharmony_ci return -ENOMEM; 11038c2ecf20Sopenharmony_ci efx->nic_data = nic_data; 11048c2ecf20Sopenharmony_ci nic_data->efx = efx; 11058c2ecf20Sopenharmony_ci net_dev->features |= efx->type->offload_features; 11068c2ecf20Sopenharmony_ci net_dev->hw_features |= efx->type->offload_features; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* Populate design-parameter defaults */ 11098c2ecf20Sopenharmony_ci nic_data->tso_max_hdr_len = ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT; 11108c2ecf20Sopenharmony_ci nic_data->tso_max_frames = ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES_DEFAULT; 11118c2ecf20Sopenharmony_ci nic_data->tso_max_payload_num_segs = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS_DEFAULT; 11128c2ecf20Sopenharmony_ci nic_data->tso_max_payload_len = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN_DEFAULT; 11138c2ecf20Sopenharmony_ci net_dev->gso_max_segs = ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS_DEFAULT; 11148c2ecf20Sopenharmony_ci /* Read design parameters */ 11158c2ecf20Sopenharmony_ci rc = ef100_check_design_params(efx); 11168c2ecf20Sopenharmony_ci if (rc) { 11178c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 11188c2ecf20Sopenharmony_ci "Unsupported design parameters\n"); 11198c2ecf20Sopenharmony_ci goto fail; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* we assume later that we can copy from this buffer in dwords */ 11238c2ecf20Sopenharmony_ci BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* MCDI buffers must be 256 byte aligned. */ 11268c2ecf20Sopenharmony_ci rc = efx_nic_alloc_buffer(efx, &nic_data->mcdi_buf, MCDI_BUF_LEN, 11278c2ecf20Sopenharmony_ci GFP_KERNEL); 11288c2ecf20Sopenharmony_ci if (rc) 11298c2ecf20Sopenharmony_ci goto fail; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* Get the MC's warm boot count. In case it's rebooting right 11328c2ecf20Sopenharmony_ci * now, be prepared to retry. 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci i = 0; 11358c2ecf20Sopenharmony_ci for (;;) { 11368c2ecf20Sopenharmony_ci rc = ef100_get_warm_boot_count(efx); 11378c2ecf20Sopenharmony_ci if (rc >= 0) 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci if (++i == 5) 11408c2ecf20Sopenharmony_ci goto fail; 11418c2ecf20Sopenharmony_ci ssleep(1); 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci nic_data->warm_boot_count = rc; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* In case we're recovering from a crash (kexec), we want to 11468c2ecf20Sopenharmony_ci * cancel any outstanding request by the previous user of this 11478c2ecf20Sopenharmony_ci * function. We send a special message using the least 11488c2ecf20Sopenharmony_ci * significant bits of the 'high' (doorbell) register. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci _efx_writed(efx, cpu_to_le32(1), efx_reg(efx, ER_GZ_MC_DB_HWRD)); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* Post-IO section. */ 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci rc = efx_mcdi_init(efx); 11558c2ecf20Sopenharmony_ci if (!rc && efx->mcdi->fn_flags & 11568c2ecf20Sopenharmony_ci (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_NO_ACTIVE_PORT)) { 11578c2ecf20Sopenharmony_ci netif_info(efx, probe, efx->net_dev, 11588c2ecf20Sopenharmony_ci "No network port on this PCI function"); 11598c2ecf20Sopenharmony_ci rc = -ENODEV; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci if (rc) 11628c2ecf20Sopenharmony_ci goto fail; 11638c2ecf20Sopenharmony_ci /* Reset (most) configuration for this function */ 11648c2ecf20Sopenharmony_ci rc = efx_mcdi_reset(efx, RESET_TYPE_ALL); 11658c2ecf20Sopenharmony_ci if (rc) 11668c2ecf20Sopenharmony_ci goto fail; 11678c2ecf20Sopenharmony_ci /* Enable event logging */ 11688c2ecf20Sopenharmony_ci rc = efx_mcdi_log_ctrl(efx, true, false, 0); 11698c2ecf20Sopenharmony_ci if (rc) 11708c2ecf20Sopenharmony_ci goto fail; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci rc = efx_get_pf_index(efx, &nic_data->pf_index); 11738c2ecf20Sopenharmony_ci if (rc) 11748c2ecf20Sopenharmony_ci goto fail; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci rc = efx_ef100_init_datapath_caps(efx); 11778c2ecf20Sopenharmony_ci if (rc < 0) 11788c2ecf20Sopenharmony_ci goto fail; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci efx->max_vis = EF100_MAX_VIS; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci rc = efx_mcdi_port_get_number(efx); 11838c2ecf20Sopenharmony_ci if (rc < 0) 11848c2ecf20Sopenharmony_ci goto fail; 11858c2ecf20Sopenharmony_ci efx->port_num = rc; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci efx_mcdi_print_fwver(efx, fw_version, sizeof(fw_version)); 11888c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "Firmware version %s\n", fw_version); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (compare_versions(fw_version, "1.1.0.1000") < 0) { 11918c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "Firmware uses old event descriptors\n"); 11928c2ecf20Sopenharmony_ci rc = -EINVAL; 11938c2ecf20Sopenharmony_ci goto fail; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (efx_has_cap(efx, UNSOL_EV_CREDIT_SUPPORTED)) { 11978c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "Firmware uses unsolicited-event credits\n"); 11988c2ecf20Sopenharmony_ci rc = -EINVAL; 11998c2ecf20Sopenharmony_ci goto fail; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci rc = ef100_phy_probe(efx); 12038c2ecf20Sopenharmony_ci if (rc) 12048c2ecf20Sopenharmony_ci goto fail; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci down_write(&efx->filter_sem); 12078c2ecf20Sopenharmony_ci rc = ef100_filter_table_probe(efx); 12088c2ecf20Sopenharmony_ci up_write(&efx->filter_sem); 12098c2ecf20Sopenharmony_ci if (rc) 12108c2ecf20Sopenharmony_ci goto fail; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci netdev_rss_key_fill(efx->rss_context.rx_hash_key, 12138c2ecf20Sopenharmony_ci sizeof(efx->rss_context.rx_hash_key)); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* Don't fail init if RSS setup doesn't work. */ 12168c2ecf20Sopenharmony_ci efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci rc = ef100_register_netdev(efx); 12198c2ecf20Sopenharmony_ci if (rc) 12208c2ecf20Sopenharmony_ci goto fail; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_cifail: 12248c2ecf20Sopenharmony_ci return rc; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ciint ef100_probe_pf(struct efx_nic *efx) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 12308c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data; 12318c2ecf20Sopenharmony_ci int rc = ef100_probe_main(efx); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (rc) 12348c2ecf20Sopenharmony_ci goto fail; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci nic_data = efx->nic_data; 12378c2ecf20Sopenharmony_ci rc = ef100_get_mac_address(efx, net_dev->perm_addr); 12388c2ecf20Sopenharmony_ci if (rc) 12398c2ecf20Sopenharmony_ci goto fail; 12408c2ecf20Sopenharmony_ci /* Assign MAC address */ 12418c2ecf20Sopenharmony_ci memcpy(net_dev->dev_addr, net_dev->perm_addr, ETH_ALEN); 12428c2ecf20Sopenharmony_ci memcpy(nic_data->port_id, net_dev->perm_addr, ETH_ALEN); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cifail: 12478c2ecf20Sopenharmony_ci return rc; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ciint ef100_probe_vf(struct efx_nic *efx) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci return ef100_probe_main(efx); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_civoid ef100_remove(struct efx_nic *efx) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci struct ef100_nic_data *nic_data = efx->nic_data; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci ef100_unregister_netdev(efx); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci down_write(&efx->filter_sem); 12628c2ecf20Sopenharmony_ci efx_mcdi_filter_table_remove(efx); 12638c2ecf20Sopenharmony_ci up_write(&efx->filter_sem); 12648c2ecf20Sopenharmony_ci efx_fini_channels(efx); 12658c2ecf20Sopenharmony_ci kfree(efx->phy_data); 12668c2ecf20Sopenharmony_ci efx->phy_data = NULL; 12678c2ecf20Sopenharmony_ci efx_mcdi_detach(efx); 12688c2ecf20Sopenharmony_ci efx_mcdi_fini(efx); 12698c2ecf20Sopenharmony_ci if (nic_data) 12708c2ecf20Sopenharmony_ci efx_nic_free_buffer(efx, &nic_data->mcdi_buf); 12718c2ecf20Sopenharmony_ci kfree(nic_data); 12728c2ecf20Sopenharmony_ci efx->nic_data = NULL; 12738c2ecf20Sopenharmony_ci} 1274