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, &reg, 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, &reg, 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, &reg, 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