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