18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 58c2ecf20Sopenharmony_ci * Copyright 2006-2013 Solarflare Communications Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 148c2ecf20Sopenharmony_ci#include <linux/cpu_rmap.h> 158c2ecf20Sopenharmony_ci#include "net_driver.h" 168c2ecf20Sopenharmony_ci#include "bitfield.h" 178c2ecf20Sopenharmony_ci#include "efx.h" 188c2ecf20Sopenharmony_ci#include "nic.h" 198c2ecf20Sopenharmony_ci#include "ef10_regs.h" 208c2ecf20Sopenharmony_ci#include "farch_regs.h" 218c2ecf20Sopenharmony_ci#include "io.h" 228c2ecf20Sopenharmony_ci#include "workarounds.h" 238c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/************************************************************************** 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Generic buffer handling 288c2ecf20Sopenharmony_ci * These buffers are used for interrupt status, MAC stats, etc. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci **************************************************************************/ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciint efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, 338c2ecf20Sopenharmony_ci unsigned int len, gfp_t gfp_flags) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, 368c2ecf20Sopenharmony_ci &buffer->dma_addr, gfp_flags); 378c2ecf20Sopenharmony_ci if (!buffer->addr) 388c2ecf20Sopenharmony_ci return -ENOMEM; 398c2ecf20Sopenharmony_ci buffer->len = len; 408c2ecf20Sopenharmony_ci return 0; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_civoid efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (buffer->addr) { 468c2ecf20Sopenharmony_ci dma_free_coherent(&efx->pci_dev->dev, buffer->len, 478c2ecf20Sopenharmony_ci buffer->addr, buffer->dma_addr); 488c2ecf20Sopenharmony_ci buffer->addr = NULL; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Check whether an event is present in the eventq at the current 538c2ecf20Sopenharmony_ci * read pointer. Only useful for self-test. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cibool efx_nic_event_present(struct efx_channel *channel) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return efx_event_present(efx_event(channel, channel->eventq_read_ptr)); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_civoid efx_nic_event_test_start(struct efx_channel *channel) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci channel->event_test_cpu = -1; 638c2ecf20Sopenharmony_ci smp_wmb(); 648c2ecf20Sopenharmony_ci channel->efx->type->ev_test_generate(channel); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciint efx_nic_irq_test_start(struct efx_nic *efx) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci efx->last_irq_cpu = -1; 708c2ecf20Sopenharmony_ci smp_wmb(); 718c2ecf20Sopenharmony_ci return efx->type->irq_test_generate(efx); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Hook interrupt handler(s) 758c2ecf20Sopenharmony_ci * Try MSI and then legacy interrupts. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ciint efx_nic_init_interrupt(struct efx_nic *efx) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct efx_channel *channel; 808c2ecf20Sopenharmony_ci unsigned int n_irqs; 818c2ecf20Sopenharmony_ci int rc; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!EFX_INT_MODE_USE_MSI(efx)) { 848c2ecf20Sopenharmony_ci rc = request_irq(efx->legacy_irq, 858c2ecf20Sopenharmony_ci efx->type->irq_handle_legacy, IRQF_SHARED, 868c2ecf20Sopenharmony_ci efx->name, efx); 878c2ecf20Sopenharmony_ci if (rc) { 888c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 898c2ecf20Sopenharmony_ci "failed to hook legacy IRQ %d\n", 908c2ecf20Sopenharmony_ci efx->pci_dev->irq); 918c2ecf20Sopenharmony_ci goto fail1; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci efx->irqs_hooked = true; 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 988c2ecf20Sopenharmony_ci if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { 998c2ecf20Sopenharmony_ci efx->net_dev->rx_cpu_rmap = 1008c2ecf20Sopenharmony_ci alloc_irq_cpu_rmap(efx->n_rx_channels); 1018c2ecf20Sopenharmony_ci if (!efx->net_dev->rx_cpu_rmap) { 1028c2ecf20Sopenharmony_ci rc = -ENOMEM; 1038c2ecf20Sopenharmony_ci goto fail1; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci#endif 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Hook MSI or MSI-X interrupt */ 1098c2ecf20Sopenharmony_ci n_irqs = 0; 1108c2ecf20Sopenharmony_ci efx_for_each_channel(channel, efx) { 1118c2ecf20Sopenharmony_ci rc = request_irq(channel->irq, efx->type->irq_handle_msi, 1128c2ecf20Sopenharmony_ci IRQF_PROBE_SHARED, /* Not shared */ 1138c2ecf20Sopenharmony_ci efx->msi_context[channel->channel].name, 1148c2ecf20Sopenharmony_ci &efx->msi_context[channel->channel]); 1158c2ecf20Sopenharmony_ci if (rc) { 1168c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 1178c2ecf20Sopenharmony_ci "failed to hook IRQ %d\n", channel->irq); 1188c2ecf20Sopenharmony_ci goto fail2; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci ++n_irqs; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 1238c2ecf20Sopenharmony_ci if (efx->interrupt_mode == EFX_INT_MODE_MSIX && 1248c2ecf20Sopenharmony_ci channel->channel < efx->n_rx_channels) { 1258c2ecf20Sopenharmony_ci rc = irq_cpu_rmap_add(efx->net_dev->rx_cpu_rmap, 1268c2ecf20Sopenharmony_ci channel->irq); 1278c2ecf20Sopenharmony_ci if (rc) 1288c2ecf20Sopenharmony_ci goto fail2; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci efx->irqs_hooked = true; 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci fail2: 1378c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 1388c2ecf20Sopenharmony_ci free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); 1398c2ecf20Sopenharmony_ci efx->net_dev->rx_cpu_rmap = NULL; 1408c2ecf20Sopenharmony_ci#endif 1418c2ecf20Sopenharmony_ci efx_for_each_channel(channel, efx) { 1428c2ecf20Sopenharmony_ci if (n_irqs-- == 0) 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci free_irq(channel->irq, &efx->msi_context[channel->channel]); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci fail1: 1478c2ecf20Sopenharmony_ci return rc; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid efx_nic_fini_interrupt(struct efx_nic *efx) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct efx_channel *channel; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 1558c2ecf20Sopenharmony_ci free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); 1568c2ecf20Sopenharmony_ci efx->net_dev->rx_cpu_rmap = NULL; 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!efx->irqs_hooked) 1608c2ecf20Sopenharmony_ci return; 1618c2ecf20Sopenharmony_ci if (EFX_INT_MODE_USE_MSI(efx)) { 1628c2ecf20Sopenharmony_ci /* Disable MSI/MSI-X interrupts */ 1638c2ecf20Sopenharmony_ci efx_for_each_channel(channel, efx) 1648c2ecf20Sopenharmony_ci free_irq(channel->irq, 1658c2ecf20Sopenharmony_ci &efx->msi_context[channel->channel]); 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci /* Disable legacy interrupt */ 1688c2ecf20Sopenharmony_ci free_irq(efx->legacy_irq, efx); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci efx->irqs_hooked = false; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* Register dump */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define REGISTER_REVISION_FA 1 1768c2ecf20Sopenharmony_ci#define REGISTER_REVISION_FB 2 1778c2ecf20Sopenharmony_ci#define REGISTER_REVISION_FC 3 1788c2ecf20Sopenharmony_ci#define REGISTER_REVISION_FZ 3 /* last Falcon arch revision */ 1798c2ecf20Sopenharmony_ci#define REGISTER_REVISION_ED 4 1808c2ecf20Sopenharmony_ci#define REGISTER_REVISION_EZ 4 /* latest EF10 revision */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistruct efx_nic_reg { 1838c2ecf20Sopenharmony_ci u32 offset:24; 1848c2ecf20Sopenharmony_ci u32 min_revision:3, max_revision:3; 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#define REGISTER(name, arch, min_rev, max_rev) { \ 1888c2ecf20Sopenharmony_ci arch ## R_ ## min_rev ## max_rev ## _ ## name, \ 1898c2ecf20Sopenharmony_ci REGISTER_REVISION_ ## arch ## min_rev, \ 1908c2ecf20Sopenharmony_ci REGISTER_REVISION_ ## arch ## max_rev \ 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci#define REGISTER_AA(name) REGISTER(name, F, A, A) 1938c2ecf20Sopenharmony_ci#define REGISTER_AB(name) REGISTER(name, F, A, B) 1948c2ecf20Sopenharmony_ci#define REGISTER_AZ(name) REGISTER(name, F, A, Z) 1958c2ecf20Sopenharmony_ci#define REGISTER_BB(name) REGISTER(name, F, B, B) 1968c2ecf20Sopenharmony_ci#define REGISTER_BZ(name) REGISTER(name, F, B, Z) 1978c2ecf20Sopenharmony_ci#define REGISTER_CZ(name) REGISTER(name, F, C, Z) 1988c2ecf20Sopenharmony_ci#define REGISTER_DZ(name) REGISTER(name, E, D, Z) 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic const struct efx_nic_reg efx_nic_regs[] = { 2018c2ecf20Sopenharmony_ci REGISTER_AZ(ADR_REGION), 2028c2ecf20Sopenharmony_ci REGISTER_AZ(INT_EN_KER), 2038c2ecf20Sopenharmony_ci REGISTER_BZ(INT_EN_CHAR), 2048c2ecf20Sopenharmony_ci REGISTER_AZ(INT_ADR_KER), 2058c2ecf20Sopenharmony_ci REGISTER_BZ(INT_ADR_CHAR), 2068c2ecf20Sopenharmony_ci /* INT_ACK_KER is WO */ 2078c2ecf20Sopenharmony_ci /* INT_ISR0 is RC */ 2088c2ecf20Sopenharmony_ci REGISTER_AZ(HW_INIT), 2098c2ecf20Sopenharmony_ci REGISTER_CZ(USR_EV_CFG), 2108c2ecf20Sopenharmony_ci REGISTER_AB(EE_SPI_HCMD), 2118c2ecf20Sopenharmony_ci REGISTER_AB(EE_SPI_HADR), 2128c2ecf20Sopenharmony_ci REGISTER_AB(EE_SPI_HDATA), 2138c2ecf20Sopenharmony_ci REGISTER_AB(EE_BASE_PAGE), 2148c2ecf20Sopenharmony_ci REGISTER_AB(EE_VPD_CFG0), 2158c2ecf20Sopenharmony_ci /* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */ 2168c2ecf20Sopenharmony_ci /* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */ 2178c2ecf20Sopenharmony_ci /* PCIE_CORE_INDIRECT is indirect */ 2188c2ecf20Sopenharmony_ci REGISTER_AB(NIC_STAT), 2198c2ecf20Sopenharmony_ci REGISTER_AB(GPIO_CTL), 2208c2ecf20Sopenharmony_ci REGISTER_AB(GLB_CTL), 2218c2ecf20Sopenharmony_ci /* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */ 2228c2ecf20Sopenharmony_ci REGISTER_BZ(DP_CTRL), 2238c2ecf20Sopenharmony_ci REGISTER_AZ(MEM_STAT), 2248c2ecf20Sopenharmony_ci REGISTER_AZ(CS_DEBUG), 2258c2ecf20Sopenharmony_ci REGISTER_AZ(ALTERA_BUILD), 2268c2ecf20Sopenharmony_ci REGISTER_AZ(CSR_SPARE), 2278c2ecf20Sopenharmony_ci REGISTER_AB(PCIE_SD_CTL0123), 2288c2ecf20Sopenharmony_ci REGISTER_AB(PCIE_SD_CTL45), 2298c2ecf20Sopenharmony_ci REGISTER_AB(PCIE_PCS_CTL_STAT), 2308c2ecf20Sopenharmony_ci /* DEBUG_DATA_OUT is not used */ 2318c2ecf20Sopenharmony_ci /* DRV_EV is WO */ 2328c2ecf20Sopenharmony_ci REGISTER_AZ(EVQ_CTL), 2338c2ecf20Sopenharmony_ci REGISTER_AZ(EVQ_CNT1), 2348c2ecf20Sopenharmony_ci REGISTER_AZ(EVQ_CNT2), 2358c2ecf20Sopenharmony_ci REGISTER_AZ(BUF_TBL_CFG), 2368c2ecf20Sopenharmony_ci REGISTER_AZ(SRM_RX_DC_CFG), 2378c2ecf20Sopenharmony_ci REGISTER_AZ(SRM_TX_DC_CFG), 2388c2ecf20Sopenharmony_ci REGISTER_AZ(SRM_CFG), 2398c2ecf20Sopenharmony_ci /* BUF_TBL_UPD is WO */ 2408c2ecf20Sopenharmony_ci REGISTER_AZ(SRM_UPD_EVQ), 2418c2ecf20Sopenharmony_ci REGISTER_AZ(SRAM_PARITY), 2428c2ecf20Sopenharmony_ci REGISTER_AZ(RX_CFG), 2438c2ecf20Sopenharmony_ci REGISTER_BZ(RX_FILTER_CTL), 2448c2ecf20Sopenharmony_ci /* RX_FLUSH_DESCQ is WO */ 2458c2ecf20Sopenharmony_ci REGISTER_AZ(RX_DC_CFG), 2468c2ecf20Sopenharmony_ci REGISTER_AZ(RX_DC_PF_WM), 2478c2ecf20Sopenharmony_ci REGISTER_BZ(RX_RSS_TKEY), 2488c2ecf20Sopenharmony_ci /* RX_NODESC_DROP is RC */ 2498c2ecf20Sopenharmony_ci REGISTER_AA(RX_SELF_RST), 2508c2ecf20Sopenharmony_ci /* RX_DEBUG, RX_PUSH_DROP are not used */ 2518c2ecf20Sopenharmony_ci REGISTER_CZ(RX_RSS_IPV6_REG1), 2528c2ecf20Sopenharmony_ci REGISTER_CZ(RX_RSS_IPV6_REG2), 2538c2ecf20Sopenharmony_ci REGISTER_CZ(RX_RSS_IPV6_REG3), 2548c2ecf20Sopenharmony_ci /* TX_FLUSH_DESCQ is WO */ 2558c2ecf20Sopenharmony_ci REGISTER_AZ(TX_DC_CFG), 2568c2ecf20Sopenharmony_ci REGISTER_AA(TX_CHKSM_CFG), 2578c2ecf20Sopenharmony_ci REGISTER_AZ(TX_CFG), 2588c2ecf20Sopenharmony_ci /* TX_PUSH_DROP is not used */ 2598c2ecf20Sopenharmony_ci REGISTER_AZ(TX_RESERVED), 2608c2ecf20Sopenharmony_ci REGISTER_BZ(TX_PACE), 2618c2ecf20Sopenharmony_ci /* TX_PACE_DROP_QID is RC */ 2628c2ecf20Sopenharmony_ci REGISTER_BB(TX_VLAN), 2638c2ecf20Sopenharmony_ci REGISTER_BZ(TX_IPFIL_PORTEN), 2648c2ecf20Sopenharmony_ci REGISTER_AB(MD_TXD), 2658c2ecf20Sopenharmony_ci REGISTER_AB(MD_RXD), 2668c2ecf20Sopenharmony_ci REGISTER_AB(MD_CS), 2678c2ecf20Sopenharmony_ci REGISTER_AB(MD_PHY_ADR), 2688c2ecf20Sopenharmony_ci REGISTER_AB(MD_ID), 2698c2ecf20Sopenharmony_ci /* MD_STAT is RC */ 2708c2ecf20Sopenharmony_ci REGISTER_AB(MAC_STAT_DMA), 2718c2ecf20Sopenharmony_ci REGISTER_AB(MAC_CTRL), 2728c2ecf20Sopenharmony_ci REGISTER_BB(GEN_MODE), 2738c2ecf20Sopenharmony_ci REGISTER_AB(MAC_MC_HASH_REG0), 2748c2ecf20Sopenharmony_ci REGISTER_AB(MAC_MC_HASH_REG1), 2758c2ecf20Sopenharmony_ci REGISTER_AB(GM_CFG1), 2768c2ecf20Sopenharmony_ci REGISTER_AB(GM_CFG2), 2778c2ecf20Sopenharmony_ci /* GM_IPG and GM_HD are not used */ 2788c2ecf20Sopenharmony_ci REGISTER_AB(GM_MAX_FLEN), 2798c2ecf20Sopenharmony_ci /* GM_TEST is not used */ 2808c2ecf20Sopenharmony_ci REGISTER_AB(GM_ADR1), 2818c2ecf20Sopenharmony_ci REGISTER_AB(GM_ADR2), 2828c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG0), 2838c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG1), 2848c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG2), 2858c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG3), 2868c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG4), 2878c2ecf20Sopenharmony_ci REGISTER_AB(GMF_CFG5), 2888c2ecf20Sopenharmony_ci REGISTER_BB(TX_SRC_MAC_CTL), 2898c2ecf20Sopenharmony_ci REGISTER_AB(XM_ADR_LO), 2908c2ecf20Sopenharmony_ci REGISTER_AB(XM_ADR_HI), 2918c2ecf20Sopenharmony_ci REGISTER_AB(XM_GLB_CFG), 2928c2ecf20Sopenharmony_ci REGISTER_AB(XM_TX_CFG), 2938c2ecf20Sopenharmony_ci REGISTER_AB(XM_RX_CFG), 2948c2ecf20Sopenharmony_ci REGISTER_AB(XM_MGT_INT_MASK), 2958c2ecf20Sopenharmony_ci REGISTER_AB(XM_FC), 2968c2ecf20Sopenharmony_ci REGISTER_AB(XM_PAUSE_TIME), 2978c2ecf20Sopenharmony_ci REGISTER_AB(XM_TX_PARAM), 2988c2ecf20Sopenharmony_ci REGISTER_AB(XM_RX_PARAM), 2998c2ecf20Sopenharmony_ci /* XM_MGT_INT_MSK (note no 'A') is RC */ 3008c2ecf20Sopenharmony_ci REGISTER_AB(XX_PWR_RST), 3018c2ecf20Sopenharmony_ci REGISTER_AB(XX_SD_CTL), 3028c2ecf20Sopenharmony_ci REGISTER_AB(XX_TXDRV_CTL), 3038c2ecf20Sopenharmony_ci /* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */ 3048c2ecf20Sopenharmony_ci /* XX_CORE_STAT is partly RC */ 3058c2ecf20Sopenharmony_ci REGISTER_DZ(BIU_HW_REV_ID), 3068c2ecf20Sopenharmony_ci REGISTER_DZ(MC_DB_LWRD), 3078c2ecf20Sopenharmony_ci REGISTER_DZ(MC_DB_HWRD), 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistruct efx_nic_reg_table { 3118c2ecf20Sopenharmony_ci u32 offset:24; 3128c2ecf20Sopenharmony_ci u32 min_revision:3, max_revision:3; 3138c2ecf20Sopenharmony_ci u32 step:6, rows:21; 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci#define REGISTER_TABLE_DIMENSIONS(_, offset, arch, min_rev, max_rev, step, rows) { \ 3178c2ecf20Sopenharmony_ci offset, \ 3188c2ecf20Sopenharmony_ci REGISTER_REVISION_ ## arch ## min_rev, \ 3198c2ecf20Sopenharmony_ci REGISTER_REVISION_ ## arch ## max_rev, \ 3208c2ecf20Sopenharmony_ci step, rows \ 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci#define REGISTER_TABLE(name, arch, min_rev, max_rev) \ 3238c2ecf20Sopenharmony_ci REGISTER_TABLE_DIMENSIONS( \ 3248c2ecf20Sopenharmony_ci name, arch ## R_ ## min_rev ## max_rev ## _ ## name, \ 3258c2ecf20Sopenharmony_ci arch, min_rev, max_rev, \ 3268c2ecf20Sopenharmony_ci arch ## R_ ## min_rev ## max_rev ## _ ## name ## _STEP, \ 3278c2ecf20Sopenharmony_ci arch ## R_ ## min_rev ## max_rev ## _ ## name ## _ROWS) 3288c2ecf20Sopenharmony_ci#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, F, A, A) 3298c2ecf20Sopenharmony_ci#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, F, A, Z) 3308c2ecf20Sopenharmony_ci#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, F, B, B) 3318c2ecf20Sopenharmony_ci#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, F, B, Z) 3328c2ecf20Sopenharmony_ci#define REGISTER_TABLE_BB_CZ(name) \ 3338c2ecf20Sopenharmony_ci REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, B, B, \ 3348c2ecf20Sopenharmony_ci FR_BZ_ ## name ## _STEP, \ 3358c2ecf20Sopenharmony_ci FR_BB_ ## name ## _ROWS), \ 3368c2ecf20Sopenharmony_ci REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, C, Z, \ 3378c2ecf20Sopenharmony_ci FR_BZ_ ## name ## _STEP, \ 3388c2ecf20Sopenharmony_ci FR_CZ_ ## name ## _ROWS) 3398c2ecf20Sopenharmony_ci#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, F, C, Z) 3408c2ecf20Sopenharmony_ci#define REGISTER_TABLE_DZ(name) REGISTER_TABLE(name, E, D, Z) 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic const struct efx_nic_reg_table efx_nic_reg_tables[] = { 3438c2ecf20Sopenharmony_ci /* DRIVER is not used */ 3448c2ecf20Sopenharmony_ci /* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */ 3458c2ecf20Sopenharmony_ci REGISTER_TABLE_BB(TX_IPFIL_TBL), 3468c2ecf20Sopenharmony_ci REGISTER_TABLE_BB(TX_SRC_MAC_TBL), 3478c2ecf20Sopenharmony_ci REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER), 3488c2ecf20Sopenharmony_ci REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL), 3498c2ecf20Sopenharmony_ci REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER), 3508c2ecf20Sopenharmony_ci REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL), 3518c2ecf20Sopenharmony_ci REGISTER_TABLE_AA(EVQ_PTR_TBL_KER), 3528c2ecf20Sopenharmony_ci REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL), 3538c2ecf20Sopenharmony_ci /* We can't reasonably read all of the buffer table (up to 8MB!). 3548c2ecf20Sopenharmony_ci * However this driver will only use a few entries. Reading 3558c2ecf20Sopenharmony_ci * 1K entries allows for some expansion of queue count and 3568c2ecf20Sopenharmony_ci * size before we need to change the version. */ 3578c2ecf20Sopenharmony_ci REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER, 3588c2ecf20Sopenharmony_ci F, A, A, 8, 1024), 3598c2ecf20Sopenharmony_ci REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL, 3608c2ecf20Sopenharmony_ci F, B, Z, 8, 1024), 3618c2ecf20Sopenharmony_ci REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0), 3628c2ecf20Sopenharmony_ci REGISTER_TABLE_BB_CZ(TIMER_TBL), 3638c2ecf20Sopenharmony_ci REGISTER_TABLE_BB_CZ(TX_PACE_TBL), 3648c2ecf20Sopenharmony_ci REGISTER_TABLE_BZ(RX_INDIRECTION_TBL), 3658c2ecf20Sopenharmony_ci /* TX_FILTER_TBL0 is huge and not used by this driver */ 3668c2ecf20Sopenharmony_ci REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0), 3678c2ecf20Sopenharmony_ci REGISTER_TABLE_CZ(MC_TREG_SMEM), 3688c2ecf20Sopenharmony_ci /* MSIX_PBA_TABLE is not mapped */ 3698c2ecf20Sopenharmony_ci /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */ 3708c2ecf20Sopenharmony_ci REGISTER_TABLE_BZ(RX_FILTER_TBL0), 3718c2ecf20Sopenharmony_ci REGISTER_TABLE_DZ(BIU_MC_SFT_STATUS), 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cisize_t efx_nic_get_regs_len(struct efx_nic *efx) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci const struct efx_nic_reg *reg; 3778c2ecf20Sopenharmony_ci const struct efx_nic_reg_table *table; 3788c2ecf20Sopenharmony_ci size_t len = 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci for (reg = efx_nic_regs; 3818c2ecf20Sopenharmony_ci reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs); 3828c2ecf20Sopenharmony_ci reg++) 3838c2ecf20Sopenharmony_ci if (efx->type->revision >= reg->min_revision && 3848c2ecf20Sopenharmony_ci efx->type->revision <= reg->max_revision) 3858c2ecf20Sopenharmony_ci len += sizeof(efx_oword_t); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci for (table = efx_nic_reg_tables; 3888c2ecf20Sopenharmony_ci table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables); 3898c2ecf20Sopenharmony_ci table++) 3908c2ecf20Sopenharmony_ci if (efx->type->revision >= table->min_revision && 3918c2ecf20Sopenharmony_ci efx->type->revision <= table->max_revision) 3928c2ecf20Sopenharmony_ci len += table->rows * min_t(size_t, table->step, 16); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return len; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_civoid efx_nic_get_regs(struct efx_nic *efx, void *buf) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci const struct efx_nic_reg *reg; 4008c2ecf20Sopenharmony_ci const struct efx_nic_reg_table *table; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (reg = efx_nic_regs; 4038c2ecf20Sopenharmony_ci reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs); 4048c2ecf20Sopenharmony_ci reg++) { 4058c2ecf20Sopenharmony_ci if (efx->type->revision >= reg->min_revision && 4068c2ecf20Sopenharmony_ci efx->type->revision <= reg->max_revision) { 4078c2ecf20Sopenharmony_ci efx_reado(efx, (efx_oword_t *)buf, reg->offset); 4088c2ecf20Sopenharmony_ci buf += sizeof(efx_oword_t); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci for (table = efx_nic_reg_tables; 4138c2ecf20Sopenharmony_ci table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables); 4148c2ecf20Sopenharmony_ci table++) { 4158c2ecf20Sopenharmony_ci size_t size, i; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (!(efx->type->revision >= table->min_revision && 4188c2ecf20Sopenharmony_ci efx->type->revision <= table->max_revision)) 4198c2ecf20Sopenharmony_ci continue; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci size = min_t(size_t, table->step, 16); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci for (i = 0; i < table->rows; i++) { 4248c2ecf20Sopenharmony_ci switch (table->step) { 4258c2ecf20Sopenharmony_ci case 4: /* 32-bit SRAM */ 4268c2ecf20Sopenharmony_ci efx_readd(efx, buf, table->offset + 4 * i); 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case 8: /* 64-bit SRAM */ 4298c2ecf20Sopenharmony_ci efx_sram_readq(efx, 4308c2ecf20Sopenharmony_ci efx->membase + table->offset, 4318c2ecf20Sopenharmony_ci buf, i); 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case 16: /* 128-bit-readable register */ 4348c2ecf20Sopenharmony_ci efx_reado_table(efx, buf, table->offset, i); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case 32: /* 128-bit register, interleaved */ 4378c2ecf20Sopenharmony_ci efx_reado_table(efx, buf, table->offset, 2 * i); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci WARN_ON(1); 4418c2ecf20Sopenharmony_ci return; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci buf += size; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * efx_nic_describe_stats - Describe supported statistics for ethtool 4508c2ecf20Sopenharmony_ci * @desc: Array of &struct efx_hw_stat_desc describing the statistics 4518c2ecf20Sopenharmony_ci * @count: Length of the @desc array 4528c2ecf20Sopenharmony_ci * @mask: Bitmask of which elements of @desc are enabled 4538c2ecf20Sopenharmony_ci * @names: Buffer to copy names to, or %NULL. The names are copied 4548c2ecf20Sopenharmony_ci * starting at intervals of %ETH_GSTRING_LEN bytes. 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * Returns the number of visible statistics, i.e. the number of set 4578c2ecf20Sopenharmony_ci * bits in the first @count bits of @mask for which a name is defined. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cisize_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, 4608c2ecf20Sopenharmony_ci const unsigned long *mask, u8 *names) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci size_t visible = 0; 4638c2ecf20Sopenharmony_ci size_t index; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci for_each_set_bit(index, mask, count) { 4668c2ecf20Sopenharmony_ci if (desc[index].name) { 4678c2ecf20Sopenharmony_ci if (names) { 4688c2ecf20Sopenharmony_ci strlcpy(names, desc[index].name, 4698c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 4708c2ecf20Sopenharmony_ci names += ETH_GSTRING_LEN; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci ++visible; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return visible; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/** 4808c2ecf20Sopenharmony_ci * efx_nic_copy_stats - Copy stats from the DMA buffer in to an 4818c2ecf20Sopenharmony_ci * intermediate buffer. This is used to get a consistent 4828c2ecf20Sopenharmony_ci * set of stats while the DMA buffer can be written at any time 4838c2ecf20Sopenharmony_ci * by the NIC. 4848c2ecf20Sopenharmony_ci * @efx: The associated NIC. 4858c2ecf20Sopenharmony_ci * @dest: Destination buffer. Must be the same size as the DMA buffer. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ciint efx_nic_copy_stats(struct efx_nic *efx, __le64 *dest) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci __le64 *dma_stats = efx->stats_buffer.addr; 4908c2ecf20Sopenharmony_ci __le64 generation_start, generation_end; 4918c2ecf20Sopenharmony_ci int rc = 0, retry; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (!dest) 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!dma_stats) 4978c2ecf20Sopenharmony_ci goto return_zeroes; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* If we're unlucky enough to read statistics during the DMA, wait 5008c2ecf20Sopenharmony_ci * up to 10ms for it to finish (typically takes <500us) 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci for (retry = 0; retry < 100; ++retry) { 5038c2ecf20Sopenharmony_ci generation_end = dma_stats[efx->num_mac_stats - 1]; 5048c2ecf20Sopenharmony_ci if (generation_end == EFX_MC_STATS_GENERATION_INVALID) 5058c2ecf20Sopenharmony_ci goto return_zeroes; 5068c2ecf20Sopenharmony_ci rmb(); 5078c2ecf20Sopenharmony_ci memcpy(dest, dma_stats, efx->num_mac_stats * sizeof(__le64)); 5088c2ecf20Sopenharmony_ci rmb(); 5098c2ecf20Sopenharmony_ci generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; 5108c2ecf20Sopenharmony_ci if (generation_end == generation_start) 5118c2ecf20Sopenharmony_ci return 0; /* return good data */ 5128c2ecf20Sopenharmony_ci udelay(100); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci rc = -EIO; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cireturn_zeroes: 5188c2ecf20Sopenharmony_ci memset(dest, 0, efx->num_mac_stats * sizeof(u64)); 5198c2ecf20Sopenharmony_ci return rc; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/** 5238c2ecf20Sopenharmony_ci * efx_nic_update_stats - Convert statistics DMA buffer to array of u64 5248c2ecf20Sopenharmony_ci * @desc: Array of &struct efx_hw_stat_desc describing the DMA buffer 5258c2ecf20Sopenharmony_ci * layout. DMA widths of 0, 16, 32 and 64 are supported; where 5268c2ecf20Sopenharmony_ci * the width is specified as 0 the corresponding element of 5278c2ecf20Sopenharmony_ci * @stats is not updated. 5288c2ecf20Sopenharmony_ci * @count: Length of the @desc array 5298c2ecf20Sopenharmony_ci * @mask: Bitmask of which elements of @desc are enabled 5308c2ecf20Sopenharmony_ci * @stats: Buffer to update with the converted statistics. The length 5318c2ecf20Sopenharmony_ci * of this array must be at least @count. 5328c2ecf20Sopenharmony_ci * @dma_buf: DMA buffer containing hardware statistics 5338c2ecf20Sopenharmony_ci * @accumulate: If set, the converted values will be added rather than 5348c2ecf20Sopenharmony_ci * directly stored to the corresponding elements of @stats 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_civoid efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, 5378c2ecf20Sopenharmony_ci const unsigned long *mask, 5388c2ecf20Sopenharmony_ci u64 *stats, const void *dma_buf, bool accumulate) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci size_t index; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci for_each_set_bit(index, mask, count) { 5438c2ecf20Sopenharmony_ci if (desc[index].dma_width) { 5448c2ecf20Sopenharmony_ci const void *addr = dma_buf + desc[index].offset; 5458c2ecf20Sopenharmony_ci u64 val; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci switch (desc[index].dma_width) { 5488c2ecf20Sopenharmony_ci case 16: 5498c2ecf20Sopenharmony_ci val = le16_to_cpup((__le16 *)addr); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case 32: 5528c2ecf20Sopenharmony_ci val = le32_to_cpup((__le32 *)addr); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci case 64: 5558c2ecf20Sopenharmony_ci val = le64_to_cpup((__le64 *)addr); 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci default: 5588c2ecf20Sopenharmony_ci WARN_ON(1); 5598c2ecf20Sopenharmony_ci val = 0; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (accumulate) 5648c2ecf20Sopenharmony_ci stats[index] += val; 5658c2ecf20Sopenharmony_ci else 5668c2ecf20Sopenharmony_ci stats[index] = val; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_civoid efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci /* if down, or this is the first update after coming up */ 5748c2ecf20Sopenharmony_ci if (!(efx->net_dev->flags & IFF_UP) || !efx->rx_nodesc_drops_prev_state) 5758c2ecf20Sopenharmony_ci efx->rx_nodesc_drops_while_down += 5768c2ecf20Sopenharmony_ci *rx_nodesc_drops - efx->rx_nodesc_drops_total; 5778c2ecf20Sopenharmony_ci efx->rx_nodesc_drops_total = *rx_nodesc_drops; 5788c2ecf20Sopenharmony_ci efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP); 5798c2ecf20Sopenharmony_ci *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down; 5808c2ecf20Sopenharmony_ci} 581