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/pci.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/random.h> 148c2ecf20Sopenharmony_ci#include "net_driver.h" 158c2ecf20Sopenharmony_ci#include "bitfield.h" 168c2ecf20Sopenharmony_ci#include "efx.h" 178c2ecf20Sopenharmony_ci#include "efx_common.h" 188c2ecf20Sopenharmony_ci#include "nic.h" 198c2ecf20Sopenharmony_ci#include "farch_regs.h" 208c2ecf20Sopenharmony_ci#include "io.h" 218c2ecf20Sopenharmony_ci#include "workarounds.h" 228c2ecf20Sopenharmony_ci#include "mcdi.h" 238c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 248c2ecf20Sopenharmony_ci#include "mcdi_port.h" 258c2ecf20Sopenharmony_ci#include "mcdi_port_common.h" 268c2ecf20Sopenharmony_ci#include "selftest.h" 278c2ecf20Sopenharmony_ci#include "siena_sriov.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void siena_init_wol(struct efx_nic *efx); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void siena_push_irq_moderation(struct efx_channel *channel) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct efx_nic *efx = channel->efx; 378c2ecf20Sopenharmony_ci efx_dword_t timer_cmd; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (channel->irq_moderation_us) { 408c2ecf20Sopenharmony_ci unsigned int ticks; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci ticks = efx_usecs_to_ticks(efx, channel->irq_moderation_us); 438c2ecf20Sopenharmony_ci EFX_POPULATE_DWORD_2(timer_cmd, 448c2ecf20Sopenharmony_ci FRF_CZ_TC_TIMER_MODE, 458c2ecf20Sopenharmony_ci FFE_CZ_TIMER_MODE_INT_HLDOFF, 468c2ecf20Sopenharmony_ci FRF_CZ_TC_TIMER_VAL, 478c2ecf20Sopenharmony_ci ticks - 1); 488c2ecf20Sopenharmony_ci } else { 498c2ecf20Sopenharmony_ci EFX_POPULATE_DWORD_2(timer_cmd, 508c2ecf20Sopenharmony_ci FRF_CZ_TC_TIMER_MODE, 518c2ecf20Sopenharmony_ci FFE_CZ_TIMER_MODE_DIS, 528c2ecf20Sopenharmony_ci FRF_CZ_TC_TIMER_VAL, 0); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, 558c2ecf20Sopenharmony_ci channel->channel); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_civoid siena_prepare_flush(struct efx_nic *efx) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci if (efx->fc_disable++ == 0) 618c2ecf20Sopenharmony_ci efx_mcdi_set_mac(efx); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_civoid siena_finish_flush(struct efx_nic *efx) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci if (--efx->fc_disable == 0) 678c2ecf20Sopenharmony_ci efx_mcdi_set_mac(efx); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic const struct efx_farch_register_test siena_register_tests[] = { 718c2ecf20Sopenharmony_ci { FR_AZ_ADR_REGION, 728c2ecf20Sopenharmony_ci EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, 738c2ecf20Sopenharmony_ci { FR_CZ_USR_EV_CFG, 748c2ecf20Sopenharmony_ci EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) }, 758c2ecf20Sopenharmony_ci { FR_AZ_RX_CFG, 768c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000) }, 778c2ecf20Sopenharmony_ci { FR_AZ_TX_CFG, 788c2ecf20Sopenharmony_ci EFX_OWORD32(0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF) }, 798c2ecf20Sopenharmony_ci { FR_AZ_TX_RESERVED, 808c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, 818c2ecf20Sopenharmony_ci { FR_AZ_SRM_TX_DC_CFG, 828c2ecf20Sopenharmony_ci EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, 838c2ecf20Sopenharmony_ci { FR_AZ_RX_DC_CFG, 848c2ecf20Sopenharmony_ci EFX_OWORD32(0x00000003, 0x00000000, 0x00000000, 0x00000000) }, 858c2ecf20Sopenharmony_ci { FR_AZ_RX_DC_PF_WM, 868c2ecf20Sopenharmony_ci EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, 878c2ecf20Sopenharmony_ci { FR_BZ_DP_CTRL, 888c2ecf20Sopenharmony_ci EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, 898c2ecf20Sopenharmony_ci { FR_BZ_RX_RSS_TKEY, 908c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, 918c2ecf20Sopenharmony_ci { FR_CZ_RX_RSS_IPV6_REG1, 928c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, 938c2ecf20Sopenharmony_ci { FR_CZ_RX_RSS_IPV6_REG2, 948c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, 958c2ecf20Sopenharmony_ci { FR_CZ_RX_RSS_IPV6_REG3, 968c2ecf20Sopenharmony_ci EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int siena_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci enum reset_type reset_method = RESET_TYPE_ALL; 1028c2ecf20Sopenharmony_ci int rc, rc2; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci efx_reset_down(efx, reset_method); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Reset the chip immediately so that it is completely 1078c2ecf20Sopenharmony_ci * quiescent regardless of what any VF driver does. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci rc = efx_mcdi_reset(efx, reset_method); 1108c2ecf20Sopenharmony_ci if (rc) 1118c2ecf20Sopenharmony_ci goto out; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci tests->registers = 1148c2ecf20Sopenharmony_ci efx_farch_test_registers(efx, siena_register_tests, 1158c2ecf20Sopenharmony_ci ARRAY_SIZE(siena_register_tests)) 1168c2ecf20Sopenharmony_ci ? -1 : 1; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci rc = efx_mcdi_reset(efx, reset_method); 1198c2ecf20Sopenharmony_ciout: 1208c2ecf20Sopenharmony_ci rc2 = efx_reset_up(efx, reset_method, rc == 0); 1218c2ecf20Sopenharmony_ci return rc ? rc : rc2; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/************************************************************************** 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * PTP 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci ************************************************************************** 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void siena_ptp_write_host_time(struct efx_nic *efx, u32 host_time) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci _efx_writed(efx, cpu_to_le32(host_time), 1348c2ecf20Sopenharmony_ci FR_CZ_MC_TREG_SMEM + MC_SMEM_P0_PTP_TIME_OFST); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int siena_ptp_set_ts_config(struct efx_nic *efx, 1388c2ecf20Sopenharmony_ci struct hwtstamp_config *init) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int rc; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci switch (init->rx_filter) { 1438c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 1448c2ecf20Sopenharmony_ci /* if TX timestamping is still requested then leave PTP on */ 1458c2ecf20Sopenharmony_ci return efx_ptp_change_mode(efx, 1468c2ecf20Sopenharmony_ci init->tx_type != HWTSTAMP_TX_OFF, 1478c2ecf20Sopenharmony_ci efx_ptp_get_mode(efx)); 1488c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 1498c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 1508c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 1518c2ecf20Sopenharmony_ci init->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; 1528c2ecf20Sopenharmony_ci return efx_ptp_change_mode(efx, true, MC_CMD_PTP_MODE_V1); 1538c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 1548c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 1558c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 1568c2ecf20Sopenharmony_ci init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; 1578c2ecf20Sopenharmony_ci rc = efx_ptp_change_mode(efx, true, 1588c2ecf20Sopenharmony_ci MC_CMD_PTP_MODE_V2_ENHANCED); 1598c2ecf20Sopenharmony_ci /* bug 33070 - old versions of the firmware do not support the 1608c2ecf20Sopenharmony_ci * improved UUID filtering option. Similarly old versions of the 1618c2ecf20Sopenharmony_ci * application do not expect it to be enabled. If the firmware 1628c2ecf20Sopenharmony_ci * does not accept the enhanced mode, fall back to the standard 1638c2ecf20Sopenharmony_ci * PTP v2 UUID filtering. */ 1648c2ecf20Sopenharmony_ci if (rc != 0) 1658c2ecf20Sopenharmony_ci rc = efx_ptp_change_mode(efx, true, MC_CMD_PTP_MODE_V2); 1668c2ecf20Sopenharmony_ci return rc; 1678c2ecf20Sopenharmony_ci default: 1688c2ecf20Sopenharmony_ci return -ERANGE; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/************************************************************************** 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Device reset 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci ************************************************************************** 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int siena_map_reset_flags(u32 *flags) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci enum { 1828c2ecf20Sopenharmony_ci SIENA_RESET_PORT = (ETH_RESET_DMA | ETH_RESET_FILTER | 1838c2ecf20Sopenharmony_ci ETH_RESET_OFFLOAD | ETH_RESET_MAC | 1848c2ecf20Sopenharmony_ci ETH_RESET_PHY), 1858c2ecf20Sopenharmony_ci SIENA_RESET_MC = (SIENA_RESET_PORT | 1868c2ecf20Sopenharmony_ci ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT), 1878c2ecf20Sopenharmony_ci }; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if ((*flags & SIENA_RESET_MC) == SIENA_RESET_MC) { 1908c2ecf20Sopenharmony_ci *flags &= ~SIENA_RESET_MC; 1918c2ecf20Sopenharmony_ci return RESET_TYPE_WORLD; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if ((*flags & SIENA_RESET_PORT) == SIENA_RESET_PORT) { 1958c2ecf20Sopenharmony_ci *flags &= ~SIENA_RESET_PORT; 1968c2ecf20Sopenharmony_ci return RESET_TYPE_ALL; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* no invisible reset implemented */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#ifdef CONFIG_EEH 2058c2ecf20Sopenharmony_ci/* When a PCI device is isolated from the bus, a subsequent MMIO read is 2068c2ecf20Sopenharmony_ci * required for the kernel EEH mechanisms to notice. As the Solarflare driver 2078c2ecf20Sopenharmony_ci * was written to minimise MMIO read (for latency) then a periodic call to check 2088c2ecf20Sopenharmony_ci * the EEH status of the device is required so that device recovery can happen 2098c2ecf20Sopenharmony_ci * in a timely fashion. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic void siena_monitor(struct efx_nic *efx) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct eeh_dev *eehdev = pci_dev_to_eeh_dev(efx->pci_dev); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci eeh_dev_check_failure(eehdev); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci#endif 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int siena_probe_nvconfig(struct efx_nic *efx) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci u32 caps = 0; 2228c2ecf20Sopenharmony_ci int rc; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci rc = efx_mcdi_get_board_cfg(efx, efx->net_dev->perm_addr, NULL, &caps); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci efx->timer_quantum_ns = 2278c2ecf20Sopenharmony_ci (caps & (1 << MC_CMD_CAPABILITIES_TURBO_ACTIVE_LBN)) ? 2288c2ecf20Sopenharmony_ci 3072 : 6144; /* 768 cycles */ 2298c2ecf20Sopenharmony_ci efx->timer_max_ns = efx->type->timer_period_max * 2308c2ecf20Sopenharmony_ci efx->timer_quantum_ns; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return rc; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int siena_dimension_resources(struct efx_nic *efx) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci /* Each port has a small block of internal SRAM dedicated to 2388c2ecf20Sopenharmony_ci * the buffer table and descriptor caches. In theory we can 2398c2ecf20Sopenharmony_ci * map both blocks to one port, but we don't. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci efx_farch_dimension_resources(efx, FR_CZ_BUF_FULL_TBL_ROWS / 2); 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/* On all Falcon-architecture NICs, PFs use BAR 0 for I/O space and BAR 2(&3) 2468c2ecf20Sopenharmony_ci * for memory. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_cistatic unsigned int siena_mem_bar(struct efx_nic *efx) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci return 2; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic unsigned int siena_mem_map_size(struct efx_nic *efx) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci return FR_CZ_MC_TREG_SMEM + 2568c2ecf20Sopenharmony_ci FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int siena_probe_nic(struct efx_nic *efx) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data; 2628c2ecf20Sopenharmony_ci efx_oword_t reg; 2638c2ecf20Sopenharmony_ci int rc; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Allocate storage for hardware specific data */ 2668c2ecf20Sopenharmony_ci nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL); 2678c2ecf20Sopenharmony_ci if (!nic_data) 2688c2ecf20Sopenharmony_ci return -ENOMEM; 2698c2ecf20Sopenharmony_ci nic_data->efx = efx; 2708c2ecf20Sopenharmony_ci efx->nic_data = nic_data; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (efx_farch_fpga_ver(efx) != 0) { 2738c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 2748c2ecf20Sopenharmony_ci "Siena FPGA not supported\n"); 2758c2ecf20Sopenharmony_ci rc = -ENODEV; 2768c2ecf20Sopenharmony_ci goto fail1; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci efx->max_channels = EFX_MAX_CHANNELS; 2808c2ecf20Sopenharmony_ci efx->max_vis = EFX_MAX_CHANNELS; 2818c2ecf20Sopenharmony_ci efx->max_tx_channels = EFX_MAX_CHANNELS; 2828c2ecf20Sopenharmony_ci efx->tx_queues_per_channel = 4; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci efx_reado(efx, ®, FR_AZ_CS_DEBUG); 2858c2ecf20Sopenharmony_ci efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci rc = efx_mcdi_init(efx); 2888c2ecf20Sopenharmony_ci if (rc) 2898c2ecf20Sopenharmony_ci goto fail1; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Now we can reset the NIC */ 2928c2ecf20Sopenharmony_ci rc = efx_mcdi_reset(efx, RESET_TYPE_ALL); 2938c2ecf20Sopenharmony_ci if (rc) { 2948c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n"); 2958c2ecf20Sopenharmony_ci goto fail3; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci siena_init_wol(efx); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Allocate memory for INT_KER */ 3018c2ecf20Sopenharmony_ci rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t), 3028c2ecf20Sopenharmony_ci GFP_KERNEL); 3038c2ecf20Sopenharmony_ci if (rc) 3048c2ecf20Sopenharmony_ci goto fail4; 3058c2ecf20Sopenharmony_ci BUG_ON(efx->irq_status.dma_addr & 0x0f); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 3088c2ecf20Sopenharmony_ci "INT_KER at %llx (virt %p phys %llx)\n", 3098c2ecf20Sopenharmony_ci (unsigned long long)efx->irq_status.dma_addr, 3108c2ecf20Sopenharmony_ci efx->irq_status.addr, 3118c2ecf20Sopenharmony_ci (unsigned long long)virt_to_phys(efx->irq_status.addr)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Read in the non-volatile configuration */ 3148c2ecf20Sopenharmony_ci rc = siena_probe_nvconfig(efx); 3158c2ecf20Sopenharmony_ci if (rc == -EINVAL) { 3168c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 3178c2ecf20Sopenharmony_ci "NVRAM is invalid therefore using defaults\n"); 3188c2ecf20Sopenharmony_ci efx->phy_type = PHY_TYPE_NONE; 3198c2ecf20Sopenharmony_ci efx->mdio.prtad = MDIO_PRTAD_NONE; 3208c2ecf20Sopenharmony_ci } else if (rc) { 3218c2ecf20Sopenharmony_ci goto fail5; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci rc = efx_mcdi_mon_probe(efx); 3258c2ecf20Sopenharmony_ci if (rc) 3268c2ecf20Sopenharmony_ci goto fail5; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_SRIOV 3298c2ecf20Sopenharmony_ci efx_siena_sriov_probe(efx); 3308c2ecf20Sopenharmony_ci#endif 3318c2ecf20Sopenharmony_ci efx_ptp_defer_probe_with_channel(efx); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cifail5: 3368c2ecf20Sopenharmony_ci efx_nic_free_buffer(efx, &efx->irq_status); 3378c2ecf20Sopenharmony_cifail4: 3388c2ecf20Sopenharmony_cifail3: 3398c2ecf20Sopenharmony_ci efx_mcdi_detach(efx); 3408c2ecf20Sopenharmony_ci efx_mcdi_fini(efx); 3418c2ecf20Sopenharmony_cifail1: 3428c2ecf20Sopenharmony_ci kfree(efx->nic_data); 3438c2ecf20Sopenharmony_ci return rc; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int siena_rx_pull_rss_config(struct efx_nic *efx) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci efx_oword_t temp; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Read from IPv6 RSS key as that's longer (the IPv4 key is just the 3518c2ecf20Sopenharmony_ci * first 128 bits of the same key, assuming it's been set by 3528c2ecf20Sopenharmony_ci * siena_rx_push_rss_config, below) 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1); 3558c2ecf20Sopenharmony_ci memcpy(efx->rss_context.rx_hash_key, &temp, sizeof(temp)); 3568c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2); 3578c2ecf20Sopenharmony_ci memcpy(efx->rss_context.rx_hash_key + sizeof(temp), &temp, sizeof(temp)); 3588c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); 3598c2ecf20Sopenharmony_ci memcpy(efx->rss_context.rx_hash_key + 2 * sizeof(temp), &temp, 3608c2ecf20Sopenharmony_ci FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); 3618c2ecf20Sopenharmony_ci efx_farch_rx_pull_indir_table(efx); 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int siena_rx_push_rss_config(struct efx_nic *efx, bool user, 3668c2ecf20Sopenharmony_ci const u32 *rx_indir_table, const u8 *key) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci efx_oword_t temp; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Set hash key for IPv4 */ 3718c2ecf20Sopenharmony_ci if (key) 3728c2ecf20Sopenharmony_ci memcpy(efx->rss_context.rx_hash_key, key, sizeof(temp)); 3738c2ecf20Sopenharmony_ci memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp)); 3748c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Enable IPv6 RSS */ 3778c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(efx->rss_context.rx_hash_key) < 3788c2ecf20Sopenharmony_ci 2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 || 3798c2ecf20Sopenharmony_ci FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0); 3808c2ecf20Sopenharmony_ci memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp)); 3818c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1); 3828c2ecf20Sopenharmony_ci memcpy(&temp, efx->rss_context.rx_hash_key + sizeof(temp), sizeof(temp)); 3838c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2); 3848c2ecf20Sopenharmony_ci EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1, 3858c2ecf20Sopenharmony_ci FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1); 3868c2ecf20Sopenharmony_ci memcpy(&temp, efx->rss_context.rx_hash_key + 2 * sizeof(temp), 3878c2ecf20Sopenharmony_ci FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); 3888c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci memcpy(efx->rss_context.rx_indir_table, rx_indir_table, 3918c2ecf20Sopenharmony_ci sizeof(efx->rss_context.rx_indir_table)); 3928c2ecf20Sopenharmony_ci efx_farch_rx_push_indir_table(efx); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* This call performs hardware-specific global initialisation, such as 3988c2ecf20Sopenharmony_ci * defining the descriptor cache sizes and number of RSS channels. 3998c2ecf20Sopenharmony_ci * It does not set up any buffers, descriptor rings or event queues. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_cistatic int siena_init_nic(struct efx_nic *efx) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci efx_oword_t temp; 4048c2ecf20Sopenharmony_ci int rc; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Recover from a failed assertion post-reset */ 4078c2ecf20Sopenharmony_ci rc = efx_mcdi_handle_assertion(efx); 4088c2ecf20Sopenharmony_ci if (rc) 4098c2ecf20Sopenharmony_ci return rc; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Squash TX of packets of 16 bytes or less */ 4128c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_AZ_TX_RESERVED); 4138c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); 4148c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 4178c2ecf20Sopenharmony_ci * descriptors (which is bad). 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_AZ_TX_CFG); 4208c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); 4218c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_CZ_TX_FILTER_EN_BIT, 1); 4228c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_AZ_TX_CFG); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci efx_reado(efx, &temp, FR_AZ_RX_CFG); 4258c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0); 4268c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1); 4278c2ecf20Sopenharmony_ci /* Enable hash insertion. This is broken for the 'Falcon' hash 4288c2ecf20Sopenharmony_ci * if IPv6 hashing is also enabled, so also select Toeplitz 4298c2ecf20Sopenharmony_ci * TCP/IPv4 and IPv4 hashes. */ 4308c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_INSRT_HDR, 1); 4318c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_ALG, 1); 4328c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_IP_HASH, 1); 4338c2ecf20Sopenharmony_ci EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_USR_BUF_SIZE, 4348c2ecf20Sopenharmony_ci EFX_RX_USR_BUF_SIZE >> 5); 4358c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_AZ_RX_CFG); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci siena_rx_push_rss_config(efx, false, efx->rss_context.rx_indir_table, NULL); 4388c2ecf20Sopenharmony_ci efx->rss_context.context_id = 0; /* indicates RSS is active */ 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Enable event logging */ 4418c2ecf20Sopenharmony_ci rc = efx_mcdi_log_ctrl(efx, true, false, 0); 4428c2ecf20Sopenharmony_ci if (rc) 4438c2ecf20Sopenharmony_ci return rc; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Set destination of both TX and RX Flush events */ 4468c2ecf20Sopenharmony_ci EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); 4478c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_BZ_DP_CTRL); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci EFX_POPULATE_OWORD_1(temp, FRF_CZ_USREV_DIS, 1); 4508c2ecf20Sopenharmony_ci efx_writeo(efx, &temp, FR_CZ_USR_EV_CFG); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci efx_farch_init_common(efx); 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void siena_remove_nic(struct efx_nic *efx) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci efx_mcdi_mon_remove(efx); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci efx_nic_free_buffer(efx, &efx->irq_status); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci efx_mcdi_reset(efx, RESET_TYPE_ALL); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci efx_mcdi_detach(efx); 4658c2ecf20Sopenharmony_ci efx_mcdi_fini(efx); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Tear down the private nic state */ 4688c2ecf20Sopenharmony_ci kfree(efx->nic_data); 4698c2ecf20Sopenharmony_ci efx->nic_data = NULL; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci#define SIENA_DMA_STAT(ext_name, mcdi_name) \ 4738c2ecf20Sopenharmony_ci [SIENA_STAT_ ## ext_name] = \ 4748c2ecf20Sopenharmony_ci { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name } 4758c2ecf20Sopenharmony_ci#define SIENA_OTHER_STAT(ext_name) \ 4768c2ecf20Sopenharmony_ci [SIENA_STAT_ ## ext_name] = { #ext_name, 0, 0 } 4778c2ecf20Sopenharmony_ci#define GENERIC_SW_STAT(ext_name) \ 4788c2ecf20Sopenharmony_ci [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic const struct efx_hw_stat_desc siena_stat_desc[SIENA_STAT_COUNT] = { 4818c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_bytes, TX_BYTES), 4828c2ecf20Sopenharmony_ci SIENA_OTHER_STAT(tx_good_bytes), 4838c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_bad_bytes, TX_BAD_BYTES), 4848c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_packets, TX_PKTS), 4858c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_bad, TX_BAD_FCS_PKTS), 4868c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_pause, TX_PAUSE_PKTS), 4878c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_control, TX_CONTROL_PKTS), 4888c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_unicast, TX_UNICAST_PKTS), 4898c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_multicast, TX_MULTICAST_PKTS), 4908c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_broadcast, TX_BROADCAST_PKTS), 4918c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_lt64, TX_LT64_PKTS), 4928c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_64, TX_64_PKTS), 4938c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_65_to_127, TX_65_TO_127_PKTS), 4948c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_128_to_255, TX_128_TO_255_PKTS), 4958c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_256_to_511, TX_256_TO_511_PKTS), 4968c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS), 4978c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS), 4988c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS), 4998c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_gtjumbo, TX_GTJUMBO_PKTS), 5008c2ecf20Sopenharmony_ci SIENA_OTHER_STAT(tx_collision), 5018c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_single_collision, TX_SINGLE_COLLISION_PKTS), 5028c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_multiple_collision, TX_MULTIPLE_COLLISION_PKTS), 5038c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_excessive_collision, TX_EXCESSIVE_COLLISION_PKTS), 5048c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_deferred, TX_DEFERRED_PKTS), 5058c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_late_collision, TX_LATE_COLLISION_PKTS), 5068c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_excessive_deferred, TX_EXCESSIVE_DEFERRED_PKTS), 5078c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_non_tcpudp, TX_NON_TCPUDP_PKTS), 5088c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_mac_src_error, TX_MAC_SRC_ERR_PKTS), 5098c2ecf20Sopenharmony_ci SIENA_DMA_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS), 5108c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_bytes, RX_BYTES), 5118c2ecf20Sopenharmony_ci SIENA_OTHER_STAT(rx_good_bytes), 5128c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_bad_bytes, RX_BAD_BYTES), 5138c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_packets, RX_PKTS), 5148c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_good, RX_GOOD_PKTS), 5158c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_bad, RX_BAD_FCS_PKTS), 5168c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_pause, RX_PAUSE_PKTS), 5178c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_control, RX_CONTROL_PKTS), 5188c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_unicast, RX_UNICAST_PKTS), 5198c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_multicast, RX_MULTICAST_PKTS), 5208c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_broadcast, RX_BROADCAST_PKTS), 5218c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_lt64, RX_UNDERSIZE_PKTS), 5228c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_64, RX_64_PKTS), 5238c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_65_to_127, RX_65_TO_127_PKTS), 5248c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_128_to_255, RX_128_TO_255_PKTS), 5258c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_256_to_511, RX_256_TO_511_PKTS), 5268c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS), 5278c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS), 5288c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS), 5298c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS), 5308c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS), 5318c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_overflow, RX_OVERFLOW_PKTS), 5328c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_false_carrier, RX_FALSE_CARRIER_PKTS), 5338c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_symbol_error, RX_SYMBOL_ERROR_PKTS), 5348c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS), 5358c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS), 5368c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS), 5378c2ecf20Sopenharmony_ci SIENA_DMA_STAT(rx_nodesc_drop_cnt, RX_NODESC_DROPS), 5388c2ecf20Sopenharmony_ci GENERIC_SW_STAT(rx_nodesc_trunc), 5398c2ecf20Sopenharmony_ci GENERIC_SW_STAT(rx_noskb_drops), 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_cistatic const unsigned long siena_stat_mask[] = { 5428c2ecf20Sopenharmony_ci [0 ... BITS_TO_LONGS(SIENA_STAT_COUNT) - 1] = ~0UL, 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic size_t siena_describe_nic_stats(struct efx_nic *efx, u8 *names) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci return efx_nic_describe_stats(siena_stat_desc, SIENA_STAT_COUNT, 5488c2ecf20Sopenharmony_ci siena_stat_mask, names); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int siena_try_update_nic_stats(struct efx_nic *efx) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 5548c2ecf20Sopenharmony_ci u64 *stats = nic_data->stats; 5558c2ecf20Sopenharmony_ci __le64 *dma_stats; 5568c2ecf20Sopenharmony_ci __le64 generation_start, generation_end; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci dma_stats = efx->stats_buffer.addr; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci generation_end = dma_stats[efx->num_mac_stats - 1]; 5618c2ecf20Sopenharmony_ci if (generation_end == EFX_MC_STATS_GENERATION_INVALID) 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci rmb(); 5648c2ecf20Sopenharmony_ci efx_nic_update_stats(siena_stat_desc, SIENA_STAT_COUNT, siena_stat_mask, 5658c2ecf20Sopenharmony_ci stats, efx->stats_buffer.addr, false); 5668c2ecf20Sopenharmony_ci rmb(); 5678c2ecf20Sopenharmony_ci generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; 5688c2ecf20Sopenharmony_ci if (generation_end != generation_start) 5698c2ecf20Sopenharmony_ci return -EAGAIN; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Update derived statistics */ 5728c2ecf20Sopenharmony_ci efx_nic_fix_nodesc_drop_stat(efx, 5738c2ecf20Sopenharmony_ci &stats[SIENA_STAT_rx_nodesc_drop_cnt]); 5748c2ecf20Sopenharmony_ci efx_update_diff_stat(&stats[SIENA_STAT_tx_good_bytes], 5758c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_bytes] - 5768c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_bad_bytes]); 5778c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_collision] = 5788c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_single_collision] + 5798c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_multiple_collision] + 5808c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_excessive_collision] + 5818c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_late_collision]; 5828c2ecf20Sopenharmony_ci efx_update_diff_stat(&stats[SIENA_STAT_rx_good_bytes], 5838c2ecf20Sopenharmony_ci stats[SIENA_STAT_rx_bytes] - 5848c2ecf20Sopenharmony_ci stats[SIENA_STAT_rx_bad_bytes]); 5858c2ecf20Sopenharmony_ci efx_update_sw_stats(efx, stats); 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic size_t siena_update_nic_stats(struct efx_nic *efx, u64 *full_stats, 5908c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *core_stats) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 5938c2ecf20Sopenharmony_ci u64 *stats = nic_data->stats; 5948c2ecf20Sopenharmony_ci int retry; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* If we're unlucky enough to read statistics wduring the DMA, wait 5978c2ecf20Sopenharmony_ci * up to 10ms for it to finish (typically takes <500us) */ 5988c2ecf20Sopenharmony_ci for (retry = 0; retry < 100; ++retry) { 5998c2ecf20Sopenharmony_ci if (siena_try_update_nic_stats(efx) == 0) 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci udelay(100); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (full_stats) 6058c2ecf20Sopenharmony_ci memcpy(full_stats, stats, sizeof(u64) * SIENA_STAT_COUNT); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (core_stats) { 6088c2ecf20Sopenharmony_ci core_stats->rx_packets = stats[SIENA_STAT_rx_packets]; 6098c2ecf20Sopenharmony_ci core_stats->tx_packets = stats[SIENA_STAT_tx_packets]; 6108c2ecf20Sopenharmony_ci core_stats->rx_bytes = stats[SIENA_STAT_rx_bytes]; 6118c2ecf20Sopenharmony_ci core_stats->tx_bytes = stats[SIENA_STAT_tx_bytes]; 6128c2ecf20Sopenharmony_ci core_stats->rx_dropped = stats[SIENA_STAT_rx_nodesc_drop_cnt] + 6138c2ecf20Sopenharmony_ci stats[GENERIC_STAT_rx_nodesc_trunc] + 6148c2ecf20Sopenharmony_ci stats[GENERIC_STAT_rx_noskb_drops]; 6158c2ecf20Sopenharmony_ci core_stats->multicast = stats[SIENA_STAT_rx_multicast]; 6168c2ecf20Sopenharmony_ci core_stats->collisions = stats[SIENA_STAT_tx_collision]; 6178c2ecf20Sopenharmony_ci core_stats->rx_length_errors = 6188c2ecf20Sopenharmony_ci stats[SIENA_STAT_rx_gtjumbo] + 6198c2ecf20Sopenharmony_ci stats[SIENA_STAT_rx_length_error]; 6208c2ecf20Sopenharmony_ci core_stats->rx_crc_errors = stats[SIENA_STAT_rx_bad]; 6218c2ecf20Sopenharmony_ci core_stats->rx_frame_errors = stats[SIENA_STAT_rx_align_error]; 6228c2ecf20Sopenharmony_ci core_stats->rx_fifo_errors = stats[SIENA_STAT_rx_overflow]; 6238c2ecf20Sopenharmony_ci core_stats->tx_window_errors = 6248c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_late_collision]; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci core_stats->rx_errors = (core_stats->rx_length_errors + 6278c2ecf20Sopenharmony_ci core_stats->rx_crc_errors + 6288c2ecf20Sopenharmony_ci core_stats->rx_frame_errors + 6298c2ecf20Sopenharmony_ci stats[SIENA_STAT_rx_symbol_error]); 6308c2ecf20Sopenharmony_ci core_stats->tx_errors = (core_stats->tx_window_errors + 6318c2ecf20Sopenharmony_ci stats[SIENA_STAT_tx_bad]); 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return SIENA_STAT_COUNT; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int siena_mac_reconfigure(struct efx_nic *efx, bool mtu_only __always_unused) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_MCAST_HASH_IN_LEN); 6408c2ecf20Sopenharmony_ci int rc; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci BUILD_BUG_ON(MC_CMD_SET_MCAST_HASH_IN_LEN != 6438c2ecf20Sopenharmony_ci MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST + 6448c2ecf20Sopenharmony_ci sizeof(efx->multicast_hash)); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci efx_farch_filter_sync_rx_mode(efx); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci rc = efx_mcdi_set_mac(efx); 6518c2ecf20Sopenharmony_ci if (rc != 0) 6528c2ecf20Sopenharmony_ci return rc; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci memcpy(MCDI_PTR(inbuf, SET_MCAST_HASH_IN_HASH0), 6558c2ecf20Sopenharmony_ci efx->multicast_hash.byte, sizeof(efx->multicast_hash)); 6568c2ecf20Sopenharmony_ci return efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH, 6578c2ecf20Sopenharmony_ci inbuf, sizeof(inbuf), NULL, 0, NULL); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/************************************************************************** 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * Wake on LAN 6638c2ecf20Sopenharmony_ci * 6648c2ecf20Sopenharmony_ci ************************************************************************** 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic void siena_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 6728c2ecf20Sopenharmony_ci if (nic_data->wol_filter_id != -1) 6738c2ecf20Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 6748c2ecf20Sopenharmony_ci else 6758c2ecf20Sopenharmony_ci wol->wolopts = 0; 6768c2ecf20Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int siena_set_wol(struct efx_nic *efx, u32 type) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 6838c2ecf20Sopenharmony_ci int rc; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (type & ~WAKE_MAGIC) 6868c2ecf20Sopenharmony_ci return -EINVAL; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (type & WAKE_MAGIC) { 6898c2ecf20Sopenharmony_ci if (nic_data->wol_filter_id != -1) 6908c2ecf20Sopenharmony_ci efx_mcdi_wol_filter_remove(efx, 6918c2ecf20Sopenharmony_ci nic_data->wol_filter_id); 6928c2ecf20Sopenharmony_ci rc = efx_mcdi_wol_filter_set_magic(efx, efx->net_dev->dev_addr, 6938c2ecf20Sopenharmony_ci &nic_data->wol_filter_id); 6948c2ecf20Sopenharmony_ci if (rc) 6958c2ecf20Sopenharmony_ci goto fail; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci pci_wake_from_d3(efx->pci_dev, true); 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci rc = efx_mcdi_wol_filter_reset(efx); 7008c2ecf20Sopenharmony_ci nic_data->wol_filter_id = -1; 7018c2ecf20Sopenharmony_ci pci_wake_from_d3(efx->pci_dev, false); 7028c2ecf20Sopenharmony_ci if (rc) 7038c2ecf20Sopenharmony_ci goto fail; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci fail: 7088c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "%s failed: type=%d rc=%d\n", 7098c2ecf20Sopenharmony_ci __func__, type, rc); 7108c2ecf20Sopenharmony_ci return rc; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void siena_init_wol(struct efx_nic *efx) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 7178c2ecf20Sopenharmony_ci int rc; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci rc = efx_mcdi_wol_filter_get_magic(efx, &nic_data->wol_filter_id); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (rc != 0) { 7228c2ecf20Sopenharmony_ci /* If it failed, attempt to get into a synchronised 7238c2ecf20Sopenharmony_ci * state with MC by resetting any set WoL filters */ 7248c2ecf20Sopenharmony_ci efx_mcdi_wol_filter_reset(efx); 7258c2ecf20Sopenharmony_ci nic_data->wol_filter_id = -1; 7268c2ecf20Sopenharmony_ci } else if (nic_data->wol_filter_id != -1) { 7278c2ecf20Sopenharmony_ci pci_wake_from_d3(efx->pci_dev, true); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci/************************************************************************** 7328c2ecf20Sopenharmony_ci * 7338c2ecf20Sopenharmony_ci * MCDI 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci ************************************************************************** 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci#define MCDI_PDU(efx) \ 7398c2ecf20Sopenharmony_ci (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) 7408c2ecf20Sopenharmony_ci#define MCDI_DOORBELL(efx) \ 7418c2ecf20Sopenharmony_ci (efx_port_num(efx) ? MC_SMEM_P1_DOORBELL_OFST : MC_SMEM_P0_DOORBELL_OFST) 7428c2ecf20Sopenharmony_ci#define MCDI_STATUS(efx) \ 7438c2ecf20Sopenharmony_ci (efx_port_num(efx) ? MC_SMEM_P1_STATUS_OFST : MC_SMEM_P0_STATUS_OFST) 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void siena_mcdi_request(struct efx_nic *efx, 7468c2ecf20Sopenharmony_ci const efx_dword_t *hdr, size_t hdr_len, 7478c2ecf20Sopenharmony_ci const efx_dword_t *sdu, size_t sdu_len) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 7508c2ecf20Sopenharmony_ci unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); 7518c2ecf20Sopenharmony_ci unsigned int i; 7528c2ecf20Sopenharmony_ci unsigned int inlen_dw = DIV_ROUND_UP(sdu_len, 4); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci EFX_WARN_ON_PARANOID(hdr_len != 4); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci efx_writed(efx, hdr, pdu); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci for (i = 0; i < inlen_dw; i++) 7598c2ecf20Sopenharmony_ci efx_writed(efx, &sdu[i], pdu + hdr_len + 4 * i); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* Ensure the request is written out before the doorbell */ 7628c2ecf20Sopenharmony_ci wmb(); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* ring the doorbell with a distinctive value */ 7658c2ecf20Sopenharmony_ci _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic bool siena_mcdi_poll_response(struct efx_nic *efx) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 7718c2ecf20Sopenharmony_ci efx_dword_t hdr; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci efx_readd(efx, &hdr, pdu); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* All 1's indicates that shared memory is in reset (and is 7768c2ecf20Sopenharmony_ci * not a valid hdr). Wait for it to come out reset before 7778c2ecf20Sopenharmony_ci * completing the command 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci return EFX_DWORD_FIELD(hdr, EFX_DWORD_0) != 0xffffffff && 7808c2ecf20Sopenharmony_ci EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void siena_mcdi_read_response(struct efx_nic *efx, efx_dword_t *outbuf, 7848c2ecf20Sopenharmony_ci size_t offset, size_t outlen) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 7878c2ecf20Sopenharmony_ci unsigned int outlen_dw = DIV_ROUND_UP(outlen, 4); 7888c2ecf20Sopenharmony_ci int i; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci for (i = 0; i < outlen_dw; i++) 7918c2ecf20Sopenharmony_ci efx_readd(efx, &outbuf[i], pdu + offset + 4 * i); 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic int siena_mcdi_poll_reboot(struct efx_nic *efx) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct siena_nic_data *nic_data = efx->nic_data; 7978c2ecf20Sopenharmony_ci unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx); 7988c2ecf20Sopenharmony_ci efx_dword_t reg; 7998c2ecf20Sopenharmony_ci u32 value; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci efx_readd(efx, ®, addr); 8028c2ecf20Sopenharmony_ci value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (value == 0) 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci EFX_ZERO_DWORD(reg); 8088c2ecf20Sopenharmony_ci efx_writed(efx, ®, addr); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* MAC statistics have been cleared on the NIC; clear the local 8118c2ecf20Sopenharmony_ci * copies that we update with efx_update_diff_stat(). 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci nic_data->stats[SIENA_STAT_tx_good_bytes] = 0; 8148c2ecf20Sopenharmony_ci nic_data->stats[SIENA_STAT_rx_good_bytes] = 0; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (value == MC_STATUS_DWORD_ASSERT) 8178c2ecf20Sopenharmony_ci return -EINTR; 8188c2ecf20Sopenharmony_ci else 8198c2ecf20Sopenharmony_ci return -EIO; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci/************************************************************************** 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * MTD 8258c2ecf20Sopenharmony_ci * 8268c2ecf20Sopenharmony_ci ************************************************************************** 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_MTD 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistruct siena_nvram_type_info { 8328c2ecf20Sopenharmony_ci int port; 8338c2ecf20Sopenharmony_ci const char *name; 8348c2ecf20Sopenharmony_ci}; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic const struct siena_nvram_type_info siena_nvram_types[] = { 8378c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, 8388c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, 8398c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, 8408c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, 8418c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, 8428c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, 8438c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, 8448c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, 8458c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, 8468c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, 8478c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, 8488c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, 8498c2ecf20Sopenharmony_ci [MC_CMD_NVRAM_TYPE_FPGA] = { 0, "sfc_fpga" }, 8508c2ecf20Sopenharmony_ci}; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int siena_mtd_probe_partition(struct efx_nic *efx, 8538c2ecf20Sopenharmony_ci struct efx_mcdi_mtd_partition *part, 8548c2ecf20Sopenharmony_ci unsigned int type) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci const struct siena_nvram_type_info *info; 8578c2ecf20Sopenharmony_ci size_t size, erase_size; 8588c2ecf20Sopenharmony_ci bool protected; 8598c2ecf20Sopenharmony_ci int rc; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (type >= ARRAY_SIZE(siena_nvram_types) || 8628c2ecf20Sopenharmony_ci siena_nvram_types[type].name == NULL) 8638c2ecf20Sopenharmony_ci return -ENODEV; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci info = &siena_nvram_types[type]; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (info->port != efx_port_num(efx)) 8688c2ecf20Sopenharmony_ci return -ENODEV; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); 8718c2ecf20Sopenharmony_ci if (rc) 8728c2ecf20Sopenharmony_ci return rc; 8738c2ecf20Sopenharmony_ci if (protected) 8748c2ecf20Sopenharmony_ci return -ENODEV; /* hide it */ 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci part->nvram_type = type; 8778c2ecf20Sopenharmony_ci part->common.dev_type_name = "Siena NVRAM manager"; 8788c2ecf20Sopenharmony_ci part->common.type_name = info->name; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci part->common.mtd.type = MTD_NORFLASH; 8818c2ecf20Sopenharmony_ci part->common.mtd.flags = MTD_CAP_NORFLASH; 8828c2ecf20Sopenharmony_ci part->common.mtd.size = size; 8838c2ecf20Sopenharmony_ci part->common.mtd.erasesize = erase_size; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 0; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int siena_mtd_get_fw_subtypes(struct efx_nic *efx, 8898c2ecf20Sopenharmony_ci struct efx_mcdi_mtd_partition *parts, 8908c2ecf20Sopenharmony_ci size_t n_parts) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci uint16_t fw_subtype_list[ 8938c2ecf20Sopenharmony_ci MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM]; 8948c2ecf20Sopenharmony_ci size_t i; 8958c2ecf20Sopenharmony_ci int rc; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list, NULL); 8988c2ecf20Sopenharmony_ci if (rc) 8998c2ecf20Sopenharmony_ci return rc; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci for (i = 0; i < n_parts; i++) 9028c2ecf20Sopenharmony_ci parts[i].fw_subtype = fw_subtype_list[parts[i].nvram_type]; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int siena_mtd_probe(struct efx_nic *efx) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct efx_mcdi_mtd_partition *parts; 9108c2ecf20Sopenharmony_ci u32 nvram_types; 9118c2ecf20Sopenharmony_ci unsigned int type; 9128c2ecf20Sopenharmony_ci size_t n_parts; 9138c2ecf20Sopenharmony_ci int rc; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci ASSERT_RTNL(); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci rc = efx_mcdi_nvram_types(efx, &nvram_types); 9188c2ecf20Sopenharmony_ci if (rc) 9198c2ecf20Sopenharmony_ci return rc; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci parts = kcalloc(hweight32(nvram_types), sizeof(*parts), GFP_KERNEL); 9228c2ecf20Sopenharmony_ci if (!parts) 9238c2ecf20Sopenharmony_ci return -ENOMEM; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci type = 0; 9268c2ecf20Sopenharmony_ci n_parts = 0; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci while (nvram_types != 0) { 9298c2ecf20Sopenharmony_ci if (nvram_types & 1) { 9308c2ecf20Sopenharmony_ci rc = siena_mtd_probe_partition(efx, &parts[n_parts], 9318c2ecf20Sopenharmony_ci type); 9328c2ecf20Sopenharmony_ci if (rc == 0) 9338c2ecf20Sopenharmony_ci n_parts++; 9348c2ecf20Sopenharmony_ci else if (rc != -ENODEV) 9358c2ecf20Sopenharmony_ci goto fail; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci type++; 9388c2ecf20Sopenharmony_ci nvram_types >>= 1; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci rc = siena_mtd_get_fw_subtypes(efx, parts, n_parts); 9428c2ecf20Sopenharmony_ci if (rc) 9438c2ecf20Sopenharmony_ci goto fail; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts)); 9468c2ecf20Sopenharmony_cifail: 9478c2ecf20Sopenharmony_ci if (rc) 9488c2ecf20Sopenharmony_ci kfree(parts); 9498c2ecf20Sopenharmony_ci return rc; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci#endif /* CONFIG_SFC_MTD */ 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic unsigned int siena_check_caps(const struct efx_nic *efx, 9558c2ecf20Sopenharmony_ci u8 flag, u32 offset) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci /* Siena did not support MC_CMD_GET_CAPABILITIES */ 9588c2ecf20Sopenharmony_ci return 0; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci/************************************************************************** 9628c2ecf20Sopenharmony_ci * 9638c2ecf20Sopenharmony_ci * Revision-dependent attributes used by efx.c and nic.c 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci ************************************************************************** 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ciconst struct efx_nic_type siena_a0_nic_type = { 9698c2ecf20Sopenharmony_ci .is_vf = false, 9708c2ecf20Sopenharmony_ci .mem_bar = siena_mem_bar, 9718c2ecf20Sopenharmony_ci .mem_map_size = siena_mem_map_size, 9728c2ecf20Sopenharmony_ci .probe = siena_probe_nic, 9738c2ecf20Sopenharmony_ci .remove = siena_remove_nic, 9748c2ecf20Sopenharmony_ci .init = siena_init_nic, 9758c2ecf20Sopenharmony_ci .dimension_resources = siena_dimension_resources, 9768c2ecf20Sopenharmony_ci .fini = efx_port_dummy_op_void, 9778c2ecf20Sopenharmony_ci#ifdef CONFIG_EEH 9788c2ecf20Sopenharmony_ci .monitor = siena_monitor, 9798c2ecf20Sopenharmony_ci#else 9808c2ecf20Sopenharmony_ci .monitor = NULL, 9818c2ecf20Sopenharmony_ci#endif 9828c2ecf20Sopenharmony_ci .map_reset_reason = efx_mcdi_map_reset_reason, 9838c2ecf20Sopenharmony_ci .map_reset_flags = siena_map_reset_flags, 9848c2ecf20Sopenharmony_ci .reset = efx_mcdi_reset, 9858c2ecf20Sopenharmony_ci .probe_port = efx_mcdi_port_probe, 9868c2ecf20Sopenharmony_ci .remove_port = efx_mcdi_port_remove, 9878c2ecf20Sopenharmony_ci .fini_dmaq = efx_farch_fini_dmaq, 9888c2ecf20Sopenharmony_ci .prepare_flush = siena_prepare_flush, 9898c2ecf20Sopenharmony_ci .finish_flush = siena_finish_flush, 9908c2ecf20Sopenharmony_ci .prepare_flr = efx_port_dummy_op_void, 9918c2ecf20Sopenharmony_ci .finish_flr = efx_farch_finish_flr, 9928c2ecf20Sopenharmony_ci .describe_stats = siena_describe_nic_stats, 9938c2ecf20Sopenharmony_ci .update_stats = siena_update_nic_stats, 9948c2ecf20Sopenharmony_ci .start_stats = efx_mcdi_mac_start_stats, 9958c2ecf20Sopenharmony_ci .pull_stats = efx_mcdi_mac_pull_stats, 9968c2ecf20Sopenharmony_ci .stop_stats = efx_mcdi_mac_stop_stats, 9978c2ecf20Sopenharmony_ci .push_irq_moderation = siena_push_irq_moderation, 9988c2ecf20Sopenharmony_ci .reconfigure_mac = siena_mac_reconfigure, 9998c2ecf20Sopenharmony_ci .check_mac_fault = efx_mcdi_mac_check_fault, 10008c2ecf20Sopenharmony_ci .reconfigure_port = efx_mcdi_port_reconfigure, 10018c2ecf20Sopenharmony_ci .get_wol = siena_get_wol, 10028c2ecf20Sopenharmony_ci .set_wol = siena_set_wol, 10038c2ecf20Sopenharmony_ci .resume_wol = siena_init_wol, 10048c2ecf20Sopenharmony_ci .test_chip = siena_test_chip, 10058c2ecf20Sopenharmony_ci .test_nvram = efx_mcdi_nvram_test_all, 10068c2ecf20Sopenharmony_ci .mcdi_request = siena_mcdi_request, 10078c2ecf20Sopenharmony_ci .mcdi_poll_response = siena_mcdi_poll_response, 10088c2ecf20Sopenharmony_ci .mcdi_read_response = siena_mcdi_read_response, 10098c2ecf20Sopenharmony_ci .mcdi_poll_reboot = siena_mcdi_poll_reboot, 10108c2ecf20Sopenharmony_ci .irq_enable_master = efx_farch_irq_enable_master, 10118c2ecf20Sopenharmony_ci .irq_test_generate = efx_farch_irq_test_generate, 10128c2ecf20Sopenharmony_ci .irq_disable_non_ev = efx_farch_irq_disable_master, 10138c2ecf20Sopenharmony_ci .irq_handle_msi = efx_farch_msi_interrupt, 10148c2ecf20Sopenharmony_ci .irq_handle_legacy = efx_farch_legacy_interrupt, 10158c2ecf20Sopenharmony_ci .tx_probe = efx_farch_tx_probe, 10168c2ecf20Sopenharmony_ci .tx_init = efx_farch_tx_init, 10178c2ecf20Sopenharmony_ci .tx_remove = efx_farch_tx_remove, 10188c2ecf20Sopenharmony_ci .tx_write = efx_farch_tx_write, 10198c2ecf20Sopenharmony_ci .tx_limit_len = efx_farch_tx_limit_len, 10208c2ecf20Sopenharmony_ci .tx_enqueue = __efx_enqueue_skb, 10218c2ecf20Sopenharmony_ci .rx_push_rss_config = siena_rx_push_rss_config, 10228c2ecf20Sopenharmony_ci .rx_pull_rss_config = siena_rx_pull_rss_config, 10238c2ecf20Sopenharmony_ci .rx_probe = efx_farch_rx_probe, 10248c2ecf20Sopenharmony_ci .rx_init = efx_farch_rx_init, 10258c2ecf20Sopenharmony_ci .rx_remove = efx_farch_rx_remove, 10268c2ecf20Sopenharmony_ci .rx_write = efx_farch_rx_write, 10278c2ecf20Sopenharmony_ci .rx_defer_refill = efx_farch_rx_defer_refill, 10288c2ecf20Sopenharmony_ci .rx_packet = __efx_rx_packet, 10298c2ecf20Sopenharmony_ci .ev_probe = efx_farch_ev_probe, 10308c2ecf20Sopenharmony_ci .ev_init = efx_farch_ev_init, 10318c2ecf20Sopenharmony_ci .ev_fini = efx_farch_ev_fini, 10328c2ecf20Sopenharmony_ci .ev_remove = efx_farch_ev_remove, 10338c2ecf20Sopenharmony_ci .ev_process = efx_farch_ev_process, 10348c2ecf20Sopenharmony_ci .ev_read_ack = efx_farch_ev_read_ack, 10358c2ecf20Sopenharmony_ci .ev_test_generate = efx_farch_ev_test_generate, 10368c2ecf20Sopenharmony_ci .filter_table_probe = efx_farch_filter_table_probe, 10378c2ecf20Sopenharmony_ci .filter_table_restore = efx_farch_filter_table_restore, 10388c2ecf20Sopenharmony_ci .filter_table_remove = efx_farch_filter_table_remove, 10398c2ecf20Sopenharmony_ci .filter_update_rx_scatter = efx_farch_filter_update_rx_scatter, 10408c2ecf20Sopenharmony_ci .filter_insert = efx_farch_filter_insert, 10418c2ecf20Sopenharmony_ci .filter_remove_safe = efx_farch_filter_remove_safe, 10428c2ecf20Sopenharmony_ci .filter_get_safe = efx_farch_filter_get_safe, 10438c2ecf20Sopenharmony_ci .filter_clear_rx = efx_farch_filter_clear_rx, 10448c2ecf20Sopenharmony_ci .filter_count_rx_used = efx_farch_filter_count_rx_used, 10458c2ecf20Sopenharmony_ci .filter_get_rx_id_limit = efx_farch_filter_get_rx_id_limit, 10468c2ecf20Sopenharmony_ci .filter_get_rx_ids = efx_farch_filter_get_rx_ids, 10478c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 10488c2ecf20Sopenharmony_ci .filter_rfs_expire_one = efx_farch_filter_rfs_expire_one, 10498c2ecf20Sopenharmony_ci#endif 10508c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_MTD 10518c2ecf20Sopenharmony_ci .mtd_probe = siena_mtd_probe, 10528c2ecf20Sopenharmony_ci .mtd_rename = efx_mcdi_mtd_rename, 10538c2ecf20Sopenharmony_ci .mtd_read = efx_mcdi_mtd_read, 10548c2ecf20Sopenharmony_ci .mtd_erase = efx_mcdi_mtd_erase, 10558c2ecf20Sopenharmony_ci .mtd_write = efx_mcdi_mtd_write, 10568c2ecf20Sopenharmony_ci .mtd_sync = efx_mcdi_mtd_sync, 10578c2ecf20Sopenharmony_ci#endif 10588c2ecf20Sopenharmony_ci .ptp_write_host_time = siena_ptp_write_host_time, 10598c2ecf20Sopenharmony_ci .ptp_set_ts_config = siena_ptp_set_ts_config, 10608c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_SRIOV 10618c2ecf20Sopenharmony_ci .sriov_configure = efx_siena_sriov_configure, 10628c2ecf20Sopenharmony_ci .sriov_init = efx_siena_sriov_init, 10638c2ecf20Sopenharmony_ci .sriov_fini = efx_siena_sriov_fini, 10648c2ecf20Sopenharmony_ci .sriov_wanted = efx_siena_sriov_wanted, 10658c2ecf20Sopenharmony_ci .sriov_reset = efx_siena_sriov_reset, 10668c2ecf20Sopenharmony_ci .sriov_flr = efx_siena_sriov_flr, 10678c2ecf20Sopenharmony_ci .sriov_set_vf_mac = efx_siena_sriov_set_vf_mac, 10688c2ecf20Sopenharmony_ci .sriov_set_vf_vlan = efx_siena_sriov_set_vf_vlan, 10698c2ecf20Sopenharmony_ci .sriov_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk, 10708c2ecf20Sopenharmony_ci .sriov_get_vf_config = efx_siena_sriov_get_vf_config, 10718c2ecf20Sopenharmony_ci .vswitching_probe = efx_port_dummy_op_int, 10728c2ecf20Sopenharmony_ci .vswitching_restore = efx_port_dummy_op_int, 10738c2ecf20Sopenharmony_ci .vswitching_remove = efx_port_dummy_op_void, 10748c2ecf20Sopenharmony_ci .set_mac_address = efx_siena_sriov_mac_address_changed, 10758c2ecf20Sopenharmony_ci#endif 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci .revision = EFX_REV_SIENA_A0, 10788c2ecf20Sopenharmony_ci .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, 10798c2ecf20Sopenharmony_ci .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, 10808c2ecf20Sopenharmony_ci .buf_tbl_base = FR_BZ_BUF_FULL_TBL, 10818c2ecf20Sopenharmony_ci .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, 10828c2ecf20Sopenharmony_ci .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, 10838c2ecf20Sopenharmony_ci .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), 10848c2ecf20Sopenharmony_ci .rx_prefix_size = FS_BZ_RX_PREFIX_SIZE, 10858c2ecf20Sopenharmony_ci .rx_hash_offset = FS_BZ_RX_PREFIX_HASH_OFST, 10868c2ecf20Sopenharmony_ci .rx_buffer_padding = 0, 10878c2ecf20Sopenharmony_ci .can_rx_scatter = true, 10888c2ecf20Sopenharmony_ci .option_descriptors = false, 10898c2ecf20Sopenharmony_ci .min_interrupt_mode = EFX_INT_MODE_LEGACY, 10908c2ecf20Sopenharmony_ci .timer_period_max = 1 << FRF_CZ_TC_TIMER_VAL_WIDTH, 10918c2ecf20Sopenharmony_ci .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 10928c2ecf20Sopenharmony_ci NETIF_F_RXHASH | NETIF_F_NTUPLE), 10938c2ecf20Sopenharmony_ci .mcdi_max_ver = 1, 10948c2ecf20Sopenharmony_ci .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, 10958c2ecf20Sopenharmony_ci .hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE | 10968c2ecf20Sopenharmony_ci 1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT | 10978c2ecf20Sopenharmony_ci 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT), 10988c2ecf20Sopenharmony_ci .rx_hash_key_size = 16, 10998c2ecf20Sopenharmony_ci .check_caps = siena_check_caps, 11008c2ecf20Sopenharmony_ci .sensor_event = efx_mcdi_sensor_event, 11018c2ecf20Sopenharmony_ci}; 1102