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/seq_file.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/mii.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "net_driver.h"
198c2ecf20Sopenharmony_ci#include "bitfield.h"
208c2ecf20Sopenharmony_ci#include "efx.h"
218c2ecf20Sopenharmony_ci#include "nic.h"
228c2ecf20Sopenharmony_ci#include "farch_regs.h"
238c2ecf20Sopenharmony_ci#include "io.h"
248c2ecf20Sopenharmony_ci#include "phy.h"
258c2ecf20Sopenharmony_ci#include "workarounds.h"
268c2ecf20Sopenharmony_ci#include "selftest.h"
278c2ecf20Sopenharmony_ci#include "mdio_10g.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Hardware control for SFC4000 (aka Falcon). */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**************************************************************************
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * NIC stats
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci **************************************************************************
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define FALCON_MAC_STATS_SIZE 0x100
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define XgRxOctets_offset 0x0
418c2ecf20Sopenharmony_ci#define XgRxOctets_WIDTH 48
428c2ecf20Sopenharmony_ci#define XgRxOctetsOK_offset 0x8
438c2ecf20Sopenharmony_ci#define XgRxOctetsOK_WIDTH 48
448c2ecf20Sopenharmony_ci#define XgRxPkts_offset 0x10
458c2ecf20Sopenharmony_ci#define XgRxPkts_WIDTH 32
468c2ecf20Sopenharmony_ci#define XgRxPktsOK_offset 0x14
478c2ecf20Sopenharmony_ci#define XgRxPktsOK_WIDTH 32
488c2ecf20Sopenharmony_ci#define XgRxBroadcastPkts_offset 0x18
498c2ecf20Sopenharmony_ci#define XgRxBroadcastPkts_WIDTH 32
508c2ecf20Sopenharmony_ci#define XgRxMulticastPkts_offset 0x1C
518c2ecf20Sopenharmony_ci#define XgRxMulticastPkts_WIDTH 32
528c2ecf20Sopenharmony_ci#define XgRxUnicastPkts_offset 0x20
538c2ecf20Sopenharmony_ci#define XgRxUnicastPkts_WIDTH 32
548c2ecf20Sopenharmony_ci#define XgRxUndersizePkts_offset 0x24
558c2ecf20Sopenharmony_ci#define XgRxUndersizePkts_WIDTH 32
568c2ecf20Sopenharmony_ci#define XgRxOversizePkts_offset 0x28
578c2ecf20Sopenharmony_ci#define XgRxOversizePkts_WIDTH 32
588c2ecf20Sopenharmony_ci#define XgRxJabberPkts_offset 0x2C
598c2ecf20Sopenharmony_ci#define XgRxJabberPkts_WIDTH 32
608c2ecf20Sopenharmony_ci#define XgRxUndersizeFCSerrorPkts_offset 0x30
618c2ecf20Sopenharmony_ci#define XgRxUndersizeFCSerrorPkts_WIDTH 32
628c2ecf20Sopenharmony_ci#define XgRxDropEvents_offset 0x34
638c2ecf20Sopenharmony_ci#define XgRxDropEvents_WIDTH 32
648c2ecf20Sopenharmony_ci#define XgRxFCSerrorPkts_offset 0x38
658c2ecf20Sopenharmony_ci#define XgRxFCSerrorPkts_WIDTH 32
668c2ecf20Sopenharmony_ci#define XgRxAlignError_offset 0x3C
678c2ecf20Sopenharmony_ci#define XgRxAlignError_WIDTH 32
688c2ecf20Sopenharmony_ci#define XgRxSymbolError_offset 0x40
698c2ecf20Sopenharmony_ci#define XgRxSymbolError_WIDTH 32
708c2ecf20Sopenharmony_ci#define XgRxInternalMACError_offset 0x44
718c2ecf20Sopenharmony_ci#define XgRxInternalMACError_WIDTH 32
728c2ecf20Sopenharmony_ci#define XgRxControlPkts_offset 0x48
738c2ecf20Sopenharmony_ci#define XgRxControlPkts_WIDTH 32
748c2ecf20Sopenharmony_ci#define XgRxPausePkts_offset 0x4C
758c2ecf20Sopenharmony_ci#define XgRxPausePkts_WIDTH 32
768c2ecf20Sopenharmony_ci#define XgRxPkts64Octets_offset 0x50
778c2ecf20Sopenharmony_ci#define XgRxPkts64Octets_WIDTH 32
788c2ecf20Sopenharmony_ci#define XgRxPkts65to127Octets_offset 0x54
798c2ecf20Sopenharmony_ci#define XgRxPkts65to127Octets_WIDTH 32
808c2ecf20Sopenharmony_ci#define XgRxPkts128to255Octets_offset 0x58
818c2ecf20Sopenharmony_ci#define XgRxPkts128to255Octets_WIDTH 32
828c2ecf20Sopenharmony_ci#define XgRxPkts256to511Octets_offset 0x5C
838c2ecf20Sopenharmony_ci#define XgRxPkts256to511Octets_WIDTH 32
848c2ecf20Sopenharmony_ci#define XgRxPkts512to1023Octets_offset 0x60
858c2ecf20Sopenharmony_ci#define XgRxPkts512to1023Octets_WIDTH 32
868c2ecf20Sopenharmony_ci#define XgRxPkts1024to15xxOctets_offset 0x64
878c2ecf20Sopenharmony_ci#define XgRxPkts1024to15xxOctets_WIDTH 32
888c2ecf20Sopenharmony_ci#define XgRxPkts15xxtoMaxOctets_offset 0x68
898c2ecf20Sopenharmony_ci#define XgRxPkts15xxtoMaxOctets_WIDTH 32
908c2ecf20Sopenharmony_ci#define XgRxLengthError_offset 0x6C
918c2ecf20Sopenharmony_ci#define XgRxLengthError_WIDTH 32
928c2ecf20Sopenharmony_ci#define XgTxPkts_offset 0x80
938c2ecf20Sopenharmony_ci#define XgTxPkts_WIDTH 32
948c2ecf20Sopenharmony_ci#define XgTxOctets_offset 0x88
958c2ecf20Sopenharmony_ci#define XgTxOctets_WIDTH 48
968c2ecf20Sopenharmony_ci#define XgTxMulticastPkts_offset 0x90
978c2ecf20Sopenharmony_ci#define XgTxMulticastPkts_WIDTH 32
988c2ecf20Sopenharmony_ci#define XgTxBroadcastPkts_offset 0x94
998c2ecf20Sopenharmony_ci#define XgTxBroadcastPkts_WIDTH 32
1008c2ecf20Sopenharmony_ci#define XgTxUnicastPkts_offset 0x98
1018c2ecf20Sopenharmony_ci#define XgTxUnicastPkts_WIDTH 32
1028c2ecf20Sopenharmony_ci#define XgTxControlPkts_offset 0x9C
1038c2ecf20Sopenharmony_ci#define XgTxControlPkts_WIDTH 32
1048c2ecf20Sopenharmony_ci#define XgTxPausePkts_offset 0xA0
1058c2ecf20Sopenharmony_ci#define XgTxPausePkts_WIDTH 32
1068c2ecf20Sopenharmony_ci#define XgTxPkts64Octets_offset 0xA4
1078c2ecf20Sopenharmony_ci#define XgTxPkts64Octets_WIDTH 32
1088c2ecf20Sopenharmony_ci#define XgTxPkts65to127Octets_offset 0xA8
1098c2ecf20Sopenharmony_ci#define XgTxPkts65to127Octets_WIDTH 32
1108c2ecf20Sopenharmony_ci#define XgTxPkts128to255Octets_offset 0xAC
1118c2ecf20Sopenharmony_ci#define XgTxPkts128to255Octets_WIDTH 32
1128c2ecf20Sopenharmony_ci#define XgTxPkts256to511Octets_offset 0xB0
1138c2ecf20Sopenharmony_ci#define XgTxPkts256to511Octets_WIDTH 32
1148c2ecf20Sopenharmony_ci#define XgTxPkts512to1023Octets_offset 0xB4
1158c2ecf20Sopenharmony_ci#define XgTxPkts512to1023Octets_WIDTH 32
1168c2ecf20Sopenharmony_ci#define XgTxPkts1024to15xxOctets_offset 0xB8
1178c2ecf20Sopenharmony_ci#define XgTxPkts1024to15xxOctets_WIDTH 32
1188c2ecf20Sopenharmony_ci#define XgTxPkts1519toMaxOctets_offset 0xBC
1198c2ecf20Sopenharmony_ci#define XgTxPkts1519toMaxOctets_WIDTH 32
1208c2ecf20Sopenharmony_ci#define XgTxUndersizePkts_offset 0xC0
1218c2ecf20Sopenharmony_ci#define XgTxUndersizePkts_WIDTH 32
1228c2ecf20Sopenharmony_ci#define XgTxOversizePkts_offset 0xC4
1238c2ecf20Sopenharmony_ci#define XgTxOversizePkts_WIDTH 32
1248c2ecf20Sopenharmony_ci#define XgTxNonTcpUdpPkt_offset 0xC8
1258c2ecf20Sopenharmony_ci#define XgTxNonTcpUdpPkt_WIDTH 16
1268c2ecf20Sopenharmony_ci#define XgTxMacSrcErrPkt_offset 0xCC
1278c2ecf20Sopenharmony_ci#define XgTxMacSrcErrPkt_WIDTH 16
1288c2ecf20Sopenharmony_ci#define XgTxIpSrcErrPkt_offset 0xD0
1298c2ecf20Sopenharmony_ci#define XgTxIpSrcErrPkt_WIDTH 16
1308c2ecf20Sopenharmony_ci#define XgDmaDone_offset 0xD4
1318c2ecf20Sopenharmony_ci#define XgDmaDone_WIDTH 32
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define FALCON_XMAC_STATS_DMA_FLAG(efx)				\
1348c2ecf20Sopenharmony_ci	(*(u32 *)((efx)->stats_buffer.addr + XgDmaDone_offset))
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define FALCON_DMA_STAT(ext_name, hw_name)				\
1378c2ecf20Sopenharmony_ci	[FALCON_STAT_ ## ext_name] =					\
1388c2ecf20Sopenharmony_ci	{ #ext_name,							\
1398c2ecf20Sopenharmony_ci	  /* 48-bit stats are zero-padded to 64 on DMA */		\
1408c2ecf20Sopenharmony_ci	  hw_name ## _ ## WIDTH == 48 ? 64 : hw_name ## _ ## WIDTH,	\
1418c2ecf20Sopenharmony_ci	  hw_name ## _ ## offset }
1428c2ecf20Sopenharmony_ci#define FALCON_OTHER_STAT(ext_name)					\
1438c2ecf20Sopenharmony_ci	[FALCON_STAT_ ## ext_name] = { #ext_name, 0, 0 }
1448c2ecf20Sopenharmony_ci#define GENERIC_SW_STAT(ext_name)				\
1458c2ecf20Sopenharmony_ci	[GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 }
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic const struct ef4_hw_stat_desc falcon_stat_desc[FALCON_STAT_COUNT] = {
1488c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_bytes, XgTxOctets),
1498c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_packets, XgTxPkts),
1508c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_pause, XgTxPausePkts),
1518c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_control, XgTxControlPkts),
1528c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_unicast, XgTxUnicastPkts),
1538c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_multicast, XgTxMulticastPkts),
1548c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_broadcast, XgTxBroadcastPkts),
1558c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_lt64, XgTxUndersizePkts),
1568c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_64, XgTxPkts64Octets),
1578c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_65_to_127, XgTxPkts65to127Octets),
1588c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_128_to_255, XgTxPkts128to255Octets),
1598c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_256_to_511, XgTxPkts256to511Octets),
1608c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_512_to_1023, XgTxPkts512to1023Octets),
1618c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_1024_to_15xx, XgTxPkts1024to15xxOctets),
1628c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_15xx_to_jumbo, XgTxPkts1519toMaxOctets),
1638c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_gtjumbo, XgTxOversizePkts),
1648c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_non_tcpudp, XgTxNonTcpUdpPkt),
1658c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_mac_src_error, XgTxMacSrcErrPkt),
1668c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(tx_ip_src_error, XgTxIpSrcErrPkt),
1678c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_bytes, XgRxOctets),
1688c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_good_bytes, XgRxOctetsOK),
1698c2ecf20Sopenharmony_ci	FALCON_OTHER_STAT(rx_bad_bytes),
1708c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_packets, XgRxPkts),
1718c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_good, XgRxPktsOK),
1728c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_bad, XgRxFCSerrorPkts),
1738c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_pause, XgRxPausePkts),
1748c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_control, XgRxControlPkts),
1758c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_unicast, XgRxUnicastPkts),
1768c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_multicast, XgRxMulticastPkts),
1778c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_broadcast, XgRxBroadcastPkts),
1788c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_lt64, XgRxUndersizePkts),
1798c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_64, XgRxPkts64Octets),
1808c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_65_to_127, XgRxPkts65to127Octets),
1818c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_128_to_255, XgRxPkts128to255Octets),
1828c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_256_to_511, XgRxPkts256to511Octets),
1838c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_512_to_1023, XgRxPkts512to1023Octets),
1848c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_1024_to_15xx, XgRxPkts1024to15xxOctets),
1858c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_15xx_to_jumbo, XgRxPkts15xxtoMaxOctets),
1868c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_gtjumbo, XgRxOversizePkts),
1878c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_bad_lt64, XgRxUndersizeFCSerrorPkts),
1888c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_bad_gtjumbo, XgRxJabberPkts),
1898c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_overflow, XgRxDropEvents),
1908c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_symbol_error, XgRxSymbolError),
1918c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_align_error, XgRxAlignError),
1928c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_length_error, XgRxLengthError),
1938c2ecf20Sopenharmony_ci	FALCON_DMA_STAT(rx_internal_error, XgRxInternalMACError),
1948c2ecf20Sopenharmony_ci	FALCON_OTHER_STAT(rx_nodesc_drop_cnt),
1958c2ecf20Sopenharmony_ci	GENERIC_SW_STAT(rx_nodesc_trunc),
1968c2ecf20Sopenharmony_ci	GENERIC_SW_STAT(rx_noskb_drops),
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_cistatic const unsigned long falcon_stat_mask[] = {
1998c2ecf20Sopenharmony_ci	[0 ... BITS_TO_LONGS(FALCON_STAT_COUNT) - 1] = ~0UL,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/**************************************************************************
2038c2ecf20Sopenharmony_ci *
2048c2ecf20Sopenharmony_ci * Basic SPI command set and bit definitions
2058c2ecf20Sopenharmony_ci *
2068c2ecf20Sopenharmony_ci *************************************************************************/
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci#define SPI_WRSR 0x01		/* Write status register */
2098c2ecf20Sopenharmony_ci#define SPI_WRITE 0x02		/* Write data to memory array */
2108c2ecf20Sopenharmony_ci#define SPI_READ 0x03		/* Read data from memory array */
2118c2ecf20Sopenharmony_ci#define SPI_WRDI 0x04		/* Reset write enable latch */
2128c2ecf20Sopenharmony_ci#define SPI_RDSR 0x05		/* Read status register */
2138c2ecf20Sopenharmony_ci#define SPI_WREN 0x06		/* Set write enable latch */
2148c2ecf20Sopenharmony_ci#define SPI_SST_EWSR 0x50	/* SST: Enable write to status register */
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci#define SPI_STATUS_WPEN 0x80	/* Write-protect pin enabled */
2178c2ecf20Sopenharmony_ci#define SPI_STATUS_BP2 0x10	/* Block protection bit 2 */
2188c2ecf20Sopenharmony_ci#define SPI_STATUS_BP1 0x08	/* Block protection bit 1 */
2198c2ecf20Sopenharmony_ci#define SPI_STATUS_BP0 0x04	/* Block protection bit 0 */
2208c2ecf20Sopenharmony_ci#define SPI_STATUS_WEN 0x02	/* State of the write enable latch */
2218c2ecf20Sopenharmony_ci#define SPI_STATUS_NRDY 0x01	/* Device busy flag */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/**************************************************************************
2248c2ecf20Sopenharmony_ci *
2258c2ecf20Sopenharmony_ci * Non-volatile memory layout
2268c2ecf20Sopenharmony_ci *
2278c2ecf20Sopenharmony_ci **************************************************************************
2288c2ecf20Sopenharmony_ci */
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/* SFC4000 flash is partitioned into:
2318c2ecf20Sopenharmony_ci *     0-0x400       chip and board config (see struct falcon_nvconfig)
2328c2ecf20Sopenharmony_ci *     0x400-0x8000  unused (or may contain VPD if EEPROM not present)
2338c2ecf20Sopenharmony_ci *     0x8000-end    boot code (mapped to PCI expansion ROM)
2348c2ecf20Sopenharmony_ci * SFC4000 small EEPROM (size < 0x400) is used for VPD only.
2358c2ecf20Sopenharmony_ci * SFC4000 large EEPROM (size >= 0x400) is partitioned into:
2368c2ecf20Sopenharmony_ci *     0-0x400       chip and board config
2378c2ecf20Sopenharmony_ci *     configurable  VPD
2388c2ecf20Sopenharmony_ci *     0x800-0x1800  boot config
2398c2ecf20Sopenharmony_ci * Aside from the chip and board config, all of these are optional and may
2408c2ecf20Sopenharmony_ci * be absent or truncated depending on the devices used.
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_ci#define FALCON_NVCONFIG_END 0x400U
2438c2ecf20Sopenharmony_ci#define FALCON_FLASH_BOOTCODE_START 0x8000U
2448c2ecf20Sopenharmony_ci#define FALCON_EEPROM_BOOTCONFIG_START 0x800U
2458c2ecf20Sopenharmony_ci#define FALCON_EEPROM_BOOTCONFIG_END 0x1800U
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
2488c2ecf20Sopenharmony_cistruct falcon_nvconfig_board_v2 {
2498c2ecf20Sopenharmony_ci	__le16 nports;
2508c2ecf20Sopenharmony_ci	u8 port0_phy_addr;
2518c2ecf20Sopenharmony_ci	u8 port0_phy_type;
2528c2ecf20Sopenharmony_ci	u8 port1_phy_addr;
2538c2ecf20Sopenharmony_ci	u8 port1_phy_type;
2548c2ecf20Sopenharmony_ci	__le16 asic_sub_revision;
2558c2ecf20Sopenharmony_ci	__le16 board_revision;
2568c2ecf20Sopenharmony_ci} __packed;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* Board configuration v3 extra information */
2598c2ecf20Sopenharmony_cistruct falcon_nvconfig_board_v3 {
2608c2ecf20Sopenharmony_ci	__le32 spi_device_type[2];
2618c2ecf20Sopenharmony_ci} __packed;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/* Bit numbers for spi_device_type */
2648c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_SIZE_LBN 0
2658c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_SIZE_WIDTH 5
2668c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
2678c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
2688c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
2698c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
2708c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
2718c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
2728c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
2738c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
2748c2ecf20Sopenharmony_ci#define SPI_DEV_TYPE_FIELD(type, field)					\
2758c2ecf20Sopenharmony_ci	(((type) >> EF4_LOW_BIT(field)) & EF4_MASK32(EF4_WIDTH(field)))
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci#define FALCON_NVCONFIG_OFFSET 0x300
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
2808c2ecf20Sopenharmony_cistruct falcon_nvconfig {
2818c2ecf20Sopenharmony_ci	ef4_oword_t ee_vpd_cfg_reg;			/* 0x300 */
2828c2ecf20Sopenharmony_ci	u8 mac_address[2][8];			/* 0x310 */
2838c2ecf20Sopenharmony_ci	ef4_oword_t pcie_sd_ctl0123_reg;		/* 0x320 */
2848c2ecf20Sopenharmony_ci	ef4_oword_t pcie_sd_ctl45_reg;			/* 0x330 */
2858c2ecf20Sopenharmony_ci	ef4_oword_t pcie_pcs_ctl_stat_reg;		/* 0x340 */
2868c2ecf20Sopenharmony_ci	ef4_oword_t hw_init_reg;			/* 0x350 */
2878c2ecf20Sopenharmony_ci	ef4_oword_t nic_stat_reg;			/* 0x360 */
2888c2ecf20Sopenharmony_ci	ef4_oword_t glb_ctl_reg;			/* 0x370 */
2898c2ecf20Sopenharmony_ci	ef4_oword_t srm_cfg_reg;			/* 0x380 */
2908c2ecf20Sopenharmony_ci	ef4_oword_t spare_reg;				/* 0x390 */
2918c2ecf20Sopenharmony_ci	__le16 board_magic_num;			/* 0x3A0 */
2928c2ecf20Sopenharmony_ci	__le16 board_struct_ver;
2938c2ecf20Sopenharmony_ci	__le16 board_checksum;
2948c2ecf20Sopenharmony_ci	struct falcon_nvconfig_board_v2 board_v2;
2958c2ecf20Sopenharmony_ci	ef4_oword_t ee_base_page_reg;			/* 0x3B0 */
2968c2ecf20Sopenharmony_ci	struct falcon_nvconfig_board_v3 board_v3;	/* 0x3C0 */
2978c2ecf20Sopenharmony_ci} __packed;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/*************************************************************************/
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int falcon_reset_hw(struct ef4_nic *efx, enum reset_type method);
3028c2ecf20Sopenharmony_cistatic void falcon_reconfigure_mac_wrapper(struct ef4_nic *efx);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic const unsigned int
3058c2ecf20Sopenharmony_ci/* "Large" EEPROM device: Atmel AT25640 or similar
3068c2ecf20Sopenharmony_ci * 8 KB, 16-bit address, 32 B write block */
3078c2ecf20Sopenharmony_cilarge_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN)
3088c2ecf20Sopenharmony_ci		     | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
3098c2ecf20Sopenharmony_ci		     | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)),
3108c2ecf20Sopenharmony_ci/* Default flash device: Atmel AT25F1024
3118c2ecf20Sopenharmony_ci * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */
3128c2ecf20Sopenharmony_cidefault_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN)
3138c2ecf20Sopenharmony_ci		      | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
3148c2ecf20Sopenharmony_ci		      | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
3158c2ecf20Sopenharmony_ci		      | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
3168c2ecf20Sopenharmony_ci		      | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN));
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci/**************************************************************************
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * I2C bus - this is a bit-bashing interface using GPIO pins
3218c2ecf20Sopenharmony_ci * Note that it uses the output enables to tristate the outputs
3228c2ecf20Sopenharmony_ci * SDA is the data pin and SCL is the clock
3238c2ecf20Sopenharmony_ci *
3248c2ecf20Sopenharmony_ci **************************************************************************
3258c2ecf20Sopenharmony_ci */
3268c2ecf20Sopenharmony_cistatic void falcon_setsda(void *data, int state)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct ef4_nic *efx = (struct ef4_nic *)data;
3298c2ecf20Sopenharmony_ci	ef4_oword_t reg;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_GPIO_CTL);
3328c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state);
3338c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_GPIO_CTL);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void falcon_setscl(void *data, int state)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct ef4_nic *efx = (struct ef4_nic *)data;
3398c2ecf20Sopenharmony_ci	ef4_oword_t reg;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_GPIO_CTL);
3428c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state);
3438c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_GPIO_CTL);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int falcon_getsda(void *data)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct ef4_nic *efx = (struct ef4_nic *)data;
3498c2ecf20Sopenharmony_ci	ef4_oword_t reg;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_GPIO_CTL);
3528c2ecf20Sopenharmony_ci	return EF4_OWORD_FIELD(reg, FRF_AB_GPIO3_IN);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int falcon_getscl(void *data)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct ef4_nic *efx = (struct ef4_nic *)data;
3588c2ecf20Sopenharmony_ci	ef4_oword_t reg;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_GPIO_CTL);
3618c2ecf20Sopenharmony_ci	return EF4_OWORD_FIELD(reg, FRF_AB_GPIO0_IN);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic const struct i2c_algo_bit_data falcon_i2c_bit_operations = {
3658c2ecf20Sopenharmony_ci	.setsda		= falcon_setsda,
3668c2ecf20Sopenharmony_ci	.setscl		= falcon_setscl,
3678c2ecf20Sopenharmony_ci	.getsda		= falcon_getsda,
3688c2ecf20Sopenharmony_ci	.getscl		= falcon_getscl,
3698c2ecf20Sopenharmony_ci	.udelay		= 5,
3708c2ecf20Sopenharmony_ci	/* Wait up to 50 ms for slave to let us pull SCL high */
3718c2ecf20Sopenharmony_ci	.timeout	= DIV_ROUND_UP(HZ, 20),
3728c2ecf20Sopenharmony_ci};
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic void falcon_push_irq_moderation(struct ef4_channel *channel)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	ef4_dword_t timer_cmd;
3778c2ecf20Sopenharmony_ci	struct ef4_nic *efx = channel->efx;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* Set timer register */
3808c2ecf20Sopenharmony_ci	if (channel->irq_moderation_us) {
3818c2ecf20Sopenharmony_ci		unsigned int ticks;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		ticks = ef4_usecs_to_ticks(efx, channel->irq_moderation_us);
3848c2ecf20Sopenharmony_ci		EF4_POPULATE_DWORD_2(timer_cmd,
3858c2ecf20Sopenharmony_ci				     FRF_AB_TC_TIMER_MODE,
3868c2ecf20Sopenharmony_ci				     FFE_BB_TIMER_MODE_INT_HLDOFF,
3878c2ecf20Sopenharmony_ci				     FRF_AB_TC_TIMER_VAL,
3888c2ecf20Sopenharmony_ci				     ticks - 1);
3898c2ecf20Sopenharmony_ci	} else {
3908c2ecf20Sopenharmony_ci		EF4_POPULATE_DWORD_2(timer_cmd,
3918c2ecf20Sopenharmony_ci				     FRF_AB_TC_TIMER_MODE,
3928c2ecf20Sopenharmony_ci				     FFE_BB_TIMER_MODE_DIS,
3938c2ecf20Sopenharmony_ci				     FRF_AB_TC_TIMER_VAL, 0);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci	BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0);
3968c2ecf20Sopenharmony_ci	ef4_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0,
3978c2ecf20Sopenharmony_ci			       channel->channel);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic void falcon_deconfigure_mac_wrapper(struct ef4_nic *efx);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void falcon_prepare_flush(struct ef4_nic *efx)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	falcon_deconfigure_mac_wrapper(efx);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* Wait for the tx and rx fifo's to get to the next packet boundary
4078c2ecf20Sopenharmony_ci	 * (~1ms without back-pressure), then to drain the remainder of the
4088c2ecf20Sopenharmony_ci	 * fifo's at data path speeds (negligible), with a healthy margin. */
4098c2ecf20Sopenharmony_ci	msleep(10);
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci/* Acknowledge a legacy interrupt from Falcon
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
4158c2ecf20Sopenharmony_ci *
4168c2ecf20Sopenharmony_ci * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
4178c2ecf20Sopenharmony_ci * BIU. Interrupt acknowledge is read sensitive so must write instead
4188c2ecf20Sopenharmony_ci * (then read to ensure the BIU collector is flushed)
4198c2ecf20Sopenharmony_ci *
4208c2ecf20Sopenharmony_ci * NB most hardware supports MSI interrupts
4218c2ecf20Sopenharmony_ci */
4228c2ecf20Sopenharmony_cistatic inline void falcon_irq_ack_a1(struct ef4_nic *efx)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	ef4_dword_t reg;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	EF4_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e);
4278c2ecf20Sopenharmony_ci	ef4_writed(efx, &reg, FR_AA_INT_ACK_KER);
4288c2ecf20Sopenharmony_ci	ef4_readd(efx, &reg, FR_AA_WORK_AROUND_BROKEN_PCI_READS);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct ef4_nic *efx = dev_id;
4348c2ecf20Sopenharmony_ci	ef4_oword_t *int_ker = efx->irq_status.addr;
4358c2ecf20Sopenharmony_ci	int syserr;
4368c2ecf20Sopenharmony_ci	int queues;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* Check to see if this is our interrupt.  If it isn't, we
4398c2ecf20Sopenharmony_ci	 * exit without having touched the hardware.
4408c2ecf20Sopenharmony_ci	 */
4418c2ecf20Sopenharmony_ci	if (unlikely(EF4_OWORD_IS_ZERO(*int_ker))) {
4428c2ecf20Sopenharmony_ci		netif_vdbg(efx, intr, efx->net_dev,
4438c2ecf20Sopenharmony_ci			   "IRQ %d on CPU %d not for me\n", irq,
4448c2ecf20Sopenharmony_ci			   raw_smp_processor_id());
4458c2ecf20Sopenharmony_ci		return IRQ_NONE;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci	efx->last_irq_cpu = raw_smp_processor_id();
4488c2ecf20Sopenharmony_ci	netif_vdbg(efx, intr, efx->net_dev,
4498c2ecf20Sopenharmony_ci		   "IRQ %d on CPU %d status " EF4_OWORD_FMT "\n",
4508c2ecf20Sopenharmony_ci		   irq, raw_smp_processor_id(), EF4_OWORD_VAL(*int_ker));
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (!likely(READ_ONCE(efx->irq_soft_enabled)))
4538c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Check to see if we have a serious error condition */
4568c2ecf20Sopenharmony_ci	syserr = EF4_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
4578c2ecf20Sopenharmony_ci	if (unlikely(syserr))
4588c2ecf20Sopenharmony_ci		return ef4_farch_fatal_interrupt(efx);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Determine interrupting queues, clear interrupt status
4618c2ecf20Sopenharmony_ci	 * register and acknowledge the device interrupt.
4628c2ecf20Sopenharmony_ci	 */
4638c2ecf20Sopenharmony_ci	BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EF4_MAX_CHANNELS);
4648c2ecf20Sopenharmony_ci	queues = EF4_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
4658c2ecf20Sopenharmony_ci	EF4_ZERO_OWORD(*int_ker);
4668c2ecf20Sopenharmony_ci	wmb(); /* Ensure the vector is cleared before interrupt ack */
4678c2ecf20Sopenharmony_ci	falcon_irq_ack_a1(efx);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (queues & 1)
4708c2ecf20Sopenharmony_ci		ef4_schedule_channel_irq(ef4_get_channel(efx, 0));
4718c2ecf20Sopenharmony_ci	if (queues & 2)
4728c2ecf20Sopenharmony_ci		ef4_schedule_channel_irq(ef4_get_channel(efx, 1));
4738c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/**************************************************************************
4778c2ecf20Sopenharmony_ci *
4788c2ecf20Sopenharmony_ci * RSS
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci **************************************************************************
4818c2ecf20Sopenharmony_ci */
4828c2ecf20Sopenharmony_cistatic int dummy_rx_push_rss_config(struct ef4_nic *efx, bool user,
4838c2ecf20Sopenharmony_ci				    const u32 *rx_indir_table)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	(void) efx;
4868c2ecf20Sopenharmony_ci	(void) user;
4878c2ecf20Sopenharmony_ci	(void) rx_indir_table;
4888c2ecf20Sopenharmony_ci	return -ENOSYS;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int falcon_b0_rx_push_rss_config(struct ef4_nic *efx, bool user,
4928c2ecf20Sopenharmony_ci					const u32 *rx_indir_table)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	ef4_oword_t temp;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	(void) user;
4978c2ecf20Sopenharmony_ci	/* Set hash key for IPv4 */
4988c2ecf20Sopenharmony_ci	memcpy(&temp, efx->rx_hash_key, sizeof(temp));
4998c2ecf20Sopenharmony_ci	ef4_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	memcpy(efx->rx_indir_table, rx_indir_table,
5028c2ecf20Sopenharmony_ci	       sizeof(efx->rx_indir_table));
5038c2ecf20Sopenharmony_ci	ef4_farch_rx_push_indir_table(efx);
5048c2ecf20Sopenharmony_ci	return 0;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/**************************************************************************
5088c2ecf20Sopenharmony_ci *
5098c2ecf20Sopenharmony_ci * EEPROM/flash
5108c2ecf20Sopenharmony_ci *
5118c2ecf20Sopenharmony_ci **************************************************************************
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci#define FALCON_SPI_MAX_LEN sizeof(ef4_oword_t)
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic int falcon_spi_poll(struct ef4_nic *efx)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	ef4_oword_t reg;
5198c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_EE_SPI_HCMD);
5208c2ecf20Sopenharmony_ci	return EF4_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/* Wait for SPI command completion */
5248c2ecf20Sopenharmony_cistatic int falcon_spi_wait(struct ef4_nic *efx)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	/* Most commands will finish quickly, so we start polling at
5278c2ecf20Sopenharmony_ci	 * very short intervals.  Sometimes the command may have to
5288c2ecf20Sopenharmony_ci	 * wait for VPD or expansion ROM access outside of our
5298c2ecf20Sopenharmony_ci	 * control, so we allow up to 100 ms. */
5308c2ecf20Sopenharmony_ci	unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10);
5318c2ecf20Sopenharmony_ci	int i;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
5348c2ecf20Sopenharmony_ci		if (!falcon_spi_poll(efx))
5358c2ecf20Sopenharmony_ci			return 0;
5368c2ecf20Sopenharmony_ci		udelay(10);
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	for (;;) {
5408c2ecf20Sopenharmony_ci		if (!falcon_spi_poll(efx))
5418c2ecf20Sopenharmony_ci			return 0;
5428c2ecf20Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
5438c2ecf20Sopenharmony_ci			netif_err(efx, hw, efx->net_dev,
5448c2ecf20Sopenharmony_ci				  "timed out waiting for SPI\n");
5458c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
5468c2ecf20Sopenharmony_ci		}
5478c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic int
5528c2ecf20Sopenharmony_cifalcon_spi_cmd(struct ef4_nic *efx, const struct falcon_spi_device *spi,
5538c2ecf20Sopenharmony_ci	       unsigned int command, int address,
5548c2ecf20Sopenharmony_ci	       const void *in, void *out, size_t len)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	bool addressed = (address >= 0);
5578c2ecf20Sopenharmony_ci	bool reading = (out != NULL);
5588c2ecf20Sopenharmony_ci	ef4_oword_t reg;
5598c2ecf20Sopenharmony_ci	int rc;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/* Input validation */
5628c2ecf20Sopenharmony_ci	if (len > FALCON_SPI_MAX_LEN)
5638c2ecf20Sopenharmony_ci		return -EINVAL;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* Check that previous command is not still running */
5668c2ecf20Sopenharmony_ci	rc = falcon_spi_poll(efx);
5678c2ecf20Sopenharmony_ci	if (rc)
5688c2ecf20Sopenharmony_ci		return rc;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	/* Program address register, if we have an address */
5718c2ecf20Sopenharmony_ci	if (addressed) {
5728c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address);
5738c2ecf20Sopenharmony_ci		ef4_writeo(efx, &reg, FR_AB_EE_SPI_HADR);
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* Program data register, if we have data */
5778c2ecf20Sopenharmony_ci	if (in != NULL) {
5788c2ecf20Sopenharmony_ci		memcpy(&reg, in, len);
5798c2ecf20Sopenharmony_ci		ef4_writeo(efx, &reg, FR_AB_EE_SPI_HDATA);
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Issue read/write command */
5838c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_7(reg,
5848c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_CMD_EN, 1,
5858c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id,
5868c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_DABCNT, len,
5878c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_READ, reading,
5888c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_DUBCNT, 0,
5898c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_ADBCNT,
5908c2ecf20Sopenharmony_ci			     (addressed ? spi->addr_len : 0),
5918c2ecf20Sopenharmony_ci			     FRF_AB_EE_SPI_HCMD_ENC, command);
5928c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_EE_SPI_HCMD);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* Wait for read/write to complete */
5958c2ecf20Sopenharmony_ci	rc = falcon_spi_wait(efx);
5968c2ecf20Sopenharmony_ci	if (rc)
5978c2ecf20Sopenharmony_ci		return rc;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* Read data */
6008c2ecf20Sopenharmony_ci	if (out != NULL) {
6018c2ecf20Sopenharmony_ci		ef4_reado(efx, &reg, FR_AB_EE_SPI_HDATA);
6028c2ecf20Sopenharmony_ci		memcpy(out, &reg, len);
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return 0;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic inline u8
6098c2ecf20Sopenharmony_cifalcon_spi_munge_command(const struct falcon_spi_device *spi,
6108c2ecf20Sopenharmony_ci			 const u8 command, const unsigned int address)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	return command | (((address >> 8) & spi->munge_address) << 3);
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic int
6168c2ecf20Sopenharmony_cifalcon_spi_read(struct ef4_nic *efx, const struct falcon_spi_device *spi,
6178c2ecf20Sopenharmony_ci		loff_t start, size_t len, size_t *retlen, u8 *buffer)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	size_t block_len, pos = 0;
6208c2ecf20Sopenharmony_ci	unsigned int command;
6218c2ecf20Sopenharmony_ci	int rc = 0;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	while (pos < len) {
6248c2ecf20Sopenharmony_ci		block_len = min(len - pos, FALCON_SPI_MAX_LEN);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		command = falcon_spi_munge_command(spi, SPI_READ, start + pos);
6278c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL,
6288c2ecf20Sopenharmony_ci				    buffer + pos, block_len);
6298c2ecf20Sopenharmony_ci		if (rc)
6308c2ecf20Sopenharmony_ci			break;
6318c2ecf20Sopenharmony_ci		pos += block_len;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		/* Avoid locking up the system */
6348c2ecf20Sopenharmony_ci		cond_resched();
6358c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
6368c2ecf20Sopenharmony_ci			rc = -EINTR;
6378c2ecf20Sopenharmony_ci			break;
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (retlen)
6428c2ecf20Sopenharmony_ci		*retlen = pos;
6438c2ecf20Sopenharmony_ci	return rc;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistruct falcon_mtd_partition {
6498c2ecf20Sopenharmony_ci	struct ef4_mtd_partition common;
6508c2ecf20Sopenharmony_ci	const struct falcon_spi_device *spi;
6518c2ecf20Sopenharmony_ci	size_t offset;
6528c2ecf20Sopenharmony_ci};
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci#define to_falcon_mtd_partition(mtd)				\
6558c2ecf20Sopenharmony_ci	container_of(mtd, struct falcon_mtd_partition, common.mtd)
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic size_t
6588c2ecf20Sopenharmony_cifalcon_spi_write_limit(const struct falcon_spi_device *spi, size_t start)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	return min(FALCON_SPI_MAX_LEN,
6618c2ecf20Sopenharmony_ci		   (spi->block_size - (start & (spi->block_size - 1))));
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci/* Wait up to 10 ms for buffered write completion */
6658c2ecf20Sopenharmony_cistatic int
6668c2ecf20Sopenharmony_cifalcon_spi_wait_write(struct ef4_nic *efx, const struct falcon_spi_device *spi)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100);
6698c2ecf20Sopenharmony_ci	u8 status;
6708c2ecf20Sopenharmony_ci	int rc;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	for (;;) {
6738c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
6748c2ecf20Sopenharmony_ci				    &status, sizeof(status));
6758c2ecf20Sopenharmony_ci		if (rc)
6768c2ecf20Sopenharmony_ci			return rc;
6778c2ecf20Sopenharmony_ci		if (!(status & SPI_STATUS_NRDY))
6788c2ecf20Sopenharmony_ci			return 0;
6798c2ecf20Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
6808c2ecf20Sopenharmony_ci			netif_err(efx, hw, efx->net_dev,
6818c2ecf20Sopenharmony_ci				  "SPI write timeout on device %d"
6828c2ecf20Sopenharmony_ci				  " last status=0x%02x\n",
6838c2ecf20Sopenharmony_ci				  spi->device_id, status);
6848c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
6858c2ecf20Sopenharmony_ci		}
6868c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic int
6918c2ecf20Sopenharmony_cifalcon_spi_write(struct ef4_nic *efx, const struct falcon_spi_device *spi,
6928c2ecf20Sopenharmony_ci		 loff_t start, size_t len, size_t *retlen, const u8 *buffer)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	u8 verify_buffer[FALCON_SPI_MAX_LEN];
6958c2ecf20Sopenharmony_ci	size_t block_len, pos = 0;
6968c2ecf20Sopenharmony_ci	unsigned int command;
6978c2ecf20Sopenharmony_ci	int rc = 0;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	while (pos < len) {
7008c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
7018c2ecf20Sopenharmony_ci		if (rc)
7028c2ecf20Sopenharmony_ci			break;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		block_len = min(len - pos,
7058c2ecf20Sopenharmony_ci				falcon_spi_write_limit(spi, start + pos));
7068c2ecf20Sopenharmony_ci		command = falcon_spi_munge_command(spi, SPI_WRITE, start + pos);
7078c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, command, start + pos,
7088c2ecf20Sopenharmony_ci				    buffer + pos, NULL, block_len);
7098c2ecf20Sopenharmony_ci		if (rc)
7108c2ecf20Sopenharmony_ci			break;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		rc = falcon_spi_wait_write(efx, spi);
7138c2ecf20Sopenharmony_ci		if (rc)
7148c2ecf20Sopenharmony_ci			break;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		command = falcon_spi_munge_command(spi, SPI_READ, start + pos);
7178c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, command, start + pos,
7188c2ecf20Sopenharmony_ci				    NULL, verify_buffer, block_len);
7198c2ecf20Sopenharmony_ci		if (memcmp(verify_buffer, buffer + pos, block_len)) {
7208c2ecf20Sopenharmony_ci			rc = -EIO;
7218c2ecf20Sopenharmony_ci			break;
7228c2ecf20Sopenharmony_ci		}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		pos += block_len;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		/* Avoid locking up the system */
7278c2ecf20Sopenharmony_ci		cond_resched();
7288c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
7298c2ecf20Sopenharmony_ci			rc = -EINTR;
7308c2ecf20Sopenharmony_ci			break;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (retlen)
7358c2ecf20Sopenharmony_ci		*retlen = pos;
7368c2ecf20Sopenharmony_ci	return rc;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic int
7408c2ecf20Sopenharmony_cifalcon_spi_slow_wait(struct falcon_mtd_partition *part, bool uninterruptible)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	const struct falcon_spi_device *spi = part->spi;
7438c2ecf20Sopenharmony_ci	struct ef4_nic *efx = part->common.mtd.priv;
7448c2ecf20Sopenharmony_ci	u8 status;
7458c2ecf20Sopenharmony_ci	int rc, i;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
7488c2ecf20Sopenharmony_ci	for (i = 0; i < 40; i++) {
7498c2ecf20Sopenharmony_ci		__set_current_state(uninterruptible ?
7508c2ecf20Sopenharmony_ci				    TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
7518c2ecf20Sopenharmony_ci		schedule_timeout(HZ / 10);
7528c2ecf20Sopenharmony_ci		rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
7538c2ecf20Sopenharmony_ci				    &status, sizeof(status));
7548c2ecf20Sopenharmony_ci		if (rc)
7558c2ecf20Sopenharmony_ci			return rc;
7568c2ecf20Sopenharmony_ci		if (!(status & SPI_STATUS_NRDY))
7578c2ecf20Sopenharmony_ci			return 0;
7588c2ecf20Sopenharmony_ci		if (signal_pending(current))
7598c2ecf20Sopenharmony_ci			return -EINTR;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci	pr_err("%s: timed out waiting for %s\n",
7628c2ecf20Sopenharmony_ci	       part->common.name, part->common.dev_type_name);
7638c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic int
7678c2ecf20Sopenharmony_cifalcon_spi_unlock(struct ef4_nic *efx, const struct falcon_spi_device *spi)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
7708c2ecf20Sopenharmony_ci				SPI_STATUS_BP0);
7718c2ecf20Sopenharmony_ci	u8 status;
7728c2ecf20Sopenharmony_ci	int rc;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
7758c2ecf20Sopenharmony_ci			    &status, sizeof(status));
7768c2ecf20Sopenharmony_ci	if (rc)
7778c2ecf20Sopenharmony_ci		return rc;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (!(status & unlock_mask))
7808c2ecf20Sopenharmony_ci		return 0; /* already unlocked */
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
7838c2ecf20Sopenharmony_ci	if (rc)
7848c2ecf20Sopenharmony_ci		return rc;
7858c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
7868c2ecf20Sopenharmony_ci	if (rc)
7878c2ecf20Sopenharmony_ci		return rc;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	status &= ~unlock_mask;
7908c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status,
7918c2ecf20Sopenharmony_ci			    NULL, sizeof(status));
7928c2ecf20Sopenharmony_ci	if (rc)
7938c2ecf20Sopenharmony_ci		return rc;
7948c2ecf20Sopenharmony_ci	rc = falcon_spi_wait_write(efx, spi);
7958c2ecf20Sopenharmony_ci	if (rc)
7968c2ecf20Sopenharmony_ci		return rc;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return 0;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci#define FALCON_SPI_VERIFY_BUF_LEN 16
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic int
8048c2ecf20Sopenharmony_cifalcon_spi_erase(struct falcon_mtd_partition *part, loff_t start, size_t len)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	const struct falcon_spi_device *spi = part->spi;
8078c2ecf20Sopenharmony_ci	struct ef4_nic *efx = part->common.mtd.priv;
8088c2ecf20Sopenharmony_ci	unsigned pos, block_len;
8098c2ecf20Sopenharmony_ci	u8 empty[FALCON_SPI_VERIFY_BUF_LEN];
8108c2ecf20Sopenharmony_ci	u8 buffer[FALCON_SPI_VERIFY_BUF_LEN];
8118c2ecf20Sopenharmony_ci	int rc;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (len != spi->erase_size)
8148c2ecf20Sopenharmony_ci		return -EINVAL;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (spi->erase_command == 0)
8178c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	rc = falcon_spi_unlock(efx, spi);
8208c2ecf20Sopenharmony_ci	if (rc)
8218c2ecf20Sopenharmony_ci		return rc;
8228c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
8238c2ecf20Sopenharmony_ci	if (rc)
8248c2ecf20Sopenharmony_ci		return rc;
8258c2ecf20Sopenharmony_ci	rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL,
8268c2ecf20Sopenharmony_ci			    NULL, 0);
8278c2ecf20Sopenharmony_ci	if (rc)
8288c2ecf20Sopenharmony_ci		return rc;
8298c2ecf20Sopenharmony_ci	rc = falcon_spi_slow_wait(part, false);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* Verify the entire region has been wiped */
8328c2ecf20Sopenharmony_ci	memset(empty, 0xff, sizeof(empty));
8338c2ecf20Sopenharmony_ci	for (pos = 0; pos < len; pos += block_len) {
8348c2ecf20Sopenharmony_ci		block_len = min(len - pos, sizeof(buffer));
8358c2ecf20Sopenharmony_ci		rc = falcon_spi_read(efx, spi, start + pos, block_len,
8368c2ecf20Sopenharmony_ci				     NULL, buffer);
8378c2ecf20Sopenharmony_ci		if (rc)
8388c2ecf20Sopenharmony_ci			return rc;
8398c2ecf20Sopenharmony_ci		if (memcmp(empty, buffer, block_len))
8408c2ecf20Sopenharmony_ci			return -EIO;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci		/* Avoid locking up the system */
8438c2ecf20Sopenharmony_ci		cond_resched();
8448c2ecf20Sopenharmony_ci		if (signal_pending(current))
8458c2ecf20Sopenharmony_ci			return -EINTR;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	return rc;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_cistatic void falcon_mtd_rename(struct ef4_mtd_partition *part)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	struct ef4_nic *efx = part->mtd.priv;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	snprintf(part->name, sizeof(part->name), "%s %s",
8568c2ecf20Sopenharmony_ci		 efx->name, part->type_name);
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_cistatic int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
8608c2ecf20Sopenharmony_ci			   size_t len, size_t *retlen, u8 *buffer)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
8638c2ecf20Sopenharmony_ci	struct ef4_nic *efx = mtd->priv;
8648c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
8658c2ecf20Sopenharmony_ci	int rc;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	rc = mutex_lock_interruptible(&nic_data->spi_lock);
8688c2ecf20Sopenharmony_ci	if (rc)
8698c2ecf20Sopenharmony_ci		return rc;
8708c2ecf20Sopenharmony_ci	rc = falcon_spi_read(efx, part->spi, part->offset + start,
8718c2ecf20Sopenharmony_ci			     len, retlen, buffer);
8728c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
8738c2ecf20Sopenharmony_ci	return rc;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
8798c2ecf20Sopenharmony_ci	struct ef4_nic *efx = mtd->priv;
8808c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
8818c2ecf20Sopenharmony_ci	int rc;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	rc = mutex_lock_interruptible(&nic_data->spi_lock);
8848c2ecf20Sopenharmony_ci	if (rc)
8858c2ecf20Sopenharmony_ci		return rc;
8868c2ecf20Sopenharmony_ci	rc = falcon_spi_erase(part, part->offset + start, len);
8878c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
8888c2ecf20Sopenharmony_ci	return rc;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
8928c2ecf20Sopenharmony_ci			    size_t len, size_t *retlen, const u8 *buffer)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
8958c2ecf20Sopenharmony_ci	struct ef4_nic *efx = mtd->priv;
8968c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
8978c2ecf20Sopenharmony_ci	int rc;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	rc = mutex_lock_interruptible(&nic_data->spi_lock);
9008c2ecf20Sopenharmony_ci	if (rc)
9018c2ecf20Sopenharmony_ci		return rc;
9028c2ecf20Sopenharmony_ci	rc = falcon_spi_write(efx, part->spi, part->offset + start,
9038c2ecf20Sopenharmony_ci			      len, retlen, buffer);
9048c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
9058c2ecf20Sopenharmony_ci	return rc;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic int falcon_mtd_sync(struct mtd_info *mtd)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
9118c2ecf20Sopenharmony_ci	struct ef4_nic *efx = mtd->priv;
9128c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
9138c2ecf20Sopenharmony_ci	int rc;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	mutex_lock(&nic_data->spi_lock);
9168c2ecf20Sopenharmony_ci	rc = falcon_spi_slow_wait(part, true);
9178c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
9188c2ecf20Sopenharmony_ci	return rc;
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic int falcon_mtd_probe(struct ef4_nic *efx)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
9248c2ecf20Sopenharmony_ci	struct falcon_mtd_partition *parts;
9258c2ecf20Sopenharmony_ci	struct falcon_spi_device *spi;
9268c2ecf20Sopenharmony_ci	size_t n_parts;
9278c2ecf20Sopenharmony_ci	int rc = -ENODEV;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	ASSERT_RTNL();
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	/* Allocate space for maximum number of partitions */
9328c2ecf20Sopenharmony_ci	parts = kcalloc(2, sizeof(*parts), GFP_KERNEL);
9338c2ecf20Sopenharmony_ci	if (!parts)
9348c2ecf20Sopenharmony_ci		return -ENOMEM;
9358c2ecf20Sopenharmony_ci	n_parts = 0;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	spi = &nic_data->spi_flash;
9388c2ecf20Sopenharmony_ci	if (falcon_spi_present(spi) && spi->size > FALCON_FLASH_BOOTCODE_START) {
9398c2ecf20Sopenharmony_ci		parts[n_parts].spi = spi;
9408c2ecf20Sopenharmony_ci		parts[n_parts].offset = FALCON_FLASH_BOOTCODE_START;
9418c2ecf20Sopenharmony_ci		parts[n_parts].common.dev_type_name = "flash";
9428c2ecf20Sopenharmony_ci		parts[n_parts].common.type_name = "sfc_flash_bootrom";
9438c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.type = MTD_NORFLASH;
9448c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.flags = MTD_CAP_NORFLASH;
9458c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
9468c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.erasesize = spi->erase_size;
9478c2ecf20Sopenharmony_ci		n_parts++;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	spi = &nic_data->spi_eeprom;
9518c2ecf20Sopenharmony_ci	if (falcon_spi_present(spi) && spi->size > FALCON_EEPROM_BOOTCONFIG_START) {
9528c2ecf20Sopenharmony_ci		parts[n_parts].spi = spi;
9538c2ecf20Sopenharmony_ci		parts[n_parts].offset = FALCON_EEPROM_BOOTCONFIG_START;
9548c2ecf20Sopenharmony_ci		parts[n_parts].common.dev_type_name = "EEPROM";
9558c2ecf20Sopenharmony_ci		parts[n_parts].common.type_name = "sfc_bootconfig";
9568c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.type = MTD_RAM;
9578c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.flags = MTD_CAP_RAM;
9588c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.size =
9598c2ecf20Sopenharmony_ci			min(spi->size, FALCON_EEPROM_BOOTCONFIG_END) -
9608c2ecf20Sopenharmony_ci			FALCON_EEPROM_BOOTCONFIG_START;
9618c2ecf20Sopenharmony_ci		parts[n_parts].common.mtd.erasesize = spi->erase_size;
9628c2ecf20Sopenharmony_ci		n_parts++;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	rc = ef4_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts));
9668c2ecf20Sopenharmony_ci	if (rc)
9678c2ecf20Sopenharmony_ci		kfree(parts);
9688c2ecf20Sopenharmony_ci	return rc;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci#endif /* CONFIG_SFC_FALCON_MTD */
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci/**************************************************************************
9748c2ecf20Sopenharmony_ci *
9758c2ecf20Sopenharmony_ci * XMAC operations
9768c2ecf20Sopenharmony_ci *
9778c2ecf20Sopenharmony_ci **************************************************************************
9788c2ecf20Sopenharmony_ci */
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/* Configure the XAUI driver that is an output from Falcon */
9818c2ecf20Sopenharmony_cistatic void falcon_setup_xaui(struct ef4_nic *efx)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	ef4_oword_t sdctl, txdrv;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	/* Move the XAUI into low power, unless there is no PHY, in
9868c2ecf20Sopenharmony_ci	 * which case the XAUI will have to drive a cable. */
9878c2ecf20Sopenharmony_ci	if (efx->phy_type == PHY_TYPE_NONE)
9888c2ecf20Sopenharmony_ci		return;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	ef4_reado(efx, &sdctl, FR_AB_XX_SD_CTL);
9918c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
9928c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
9938c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
9948c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
9958c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
9968c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
9978c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
9988c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
9998c2ecf20Sopenharmony_ci	ef4_writeo(efx, &sdctl, FR_AB_XX_SD_CTL);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_8(txdrv,
10028c2ecf20Sopenharmony_ci			     FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF,
10038c2ecf20Sopenharmony_ci			     FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF,
10048c2ecf20Sopenharmony_ci			     FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF,
10058c2ecf20Sopenharmony_ci			     FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF,
10068c2ecf20Sopenharmony_ci			     FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF,
10078c2ecf20Sopenharmony_ci			     FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF,
10088c2ecf20Sopenharmony_ci			     FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF,
10098c2ecf20Sopenharmony_ci			     FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF);
10108c2ecf20Sopenharmony_ci	ef4_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL);
10118c2ecf20Sopenharmony_ci}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ciint falcon_reset_xaui(struct ef4_nic *efx)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
10168c2ecf20Sopenharmony_ci	ef4_oword_t reg;
10178c2ecf20Sopenharmony_ci	int count;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	/* Don't fetch MAC statistics over an XMAC reset */
10208c2ecf20Sopenharmony_ci	WARN_ON(nic_data->stats_disable_count == 0);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	/* Start reset sequence */
10238c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
10248c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XX_PWR_RST);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	/* Wait up to 10 ms for completion, then reinitialise */
10278c2ecf20Sopenharmony_ci	for (count = 0; count < 1000; count++) {
10288c2ecf20Sopenharmony_ci		ef4_reado(efx, &reg, FR_AB_XX_PWR_RST);
10298c2ecf20Sopenharmony_ci		if (EF4_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 &&
10308c2ecf20Sopenharmony_ci		    EF4_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) {
10318c2ecf20Sopenharmony_ci			falcon_setup_xaui(efx);
10328c2ecf20Sopenharmony_ci			return 0;
10338c2ecf20Sopenharmony_ci		}
10348c2ecf20Sopenharmony_ci		udelay(10);
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci	netif_err(efx, hw, efx->net_dev,
10378c2ecf20Sopenharmony_ci		  "timed out waiting for XAUI/XGXS reset\n");
10388c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic void falcon_ack_status_intr(struct ef4_nic *efx)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
10448c2ecf20Sopenharmony_ci	ef4_oword_t reg;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if ((ef4_nic_rev(efx) != EF4_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
10478c2ecf20Sopenharmony_ci		return;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* We expect xgmii faults if the wireside link is down */
10508c2ecf20Sopenharmony_ci	if (!efx->link_state.up)
10518c2ecf20Sopenharmony_ci		return;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* We can only use this interrupt to signal the negative edge of
10548c2ecf20Sopenharmony_ci	 * xaui_align [we have to poll the positive edge]. */
10558c2ecf20Sopenharmony_ci	if (nic_data->xmac_poll_required)
10568c2ecf20Sopenharmony_ci		return;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic bool falcon_xgxs_link_ok(struct ef4_nic *efx)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	ef4_oword_t reg;
10648c2ecf20Sopenharmony_ci	bool align_done, link_ok = false;
10658c2ecf20Sopenharmony_ci	int sync_status;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	/* Read link status */
10688c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XX_CORE_STAT);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	align_done = EF4_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE);
10718c2ecf20Sopenharmony_ci	sync_status = EF4_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT);
10728c2ecf20Sopenharmony_ci	if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES))
10738c2ecf20Sopenharmony_ci		link_ok = true;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/* Clear link status ready for next read */
10768c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES);
10778c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES);
10788c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
10798c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	return link_ok;
10828c2ecf20Sopenharmony_ci}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_cistatic bool falcon_xmac_link_ok(struct ef4_nic *efx)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	/*
10878c2ecf20Sopenharmony_ci	 * Check MAC's XGXS link status except when using XGMII loopback
10888c2ecf20Sopenharmony_ci	 * which bypasses the XGXS block.
10898c2ecf20Sopenharmony_ci	 * If possible, check PHY's XGXS link status except when using
10908c2ecf20Sopenharmony_ci	 * MAC loopback.
10918c2ecf20Sopenharmony_ci	 */
10928c2ecf20Sopenharmony_ci	return (efx->loopback_mode == LOOPBACK_XGMII ||
10938c2ecf20Sopenharmony_ci		falcon_xgxs_link_ok(efx)) &&
10948c2ecf20Sopenharmony_ci		(!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) ||
10958c2ecf20Sopenharmony_ci		 LOOPBACK_INTERNAL(efx) ||
10968c2ecf20Sopenharmony_ci		 ef4_mdio_phyxgxs_lane_sync(efx));
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic void falcon_reconfigure_xmac_core(struct ef4_nic *efx)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	unsigned int max_frame_len;
11028c2ecf20Sopenharmony_ci	ef4_oword_t reg;
11038c2ecf20Sopenharmony_ci	bool rx_fc = !!(efx->link_state.fc & EF4_FC_RX);
11048c2ecf20Sopenharmony_ci	bool tx_fc = !!(efx->link_state.fc & EF4_FC_TX);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* Configure MAC  - cut-thru mode is hard wired on */
11078c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_3(reg,
11088c2ecf20Sopenharmony_ci			     FRF_AB_XM_RX_JUMBO_MODE, 1,
11098c2ecf20Sopenharmony_ci			     FRF_AB_XM_TX_STAT_EN, 1,
11108c2ecf20Sopenharmony_ci			     FRF_AB_XM_RX_STAT_EN, 1);
11118c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	/* Configure TX */
11148c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_6(reg,
11158c2ecf20Sopenharmony_ci			     FRF_AB_XM_TXEN, 1,
11168c2ecf20Sopenharmony_ci			     FRF_AB_XM_TX_PRMBL, 1,
11178c2ecf20Sopenharmony_ci			     FRF_AB_XM_AUTO_PAD, 1,
11188c2ecf20Sopenharmony_ci			     FRF_AB_XM_TXCRC, 1,
11198c2ecf20Sopenharmony_ci			     FRF_AB_XM_FCNTL, tx_fc,
11208c2ecf20Sopenharmony_ci			     FRF_AB_XM_IPG, 0x3);
11218c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_TX_CFG);
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	/* Configure RX */
11248c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_5(reg,
11258c2ecf20Sopenharmony_ci			     FRF_AB_XM_RXEN, 1,
11268c2ecf20Sopenharmony_ci			     FRF_AB_XM_AUTO_DEPAD, 0,
11278c2ecf20Sopenharmony_ci			     FRF_AB_XM_ACPT_ALL_MCAST, 1,
11288c2ecf20Sopenharmony_ci			     FRF_AB_XM_ACPT_ALL_UCAST, !efx->unicast_filter,
11298c2ecf20Sopenharmony_ci			     FRF_AB_XM_PASS_CRC_ERR, 1);
11308c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_RX_CFG);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	/* Set frame length */
11338c2ecf20Sopenharmony_ci	max_frame_len = EF4_MAX_FRAME_LEN(efx->net_dev->mtu);
11348c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
11358c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_RX_PARAM);
11368c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg,
11378c2ecf20Sopenharmony_ci			     FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
11388c2ecf20Sopenharmony_ci			     FRF_AB_XM_TX_JUMBO_MODE, 1);
11398c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_TX_PARAM);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg,
11428c2ecf20Sopenharmony_ci			     FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
11438c2ecf20Sopenharmony_ci			     FRF_AB_XM_DIS_FCNTL, !rx_fc);
11448c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_FC);
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	/* Set MAC address */
11478c2ecf20Sopenharmony_ci	memcpy(&reg, &efx->net_dev->dev_addr[0], 4);
11488c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_ADR_LO);
11498c2ecf20Sopenharmony_ci	memcpy(&reg, &efx->net_dev->dev_addr[4], 2);
11508c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XM_ADR_HI);
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic void falcon_reconfigure_xgxs_core(struct ef4_nic *efx)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	ef4_oword_t reg;
11568c2ecf20Sopenharmony_ci	bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS);
11578c2ecf20Sopenharmony_ci	bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI);
11588c2ecf20Sopenharmony_ci	bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII);
11598c2ecf20Sopenharmony_ci	bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* XGXS block is flaky and will need to be reset if moving
11628c2ecf20Sopenharmony_ci	 * into our out of XGMII, XGXS or XAUI loopbacks. */
11638c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XX_CORE_STAT);
11648c2ecf20Sopenharmony_ci	old_xgxs_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN);
11658c2ecf20Sopenharmony_ci	old_xgmii_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XX_SD_CTL);
11688c2ecf20Sopenharmony_ci	old_xaui_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_LPBKA);
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	/* The PHY driver may have turned XAUI off */
11718c2ecf20Sopenharmony_ci	if ((xgxs_loopback != old_xgxs_loopback) ||
11728c2ecf20Sopenharmony_ci	    (xaui_loopback != old_xaui_loopback) ||
11738c2ecf20Sopenharmony_ci	    (xgmii_loopback != old_xgmii_loopback))
11748c2ecf20Sopenharmony_ci		falcon_reset_xaui(efx);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XX_CORE_STAT);
11778c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG,
11788c2ecf20Sopenharmony_ci			    (xgxs_loopback || xaui_loopback) ?
11798c2ecf20Sopenharmony_ci			    FFE_AB_XX_FORCE_SIG_ALL_LANES : 0);
11808c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback);
11818c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback);
11828c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_XX_SD_CTL);
11858c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback);
11868c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback);
11878c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback);
11888c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback);
11898c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_XX_SD_CTL);
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */
11948c2ecf20Sopenharmony_cistatic bool falcon_xmac_link_ok_retry(struct ef4_nic *efx, int tries)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	bool mac_up = falcon_xmac_link_ok(efx);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
11998c2ecf20Sopenharmony_ci	    ef4_phy_mode_disabled(efx->phy_mode))
12008c2ecf20Sopenharmony_ci		/* XAUI link is expected to be down */
12018c2ecf20Sopenharmony_ci		return mac_up;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	falcon_stop_nic_stats(efx);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	while (!mac_up && tries) {
12068c2ecf20Sopenharmony_ci		netif_dbg(efx, hw, efx->net_dev, "bashing xaui\n");
12078c2ecf20Sopenharmony_ci		falcon_reset_xaui(efx);
12088c2ecf20Sopenharmony_ci		udelay(200);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci		mac_up = falcon_xmac_link_ok(efx);
12118c2ecf20Sopenharmony_ci		--tries;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	falcon_start_nic_stats(efx);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	return mac_up;
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_cistatic bool falcon_xmac_check_fault(struct ef4_nic *efx)
12208c2ecf20Sopenharmony_ci{
12218c2ecf20Sopenharmony_ci	return !falcon_xmac_link_ok_retry(efx, 5);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_cistatic int falcon_reconfigure_xmac(struct ef4_nic *efx)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	ef4_farch_filter_sync_rx_mode(efx);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	falcon_reconfigure_xgxs_core(efx);
12318c2ecf20Sopenharmony_ci	falcon_reconfigure_xmac_core(efx);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	falcon_reconfigure_mac_wrapper(efx);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
12368c2ecf20Sopenharmony_ci	falcon_ack_status_intr(efx);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	return 0;
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_cistatic void falcon_poll_xmac(struct ef4_nic *efx)
12428c2ecf20Sopenharmony_ci{
12438c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	/* We expect xgmii faults if the wireside link is down */
12468c2ecf20Sopenharmony_ci	if (!efx->link_state.up || !nic_data->xmac_poll_required)
12478c2ecf20Sopenharmony_ci		return;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
12508c2ecf20Sopenharmony_ci	falcon_ack_status_intr(efx);
12518c2ecf20Sopenharmony_ci}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci/**************************************************************************
12548c2ecf20Sopenharmony_ci *
12558c2ecf20Sopenharmony_ci * MAC wrapper
12568c2ecf20Sopenharmony_ci *
12578c2ecf20Sopenharmony_ci **************************************************************************
12588c2ecf20Sopenharmony_ci */
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic void falcon_push_multicast_hash(struct ef4_nic *efx)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	union ef4_multicast_hash *mc_hash = &efx->multicast_hash;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	WARN_ON(!mutex_is_locked(&efx->mac_lock));
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	ef4_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
12678c2ecf20Sopenharmony_ci	ef4_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic void falcon_reset_macs(struct ef4_nic *efx)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
12738c2ecf20Sopenharmony_ci	ef4_oword_t reg, mac_ctrl;
12748c2ecf20Sopenharmony_ci	int count;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) < EF4_REV_FALCON_B0) {
12778c2ecf20Sopenharmony_ci		/* It's not safe to use GLB_CTL_REG to reset the
12788c2ecf20Sopenharmony_ci		 * macs, so instead use the internal MAC resets
12798c2ecf20Sopenharmony_ci		 */
12808c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
12818c2ecf20Sopenharmony_ci		ef4_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci		for (count = 0; count < 10000; count++) {
12848c2ecf20Sopenharmony_ci			ef4_reado(efx, &reg, FR_AB_XM_GLB_CFG);
12858c2ecf20Sopenharmony_ci			if (EF4_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
12868c2ecf20Sopenharmony_ci			    0)
12878c2ecf20Sopenharmony_ci				return;
12888c2ecf20Sopenharmony_ci			udelay(10);
12898c2ecf20Sopenharmony_ci		}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
12928c2ecf20Sopenharmony_ci			  "timed out waiting for XMAC core reset\n");
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	/* Mac stats will fail whist the TX fifo is draining */
12968c2ecf20Sopenharmony_ci	WARN_ON(nic_data->stats_disable_count == 0);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	ef4_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
12998c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
13008c2ecf20Sopenharmony_ci	ef4_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_GLB_CTL);
13038c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
13048c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1);
13058c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1);
13068c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_GLB_CTL);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	count = 0;
13098c2ecf20Sopenharmony_ci	while (1) {
13108c2ecf20Sopenharmony_ci		ef4_reado(efx, &reg, FR_AB_GLB_CTL);
13118c2ecf20Sopenharmony_ci		if (!EF4_OWORD_FIELD(reg, FRF_AB_RST_XGTX) &&
13128c2ecf20Sopenharmony_ci		    !EF4_OWORD_FIELD(reg, FRF_AB_RST_XGRX) &&
13138c2ecf20Sopenharmony_ci		    !EF4_OWORD_FIELD(reg, FRF_AB_RST_EM)) {
13148c2ecf20Sopenharmony_ci			netif_dbg(efx, hw, efx->net_dev,
13158c2ecf20Sopenharmony_ci				  "Completed MAC reset after %d loops\n",
13168c2ecf20Sopenharmony_ci				  count);
13178c2ecf20Sopenharmony_ci			break;
13188c2ecf20Sopenharmony_ci		}
13198c2ecf20Sopenharmony_ci		if (count > 20) {
13208c2ecf20Sopenharmony_ci			netif_err(efx, hw, efx->net_dev, "MAC reset failed\n");
13218c2ecf20Sopenharmony_ci			break;
13228c2ecf20Sopenharmony_ci		}
13238c2ecf20Sopenharmony_ci		count++;
13248c2ecf20Sopenharmony_ci		udelay(10);
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* Ensure the correct MAC is selected before statistics
13288c2ecf20Sopenharmony_ci	 * are re-enabled by the caller */
13298c2ecf20Sopenharmony_ci	ef4_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	falcon_setup_xaui(efx);
13328c2ecf20Sopenharmony_ci}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_cistatic void falcon_drain_tx_fifo(struct ef4_nic *efx)
13358c2ecf20Sopenharmony_ci{
13368c2ecf20Sopenharmony_ci	ef4_oword_t reg;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if ((ef4_nic_rev(efx) < EF4_REV_FALCON_B0) ||
13398c2ecf20Sopenharmony_ci	    (efx->loopback_mode != LOOPBACK_NONE))
13408c2ecf20Sopenharmony_ci		return;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AB_MAC_CTRL);
13438c2ecf20Sopenharmony_ci	/* There is no point in draining more than once */
13448c2ecf20Sopenharmony_ci	if (EF4_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN))
13458c2ecf20Sopenharmony_ci		return;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	falcon_reset_macs(efx);
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_cistatic void falcon_deconfigure_mac_wrapper(struct ef4_nic *efx)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	ef4_oword_t reg;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) < EF4_REV_FALCON_B0)
13558c2ecf20Sopenharmony_ci		return;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/* Isolate the MAC -> RX */
13588c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AZ_RX_CFG);
13598c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
13608c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AZ_RX_CFG);
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	/* Isolate TX -> MAC */
13638c2ecf20Sopenharmony_ci	falcon_drain_tx_fifo(efx);
13648c2ecf20Sopenharmony_ci}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic void falcon_reconfigure_mac_wrapper(struct ef4_nic *efx)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	struct ef4_link_state *link_state = &efx->link_state;
13698c2ecf20Sopenharmony_ci	ef4_oword_t reg;
13708c2ecf20Sopenharmony_ci	int link_speed, isolate;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	isolate = !!READ_ONCE(efx->reset_pending);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	switch (link_state->speed) {
13758c2ecf20Sopenharmony_ci	case 10000: link_speed = 3; break;
13768c2ecf20Sopenharmony_ci	case 1000:  link_speed = 2; break;
13778c2ecf20Sopenharmony_ci	case 100:   link_speed = 1; break;
13788c2ecf20Sopenharmony_ci	default:    link_speed = 0; break;
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	/* MAC_LINK_STATUS controls MAC backpressure but doesn't work
13828c2ecf20Sopenharmony_ci	 * as advertised.  Disable to ensure packets are not
13838c2ecf20Sopenharmony_ci	 * indefinitely held and TX queue can be flushed at any point
13848c2ecf20Sopenharmony_ci	 * while the link is down. */
13858c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_5(reg,
13868c2ecf20Sopenharmony_ci			     FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */,
13878c2ecf20Sopenharmony_ci			     FRF_AB_MAC_BCAD_ACPT, 1,
13888c2ecf20Sopenharmony_ci			     FRF_AB_MAC_UC_PROM, !efx->unicast_filter,
13898c2ecf20Sopenharmony_ci			     FRF_AB_MAC_LINK_STATUS, 1, /* always set */
13908c2ecf20Sopenharmony_ci			     FRF_AB_MAC_SPEED, link_speed);
13918c2ecf20Sopenharmony_ci	/* On B0, MAC backpressure can be disabled and packets get
13928c2ecf20Sopenharmony_ci	 * discarded. */
13938c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) {
13948c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
13958c2ecf20Sopenharmony_ci				    !link_state->up || isolate);
13968c2ecf20Sopenharmony_ci	}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MAC_CTRL);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	/* Restore the multicast hash registers. */
14018c2ecf20Sopenharmony_ci	falcon_push_multicast_hash(efx);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AZ_RX_CFG);
14048c2ecf20Sopenharmony_ci	/* Enable XOFF signal from RX FIFO (we enabled it during NIC
14058c2ecf20Sopenharmony_ci	 * initialisation but it may read back as 0) */
14068c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
14078c2ecf20Sopenharmony_ci	/* Unisolate the MAC -> RX */
14088c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0)
14098c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
14108c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AZ_RX_CFG);
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_cistatic void falcon_stats_request(struct ef4_nic *efx)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
14168c2ecf20Sopenharmony_ci	ef4_oword_t reg;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	WARN_ON(nic_data->stats_pending);
14198c2ecf20Sopenharmony_ci	WARN_ON(nic_data->stats_disable_count);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	FALCON_XMAC_STATS_DMA_FLAG(efx) = 0;
14228c2ecf20Sopenharmony_ci	nic_data->stats_pending = true;
14238c2ecf20Sopenharmony_ci	wmb(); /* ensure done flag is clear */
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	/* Initiate DMA transfer of stats */
14268c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg,
14278c2ecf20Sopenharmony_ci			     FRF_AB_MAC_STAT_DMA_CMD, 1,
14288c2ecf20Sopenharmony_ci			     FRF_AB_MAC_STAT_DMA_ADR,
14298c2ecf20Sopenharmony_ci			     efx->stats_buffer.dma_addr);
14308c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MAC_STAT_DMA);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2));
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cistatic void falcon_stats_complete(struct ef4_nic *efx)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	if (!nic_data->stats_pending)
14408c2ecf20Sopenharmony_ci		return;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	nic_data->stats_pending = false;
14438c2ecf20Sopenharmony_ci	if (FALCON_XMAC_STATS_DMA_FLAG(efx)) {
14448c2ecf20Sopenharmony_ci		rmb(); /* read the done flag before the stats */
14458c2ecf20Sopenharmony_ci		ef4_nic_update_stats(falcon_stat_desc, FALCON_STAT_COUNT,
14468c2ecf20Sopenharmony_ci				     falcon_stat_mask, nic_data->stats,
14478c2ecf20Sopenharmony_ci				     efx->stats_buffer.addr, true);
14488c2ecf20Sopenharmony_ci	} else {
14498c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
14508c2ecf20Sopenharmony_ci			  "timed out waiting for statistics\n");
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_cistatic void falcon_stats_timer_func(struct timer_list *t)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = from_timer(nic_data, t,
14578c2ecf20Sopenharmony_ci						      stats_timer);
14588c2ecf20Sopenharmony_ci	struct ef4_nic *efx = nic_data->efx;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	spin_lock(&efx->stats_lock);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	falcon_stats_complete(efx);
14638c2ecf20Sopenharmony_ci	if (nic_data->stats_disable_count == 0)
14648c2ecf20Sopenharmony_ci		falcon_stats_request(efx);
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	spin_unlock(&efx->stats_lock);
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic bool falcon_loopback_link_poll(struct ef4_nic *efx)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct ef4_link_state old_state = efx->link_state;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	WARN_ON(!mutex_is_locked(&efx->mac_lock));
14748c2ecf20Sopenharmony_ci	WARN_ON(!LOOPBACK_INTERNAL(efx));
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	efx->link_state.fd = true;
14778c2ecf20Sopenharmony_ci	efx->link_state.fc = efx->wanted_fc;
14788c2ecf20Sopenharmony_ci	efx->link_state.up = true;
14798c2ecf20Sopenharmony_ci	efx->link_state.speed = 10000;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	return !ef4_link_state_equal(&efx->link_state, &old_state);
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic int falcon_reconfigure_port(struct ef4_nic *efx)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	int rc;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	WARN_ON(ef4_nic_rev(efx) > EF4_REV_FALCON_B0);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	/* Poll the PHY link state *before* reconfiguring it. This means we
14918c2ecf20Sopenharmony_ci	 * will pick up the correct speed (in loopback) to select the correct
14928c2ecf20Sopenharmony_ci	 * MAC.
14938c2ecf20Sopenharmony_ci	 */
14948c2ecf20Sopenharmony_ci	if (LOOPBACK_INTERNAL(efx))
14958c2ecf20Sopenharmony_ci		falcon_loopback_link_poll(efx);
14968c2ecf20Sopenharmony_ci	else
14978c2ecf20Sopenharmony_ci		efx->phy_op->poll(efx);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	falcon_stop_nic_stats(efx);
15008c2ecf20Sopenharmony_ci	falcon_deconfigure_mac_wrapper(efx);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	falcon_reset_macs(efx);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	efx->phy_op->reconfigure(efx);
15058c2ecf20Sopenharmony_ci	rc = falcon_reconfigure_xmac(efx);
15068c2ecf20Sopenharmony_ci	BUG_ON(rc);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	falcon_start_nic_stats(efx);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	/* Synchronise efx->link_state with the kernel */
15118c2ecf20Sopenharmony_ci	ef4_link_status_changed(efx);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	return 0;
15148c2ecf20Sopenharmony_ci}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci/* TX flow control may automatically turn itself off if the link
15178c2ecf20Sopenharmony_ci * partner (intermittently) stops responding to pause frames. There
15188c2ecf20Sopenharmony_ci * isn't any indication that this has happened, so the best we do is
15198c2ecf20Sopenharmony_ci * leave it up to the user to spot this and fix it by cycling transmit
15208c2ecf20Sopenharmony_ci * flow control on this end.
15218c2ecf20Sopenharmony_ci */
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void falcon_a1_prepare_enable_fc_tx(struct ef4_nic *efx)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	/* Schedule a reset to recover */
15268c2ecf20Sopenharmony_ci	ef4_schedule_reset(efx, RESET_TYPE_INVISIBLE);
15278c2ecf20Sopenharmony_ci}
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_cistatic void falcon_b0_prepare_enable_fc_tx(struct ef4_nic *efx)
15308c2ecf20Sopenharmony_ci{
15318c2ecf20Sopenharmony_ci	/* Recover by resetting the EM block */
15328c2ecf20Sopenharmony_ci	falcon_stop_nic_stats(efx);
15338c2ecf20Sopenharmony_ci	falcon_drain_tx_fifo(efx);
15348c2ecf20Sopenharmony_ci	falcon_reconfigure_xmac(efx);
15358c2ecf20Sopenharmony_ci	falcon_start_nic_stats(efx);
15368c2ecf20Sopenharmony_ci}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci/**************************************************************************
15398c2ecf20Sopenharmony_ci *
15408c2ecf20Sopenharmony_ci * PHY access via GMII
15418c2ecf20Sopenharmony_ci *
15428c2ecf20Sopenharmony_ci **************************************************************************
15438c2ecf20Sopenharmony_ci */
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci/* Wait for GMII access to complete */
15468c2ecf20Sopenharmony_cistatic int falcon_gmii_wait(struct ef4_nic *efx)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	ef4_oword_t md_stat;
15498c2ecf20Sopenharmony_ci	int count;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	/* wait up to 50ms - taken max from datasheet */
15528c2ecf20Sopenharmony_ci	for (count = 0; count < 5000; count++) {
15538c2ecf20Sopenharmony_ci		ef4_reado(efx, &md_stat, FR_AB_MD_STAT);
15548c2ecf20Sopenharmony_ci		if (EF4_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
15558c2ecf20Sopenharmony_ci			if (EF4_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
15568c2ecf20Sopenharmony_ci			    EF4_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
15578c2ecf20Sopenharmony_ci				netif_err(efx, hw, efx->net_dev,
15588c2ecf20Sopenharmony_ci					  "error from GMII access "
15598c2ecf20Sopenharmony_ci					  EF4_OWORD_FMT"\n",
15608c2ecf20Sopenharmony_ci					  EF4_OWORD_VAL(md_stat));
15618c2ecf20Sopenharmony_ci				return -EIO;
15628c2ecf20Sopenharmony_ci			}
15638c2ecf20Sopenharmony_ci			return 0;
15648c2ecf20Sopenharmony_ci		}
15658c2ecf20Sopenharmony_ci		udelay(10);
15668c2ecf20Sopenharmony_ci	}
15678c2ecf20Sopenharmony_ci	netif_err(efx, hw, efx->net_dev, "timed out waiting for GMII\n");
15688c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
15698c2ecf20Sopenharmony_ci}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci/* Write an MDIO register of a PHY connected to Falcon. */
15728c2ecf20Sopenharmony_cistatic int falcon_mdio_write(struct net_device *net_dev,
15738c2ecf20Sopenharmony_ci			     int prtad, int devad, u16 addr, u16 value)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct ef4_nic *efx = netdev_priv(net_dev);
15768c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
15778c2ecf20Sopenharmony_ci	ef4_oword_t reg;
15788c2ecf20Sopenharmony_ci	int rc;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	netif_vdbg(efx, hw, efx->net_dev,
15818c2ecf20Sopenharmony_ci		   "writing MDIO %d register %d.%d with 0x%04x\n",
15828c2ecf20Sopenharmony_ci		    prtad, devad, addr, value);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	mutex_lock(&nic_data->mdio_lock);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	/* Check MDIO not currently being accessed */
15878c2ecf20Sopenharmony_ci	rc = falcon_gmii_wait(efx);
15888c2ecf20Sopenharmony_ci	if (rc)
15898c2ecf20Sopenharmony_ci		goto out;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	/* Write the address/ID register */
15928c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
15938c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
15968c2ecf20Sopenharmony_ci			     FRF_AB_MD_DEV_ADR, devad);
15978c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_ID);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	/* Write data */
16008c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value);
16018c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_TXD);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg,
16048c2ecf20Sopenharmony_ci			     FRF_AB_MD_WRC, 1,
16058c2ecf20Sopenharmony_ci			     FRF_AB_MD_GC, 0);
16068c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_CS);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	/* Wait for data to be written */
16098c2ecf20Sopenharmony_ci	rc = falcon_gmii_wait(efx);
16108c2ecf20Sopenharmony_ci	if (rc) {
16118c2ecf20Sopenharmony_ci		/* Abort the write operation */
16128c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_2(reg,
16138c2ecf20Sopenharmony_ci				     FRF_AB_MD_WRC, 0,
16148c2ecf20Sopenharmony_ci				     FRF_AB_MD_GC, 1);
16158c2ecf20Sopenharmony_ci		ef4_writeo(efx, &reg, FR_AB_MD_CS);
16168c2ecf20Sopenharmony_ci		udelay(10);
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ciout:
16208c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->mdio_lock);
16218c2ecf20Sopenharmony_ci	return rc;
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci/* Read an MDIO register of a PHY connected to Falcon. */
16258c2ecf20Sopenharmony_cistatic int falcon_mdio_read(struct net_device *net_dev,
16268c2ecf20Sopenharmony_ci			    int prtad, int devad, u16 addr)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct ef4_nic *efx = netdev_priv(net_dev);
16298c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
16308c2ecf20Sopenharmony_ci	ef4_oword_t reg;
16318c2ecf20Sopenharmony_ci	int rc;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	mutex_lock(&nic_data->mdio_lock);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	/* Check MDIO not currently being accessed */
16368c2ecf20Sopenharmony_ci	rc = falcon_gmii_wait(efx);
16378c2ecf20Sopenharmony_ci	if (rc)
16388c2ecf20Sopenharmony_ci		goto out;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
16418c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
16448c2ecf20Sopenharmony_ci			     FRF_AB_MD_DEV_ADR, devad);
16458c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_ID);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	/* Request data to be read */
16488c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0);
16498c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AB_MD_CS);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	/* Wait for data to become available */
16528c2ecf20Sopenharmony_ci	rc = falcon_gmii_wait(efx);
16538c2ecf20Sopenharmony_ci	if (rc == 0) {
16548c2ecf20Sopenharmony_ci		ef4_reado(efx, &reg, FR_AB_MD_RXD);
16558c2ecf20Sopenharmony_ci		rc = EF4_OWORD_FIELD(reg, FRF_AB_MD_RXD);
16568c2ecf20Sopenharmony_ci		netif_vdbg(efx, hw, efx->net_dev,
16578c2ecf20Sopenharmony_ci			   "read from MDIO %d register %d.%d, got %04x\n",
16588c2ecf20Sopenharmony_ci			   prtad, devad, addr, rc);
16598c2ecf20Sopenharmony_ci	} else {
16608c2ecf20Sopenharmony_ci		/* Abort the read operation */
16618c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_2(reg,
16628c2ecf20Sopenharmony_ci				     FRF_AB_MD_RIC, 0,
16638c2ecf20Sopenharmony_ci				     FRF_AB_MD_GC, 1);
16648c2ecf20Sopenharmony_ci		ef4_writeo(efx, &reg, FR_AB_MD_CS);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci		netif_dbg(efx, hw, efx->net_dev,
16678c2ecf20Sopenharmony_ci			  "read from MDIO %d register %d.%d, got error %d\n",
16688c2ecf20Sopenharmony_ci			  prtad, devad, addr, rc);
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ciout:
16728c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->mdio_lock);
16738c2ecf20Sopenharmony_ci	return rc;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci/* This call is responsible for hooking in the MAC and PHY operations */
16778c2ecf20Sopenharmony_cistatic int falcon_probe_port(struct ef4_nic *efx)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
16808c2ecf20Sopenharmony_ci	int rc;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	switch (efx->phy_type) {
16838c2ecf20Sopenharmony_ci	case PHY_TYPE_SFX7101:
16848c2ecf20Sopenharmony_ci		efx->phy_op = &falcon_sfx7101_phy_ops;
16858c2ecf20Sopenharmony_ci		break;
16868c2ecf20Sopenharmony_ci	case PHY_TYPE_QT2022C2:
16878c2ecf20Sopenharmony_ci	case PHY_TYPE_QT2025C:
16888c2ecf20Sopenharmony_ci		efx->phy_op = &falcon_qt202x_phy_ops;
16898c2ecf20Sopenharmony_ci		break;
16908c2ecf20Sopenharmony_ci	case PHY_TYPE_TXC43128:
16918c2ecf20Sopenharmony_ci		efx->phy_op = &falcon_txc_phy_ops;
16928c2ecf20Sopenharmony_ci		break;
16938c2ecf20Sopenharmony_ci	default:
16948c2ecf20Sopenharmony_ci		netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n",
16958c2ecf20Sopenharmony_ci			  efx->phy_type);
16968c2ecf20Sopenharmony_ci		return -ENODEV;
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	/* Fill out MDIO structure and loopback modes */
17008c2ecf20Sopenharmony_ci	mutex_init(&nic_data->mdio_lock);
17018c2ecf20Sopenharmony_ci	efx->mdio.mdio_read = falcon_mdio_read;
17028c2ecf20Sopenharmony_ci	efx->mdio.mdio_write = falcon_mdio_write;
17038c2ecf20Sopenharmony_ci	rc = efx->phy_op->probe(efx);
17048c2ecf20Sopenharmony_ci	if (rc != 0)
17058c2ecf20Sopenharmony_ci		return rc;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	/* Initial assumption */
17088c2ecf20Sopenharmony_ci	efx->link_state.speed = 10000;
17098c2ecf20Sopenharmony_ci	efx->link_state.fd = true;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
17128c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0)
17138c2ecf20Sopenharmony_ci		efx->wanted_fc = EF4_FC_RX | EF4_FC_TX;
17148c2ecf20Sopenharmony_ci	else
17158c2ecf20Sopenharmony_ci		efx->wanted_fc = EF4_FC_RX;
17168c2ecf20Sopenharmony_ci	if (efx->mdio.mmds & MDIO_DEVS_AN)
17178c2ecf20Sopenharmony_ci		efx->wanted_fc |= EF4_FC_AUTO;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	/* Allocate buffer for stats */
17208c2ecf20Sopenharmony_ci	rc = ef4_nic_alloc_buffer(efx, &efx->stats_buffer,
17218c2ecf20Sopenharmony_ci				  FALCON_MAC_STATS_SIZE, GFP_KERNEL);
17228c2ecf20Sopenharmony_ci	if (rc)
17238c2ecf20Sopenharmony_ci		return rc;
17248c2ecf20Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev,
17258c2ecf20Sopenharmony_ci		  "stats buffer at %llx (virt %p phys %llx)\n",
17268c2ecf20Sopenharmony_ci		  (u64)efx->stats_buffer.dma_addr,
17278c2ecf20Sopenharmony_ci		  efx->stats_buffer.addr,
17288c2ecf20Sopenharmony_ci		  (u64)virt_to_phys(efx->stats_buffer.addr));
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	return 0;
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_cistatic void falcon_remove_port(struct ef4_nic *efx)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	efx->phy_op->remove(efx);
17368c2ecf20Sopenharmony_ci	ef4_nic_free_buffer(efx, &efx->stats_buffer);
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci/* Global events are basically PHY events */
17408c2ecf20Sopenharmony_cistatic bool
17418c2ecf20Sopenharmony_cifalcon_handle_global_event(struct ef4_channel *channel, ef4_qword_t *event)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	struct ef4_nic *efx = channel->efx;
17448c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	if (EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
17478c2ecf20Sopenharmony_ci	    EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
17488c2ecf20Sopenharmony_ci	    EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR))
17498c2ecf20Sopenharmony_ci		/* Ignored */
17508c2ecf20Sopenharmony_ci		return true;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if ((ef4_nic_rev(efx) == EF4_REV_FALCON_B0) &&
17538c2ecf20Sopenharmony_ci	    EF4_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
17548c2ecf20Sopenharmony_ci		nic_data->xmac_poll_required = true;
17558c2ecf20Sopenharmony_ci		return true;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1 ?
17598c2ecf20Sopenharmony_ci	    EF4_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
17608c2ecf20Sopenharmony_ci	    EF4_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
17618c2ecf20Sopenharmony_ci		netif_err(efx, rx_err, efx->net_dev,
17628c2ecf20Sopenharmony_ci			  "channel %d seen global RX_RESET event. Resetting.\n",
17638c2ecf20Sopenharmony_ci			  channel->channel);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci		atomic_inc(&efx->rx_reset);
17668c2ecf20Sopenharmony_ci		ef4_schedule_reset(efx, EF4_WORKAROUND_6555(efx) ?
17678c2ecf20Sopenharmony_ci				   RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
17688c2ecf20Sopenharmony_ci		return true;
17698c2ecf20Sopenharmony_ci	}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	return false;
17728c2ecf20Sopenharmony_ci}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci/**************************************************************************
17758c2ecf20Sopenharmony_ci *
17768c2ecf20Sopenharmony_ci * Falcon test code
17778c2ecf20Sopenharmony_ci *
17788c2ecf20Sopenharmony_ci **************************************************************************/
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_cistatic int
17818c2ecf20Sopenharmony_cifalcon_read_nvram(struct ef4_nic *efx, struct falcon_nvconfig *nvconfig_out)
17828c2ecf20Sopenharmony_ci{
17838c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
17848c2ecf20Sopenharmony_ci	struct falcon_nvconfig *nvconfig;
17858c2ecf20Sopenharmony_ci	struct falcon_spi_device *spi;
17868c2ecf20Sopenharmony_ci	void *region;
17878c2ecf20Sopenharmony_ci	int rc, magic_num, struct_ver;
17888c2ecf20Sopenharmony_ci	__le16 *word, *limit;
17898c2ecf20Sopenharmony_ci	u32 csum;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	if (falcon_spi_present(&nic_data->spi_flash))
17928c2ecf20Sopenharmony_ci		spi = &nic_data->spi_flash;
17938c2ecf20Sopenharmony_ci	else if (falcon_spi_present(&nic_data->spi_eeprom))
17948c2ecf20Sopenharmony_ci		spi = &nic_data->spi_eeprom;
17958c2ecf20Sopenharmony_ci	else
17968c2ecf20Sopenharmony_ci		return -EINVAL;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
17998c2ecf20Sopenharmony_ci	if (!region)
18008c2ecf20Sopenharmony_ci		return -ENOMEM;
18018c2ecf20Sopenharmony_ci	nvconfig = region + FALCON_NVCONFIG_OFFSET;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	mutex_lock(&nic_data->spi_lock);
18048c2ecf20Sopenharmony_ci	rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region);
18058c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
18068c2ecf20Sopenharmony_ci	if (rc) {
18078c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev, "Failed to read %s\n",
18088c2ecf20Sopenharmony_ci			  falcon_spi_present(&nic_data->spi_flash) ?
18098c2ecf20Sopenharmony_ci			  "flash" : "EEPROM");
18108c2ecf20Sopenharmony_ci		rc = -EIO;
18118c2ecf20Sopenharmony_ci		goto out;
18128c2ecf20Sopenharmony_ci	}
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	magic_num = le16_to_cpu(nvconfig->board_magic_num);
18158c2ecf20Sopenharmony_ci	struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	rc = -EINVAL;
18188c2ecf20Sopenharmony_ci	if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) {
18198c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
18208c2ecf20Sopenharmony_ci			  "NVRAM bad magic 0x%x\n", magic_num);
18218c2ecf20Sopenharmony_ci		goto out;
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci	if (struct_ver < 2) {
18248c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
18258c2ecf20Sopenharmony_ci			  "NVRAM has ancient version 0x%x\n", struct_ver);
18268c2ecf20Sopenharmony_ci		goto out;
18278c2ecf20Sopenharmony_ci	} else if (struct_ver < 4) {
18288c2ecf20Sopenharmony_ci		word = &nvconfig->board_magic_num;
18298c2ecf20Sopenharmony_ci		limit = (__le16 *) (nvconfig + 1);
18308c2ecf20Sopenharmony_ci	} else {
18318c2ecf20Sopenharmony_ci		word = region;
18328c2ecf20Sopenharmony_ci		limit = region + FALCON_NVCONFIG_END;
18338c2ecf20Sopenharmony_ci	}
18348c2ecf20Sopenharmony_ci	for (csum = 0; word < limit; ++word)
18358c2ecf20Sopenharmony_ci		csum += le16_to_cpu(*word);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	if (~csum & 0xffff) {
18388c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
18398c2ecf20Sopenharmony_ci			  "NVRAM has incorrect checksum\n");
18408c2ecf20Sopenharmony_ci		goto out;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	rc = 0;
18448c2ecf20Sopenharmony_ci	if (nvconfig_out)
18458c2ecf20Sopenharmony_ci		memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig));
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci out:
18488c2ecf20Sopenharmony_ci	kfree(region);
18498c2ecf20Sopenharmony_ci	return rc;
18508c2ecf20Sopenharmony_ci}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_cistatic int falcon_test_nvram(struct ef4_nic *efx)
18538c2ecf20Sopenharmony_ci{
18548c2ecf20Sopenharmony_ci	return falcon_read_nvram(efx, NULL);
18558c2ecf20Sopenharmony_ci}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_cistatic const struct ef4_farch_register_test falcon_b0_register_tests[] = {
18588c2ecf20Sopenharmony_ci	{ FR_AZ_ADR_REGION,
18598c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
18608c2ecf20Sopenharmony_ci	{ FR_AZ_RX_CFG,
18618c2ecf20Sopenharmony_ci	  EF4_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
18628c2ecf20Sopenharmony_ci	{ FR_AZ_TX_CFG,
18638c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) },
18648c2ecf20Sopenharmony_ci	{ FR_AZ_TX_RESERVED,
18658c2ecf20Sopenharmony_ci	  EF4_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) },
18668c2ecf20Sopenharmony_ci	{ FR_AB_MAC_CTRL,
18678c2ecf20Sopenharmony_ci	  EF4_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) },
18688c2ecf20Sopenharmony_ci	{ FR_AZ_SRM_TX_DC_CFG,
18698c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) },
18708c2ecf20Sopenharmony_ci	{ FR_AZ_RX_DC_CFG,
18718c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) },
18728c2ecf20Sopenharmony_ci	{ FR_AZ_RX_DC_PF_WM,
18738c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
18748c2ecf20Sopenharmony_ci	{ FR_BZ_DP_CTRL,
18758c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
18768c2ecf20Sopenharmony_ci	{ FR_AB_GM_CFG2,
18778c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) },
18788c2ecf20Sopenharmony_ci	{ FR_AB_GMF_CFG0,
18798c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) },
18808c2ecf20Sopenharmony_ci	{ FR_AB_XM_GLB_CFG,
18818c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
18828c2ecf20Sopenharmony_ci	{ FR_AB_XM_TX_CFG,
18838c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) },
18848c2ecf20Sopenharmony_ci	{ FR_AB_XM_RX_CFG,
18858c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) },
18868c2ecf20Sopenharmony_ci	{ FR_AB_XM_RX_PARAM,
18878c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) },
18888c2ecf20Sopenharmony_ci	{ FR_AB_XM_FC,
18898c2ecf20Sopenharmony_ci	  EF4_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) },
18908c2ecf20Sopenharmony_ci	{ FR_AB_XM_ADR_LO,
18918c2ecf20Sopenharmony_ci	  EF4_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) },
18928c2ecf20Sopenharmony_ci	{ FR_AB_XX_SD_CTL,
18938c2ecf20Sopenharmony_ci	  EF4_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) },
18948c2ecf20Sopenharmony_ci};
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_cistatic int
18978c2ecf20Sopenharmony_cifalcon_b0_test_chip(struct ef4_nic *efx, struct ef4_self_tests *tests)
18988c2ecf20Sopenharmony_ci{
18998c2ecf20Sopenharmony_ci	enum reset_type reset_method = RESET_TYPE_INVISIBLE;
19008c2ecf20Sopenharmony_ci	int rc, rc2;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	mutex_lock(&efx->mac_lock);
19038c2ecf20Sopenharmony_ci	if (efx->loopback_modes) {
19048c2ecf20Sopenharmony_ci		/* We need the 312 clock from the PHY to test the XMAC
19058c2ecf20Sopenharmony_ci		 * registers, so move into XGMII loopback if available */
19068c2ecf20Sopenharmony_ci		if (efx->loopback_modes & (1 << LOOPBACK_XGMII))
19078c2ecf20Sopenharmony_ci			efx->loopback_mode = LOOPBACK_XGMII;
19088c2ecf20Sopenharmony_ci		else
19098c2ecf20Sopenharmony_ci			efx->loopback_mode = __ffs(efx->loopback_modes);
19108c2ecf20Sopenharmony_ci	}
19118c2ecf20Sopenharmony_ci	__ef4_reconfigure_port(efx);
19128c2ecf20Sopenharmony_ci	mutex_unlock(&efx->mac_lock);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	ef4_reset_down(efx, reset_method);
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	tests->registers =
19178c2ecf20Sopenharmony_ci		ef4_farch_test_registers(efx, falcon_b0_register_tests,
19188c2ecf20Sopenharmony_ci					 ARRAY_SIZE(falcon_b0_register_tests))
19198c2ecf20Sopenharmony_ci		? -1 : 1;
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	rc = falcon_reset_hw(efx, reset_method);
19228c2ecf20Sopenharmony_ci	rc2 = ef4_reset_up(efx, reset_method, rc == 0);
19238c2ecf20Sopenharmony_ci	return rc ? rc : rc2;
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci/**************************************************************************
19278c2ecf20Sopenharmony_ci *
19288c2ecf20Sopenharmony_ci * Device reset
19298c2ecf20Sopenharmony_ci *
19308c2ecf20Sopenharmony_ci **************************************************************************
19318c2ecf20Sopenharmony_ci */
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_cistatic enum reset_type falcon_map_reset_reason(enum reset_type reason)
19348c2ecf20Sopenharmony_ci{
19358c2ecf20Sopenharmony_ci	switch (reason) {
19368c2ecf20Sopenharmony_ci	case RESET_TYPE_RX_RECOVERY:
19378c2ecf20Sopenharmony_ci	case RESET_TYPE_DMA_ERROR:
19388c2ecf20Sopenharmony_ci	case RESET_TYPE_TX_SKIP:
19398c2ecf20Sopenharmony_ci		/* These can occasionally occur due to hardware bugs.
19408c2ecf20Sopenharmony_ci		 * We try to reset without disrupting the link.
19418c2ecf20Sopenharmony_ci		 */
19428c2ecf20Sopenharmony_ci		return RESET_TYPE_INVISIBLE;
19438c2ecf20Sopenharmony_ci	default:
19448c2ecf20Sopenharmony_ci		return RESET_TYPE_ALL;
19458c2ecf20Sopenharmony_ci	}
19468c2ecf20Sopenharmony_ci}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_cistatic int falcon_map_reset_flags(u32 *flags)
19498c2ecf20Sopenharmony_ci{
19508c2ecf20Sopenharmony_ci	enum {
19518c2ecf20Sopenharmony_ci		FALCON_RESET_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
19528c2ecf20Sopenharmony_ci					  ETH_RESET_OFFLOAD | ETH_RESET_MAC),
19538c2ecf20Sopenharmony_ci		FALCON_RESET_ALL = FALCON_RESET_INVISIBLE | ETH_RESET_PHY,
19548c2ecf20Sopenharmony_ci		FALCON_RESET_WORLD = FALCON_RESET_ALL | ETH_RESET_IRQ,
19558c2ecf20Sopenharmony_ci	};
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	if ((*flags & FALCON_RESET_WORLD) == FALCON_RESET_WORLD) {
19588c2ecf20Sopenharmony_ci		*flags &= ~FALCON_RESET_WORLD;
19598c2ecf20Sopenharmony_ci		return RESET_TYPE_WORLD;
19608c2ecf20Sopenharmony_ci	}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	if ((*flags & FALCON_RESET_ALL) == FALCON_RESET_ALL) {
19638c2ecf20Sopenharmony_ci		*flags &= ~FALCON_RESET_ALL;
19648c2ecf20Sopenharmony_ci		return RESET_TYPE_ALL;
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	if ((*flags & FALCON_RESET_INVISIBLE) == FALCON_RESET_INVISIBLE) {
19688c2ecf20Sopenharmony_ci		*flags &= ~FALCON_RESET_INVISIBLE;
19698c2ecf20Sopenharmony_ci		return RESET_TYPE_INVISIBLE;
19708c2ecf20Sopenharmony_ci	}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	return -EINVAL;
19738c2ecf20Sopenharmony_ci}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci/* Resets NIC to known state.  This routine must be called in process
19768c2ecf20Sopenharmony_ci * context and is allowed to sleep. */
19778c2ecf20Sopenharmony_cistatic int __falcon_reset_hw(struct ef4_nic *efx, enum reset_type method)
19788c2ecf20Sopenharmony_ci{
19798c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
19808c2ecf20Sopenharmony_ci	ef4_oword_t glb_ctl_reg_ker;
19818c2ecf20Sopenharmony_ci	int rc;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	netif_dbg(efx, hw, efx->net_dev, "performing %s hardware reset\n",
19848c2ecf20Sopenharmony_ci		  RESET_TYPE(method));
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	/* Initiate device reset */
19878c2ecf20Sopenharmony_ci	if (method == RESET_TYPE_WORLD) {
19888c2ecf20Sopenharmony_ci		rc = pci_save_state(efx->pci_dev);
19898c2ecf20Sopenharmony_ci		if (rc) {
19908c2ecf20Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
19918c2ecf20Sopenharmony_ci				  "failed to backup PCI state of primary "
19928c2ecf20Sopenharmony_ci				  "function prior to hardware reset\n");
19938c2ecf20Sopenharmony_ci			goto fail1;
19948c2ecf20Sopenharmony_ci		}
19958c2ecf20Sopenharmony_ci		if (ef4_nic_is_dual_func(efx)) {
19968c2ecf20Sopenharmony_ci			rc = pci_save_state(nic_data->pci_dev2);
19978c2ecf20Sopenharmony_ci			if (rc) {
19988c2ecf20Sopenharmony_ci				netif_err(efx, drv, efx->net_dev,
19998c2ecf20Sopenharmony_ci					  "failed to backup PCI state of "
20008c2ecf20Sopenharmony_ci					  "secondary function prior to "
20018c2ecf20Sopenharmony_ci					  "hardware reset\n");
20028c2ecf20Sopenharmony_ci				goto fail2;
20038c2ecf20Sopenharmony_ci			}
20048c2ecf20Sopenharmony_ci		}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_2(glb_ctl_reg_ker,
20078c2ecf20Sopenharmony_ci				     FRF_AB_EXT_PHY_RST_DUR,
20088c2ecf20Sopenharmony_ci				     FFE_AB_EXT_PHY_RST_DUR_10240US,
20098c2ecf20Sopenharmony_ci				     FRF_AB_SWRST, 1);
20108c2ecf20Sopenharmony_ci	} else {
20118c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_7(glb_ctl_reg_ker,
20128c2ecf20Sopenharmony_ci				     /* exclude PHY from "invisible" reset */
20138c2ecf20Sopenharmony_ci				     FRF_AB_EXT_PHY_RST_CTL,
20148c2ecf20Sopenharmony_ci				     method == RESET_TYPE_INVISIBLE,
20158c2ecf20Sopenharmony_ci				     /* exclude EEPROM/flash and PCIe */
20168c2ecf20Sopenharmony_ci				     FRF_AB_PCIE_CORE_RST_CTL, 1,
20178c2ecf20Sopenharmony_ci				     FRF_AB_PCIE_NSTKY_RST_CTL, 1,
20188c2ecf20Sopenharmony_ci				     FRF_AB_PCIE_SD_RST_CTL, 1,
20198c2ecf20Sopenharmony_ci				     FRF_AB_EE_RST_CTL, 1,
20208c2ecf20Sopenharmony_ci				     FRF_AB_EXT_PHY_RST_DUR,
20218c2ecf20Sopenharmony_ci				     FFE_AB_EXT_PHY_RST_DUR_10240US,
20228c2ecf20Sopenharmony_ci				     FRF_AB_SWRST, 1);
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci	ef4_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	netif_dbg(efx, hw, efx->net_dev, "waiting for hardware reset\n");
20278c2ecf20Sopenharmony_ci	schedule_timeout_uninterruptible(HZ / 20);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	/* Restore PCI configuration if needed */
20308c2ecf20Sopenharmony_ci	if (method == RESET_TYPE_WORLD) {
20318c2ecf20Sopenharmony_ci		if (ef4_nic_is_dual_func(efx))
20328c2ecf20Sopenharmony_ci			pci_restore_state(nic_data->pci_dev2);
20338c2ecf20Sopenharmony_ci		pci_restore_state(efx->pci_dev);
20348c2ecf20Sopenharmony_ci		netif_dbg(efx, drv, efx->net_dev,
20358c2ecf20Sopenharmony_ci			  "successfully restored PCI config\n");
20368c2ecf20Sopenharmony_ci	}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	/* Assert that reset complete */
20398c2ecf20Sopenharmony_ci	ef4_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
20408c2ecf20Sopenharmony_ci	if (EF4_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) {
20418c2ecf20Sopenharmony_ci		rc = -ETIMEDOUT;
20428c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
20438c2ecf20Sopenharmony_ci			  "timed out waiting for hardware reset\n");
20448c2ecf20Sopenharmony_ci		goto fail3;
20458c2ecf20Sopenharmony_ci	}
20468c2ecf20Sopenharmony_ci	netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	return 0;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	/* pci_save_state() and pci_restore_state() MUST be called in pairs */
20518c2ecf20Sopenharmony_cifail2:
20528c2ecf20Sopenharmony_ci	pci_restore_state(efx->pci_dev);
20538c2ecf20Sopenharmony_cifail1:
20548c2ecf20Sopenharmony_cifail3:
20558c2ecf20Sopenharmony_ci	return rc;
20568c2ecf20Sopenharmony_ci}
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_cistatic int falcon_reset_hw(struct ef4_nic *efx, enum reset_type method)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
20618c2ecf20Sopenharmony_ci	int rc;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	mutex_lock(&nic_data->spi_lock);
20648c2ecf20Sopenharmony_ci	rc = __falcon_reset_hw(efx, method);
20658c2ecf20Sopenharmony_ci	mutex_unlock(&nic_data->spi_lock);
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	return rc;
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cistatic void falcon_monitor(struct ef4_nic *efx)
20718c2ecf20Sopenharmony_ci{
20728c2ecf20Sopenharmony_ci	bool link_changed;
20738c2ecf20Sopenharmony_ci	int rc;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	BUG_ON(!mutex_is_locked(&efx->mac_lock));
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	rc = falcon_board(efx)->type->monitor(efx);
20788c2ecf20Sopenharmony_ci	if (rc) {
20798c2ecf20Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
20808c2ecf20Sopenharmony_ci			  "Board sensor %s; shutting down PHY\n",
20818c2ecf20Sopenharmony_ci			  (rc == -ERANGE) ? "reported fault" : "failed");
20828c2ecf20Sopenharmony_ci		efx->phy_mode |= PHY_MODE_LOW_POWER;
20838c2ecf20Sopenharmony_ci		rc = __ef4_reconfigure_port(efx);
20848c2ecf20Sopenharmony_ci		WARN_ON(rc);
20858c2ecf20Sopenharmony_ci	}
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	if (LOOPBACK_INTERNAL(efx))
20888c2ecf20Sopenharmony_ci		link_changed = falcon_loopback_link_poll(efx);
20898c2ecf20Sopenharmony_ci	else
20908c2ecf20Sopenharmony_ci		link_changed = efx->phy_op->poll(efx);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	if (link_changed) {
20938c2ecf20Sopenharmony_ci		falcon_stop_nic_stats(efx);
20948c2ecf20Sopenharmony_ci		falcon_deconfigure_mac_wrapper(efx);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci		falcon_reset_macs(efx);
20978c2ecf20Sopenharmony_ci		rc = falcon_reconfigure_xmac(efx);
20988c2ecf20Sopenharmony_ci		BUG_ON(rc);
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci		falcon_start_nic_stats(efx);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci		ef4_link_status_changed(efx);
21038c2ecf20Sopenharmony_ci	}
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	falcon_poll_xmac(efx);
21068c2ecf20Sopenharmony_ci}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci/* Zeroes out the SRAM contents.  This routine must be called in
21098c2ecf20Sopenharmony_ci * process context and is allowed to sleep.
21108c2ecf20Sopenharmony_ci */
21118c2ecf20Sopenharmony_cistatic int falcon_reset_sram(struct ef4_nic *efx)
21128c2ecf20Sopenharmony_ci{
21138c2ecf20Sopenharmony_ci	ef4_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
21148c2ecf20Sopenharmony_ci	int count;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	/* Set the SRAM wake/sleep GPIO appropriately. */
21178c2ecf20Sopenharmony_ci	ef4_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL);
21188c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1);
21198c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1);
21208c2ecf20Sopenharmony_ci	ef4_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	/* Initiate SRAM reset */
21238c2ecf20Sopenharmony_ci	EF4_POPULATE_OWORD_2(srm_cfg_reg_ker,
21248c2ecf20Sopenharmony_ci			     FRF_AZ_SRM_INIT_EN, 1,
21258c2ecf20Sopenharmony_ci			     FRF_AZ_SRM_NB_SZ, 0);
21268c2ecf20Sopenharmony_ci	ef4_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	/* Wait for SRAM reset to complete */
21298c2ecf20Sopenharmony_ci	count = 0;
21308c2ecf20Sopenharmony_ci	do {
21318c2ecf20Sopenharmony_ci		netif_dbg(efx, hw, efx->net_dev,
21328c2ecf20Sopenharmony_ci			  "waiting for SRAM reset (attempt %d)...\n", count);
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci		/* SRAM reset is slow; expect around 16ms */
21358c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 50);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci		/* Check for reset complete */
21388c2ecf20Sopenharmony_ci		ef4_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
21398c2ecf20Sopenharmony_ci		if (!EF4_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) {
21408c2ecf20Sopenharmony_ci			netif_dbg(efx, hw, efx->net_dev,
21418c2ecf20Sopenharmony_ci				  "SRAM reset complete\n");
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci			return 0;
21448c2ecf20Sopenharmony_ci		}
21458c2ecf20Sopenharmony_ci	} while (++count < 20);	/* wait up to 0.4 sec */
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n");
21488c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic void falcon_spi_device_init(struct ef4_nic *efx,
21528c2ecf20Sopenharmony_ci				  struct falcon_spi_device *spi_device,
21538c2ecf20Sopenharmony_ci				  unsigned int device_id, u32 device_type)
21548c2ecf20Sopenharmony_ci{
21558c2ecf20Sopenharmony_ci	if (device_type != 0) {
21568c2ecf20Sopenharmony_ci		spi_device->device_id = device_id;
21578c2ecf20Sopenharmony_ci		spi_device->size =
21588c2ecf20Sopenharmony_ci			1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
21598c2ecf20Sopenharmony_ci		spi_device->addr_len =
21608c2ecf20Sopenharmony_ci			SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
21618c2ecf20Sopenharmony_ci		spi_device->munge_address = (spi_device->size == 1 << 9 &&
21628c2ecf20Sopenharmony_ci					     spi_device->addr_len == 1);
21638c2ecf20Sopenharmony_ci		spi_device->erase_command =
21648c2ecf20Sopenharmony_ci			SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD);
21658c2ecf20Sopenharmony_ci		spi_device->erase_size =
21668c2ecf20Sopenharmony_ci			1 << SPI_DEV_TYPE_FIELD(device_type,
21678c2ecf20Sopenharmony_ci						SPI_DEV_TYPE_ERASE_SIZE);
21688c2ecf20Sopenharmony_ci		spi_device->block_size =
21698c2ecf20Sopenharmony_ci			1 << SPI_DEV_TYPE_FIELD(device_type,
21708c2ecf20Sopenharmony_ci						SPI_DEV_TYPE_BLOCK_SIZE);
21718c2ecf20Sopenharmony_ci	} else {
21728c2ecf20Sopenharmony_ci		spi_device->size = 0;
21738c2ecf20Sopenharmony_ci	}
21748c2ecf20Sopenharmony_ci}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci/* Extract non-volatile configuration */
21778c2ecf20Sopenharmony_cistatic int falcon_probe_nvconfig(struct ef4_nic *efx)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
21808c2ecf20Sopenharmony_ci	struct falcon_nvconfig *nvconfig;
21818c2ecf20Sopenharmony_ci	int rc;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
21848c2ecf20Sopenharmony_ci	if (!nvconfig)
21858c2ecf20Sopenharmony_ci		return -ENOMEM;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	rc = falcon_read_nvram(efx, nvconfig);
21888c2ecf20Sopenharmony_ci	if (rc)
21898c2ecf20Sopenharmony_ci		goto out;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	efx->phy_type = nvconfig->board_v2.port0_phy_type;
21928c2ecf20Sopenharmony_ci	efx->mdio.prtad = nvconfig->board_v2.port0_phy_addr;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
21958c2ecf20Sopenharmony_ci		falcon_spi_device_init(
21968c2ecf20Sopenharmony_ci			efx, &nic_data->spi_flash, FFE_AB_SPI_DEVICE_FLASH,
21978c2ecf20Sopenharmony_ci			le32_to_cpu(nvconfig->board_v3
21988c2ecf20Sopenharmony_ci				    .spi_device_type[FFE_AB_SPI_DEVICE_FLASH]));
21998c2ecf20Sopenharmony_ci		falcon_spi_device_init(
22008c2ecf20Sopenharmony_ci			efx, &nic_data->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM,
22018c2ecf20Sopenharmony_ci			le32_to_cpu(nvconfig->board_v3
22028c2ecf20Sopenharmony_ci				    .spi_device_type[FFE_AB_SPI_DEVICE_EEPROM]));
22038c2ecf20Sopenharmony_ci	}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	/* Read the MAC addresses */
22068c2ecf20Sopenharmony_ci	ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
22098c2ecf20Sopenharmony_ci		  efx->phy_type, efx->mdio.prtad);
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	rc = falcon_probe_board(efx,
22128c2ecf20Sopenharmony_ci				le16_to_cpu(nvconfig->board_v2.board_revision));
22138c2ecf20Sopenharmony_ciout:
22148c2ecf20Sopenharmony_ci	kfree(nvconfig);
22158c2ecf20Sopenharmony_ci	return rc;
22168c2ecf20Sopenharmony_ci}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_cistatic int falcon_dimension_resources(struct ef4_nic *efx)
22198c2ecf20Sopenharmony_ci{
22208c2ecf20Sopenharmony_ci	efx->rx_dc_base = 0x20000;
22218c2ecf20Sopenharmony_ci	efx->tx_dc_base = 0x26000;
22228c2ecf20Sopenharmony_ci	return 0;
22238c2ecf20Sopenharmony_ci}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci/* Probe all SPI devices on the NIC */
22268c2ecf20Sopenharmony_cistatic void falcon_probe_spi_devices(struct ef4_nic *efx)
22278c2ecf20Sopenharmony_ci{
22288c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
22298c2ecf20Sopenharmony_ci	ef4_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
22308c2ecf20Sopenharmony_ci	int boot_dev;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	ef4_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL);
22338c2ecf20Sopenharmony_ci	ef4_reado(efx, &nic_stat, FR_AB_NIC_STAT);
22348c2ecf20Sopenharmony_ci	ef4_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	if (EF4_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) {
22378c2ecf20Sopenharmony_ci		boot_dev = (EF4_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ?
22388c2ecf20Sopenharmony_ci			    FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM);
22398c2ecf20Sopenharmony_ci		netif_dbg(efx, probe, efx->net_dev, "Booted from %s\n",
22408c2ecf20Sopenharmony_ci			  boot_dev == FFE_AB_SPI_DEVICE_FLASH ?
22418c2ecf20Sopenharmony_ci			  "flash" : "EEPROM");
22428c2ecf20Sopenharmony_ci	} else {
22438c2ecf20Sopenharmony_ci		/* Disable VPD and set clock dividers to safe
22448c2ecf20Sopenharmony_ci		 * values for initial programming. */
22458c2ecf20Sopenharmony_ci		boot_dev = -1;
22468c2ecf20Sopenharmony_ci		netif_dbg(efx, probe, efx->net_dev,
22478c2ecf20Sopenharmony_ci			  "Booted from internal ASIC settings;"
22488c2ecf20Sopenharmony_ci			  " setting SPI config\n");
22498c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0,
22508c2ecf20Sopenharmony_ci				     /* 125 MHz / 7 ~= 20 MHz */
22518c2ecf20Sopenharmony_ci				     FRF_AB_EE_SF_CLOCK_DIV, 7,
22528c2ecf20Sopenharmony_ci				     /* 125 MHz / 63 ~= 2 MHz */
22538c2ecf20Sopenharmony_ci				     FRF_AB_EE_EE_CLOCK_DIV, 63);
22548c2ecf20Sopenharmony_ci		ef4_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	mutex_init(&nic_data->spi_lock);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	if (boot_dev == FFE_AB_SPI_DEVICE_FLASH)
22608c2ecf20Sopenharmony_ci		falcon_spi_device_init(efx, &nic_data->spi_flash,
22618c2ecf20Sopenharmony_ci				       FFE_AB_SPI_DEVICE_FLASH,
22628c2ecf20Sopenharmony_ci				       default_flash_type);
22638c2ecf20Sopenharmony_ci	if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM)
22648c2ecf20Sopenharmony_ci		falcon_spi_device_init(efx, &nic_data->spi_eeprom,
22658c2ecf20Sopenharmony_ci				       FFE_AB_SPI_DEVICE_EEPROM,
22668c2ecf20Sopenharmony_ci				       large_eeprom_type);
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_cistatic unsigned int falcon_a1_mem_map_size(struct ef4_nic *efx)
22708c2ecf20Sopenharmony_ci{
22718c2ecf20Sopenharmony_ci	return 0x20000;
22728c2ecf20Sopenharmony_ci}
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_cistatic unsigned int falcon_b0_mem_map_size(struct ef4_nic *efx)
22758c2ecf20Sopenharmony_ci{
22768c2ecf20Sopenharmony_ci	/* Map everything up to and including the RSS indirection table.
22778c2ecf20Sopenharmony_ci	 * The PCI core takes care of mapping the MSI-X tables.
22788c2ecf20Sopenharmony_ci	 */
22798c2ecf20Sopenharmony_ci	return FR_BZ_RX_INDIRECTION_TBL +
22808c2ecf20Sopenharmony_ci		FR_BZ_RX_INDIRECTION_TBL_STEP * FR_BZ_RX_INDIRECTION_TBL_ROWS;
22818c2ecf20Sopenharmony_ci}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_cistatic int falcon_probe_nic(struct ef4_nic *efx)
22848c2ecf20Sopenharmony_ci{
22858c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data;
22868c2ecf20Sopenharmony_ci	struct falcon_board *board;
22878c2ecf20Sopenharmony_ci	int rc;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	efx->primary = efx; /* only one usable function per controller */
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci	/* Allocate storage for hardware specific data */
22928c2ecf20Sopenharmony_ci	nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
22938c2ecf20Sopenharmony_ci	if (!nic_data)
22948c2ecf20Sopenharmony_ci		return -ENOMEM;
22958c2ecf20Sopenharmony_ci	efx->nic_data = nic_data;
22968c2ecf20Sopenharmony_ci	nic_data->efx = efx;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	rc = -ENODEV;
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	if (ef4_farch_fpga_ver(efx) != 0) {
23018c2ecf20Sopenharmony_ci		netif_err(efx, probe, efx->net_dev,
23028c2ecf20Sopenharmony_ci			  "Falcon FPGA not supported\n");
23038c2ecf20Sopenharmony_ci		goto fail1;
23048c2ecf20Sopenharmony_ci	}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1) {
23078c2ecf20Sopenharmony_ci		ef4_oword_t nic_stat;
23088c2ecf20Sopenharmony_ci		struct pci_dev *dev;
23098c2ecf20Sopenharmony_ci		u8 pci_rev = efx->pci_dev->revision;
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci		if ((pci_rev == 0xff) || (pci_rev == 0)) {
23128c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev,
23138c2ecf20Sopenharmony_ci				  "Falcon rev A0 not supported\n");
23148c2ecf20Sopenharmony_ci			goto fail1;
23158c2ecf20Sopenharmony_ci		}
23168c2ecf20Sopenharmony_ci		ef4_reado(efx, &nic_stat, FR_AB_NIC_STAT);
23178c2ecf20Sopenharmony_ci		if (EF4_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
23188c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev,
23198c2ecf20Sopenharmony_ci				  "Falcon rev A1 1G not supported\n");
23208c2ecf20Sopenharmony_ci			goto fail1;
23218c2ecf20Sopenharmony_ci		}
23228c2ecf20Sopenharmony_ci		if (EF4_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
23238c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev,
23248c2ecf20Sopenharmony_ci				  "Falcon rev A1 PCI-X not supported\n");
23258c2ecf20Sopenharmony_ci			goto fail1;
23268c2ecf20Sopenharmony_ci		}
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci		dev = pci_dev_get(efx->pci_dev);
23298c2ecf20Sopenharmony_ci		while ((dev = pci_get_device(PCI_VENDOR_ID_SOLARFLARE,
23308c2ecf20Sopenharmony_ci					     PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1,
23318c2ecf20Sopenharmony_ci					     dev))) {
23328c2ecf20Sopenharmony_ci			if (dev->bus == efx->pci_dev->bus &&
23338c2ecf20Sopenharmony_ci			    dev->devfn == efx->pci_dev->devfn + 1) {
23348c2ecf20Sopenharmony_ci				nic_data->pci_dev2 = dev;
23358c2ecf20Sopenharmony_ci				break;
23368c2ecf20Sopenharmony_ci			}
23378c2ecf20Sopenharmony_ci		}
23388c2ecf20Sopenharmony_ci		if (!nic_data->pci_dev2) {
23398c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev,
23408c2ecf20Sopenharmony_ci				  "failed to find secondary function\n");
23418c2ecf20Sopenharmony_ci			rc = -ENODEV;
23428c2ecf20Sopenharmony_ci			goto fail2;
23438c2ecf20Sopenharmony_ci		}
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	/* Now we can reset the NIC */
23478c2ecf20Sopenharmony_ci	rc = __falcon_reset_hw(efx, RESET_TYPE_ALL);
23488c2ecf20Sopenharmony_ci	if (rc) {
23498c2ecf20Sopenharmony_ci		netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
23508c2ecf20Sopenharmony_ci		goto fail3;
23518c2ecf20Sopenharmony_ci	}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	/* Allocate memory for INT_KER */
23548c2ecf20Sopenharmony_ci	rc = ef4_nic_alloc_buffer(efx, &efx->irq_status, sizeof(ef4_oword_t),
23558c2ecf20Sopenharmony_ci				  GFP_KERNEL);
23568c2ecf20Sopenharmony_ci	if (rc)
23578c2ecf20Sopenharmony_ci		goto fail4;
23588c2ecf20Sopenharmony_ci	BUG_ON(efx->irq_status.dma_addr & 0x0f);
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev,
23618c2ecf20Sopenharmony_ci		  "INT_KER at %llx (virt %p phys %llx)\n",
23628c2ecf20Sopenharmony_ci		  (u64)efx->irq_status.dma_addr,
23638c2ecf20Sopenharmony_ci		  efx->irq_status.addr,
23648c2ecf20Sopenharmony_ci		  (u64)virt_to_phys(efx->irq_status.addr));
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	falcon_probe_spi_devices(efx);
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	/* Read in the non-volatile configuration */
23698c2ecf20Sopenharmony_ci	rc = falcon_probe_nvconfig(efx);
23708c2ecf20Sopenharmony_ci	if (rc) {
23718c2ecf20Sopenharmony_ci		if (rc == -EINVAL)
23728c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev, "NVRAM is invalid\n");
23738c2ecf20Sopenharmony_ci		goto fail5;
23748c2ecf20Sopenharmony_ci	}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	efx->max_channels = (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1 ? 4 :
23778c2ecf20Sopenharmony_ci			     EF4_MAX_CHANNELS);
23788c2ecf20Sopenharmony_ci	efx->max_tx_channels = efx->max_channels;
23798c2ecf20Sopenharmony_ci	efx->timer_quantum_ns = 4968; /* 621 cycles */
23808c2ecf20Sopenharmony_ci	efx->timer_max_ns = efx->type->timer_period_max *
23818c2ecf20Sopenharmony_ci			    efx->timer_quantum_ns;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/* Initialise I2C adapter */
23848c2ecf20Sopenharmony_ci	board = falcon_board(efx);
23858c2ecf20Sopenharmony_ci	board->i2c_adap.owner = THIS_MODULE;
23868c2ecf20Sopenharmony_ci	board->i2c_data = falcon_i2c_bit_operations;
23878c2ecf20Sopenharmony_ci	board->i2c_data.data = efx;
23888c2ecf20Sopenharmony_ci	board->i2c_adap.algo_data = &board->i2c_data;
23898c2ecf20Sopenharmony_ci	board->i2c_adap.dev.parent = &efx->pci_dev->dev;
23908c2ecf20Sopenharmony_ci	strlcpy(board->i2c_adap.name, "SFC4000 GPIO",
23918c2ecf20Sopenharmony_ci		sizeof(board->i2c_adap.name));
23928c2ecf20Sopenharmony_ci	rc = i2c_bit_add_bus(&board->i2c_adap);
23938c2ecf20Sopenharmony_ci	if (rc)
23948c2ecf20Sopenharmony_ci		goto fail5;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	rc = falcon_board(efx)->type->init(efx);
23978c2ecf20Sopenharmony_ci	if (rc) {
23988c2ecf20Sopenharmony_ci		netif_err(efx, probe, efx->net_dev,
23998c2ecf20Sopenharmony_ci			  "failed to initialise board\n");
24008c2ecf20Sopenharmony_ci		goto fail6;
24018c2ecf20Sopenharmony_ci	}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	nic_data->stats_disable_count = 1;
24048c2ecf20Sopenharmony_ci	timer_setup(&nic_data->stats_timer, falcon_stats_timer_func, 0);
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	return 0;
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci fail6:
24098c2ecf20Sopenharmony_ci	i2c_del_adapter(&board->i2c_adap);
24108c2ecf20Sopenharmony_ci	memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
24118c2ecf20Sopenharmony_ci fail5:
24128c2ecf20Sopenharmony_ci	ef4_nic_free_buffer(efx, &efx->irq_status);
24138c2ecf20Sopenharmony_ci fail4:
24148c2ecf20Sopenharmony_ci fail3:
24158c2ecf20Sopenharmony_ci	if (nic_data->pci_dev2) {
24168c2ecf20Sopenharmony_ci		pci_dev_put(nic_data->pci_dev2);
24178c2ecf20Sopenharmony_ci		nic_data->pci_dev2 = NULL;
24188c2ecf20Sopenharmony_ci	}
24198c2ecf20Sopenharmony_ci fail2:
24208c2ecf20Sopenharmony_ci fail1:
24218c2ecf20Sopenharmony_ci	kfree(efx->nic_data);
24228c2ecf20Sopenharmony_ci	return rc;
24238c2ecf20Sopenharmony_ci}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_cistatic void falcon_init_rx_cfg(struct ef4_nic *efx)
24268c2ecf20Sopenharmony_ci{
24278c2ecf20Sopenharmony_ci	/* RX control FIFO thresholds (32 entries) */
24288c2ecf20Sopenharmony_ci	const unsigned ctrl_xon_thr = 20;
24298c2ecf20Sopenharmony_ci	const unsigned ctrl_xoff_thr = 25;
24308c2ecf20Sopenharmony_ci	ef4_oword_t reg;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	ef4_reado(efx, &reg, FR_AZ_RX_CFG);
24338c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1) {
24348c2ecf20Sopenharmony_ci		/* Data FIFO size is 5.5K.  The RX DMA engine only
24358c2ecf20Sopenharmony_ci		 * supports scattering for user-mode queues, but will
24368c2ecf20Sopenharmony_ci		 * split DMA writes at intervals of RX_USR_BUF_SIZE
24378c2ecf20Sopenharmony_ci		 * (32-byte units) even for kernel-mode queues.  We
24388c2ecf20Sopenharmony_ci		 * set it to be so large that that never happens.
24398c2ecf20Sopenharmony_ci		 */
24408c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0);
24418c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE,
24428c2ecf20Sopenharmony_ci				    (3 * 4096) >> 5);
24438c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8);
24448c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8);
24458c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr);
24468c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr);
24478c2ecf20Sopenharmony_ci	} else {
24488c2ecf20Sopenharmony_ci		/* Data FIFO size is 80K; register fields moved */
24498c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0);
24508c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE,
24518c2ecf20Sopenharmony_ci				    EF4_RX_USR_BUF_SIZE >> 5);
24528c2ecf20Sopenharmony_ci		/* Send XON and XOFF at ~3 * max MTU away from empty/full */
24538c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8);
24548c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8);
24558c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
24568c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
24578c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci		/* Enable hash insertion. This is broken for the
24608c2ecf20Sopenharmony_ci		 * 'Falcon' hash so also select Toeplitz TCP/IPv4 and
24618c2ecf20Sopenharmony_ci		 * IPv4 hashes. */
24628c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_INSRT_HDR, 1);
24638c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_ALG, 1);
24648c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_IP_HASH, 1);
24658c2ecf20Sopenharmony_ci	}
24668c2ecf20Sopenharmony_ci	/* Always enable XOFF signal from RX FIFO.  We enable
24678c2ecf20Sopenharmony_ci	 * or disable transmission of pause frames at the MAC. */
24688c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
24698c2ecf20Sopenharmony_ci	ef4_writeo(efx, &reg, FR_AZ_RX_CFG);
24708c2ecf20Sopenharmony_ci}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci/* This call performs hardware-specific global initialisation, such as
24738c2ecf20Sopenharmony_ci * defining the descriptor cache sizes and number of RSS channels.
24748c2ecf20Sopenharmony_ci * It does not set up any buffers, descriptor rings or event queues.
24758c2ecf20Sopenharmony_ci */
24768c2ecf20Sopenharmony_cistatic int falcon_init_nic(struct ef4_nic *efx)
24778c2ecf20Sopenharmony_ci{
24788c2ecf20Sopenharmony_ci	ef4_oword_t temp;
24798c2ecf20Sopenharmony_ci	int rc;
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	/* Use on-chip SRAM */
24828c2ecf20Sopenharmony_ci	ef4_reado(efx, &temp, FR_AB_NIC_STAT);
24838c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1);
24848c2ecf20Sopenharmony_ci	ef4_writeo(efx, &temp, FR_AB_NIC_STAT);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	rc = falcon_reset_sram(efx);
24878c2ecf20Sopenharmony_ci	if (rc)
24888c2ecf20Sopenharmony_ci		return rc;
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	/* Clear the parity enables on the TX data fifos as
24918c2ecf20Sopenharmony_ci	 * they produce false parity errors because of timing issues
24928c2ecf20Sopenharmony_ci	 */
24938c2ecf20Sopenharmony_ci	if (EF4_WORKAROUND_5129(efx)) {
24948c2ecf20Sopenharmony_ci		ef4_reado(efx, &temp, FR_AZ_CSR_SPARE);
24958c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0);
24968c2ecf20Sopenharmony_ci		ef4_writeo(efx, &temp, FR_AZ_CSR_SPARE);
24978c2ecf20Sopenharmony_ci	}
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	if (EF4_WORKAROUND_7244(efx)) {
25008c2ecf20Sopenharmony_ci		ef4_reado(efx, &temp, FR_BZ_RX_FILTER_CTL);
25018c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8);
25028c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8);
25038c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8);
25048c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8);
25058c2ecf20Sopenharmony_ci		ef4_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL);
25068c2ecf20Sopenharmony_ci	}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	/* XXX This is documented only for Falcon A0/A1 */
25098c2ecf20Sopenharmony_ci	/* Setup RX.  Wait for descriptor is broken and must
25108c2ecf20Sopenharmony_ci	 * be disabled.  RXDP recovery shouldn't be needed, but is.
25118c2ecf20Sopenharmony_ci	 */
25128c2ecf20Sopenharmony_ci	ef4_reado(efx, &temp, FR_AA_RX_SELF_RST);
25138c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1);
25148c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1);
25158c2ecf20Sopenharmony_ci	if (EF4_WORKAROUND_5583(efx))
25168c2ecf20Sopenharmony_ci		EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1);
25178c2ecf20Sopenharmony_ci	ef4_writeo(efx, &temp, FR_AA_RX_SELF_RST);
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	/* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
25208c2ecf20Sopenharmony_ci	 * descriptors (which is bad).
25218c2ecf20Sopenharmony_ci	 */
25228c2ecf20Sopenharmony_ci	ef4_reado(efx, &temp, FR_AZ_TX_CFG);
25238c2ecf20Sopenharmony_ci	EF4_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
25248c2ecf20Sopenharmony_ci	ef4_writeo(efx, &temp, FR_AZ_TX_CFG);
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	falcon_init_rx_cfg(efx);
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) {
25298c2ecf20Sopenharmony_ci		falcon_b0_rx_push_rss_config(efx, false, efx->rx_indir_table);
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci		/* Set destination of both TX and RX Flush events */
25328c2ecf20Sopenharmony_ci		EF4_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
25338c2ecf20Sopenharmony_ci		ef4_writeo(efx, &temp, FR_BZ_DP_CTRL);
25348c2ecf20Sopenharmony_ci	}
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	ef4_farch_init_common(efx);
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	return 0;
25398c2ecf20Sopenharmony_ci}
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_cistatic void falcon_remove_nic(struct ef4_nic *efx)
25428c2ecf20Sopenharmony_ci{
25438c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
25448c2ecf20Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	board->type->fini(efx);
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	/* Remove I2C adapter and clear it in preparation for a retry */
25498c2ecf20Sopenharmony_ci	i2c_del_adapter(&board->i2c_adap);
25508c2ecf20Sopenharmony_ci	memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	ef4_nic_free_buffer(efx, &efx->irq_status);
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	__falcon_reset_hw(efx, RESET_TYPE_ALL);
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	/* Release the second function after the reset */
25578c2ecf20Sopenharmony_ci	if (nic_data->pci_dev2) {
25588c2ecf20Sopenharmony_ci		pci_dev_put(nic_data->pci_dev2);
25598c2ecf20Sopenharmony_ci		nic_data->pci_dev2 = NULL;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	/* Tear down the private nic state */
25638c2ecf20Sopenharmony_ci	kfree(efx->nic_data);
25648c2ecf20Sopenharmony_ci	efx->nic_data = NULL;
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 *names)
25688c2ecf20Sopenharmony_ci{
25698c2ecf20Sopenharmony_ci	return ef4_nic_describe_stats(falcon_stat_desc, FALCON_STAT_COUNT,
25708c2ecf20Sopenharmony_ci				      falcon_stat_mask, names);
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_cistatic size_t falcon_update_nic_stats(struct ef4_nic *efx, u64 *full_stats,
25748c2ecf20Sopenharmony_ci				      struct rtnl_link_stats64 *core_stats)
25758c2ecf20Sopenharmony_ci{
25768c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
25778c2ecf20Sopenharmony_ci	u64 *stats = nic_data->stats;
25788c2ecf20Sopenharmony_ci	ef4_oword_t cnt;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	if (!nic_data->stats_disable_count) {
25818c2ecf20Sopenharmony_ci		ef4_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
25828c2ecf20Sopenharmony_ci		stats[FALCON_STAT_rx_nodesc_drop_cnt] +=
25838c2ecf20Sopenharmony_ci			EF4_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		if (nic_data->stats_pending &&
25868c2ecf20Sopenharmony_ci		    FALCON_XMAC_STATS_DMA_FLAG(efx)) {
25878c2ecf20Sopenharmony_ci			nic_data->stats_pending = false;
25888c2ecf20Sopenharmony_ci			rmb(); /* read the done flag before the stats */
25898c2ecf20Sopenharmony_ci			ef4_nic_update_stats(
25908c2ecf20Sopenharmony_ci				falcon_stat_desc, FALCON_STAT_COUNT,
25918c2ecf20Sopenharmony_ci				falcon_stat_mask,
25928c2ecf20Sopenharmony_ci				stats, efx->stats_buffer.addr, true);
25938c2ecf20Sopenharmony_ci		}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci		/* Update derived statistic */
25968c2ecf20Sopenharmony_ci		ef4_update_diff_stat(&stats[FALCON_STAT_rx_bad_bytes],
25978c2ecf20Sopenharmony_ci				     stats[FALCON_STAT_rx_bytes] -
25988c2ecf20Sopenharmony_ci				     stats[FALCON_STAT_rx_good_bytes] -
25998c2ecf20Sopenharmony_ci				     stats[FALCON_STAT_rx_control] * 64);
26008c2ecf20Sopenharmony_ci		ef4_update_sw_stats(efx, stats);
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (full_stats)
26048c2ecf20Sopenharmony_ci		memcpy(full_stats, stats, sizeof(u64) * FALCON_STAT_COUNT);
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	if (core_stats) {
26078c2ecf20Sopenharmony_ci		core_stats->rx_packets = stats[FALCON_STAT_rx_packets];
26088c2ecf20Sopenharmony_ci		core_stats->tx_packets = stats[FALCON_STAT_tx_packets];
26098c2ecf20Sopenharmony_ci		core_stats->rx_bytes = stats[FALCON_STAT_rx_bytes];
26108c2ecf20Sopenharmony_ci		core_stats->tx_bytes = stats[FALCON_STAT_tx_bytes];
26118c2ecf20Sopenharmony_ci		core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt] +
26128c2ecf20Sopenharmony_ci					 stats[GENERIC_STAT_rx_nodesc_trunc] +
26138c2ecf20Sopenharmony_ci					 stats[GENERIC_STAT_rx_noskb_drops];
26148c2ecf20Sopenharmony_ci		core_stats->multicast = stats[FALCON_STAT_rx_multicast];
26158c2ecf20Sopenharmony_ci		core_stats->rx_length_errors =
26168c2ecf20Sopenharmony_ci			stats[FALCON_STAT_rx_gtjumbo] +
26178c2ecf20Sopenharmony_ci			stats[FALCON_STAT_rx_length_error];
26188c2ecf20Sopenharmony_ci		core_stats->rx_crc_errors = stats[FALCON_STAT_rx_bad];
26198c2ecf20Sopenharmony_ci		core_stats->rx_frame_errors = stats[FALCON_STAT_rx_align_error];
26208c2ecf20Sopenharmony_ci		core_stats->rx_fifo_errors = stats[FALCON_STAT_rx_overflow];
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci		core_stats->rx_errors = (core_stats->rx_length_errors +
26238c2ecf20Sopenharmony_ci					 core_stats->rx_crc_errors +
26248c2ecf20Sopenharmony_ci					 core_stats->rx_frame_errors +
26258c2ecf20Sopenharmony_ci					 stats[FALCON_STAT_rx_symbol_error]);
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	return FALCON_STAT_COUNT;
26298c2ecf20Sopenharmony_ci}
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_civoid falcon_start_nic_stats(struct ef4_nic *efx)
26328c2ecf20Sopenharmony_ci{
26338c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	spin_lock_bh(&efx->stats_lock);
26368c2ecf20Sopenharmony_ci	if (--nic_data->stats_disable_count == 0)
26378c2ecf20Sopenharmony_ci		falcon_stats_request(efx);
26388c2ecf20Sopenharmony_ci	spin_unlock_bh(&efx->stats_lock);
26398c2ecf20Sopenharmony_ci}
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci/* We don't acutally pull stats on falcon. Wait 10ms so that
26428c2ecf20Sopenharmony_ci * they arrive when we call this just after start_stats
26438c2ecf20Sopenharmony_ci */
26448c2ecf20Sopenharmony_cistatic void falcon_pull_nic_stats(struct ef4_nic *efx)
26458c2ecf20Sopenharmony_ci{
26468c2ecf20Sopenharmony_ci	msleep(10);
26478c2ecf20Sopenharmony_ci}
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_civoid falcon_stop_nic_stats(struct ef4_nic *efx)
26508c2ecf20Sopenharmony_ci{
26518c2ecf20Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
26528c2ecf20Sopenharmony_ci	int i;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	might_sleep();
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	spin_lock_bh(&efx->stats_lock);
26578c2ecf20Sopenharmony_ci	++nic_data->stats_disable_count;
26588c2ecf20Sopenharmony_ci	spin_unlock_bh(&efx->stats_lock);
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	del_timer_sync(&nic_data->stats_timer);
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	/* Wait enough time for the most recent transfer to
26638c2ecf20Sopenharmony_ci	 * complete. */
26648c2ecf20Sopenharmony_ci	for (i = 0; i < 4 && nic_data->stats_pending; i++) {
26658c2ecf20Sopenharmony_ci		if (FALCON_XMAC_STATS_DMA_FLAG(efx))
26668c2ecf20Sopenharmony_ci			break;
26678c2ecf20Sopenharmony_ci		msleep(1);
26688c2ecf20Sopenharmony_ci	}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	spin_lock_bh(&efx->stats_lock);
26718c2ecf20Sopenharmony_ci	falcon_stats_complete(efx);
26728c2ecf20Sopenharmony_ci	spin_unlock_bh(&efx->stats_lock);
26738c2ecf20Sopenharmony_ci}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_cistatic void falcon_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	falcon_board(efx)->type->set_id_led(efx, mode);
26788c2ecf20Sopenharmony_ci}
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci/**************************************************************************
26818c2ecf20Sopenharmony_ci *
26828c2ecf20Sopenharmony_ci * Wake on LAN
26838c2ecf20Sopenharmony_ci *
26848c2ecf20Sopenharmony_ci **************************************************************************
26858c2ecf20Sopenharmony_ci */
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_cistatic void falcon_get_wol(struct ef4_nic *efx, struct ethtool_wolinfo *wol)
26888c2ecf20Sopenharmony_ci{
26898c2ecf20Sopenharmony_ci	wol->supported = 0;
26908c2ecf20Sopenharmony_ci	wol->wolopts = 0;
26918c2ecf20Sopenharmony_ci	memset(&wol->sopass, 0, sizeof(wol->sopass));
26928c2ecf20Sopenharmony_ci}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_cistatic int falcon_set_wol(struct ef4_nic *efx, u32 type)
26958c2ecf20Sopenharmony_ci{
26968c2ecf20Sopenharmony_ci	if (type != 0)
26978c2ecf20Sopenharmony_ci		return -EINVAL;
26988c2ecf20Sopenharmony_ci	return 0;
26998c2ecf20Sopenharmony_ci}
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci/**************************************************************************
27028c2ecf20Sopenharmony_ci *
27038c2ecf20Sopenharmony_ci * Revision-dependent attributes used by efx.c and nic.c
27048c2ecf20Sopenharmony_ci *
27058c2ecf20Sopenharmony_ci **************************************************************************
27068c2ecf20Sopenharmony_ci */
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ciconst struct ef4_nic_type falcon_a1_nic_type = {
27098c2ecf20Sopenharmony_ci	.mem_bar = EF4_MEM_BAR,
27108c2ecf20Sopenharmony_ci	.mem_map_size = falcon_a1_mem_map_size,
27118c2ecf20Sopenharmony_ci	.probe = falcon_probe_nic,
27128c2ecf20Sopenharmony_ci	.remove = falcon_remove_nic,
27138c2ecf20Sopenharmony_ci	.init = falcon_init_nic,
27148c2ecf20Sopenharmony_ci	.dimension_resources = falcon_dimension_resources,
27158c2ecf20Sopenharmony_ci	.fini = falcon_irq_ack_a1,
27168c2ecf20Sopenharmony_ci	.monitor = falcon_monitor,
27178c2ecf20Sopenharmony_ci	.map_reset_reason = falcon_map_reset_reason,
27188c2ecf20Sopenharmony_ci	.map_reset_flags = falcon_map_reset_flags,
27198c2ecf20Sopenharmony_ci	.reset = falcon_reset_hw,
27208c2ecf20Sopenharmony_ci	.probe_port = falcon_probe_port,
27218c2ecf20Sopenharmony_ci	.remove_port = falcon_remove_port,
27228c2ecf20Sopenharmony_ci	.handle_global_event = falcon_handle_global_event,
27238c2ecf20Sopenharmony_ci	.fini_dmaq = ef4_farch_fini_dmaq,
27248c2ecf20Sopenharmony_ci	.prepare_flush = falcon_prepare_flush,
27258c2ecf20Sopenharmony_ci	.finish_flush = ef4_port_dummy_op_void,
27268c2ecf20Sopenharmony_ci	.prepare_flr = ef4_port_dummy_op_void,
27278c2ecf20Sopenharmony_ci	.finish_flr = ef4_farch_finish_flr,
27288c2ecf20Sopenharmony_ci	.describe_stats = falcon_describe_nic_stats,
27298c2ecf20Sopenharmony_ci	.update_stats = falcon_update_nic_stats,
27308c2ecf20Sopenharmony_ci	.start_stats = falcon_start_nic_stats,
27318c2ecf20Sopenharmony_ci	.pull_stats = falcon_pull_nic_stats,
27328c2ecf20Sopenharmony_ci	.stop_stats = falcon_stop_nic_stats,
27338c2ecf20Sopenharmony_ci	.set_id_led = falcon_set_id_led,
27348c2ecf20Sopenharmony_ci	.push_irq_moderation = falcon_push_irq_moderation,
27358c2ecf20Sopenharmony_ci	.reconfigure_port = falcon_reconfigure_port,
27368c2ecf20Sopenharmony_ci	.prepare_enable_fc_tx = falcon_a1_prepare_enable_fc_tx,
27378c2ecf20Sopenharmony_ci	.reconfigure_mac = falcon_reconfigure_xmac,
27388c2ecf20Sopenharmony_ci	.check_mac_fault = falcon_xmac_check_fault,
27398c2ecf20Sopenharmony_ci	.get_wol = falcon_get_wol,
27408c2ecf20Sopenharmony_ci	.set_wol = falcon_set_wol,
27418c2ecf20Sopenharmony_ci	.resume_wol = ef4_port_dummy_op_void,
27428c2ecf20Sopenharmony_ci	.test_nvram = falcon_test_nvram,
27438c2ecf20Sopenharmony_ci	.irq_enable_master = ef4_farch_irq_enable_master,
27448c2ecf20Sopenharmony_ci	.irq_test_generate = ef4_farch_irq_test_generate,
27458c2ecf20Sopenharmony_ci	.irq_disable_non_ev = ef4_farch_irq_disable_master,
27468c2ecf20Sopenharmony_ci	.irq_handle_msi = ef4_farch_msi_interrupt,
27478c2ecf20Sopenharmony_ci	.irq_handle_legacy = falcon_legacy_interrupt_a1,
27488c2ecf20Sopenharmony_ci	.tx_probe = ef4_farch_tx_probe,
27498c2ecf20Sopenharmony_ci	.tx_init = ef4_farch_tx_init,
27508c2ecf20Sopenharmony_ci	.tx_remove = ef4_farch_tx_remove,
27518c2ecf20Sopenharmony_ci	.tx_write = ef4_farch_tx_write,
27528c2ecf20Sopenharmony_ci	.tx_limit_len = ef4_farch_tx_limit_len,
27538c2ecf20Sopenharmony_ci	.rx_push_rss_config = dummy_rx_push_rss_config,
27548c2ecf20Sopenharmony_ci	.rx_probe = ef4_farch_rx_probe,
27558c2ecf20Sopenharmony_ci	.rx_init = ef4_farch_rx_init,
27568c2ecf20Sopenharmony_ci	.rx_remove = ef4_farch_rx_remove,
27578c2ecf20Sopenharmony_ci	.rx_write = ef4_farch_rx_write,
27588c2ecf20Sopenharmony_ci	.rx_defer_refill = ef4_farch_rx_defer_refill,
27598c2ecf20Sopenharmony_ci	.ev_probe = ef4_farch_ev_probe,
27608c2ecf20Sopenharmony_ci	.ev_init = ef4_farch_ev_init,
27618c2ecf20Sopenharmony_ci	.ev_fini = ef4_farch_ev_fini,
27628c2ecf20Sopenharmony_ci	.ev_remove = ef4_farch_ev_remove,
27638c2ecf20Sopenharmony_ci	.ev_process = ef4_farch_ev_process,
27648c2ecf20Sopenharmony_ci	.ev_read_ack = ef4_farch_ev_read_ack,
27658c2ecf20Sopenharmony_ci	.ev_test_generate = ef4_farch_ev_test_generate,
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	/* We don't expose the filter table on Falcon A1 as it is not
27688c2ecf20Sopenharmony_ci	 * mapped into function 0, but these implementations still
27698c2ecf20Sopenharmony_ci	 * work with a degenerate case of all tables set to size 0.
27708c2ecf20Sopenharmony_ci	 */
27718c2ecf20Sopenharmony_ci	.filter_table_probe = ef4_farch_filter_table_probe,
27728c2ecf20Sopenharmony_ci	.filter_table_restore = ef4_farch_filter_table_restore,
27738c2ecf20Sopenharmony_ci	.filter_table_remove = ef4_farch_filter_table_remove,
27748c2ecf20Sopenharmony_ci	.filter_insert = ef4_farch_filter_insert,
27758c2ecf20Sopenharmony_ci	.filter_remove_safe = ef4_farch_filter_remove_safe,
27768c2ecf20Sopenharmony_ci	.filter_get_safe = ef4_farch_filter_get_safe,
27778c2ecf20Sopenharmony_ci	.filter_clear_rx = ef4_farch_filter_clear_rx,
27788c2ecf20Sopenharmony_ci	.filter_count_rx_used = ef4_farch_filter_count_rx_used,
27798c2ecf20Sopenharmony_ci	.filter_get_rx_id_limit = ef4_farch_filter_get_rx_id_limit,
27808c2ecf20Sopenharmony_ci	.filter_get_rx_ids = ef4_farch_filter_get_rx_ids,
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD
27838c2ecf20Sopenharmony_ci	.mtd_probe = falcon_mtd_probe,
27848c2ecf20Sopenharmony_ci	.mtd_rename = falcon_mtd_rename,
27858c2ecf20Sopenharmony_ci	.mtd_read = falcon_mtd_read,
27868c2ecf20Sopenharmony_ci	.mtd_erase = falcon_mtd_erase,
27878c2ecf20Sopenharmony_ci	.mtd_write = falcon_mtd_write,
27888c2ecf20Sopenharmony_ci	.mtd_sync = falcon_mtd_sync,
27898c2ecf20Sopenharmony_ci#endif
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	.revision = EF4_REV_FALCON_A1,
27928c2ecf20Sopenharmony_ci	.txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
27938c2ecf20Sopenharmony_ci	.rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
27948c2ecf20Sopenharmony_ci	.buf_tbl_base = FR_AA_BUF_FULL_TBL_KER,
27958c2ecf20Sopenharmony_ci	.evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER,
27968c2ecf20Sopenharmony_ci	.evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER,
27978c2ecf20Sopenharmony_ci	.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
27988c2ecf20Sopenharmony_ci	.rx_buffer_padding = 0x24,
27998c2ecf20Sopenharmony_ci	.can_rx_scatter = false,
28008c2ecf20Sopenharmony_ci	.max_interrupt_mode = EF4_INT_MODE_MSI,
28018c2ecf20Sopenharmony_ci	.timer_period_max =  1 << FRF_AB_TC_TIMER_VAL_WIDTH,
28028c2ecf20Sopenharmony_ci	.offload_features = NETIF_F_IP_CSUM,
28038c2ecf20Sopenharmony_ci};
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ciconst struct ef4_nic_type falcon_b0_nic_type = {
28068c2ecf20Sopenharmony_ci	.mem_bar = EF4_MEM_BAR,
28078c2ecf20Sopenharmony_ci	.mem_map_size = falcon_b0_mem_map_size,
28088c2ecf20Sopenharmony_ci	.probe = falcon_probe_nic,
28098c2ecf20Sopenharmony_ci	.remove = falcon_remove_nic,
28108c2ecf20Sopenharmony_ci	.init = falcon_init_nic,
28118c2ecf20Sopenharmony_ci	.dimension_resources = falcon_dimension_resources,
28128c2ecf20Sopenharmony_ci	.fini = ef4_port_dummy_op_void,
28138c2ecf20Sopenharmony_ci	.monitor = falcon_monitor,
28148c2ecf20Sopenharmony_ci	.map_reset_reason = falcon_map_reset_reason,
28158c2ecf20Sopenharmony_ci	.map_reset_flags = falcon_map_reset_flags,
28168c2ecf20Sopenharmony_ci	.reset = falcon_reset_hw,
28178c2ecf20Sopenharmony_ci	.probe_port = falcon_probe_port,
28188c2ecf20Sopenharmony_ci	.remove_port = falcon_remove_port,
28198c2ecf20Sopenharmony_ci	.handle_global_event = falcon_handle_global_event,
28208c2ecf20Sopenharmony_ci	.fini_dmaq = ef4_farch_fini_dmaq,
28218c2ecf20Sopenharmony_ci	.prepare_flush = falcon_prepare_flush,
28228c2ecf20Sopenharmony_ci	.finish_flush = ef4_port_dummy_op_void,
28238c2ecf20Sopenharmony_ci	.prepare_flr = ef4_port_dummy_op_void,
28248c2ecf20Sopenharmony_ci	.finish_flr = ef4_farch_finish_flr,
28258c2ecf20Sopenharmony_ci	.describe_stats = falcon_describe_nic_stats,
28268c2ecf20Sopenharmony_ci	.update_stats = falcon_update_nic_stats,
28278c2ecf20Sopenharmony_ci	.start_stats = falcon_start_nic_stats,
28288c2ecf20Sopenharmony_ci	.pull_stats = falcon_pull_nic_stats,
28298c2ecf20Sopenharmony_ci	.stop_stats = falcon_stop_nic_stats,
28308c2ecf20Sopenharmony_ci	.set_id_led = falcon_set_id_led,
28318c2ecf20Sopenharmony_ci	.push_irq_moderation = falcon_push_irq_moderation,
28328c2ecf20Sopenharmony_ci	.reconfigure_port = falcon_reconfigure_port,
28338c2ecf20Sopenharmony_ci	.prepare_enable_fc_tx = falcon_b0_prepare_enable_fc_tx,
28348c2ecf20Sopenharmony_ci	.reconfigure_mac = falcon_reconfigure_xmac,
28358c2ecf20Sopenharmony_ci	.check_mac_fault = falcon_xmac_check_fault,
28368c2ecf20Sopenharmony_ci	.get_wol = falcon_get_wol,
28378c2ecf20Sopenharmony_ci	.set_wol = falcon_set_wol,
28388c2ecf20Sopenharmony_ci	.resume_wol = ef4_port_dummy_op_void,
28398c2ecf20Sopenharmony_ci	.test_chip = falcon_b0_test_chip,
28408c2ecf20Sopenharmony_ci	.test_nvram = falcon_test_nvram,
28418c2ecf20Sopenharmony_ci	.irq_enable_master = ef4_farch_irq_enable_master,
28428c2ecf20Sopenharmony_ci	.irq_test_generate = ef4_farch_irq_test_generate,
28438c2ecf20Sopenharmony_ci	.irq_disable_non_ev = ef4_farch_irq_disable_master,
28448c2ecf20Sopenharmony_ci	.irq_handle_msi = ef4_farch_msi_interrupt,
28458c2ecf20Sopenharmony_ci	.irq_handle_legacy = ef4_farch_legacy_interrupt,
28468c2ecf20Sopenharmony_ci	.tx_probe = ef4_farch_tx_probe,
28478c2ecf20Sopenharmony_ci	.tx_init = ef4_farch_tx_init,
28488c2ecf20Sopenharmony_ci	.tx_remove = ef4_farch_tx_remove,
28498c2ecf20Sopenharmony_ci	.tx_write = ef4_farch_tx_write,
28508c2ecf20Sopenharmony_ci	.tx_limit_len = ef4_farch_tx_limit_len,
28518c2ecf20Sopenharmony_ci	.rx_push_rss_config = falcon_b0_rx_push_rss_config,
28528c2ecf20Sopenharmony_ci	.rx_probe = ef4_farch_rx_probe,
28538c2ecf20Sopenharmony_ci	.rx_init = ef4_farch_rx_init,
28548c2ecf20Sopenharmony_ci	.rx_remove = ef4_farch_rx_remove,
28558c2ecf20Sopenharmony_ci	.rx_write = ef4_farch_rx_write,
28568c2ecf20Sopenharmony_ci	.rx_defer_refill = ef4_farch_rx_defer_refill,
28578c2ecf20Sopenharmony_ci	.ev_probe = ef4_farch_ev_probe,
28588c2ecf20Sopenharmony_ci	.ev_init = ef4_farch_ev_init,
28598c2ecf20Sopenharmony_ci	.ev_fini = ef4_farch_ev_fini,
28608c2ecf20Sopenharmony_ci	.ev_remove = ef4_farch_ev_remove,
28618c2ecf20Sopenharmony_ci	.ev_process = ef4_farch_ev_process,
28628c2ecf20Sopenharmony_ci	.ev_read_ack = ef4_farch_ev_read_ack,
28638c2ecf20Sopenharmony_ci	.ev_test_generate = ef4_farch_ev_test_generate,
28648c2ecf20Sopenharmony_ci	.filter_table_probe = ef4_farch_filter_table_probe,
28658c2ecf20Sopenharmony_ci	.filter_table_restore = ef4_farch_filter_table_restore,
28668c2ecf20Sopenharmony_ci	.filter_table_remove = ef4_farch_filter_table_remove,
28678c2ecf20Sopenharmony_ci	.filter_update_rx_scatter = ef4_farch_filter_update_rx_scatter,
28688c2ecf20Sopenharmony_ci	.filter_insert = ef4_farch_filter_insert,
28698c2ecf20Sopenharmony_ci	.filter_remove_safe = ef4_farch_filter_remove_safe,
28708c2ecf20Sopenharmony_ci	.filter_get_safe = ef4_farch_filter_get_safe,
28718c2ecf20Sopenharmony_ci	.filter_clear_rx = ef4_farch_filter_clear_rx,
28728c2ecf20Sopenharmony_ci	.filter_count_rx_used = ef4_farch_filter_count_rx_used,
28738c2ecf20Sopenharmony_ci	.filter_get_rx_id_limit = ef4_farch_filter_get_rx_id_limit,
28748c2ecf20Sopenharmony_ci	.filter_get_rx_ids = ef4_farch_filter_get_rx_ids,
28758c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
28768c2ecf20Sopenharmony_ci	.filter_rfs_insert = ef4_farch_filter_rfs_insert,
28778c2ecf20Sopenharmony_ci	.filter_rfs_expire_one = ef4_farch_filter_rfs_expire_one,
28788c2ecf20Sopenharmony_ci#endif
28798c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD
28808c2ecf20Sopenharmony_ci	.mtd_probe = falcon_mtd_probe,
28818c2ecf20Sopenharmony_ci	.mtd_rename = falcon_mtd_rename,
28828c2ecf20Sopenharmony_ci	.mtd_read = falcon_mtd_read,
28838c2ecf20Sopenharmony_ci	.mtd_erase = falcon_mtd_erase,
28848c2ecf20Sopenharmony_ci	.mtd_write = falcon_mtd_write,
28858c2ecf20Sopenharmony_ci	.mtd_sync = falcon_mtd_sync,
28868c2ecf20Sopenharmony_ci#endif
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	.revision = EF4_REV_FALCON_B0,
28898c2ecf20Sopenharmony_ci	.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
28908c2ecf20Sopenharmony_ci	.rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
28918c2ecf20Sopenharmony_ci	.buf_tbl_base = FR_BZ_BUF_FULL_TBL,
28928c2ecf20Sopenharmony_ci	.evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
28938c2ecf20Sopenharmony_ci	.evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
28948c2ecf20Sopenharmony_ci	.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
28958c2ecf20Sopenharmony_ci	.rx_prefix_size = FS_BZ_RX_PREFIX_SIZE,
28968c2ecf20Sopenharmony_ci	.rx_hash_offset = FS_BZ_RX_PREFIX_HASH_OFST,
28978c2ecf20Sopenharmony_ci	.rx_buffer_padding = 0,
28988c2ecf20Sopenharmony_ci	.can_rx_scatter = true,
28998c2ecf20Sopenharmony_ci	.max_interrupt_mode = EF4_INT_MODE_MSIX,
29008c2ecf20Sopenharmony_ci	.timer_period_max =  1 << FRF_AB_TC_TIMER_VAL_WIDTH,
29018c2ecf20Sopenharmony_ci	.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
29028c2ecf20Sopenharmony_ci	.max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS,
29038c2ecf20Sopenharmony_ci};
2904