162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/**************************************************************************** 362306a36Sopenharmony_ci * Driver for Solarflare network controllers and boards 462306a36Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 562306a36Sopenharmony_ci * Copyright 2006-2013 Solarflare Communications Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/seq_file.h> 1362306a36Sopenharmony_ci#include <linux/i2c.h> 1462306a36Sopenharmony_ci#include <linux/mii.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/sched/signal.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "net_driver.h" 1962306a36Sopenharmony_ci#include "bitfield.h" 2062306a36Sopenharmony_ci#include "efx.h" 2162306a36Sopenharmony_ci#include "nic.h" 2262306a36Sopenharmony_ci#include "farch_regs.h" 2362306a36Sopenharmony_ci#include "io.h" 2462306a36Sopenharmony_ci#include "phy.h" 2562306a36Sopenharmony_ci#include "workarounds.h" 2662306a36Sopenharmony_ci#include "selftest.h" 2762306a36Sopenharmony_ci#include "mdio_10g.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Hardware control for SFC4000 (aka Falcon). */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/************************************************************************** 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * NIC stats 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci ************************************************************************** 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define FALCON_MAC_STATS_SIZE 0x100 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define XgRxOctets_offset 0x0 4162306a36Sopenharmony_ci#define XgRxOctets_WIDTH 48 4262306a36Sopenharmony_ci#define XgRxOctetsOK_offset 0x8 4362306a36Sopenharmony_ci#define XgRxOctetsOK_WIDTH 48 4462306a36Sopenharmony_ci#define XgRxPkts_offset 0x10 4562306a36Sopenharmony_ci#define XgRxPkts_WIDTH 32 4662306a36Sopenharmony_ci#define XgRxPktsOK_offset 0x14 4762306a36Sopenharmony_ci#define XgRxPktsOK_WIDTH 32 4862306a36Sopenharmony_ci#define XgRxBroadcastPkts_offset 0x18 4962306a36Sopenharmony_ci#define XgRxBroadcastPkts_WIDTH 32 5062306a36Sopenharmony_ci#define XgRxMulticastPkts_offset 0x1C 5162306a36Sopenharmony_ci#define XgRxMulticastPkts_WIDTH 32 5262306a36Sopenharmony_ci#define XgRxUnicastPkts_offset 0x20 5362306a36Sopenharmony_ci#define XgRxUnicastPkts_WIDTH 32 5462306a36Sopenharmony_ci#define XgRxUndersizePkts_offset 0x24 5562306a36Sopenharmony_ci#define XgRxUndersizePkts_WIDTH 32 5662306a36Sopenharmony_ci#define XgRxOversizePkts_offset 0x28 5762306a36Sopenharmony_ci#define XgRxOversizePkts_WIDTH 32 5862306a36Sopenharmony_ci#define XgRxJabberPkts_offset 0x2C 5962306a36Sopenharmony_ci#define XgRxJabberPkts_WIDTH 32 6062306a36Sopenharmony_ci#define XgRxUndersizeFCSerrorPkts_offset 0x30 6162306a36Sopenharmony_ci#define XgRxUndersizeFCSerrorPkts_WIDTH 32 6262306a36Sopenharmony_ci#define XgRxDropEvents_offset 0x34 6362306a36Sopenharmony_ci#define XgRxDropEvents_WIDTH 32 6462306a36Sopenharmony_ci#define XgRxFCSerrorPkts_offset 0x38 6562306a36Sopenharmony_ci#define XgRxFCSerrorPkts_WIDTH 32 6662306a36Sopenharmony_ci#define XgRxAlignError_offset 0x3C 6762306a36Sopenharmony_ci#define XgRxAlignError_WIDTH 32 6862306a36Sopenharmony_ci#define XgRxSymbolError_offset 0x40 6962306a36Sopenharmony_ci#define XgRxSymbolError_WIDTH 32 7062306a36Sopenharmony_ci#define XgRxInternalMACError_offset 0x44 7162306a36Sopenharmony_ci#define XgRxInternalMACError_WIDTH 32 7262306a36Sopenharmony_ci#define XgRxControlPkts_offset 0x48 7362306a36Sopenharmony_ci#define XgRxControlPkts_WIDTH 32 7462306a36Sopenharmony_ci#define XgRxPausePkts_offset 0x4C 7562306a36Sopenharmony_ci#define XgRxPausePkts_WIDTH 32 7662306a36Sopenharmony_ci#define XgRxPkts64Octets_offset 0x50 7762306a36Sopenharmony_ci#define XgRxPkts64Octets_WIDTH 32 7862306a36Sopenharmony_ci#define XgRxPkts65to127Octets_offset 0x54 7962306a36Sopenharmony_ci#define XgRxPkts65to127Octets_WIDTH 32 8062306a36Sopenharmony_ci#define XgRxPkts128to255Octets_offset 0x58 8162306a36Sopenharmony_ci#define XgRxPkts128to255Octets_WIDTH 32 8262306a36Sopenharmony_ci#define XgRxPkts256to511Octets_offset 0x5C 8362306a36Sopenharmony_ci#define XgRxPkts256to511Octets_WIDTH 32 8462306a36Sopenharmony_ci#define XgRxPkts512to1023Octets_offset 0x60 8562306a36Sopenharmony_ci#define XgRxPkts512to1023Octets_WIDTH 32 8662306a36Sopenharmony_ci#define XgRxPkts1024to15xxOctets_offset 0x64 8762306a36Sopenharmony_ci#define XgRxPkts1024to15xxOctets_WIDTH 32 8862306a36Sopenharmony_ci#define XgRxPkts15xxtoMaxOctets_offset 0x68 8962306a36Sopenharmony_ci#define XgRxPkts15xxtoMaxOctets_WIDTH 32 9062306a36Sopenharmony_ci#define XgRxLengthError_offset 0x6C 9162306a36Sopenharmony_ci#define XgRxLengthError_WIDTH 32 9262306a36Sopenharmony_ci#define XgTxPkts_offset 0x80 9362306a36Sopenharmony_ci#define XgTxPkts_WIDTH 32 9462306a36Sopenharmony_ci#define XgTxOctets_offset 0x88 9562306a36Sopenharmony_ci#define XgTxOctets_WIDTH 48 9662306a36Sopenharmony_ci#define XgTxMulticastPkts_offset 0x90 9762306a36Sopenharmony_ci#define XgTxMulticastPkts_WIDTH 32 9862306a36Sopenharmony_ci#define XgTxBroadcastPkts_offset 0x94 9962306a36Sopenharmony_ci#define XgTxBroadcastPkts_WIDTH 32 10062306a36Sopenharmony_ci#define XgTxUnicastPkts_offset 0x98 10162306a36Sopenharmony_ci#define XgTxUnicastPkts_WIDTH 32 10262306a36Sopenharmony_ci#define XgTxControlPkts_offset 0x9C 10362306a36Sopenharmony_ci#define XgTxControlPkts_WIDTH 32 10462306a36Sopenharmony_ci#define XgTxPausePkts_offset 0xA0 10562306a36Sopenharmony_ci#define XgTxPausePkts_WIDTH 32 10662306a36Sopenharmony_ci#define XgTxPkts64Octets_offset 0xA4 10762306a36Sopenharmony_ci#define XgTxPkts64Octets_WIDTH 32 10862306a36Sopenharmony_ci#define XgTxPkts65to127Octets_offset 0xA8 10962306a36Sopenharmony_ci#define XgTxPkts65to127Octets_WIDTH 32 11062306a36Sopenharmony_ci#define XgTxPkts128to255Octets_offset 0xAC 11162306a36Sopenharmony_ci#define XgTxPkts128to255Octets_WIDTH 32 11262306a36Sopenharmony_ci#define XgTxPkts256to511Octets_offset 0xB0 11362306a36Sopenharmony_ci#define XgTxPkts256to511Octets_WIDTH 32 11462306a36Sopenharmony_ci#define XgTxPkts512to1023Octets_offset 0xB4 11562306a36Sopenharmony_ci#define XgTxPkts512to1023Octets_WIDTH 32 11662306a36Sopenharmony_ci#define XgTxPkts1024to15xxOctets_offset 0xB8 11762306a36Sopenharmony_ci#define XgTxPkts1024to15xxOctets_WIDTH 32 11862306a36Sopenharmony_ci#define XgTxPkts1519toMaxOctets_offset 0xBC 11962306a36Sopenharmony_ci#define XgTxPkts1519toMaxOctets_WIDTH 32 12062306a36Sopenharmony_ci#define XgTxUndersizePkts_offset 0xC0 12162306a36Sopenharmony_ci#define XgTxUndersizePkts_WIDTH 32 12262306a36Sopenharmony_ci#define XgTxOversizePkts_offset 0xC4 12362306a36Sopenharmony_ci#define XgTxOversizePkts_WIDTH 32 12462306a36Sopenharmony_ci#define XgTxNonTcpUdpPkt_offset 0xC8 12562306a36Sopenharmony_ci#define XgTxNonTcpUdpPkt_WIDTH 16 12662306a36Sopenharmony_ci#define XgTxMacSrcErrPkt_offset 0xCC 12762306a36Sopenharmony_ci#define XgTxMacSrcErrPkt_WIDTH 16 12862306a36Sopenharmony_ci#define XgTxIpSrcErrPkt_offset 0xD0 12962306a36Sopenharmony_ci#define XgTxIpSrcErrPkt_WIDTH 16 13062306a36Sopenharmony_ci#define XgDmaDone_offset 0xD4 13162306a36Sopenharmony_ci#define XgDmaDone_WIDTH 32 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define FALCON_XMAC_STATS_DMA_FLAG(efx) \ 13462306a36Sopenharmony_ci (*(u32 *)((efx)->stats_buffer.addr + XgDmaDone_offset)) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define FALCON_DMA_STAT(ext_name, hw_name) \ 13762306a36Sopenharmony_ci [FALCON_STAT_ ## ext_name] = \ 13862306a36Sopenharmony_ci { #ext_name, \ 13962306a36Sopenharmony_ci /* 48-bit stats are zero-padded to 64 on DMA */ \ 14062306a36Sopenharmony_ci hw_name ## _ ## WIDTH == 48 ? 64 : hw_name ## _ ## WIDTH, \ 14162306a36Sopenharmony_ci hw_name ## _ ## offset } 14262306a36Sopenharmony_ci#define FALCON_OTHER_STAT(ext_name) \ 14362306a36Sopenharmony_ci [FALCON_STAT_ ## ext_name] = { #ext_name, 0, 0 } 14462306a36Sopenharmony_ci#define GENERIC_SW_STAT(ext_name) \ 14562306a36Sopenharmony_ci [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct ef4_hw_stat_desc falcon_stat_desc[FALCON_STAT_COUNT] = { 14862306a36Sopenharmony_ci FALCON_DMA_STAT(tx_bytes, XgTxOctets), 14962306a36Sopenharmony_ci FALCON_DMA_STAT(tx_packets, XgTxPkts), 15062306a36Sopenharmony_ci FALCON_DMA_STAT(tx_pause, XgTxPausePkts), 15162306a36Sopenharmony_ci FALCON_DMA_STAT(tx_control, XgTxControlPkts), 15262306a36Sopenharmony_ci FALCON_DMA_STAT(tx_unicast, XgTxUnicastPkts), 15362306a36Sopenharmony_ci FALCON_DMA_STAT(tx_multicast, XgTxMulticastPkts), 15462306a36Sopenharmony_ci FALCON_DMA_STAT(tx_broadcast, XgTxBroadcastPkts), 15562306a36Sopenharmony_ci FALCON_DMA_STAT(tx_lt64, XgTxUndersizePkts), 15662306a36Sopenharmony_ci FALCON_DMA_STAT(tx_64, XgTxPkts64Octets), 15762306a36Sopenharmony_ci FALCON_DMA_STAT(tx_65_to_127, XgTxPkts65to127Octets), 15862306a36Sopenharmony_ci FALCON_DMA_STAT(tx_128_to_255, XgTxPkts128to255Octets), 15962306a36Sopenharmony_ci FALCON_DMA_STAT(tx_256_to_511, XgTxPkts256to511Octets), 16062306a36Sopenharmony_ci FALCON_DMA_STAT(tx_512_to_1023, XgTxPkts512to1023Octets), 16162306a36Sopenharmony_ci FALCON_DMA_STAT(tx_1024_to_15xx, XgTxPkts1024to15xxOctets), 16262306a36Sopenharmony_ci FALCON_DMA_STAT(tx_15xx_to_jumbo, XgTxPkts1519toMaxOctets), 16362306a36Sopenharmony_ci FALCON_DMA_STAT(tx_gtjumbo, XgTxOversizePkts), 16462306a36Sopenharmony_ci FALCON_DMA_STAT(tx_non_tcpudp, XgTxNonTcpUdpPkt), 16562306a36Sopenharmony_ci FALCON_DMA_STAT(tx_mac_src_error, XgTxMacSrcErrPkt), 16662306a36Sopenharmony_ci FALCON_DMA_STAT(tx_ip_src_error, XgTxIpSrcErrPkt), 16762306a36Sopenharmony_ci FALCON_DMA_STAT(rx_bytes, XgRxOctets), 16862306a36Sopenharmony_ci FALCON_DMA_STAT(rx_good_bytes, XgRxOctetsOK), 16962306a36Sopenharmony_ci FALCON_OTHER_STAT(rx_bad_bytes), 17062306a36Sopenharmony_ci FALCON_DMA_STAT(rx_packets, XgRxPkts), 17162306a36Sopenharmony_ci FALCON_DMA_STAT(rx_good, XgRxPktsOK), 17262306a36Sopenharmony_ci FALCON_DMA_STAT(rx_bad, XgRxFCSerrorPkts), 17362306a36Sopenharmony_ci FALCON_DMA_STAT(rx_pause, XgRxPausePkts), 17462306a36Sopenharmony_ci FALCON_DMA_STAT(rx_control, XgRxControlPkts), 17562306a36Sopenharmony_ci FALCON_DMA_STAT(rx_unicast, XgRxUnicastPkts), 17662306a36Sopenharmony_ci FALCON_DMA_STAT(rx_multicast, XgRxMulticastPkts), 17762306a36Sopenharmony_ci FALCON_DMA_STAT(rx_broadcast, XgRxBroadcastPkts), 17862306a36Sopenharmony_ci FALCON_DMA_STAT(rx_lt64, XgRxUndersizePkts), 17962306a36Sopenharmony_ci FALCON_DMA_STAT(rx_64, XgRxPkts64Octets), 18062306a36Sopenharmony_ci FALCON_DMA_STAT(rx_65_to_127, XgRxPkts65to127Octets), 18162306a36Sopenharmony_ci FALCON_DMA_STAT(rx_128_to_255, XgRxPkts128to255Octets), 18262306a36Sopenharmony_ci FALCON_DMA_STAT(rx_256_to_511, XgRxPkts256to511Octets), 18362306a36Sopenharmony_ci FALCON_DMA_STAT(rx_512_to_1023, XgRxPkts512to1023Octets), 18462306a36Sopenharmony_ci FALCON_DMA_STAT(rx_1024_to_15xx, XgRxPkts1024to15xxOctets), 18562306a36Sopenharmony_ci FALCON_DMA_STAT(rx_15xx_to_jumbo, XgRxPkts15xxtoMaxOctets), 18662306a36Sopenharmony_ci FALCON_DMA_STAT(rx_gtjumbo, XgRxOversizePkts), 18762306a36Sopenharmony_ci FALCON_DMA_STAT(rx_bad_lt64, XgRxUndersizeFCSerrorPkts), 18862306a36Sopenharmony_ci FALCON_DMA_STAT(rx_bad_gtjumbo, XgRxJabberPkts), 18962306a36Sopenharmony_ci FALCON_DMA_STAT(rx_overflow, XgRxDropEvents), 19062306a36Sopenharmony_ci FALCON_DMA_STAT(rx_symbol_error, XgRxSymbolError), 19162306a36Sopenharmony_ci FALCON_DMA_STAT(rx_align_error, XgRxAlignError), 19262306a36Sopenharmony_ci FALCON_DMA_STAT(rx_length_error, XgRxLengthError), 19362306a36Sopenharmony_ci FALCON_DMA_STAT(rx_internal_error, XgRxInternalMACError), 19462306a36Sopenharmony_ci FALCON_OTHER_STAT(rx_nodesc_drop_cnt), 19562306a36Sopenharmony_ci GENERIC_SW_STAT(rx_nodesc_trunc), 19662306a36Sopenharmony_ci GENERIC_SW_STAT(rx_noskb_drops), 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_cistatic const unsigned long falcon_stat_mask[] = { 19962306a36Sopenharmony_ci [0 ... BITS_TO_LONGS(FALCON_STAT_COUNT) - 1] = ~0UL, 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/************************************************************************** 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * Basic SPI command set and bit definitions 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci *************************************************************************/ 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define SPI_WRSR 0x01 /* Write status register */ 20962306a36Sopenharmony_ci#define SPI_WRITE 0x02 /* Write data to memory array */ 21062306a36Sopenharmony_ci#define SPI_READ 0x03 /* Read data from memory array */ 21162306a36Sopenharmony_ci#define SPI_WRDI 0x04 /* Reset write enable latch */ 21262306a36Sopenharmony_ci#define SPI_RDSR 0x05 /* Read status register */ 21362306a36Sopenharmony_ci#define SPI_WREN 0x06 /* Set write enable latch */ 21462306a36Sopenharmony_ci#define SPI_SST_EWSR 0x50 /* SST: Enable write to status register */ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci#define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */ 21762306a36Sopenharmony_ci#define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */ 21862306a36Sopenharmony_ci#define SPI_STATUS_BP1 0x08 /* Block protection bit 1 */ 21962306a36Sopenharmony_ci#define SPI_STATUS_BP0 0x04 /* Block protection bit 0 */ 22062306a36Sopenharmony_ci#define SPI_STATUS_WEN 0x02 /* State of the write enable latch */ 22162306a36Sopenharmony_ci#define SPI_STATUS_NRDY 0x01 /* Device busy flag */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/************************************************************************** 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * Non-volatile memory layout 22662306a36Sopenharmony_ci * 22762306a36Sopenharmony_ci ************************************************************************** 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* SFC4000 flash is partitioned into: 23162306a36Sopenharmony_ci * 0-0x400 chip and board config (see struct falcon_nvconfig) 23262306a36Sopenharmony_ci * 0x400-0x8000 unused (or may contain VPD if EEPROM not present) 23362306a36Sopenharmony_ci * 0x8000-end boot code (mapped to PCI expansion ROM) 23462306a36Sopenharmony_ci * SFC4000 small EEPROM (size < 0x400) is used for VPD only. 23562306a36Sopenharmony_ci * SFC4000 large EEPROM (size >= 0x400) is partitioned into: 23662306a36Sopenharmony_ci * 0-0x400 chip and board config 23762306a36Sopenharmony_ci * configurable VPD 23862306a36Sopenharmony_ci * 0x800-0x1800 boot config 23962306a36Sopenharmony_ci * Aside from the chip and board config, all of these are optional and may 24062306a36Sopenharmony_ci * be absent or truncated depending on the devices used. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci#define FALCON_NVCONFIG_END 0x400U 24362306a36Sopenharmony_ci#define FALCON_FLASH_BOOTCODE_START 0x8000U 24462306a36Sopenharmony_ci#define FALCON_EEPROM_BOOTCONFIG_START 0x800U 24562306a36Sopenharmony_ci#define FALCON_EEPROM_BOOTCONFIG_END 0x1800U 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* Board configuration v2 (v1 is obsolete; later versions are compatible) */ 24862306a36Sopenharmony_cistruct falcon_nvconfig_board_v2 { 24962306a36Sopenharmony_ci __le16 nports; 25062306a36Sopenharmony_ci u8 port0_phy_addr; 25162306a36Sopenharmony_ci u8 port0_phy_type; 25262306a36Sopenharmony_ci u8 port1_phy_addr; 25362306a36Sopenharmony_ci u8 port1_phy_type; 25462306a36Sopenharmony_ci __le16 asic_sub_revision; 25562306a36Sopenharmony_ci __le16 board_revision; 25662306a36Sopenharmony_ci} __packed; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* Board configuration v3 extra information */ 25962306a36Sopenharmony_cistruct falcon_nvconfig_board_v3 { 26062306a36Sopenharmony_ci __le32 spi_device_type[2]; 26162306a36Sopenharmony_ci} __packed; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* Bit numbers for spi_device_type */ 26462306a36Sopenharmony_ci#define SPI_DEV_TYPE_SIZE_LBN 0 26562306a36Sopenharmony_ci#define SPI_DEV_TYPE_SIZE_WIDTH 5 26662306a36Sopenharmony_ci#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 26762306a36Sopenharmony_ci#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 26862306a36Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 26962306a36Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 27062306a36Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 27162306a36Sopenharmony_ci#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 27262306a36Sopenharmony_ci#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 27362306a36Sopenharmony_ci#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 27462306a36Sopenharmony_ci#define SPI_DEV_TYPE_FIELD(type, field) \ 27562306a36Sopenharmony_ci (((type) >> EF4_LOW_BIT(field)) & EF4_MASK32(EF4_WIDTH(field))) 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci#define FALCON_NVCONFIG_OFFSET 0x300 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C 28062306a36Sopenharmony_cistruct falcon_nvconfig { 28162306a36Sopenharmony_ci ef4_oword_t ee_vpd_cfg_reg; /* 0x300 */ 28262306a36Sopenharmony_ci u8 mac_address[2][8]; /* 0x310 */ 28362306a36Sopenharmony_ci ef4_oword_t pcie_sd_ctl0123_reg; /* 0x320 */ 28462306a36Sopenharmony_ci ef4_oword_t pcie_sd_ctl45_reg; /* 0x330 */ 28562306a36Sopenharmony_ci ef4_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */ 28662306a36Sopenharmony_ci ef4_oword_t hw_init_reg; /* 0x350 */ 28762306a36Sopenharmony_ci ef4_oword_t nic_stat_reg; /* 0x360 */ 28862306a36Sopenharmony_ci ef4_oword_t glb_ctl_reg; /* 0x370 */ 28962306a36Sopenharmony_ci ef4_oword_t srm_cfg_reg; /* 0x380 */ 29062306a36Sopenharmony_ci ef4_oword_t spare_reg; /* 0x390 */ 29162306a36Sopenharmony_ci __le16 board_magic_num; /* 0x3A0 */ 29262306a36Sopenharmony_ci __le16 board_struct_ver; 29362306a36Sopenharmony_ci __le16 board_checksum; 29462306a36Sopenharmony_ci struct falcon_nvconfig_board_v2 board_v2; 29562306a36Sopenharmony_ci ef4_oword_t ee_base_page_reg; /* 0x3B0 */ 29662306a36Sopenharmony_ci struct falcon_nvconfig_board_v3 board_v3; /* 0x3C0 */ 29762306a36Sopenharmony_ci} __packed; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/*************************************************************************/ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int falcon_reset_hw(struct ef4_nic *efx, enum reset_type method); 30262306a36Sopenharmony_cistatic void falcon_reconfigure_mac_wrapper(struct ef4_nic *efx); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic const unsigned int 30562306a36Sopenharmony_ci/* "Large" EEPROM device: Atmel AT25640 or similar 30662306a36Sopenharmony_ci * 8 KB, 16-bit address, 32 B write block */ 30762306a36Sopenharmony_cilarge_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN) 30862306a36Sopenharmony_ci | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) 30962306a36Sopenharmony_ci | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)), 31062306a36Sopenharmony_ci/* Default flash device: Atmel AT25F1024 31162306a36Sopenharmony_ci * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */ 31262306a36Sopenharmony_cidefault_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) 31362306a36Sopenharmony_ci | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) 31462306a36Sopenharmony_ci | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) 31562306a36Sopenharmony_ci | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) 31662306a36Sopenharmony_ci | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/************************************************************************** 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * I2C bus - this is a bit-bashing interface using GPIO pins 32162306a36Sopenharmony_ci * Note that it uses the output enables to tristate the outputs 32262306a36Sopenharmony_ci * SDA is the data pin and SCL is the clock 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci ************************************************************************** 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cistatic void falcon_setsda(void *data, int state) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct ef4_nic *efx = (struct ef4_nic *)data; 32962306a36Sopenharmony_ci ef4_oword_t reg; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GPIO_CTL); 33262306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state); 33362306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_GPIO_CTL); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void falcon_setscl(void *data, int state) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct ef4_nic *efx = (struct ef4_nic *)data; 33962306a36Sopenharmony_ci ef4_oword_t reg; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GPIO_CTL); 34262306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state); 34362306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_GPIO_CTL); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int falcon_getsda(void *data) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct ef4_nic *efx = (struct ef4_nic *)data; 34962306a36Sopenharmony_ci ef4_oword_t reg; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GPIO_CTL); 35262306a36Sopenharmony_ci return EF4_OWORD_FIELD(reg, FRF_AB_GPIO3_IN); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int falcon_getscl(void *data) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct ef4_nic *efx = (struct ef4_nic *)data; 35862306a36Sopenharmony_ci ef4_oword_t reg; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GPIO_CTL); 36162306a36Sopenharmony_ci return EF4_OWORD_FIELD(reg, FRF_AB_GPIO0_IN); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic const struct i2c_algo_bit_data falcon_i2c_bit_operations = { 36562306a36Sopenharmony_ci .setsda = falcon_setsda, 36662306a36Sopenharmony_ci .setscl = falcon_setscl, 36762306a36Sopenharmony_ci .getsda = falcon_getsda, 36862306a36Sopenharmony_ci .getscl = falcon_getscl, 36962306a36Sopenharmony_ci .udelay = 5, 37062306a36Sopenharmony_ci /* Wait up to 50 ms for slave to let us pull SCL high */ 37162306a36Sopenharmony_ci .timeout = DIV_ROUND_UP(HZ, 20), 37262306a36Sopenharmony_ci}; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void falcon_push_irq_moderation(struct ef4_channel *channel) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci ef4_dword_t timer_cmd; 37762306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Set timer register */ 38062306a36Sopenharmony_ci if (channel->irq_moderation_us) { 38162306a36Sopenharmony_ci unsigned int ticks; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ticks = ef4_usecs_to_ticks(efx, channel->irq_moderation_us); 38462306a36Sopenharmony_ci EF4_POPULATE_DWORD_2(timer_cmd, 38562306a36Sopenharmony_ci FRF_AB_TC_TIMER_MODE, 38662306a36Sopenharmony_ci FFE_BB_TIMER_MODE_INT_HLDOFF, 38762306a36Sopenharmony_ci FRF_AB_TC_TIMER_VAL, 38862306a36Sopenharmony_ci ticks - 1); 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci EF4_POPULATE_DWORD_2(timer_cmd, 39162306a36Sopenharmony_ci FRF_AB_TC_TIMER_MODE, 39262306a36Sopenharmony_ci FFE_BB_TIMER_MODE_DIS, 39362306a36Sopenharmony_ci FRF_AB_TC_TIMER_VAL, 0); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0); 39662306a36Sopenharmony_ci ef4_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, 39762306a36Sopenharmony_ci channel->channel); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void falcon_deconfigure_mac_wrapper(struct ef4_nic *efx); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void falcon_prepare_flush(struct ef4_nic *efx) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci falcon_deconfigure_mac_wrapper(efx); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Wait for the tx and rx fifo's to get to the next packet boundary 40762306a36Sopenharmony_ci * (~1ms without back-pressure), then to drain the remainder of the 40862306a36Sopenharmony_ci * fifo's at data path speeds (negligible), with a healthy margin. */ 40962306a36Sopenharmony_ci msleep(10); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/* Acknowledge a legacy interrupt from Falcon 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG. 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the 41762306a36Sopenharmony_ci * BIU. Interrupt acknowledge is read sensitive so must write instead 41862306a36Sopenharmony_ci * (then read to ensure the BIU collector is flushed) 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * NB most hardware supports MSI interrupts 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic inline void falcon_irq_ack_a1(struct ef4_nic *efx) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci ef4_dword_t reg; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci EF4_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e); 42762306a36Sopenharmony_ci ef4_writed(efx, ®, FR_AA_INT_ACK_KER); 42862306a36Sopenharmony_ci ef4_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct ef4_nic *efx = dev_id; 43462306a36Sopenharmony_ci ef4_oword_t *int_ker = efx->irq_status.addr; 43562306a36Sopenharmony_ci int syserr; 43662306a36Sopenharmony_ci int queues; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Check to see if this is our interrupt. If it isn't, we 43962306a36Sopenharmony_ci * exit without having touched the hardware. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci if (unlikely(EF4_OWORD_IS_ZERO(*int_ker))) { 44262306a36Sopenharmony_ci netif_vdbg(efx, intr, efx->net_dev, 44362306a36Sopenharmony_ci "IRQ %d on CPU %d not for me\n", irq, 44462306a36Sopenharmony_ci raw_smp_processor_id()); 44562306a36Sopenharmony_ci return IRQ_NONE; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci efx->last_irq_cpu = raw_smp_processor_id(); 44862306a36Sopenharmony_ci netif_vdbg(efx, intr, efx->net_dev, 44962306a36Sopenharmony_ci "IRQ %d on CPU %d status " EF4_OWORD_FMT "\n", 45062306a36Sopenharmony_ci irq, raw_smp_processor_id(), EF4_OWORD_VAL(*int_ker)); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (!likely(READ_ONCE(efx->irq_soft_enabled))) 45362306a36Sopenharmony_ci return IRQ_HANDLED; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Check to see if we have a serious error condition */ 45662306a36Sopenharmony_ci syserr = EF4_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); 45762306a36Sopenharmony_ci if (unlikely(syserr)) 45862306a36Sopenharmony_ci return ef4_farch_fatal_interrupt(efx); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Determine interrupting queues, clear interrupt status 46162306a36Sopenharmony_ci * register and acknowledge the device interrupt. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EF4_MAX_CHANNELS); 46462306a36Sopenharmony_ci queues = EF4_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); 46562306a36Sopenharmony_ci EF4_ZERO_OWORD(*int_ker); 46662306a36Sopenharmony_ci wmb(); /* Ensure the vector is cleared before interrupt ack */ 46762306a36Sopenharmony_ci falcon_irq_ack_a1(efx); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (queues & 1) 47062306a36Sopenharmony_ci ef4_schedule_channel_irq(ef4_get_channel(efx, 0)); 47162306a36Sopenharmony_ci if (queues & 2) 47262306a36Sopenharmony_ci ef4_schedule_channel_irq(ef4_get_channel(efx, 1)); 47362306a36Sopenharmony_ci return IRQ_HANDLED; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/************************************************************************** 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * RSS 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci ************************************************************************** 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_cistatic int dummy_rx_push_rss_config(struct ef4_nic *efx, bool user, 48362306a36Sopenharmony_ci const u32 *rx_indir_table) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci (void) efx; 48662306a36Sopenharmony_ci (void) user; 48762306a36Sopenharmony_ci (void) rx_indir_table; 48862306a36Sopenharmony_ci return -ENOSYS; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic int falcon_b0_rx_push_rss_config(struct ef4_nic *efx, bool user, 49262306a36Sopenharmony_ci const u32 *rx_indir_table) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci ef4_oword_t temp; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci (void) user; 49762306a36Sopenharmony_ci /* Set hash key for IPv4 */ 49862306a36Sopenharmony_ci memcpy(&temp, efx->rx_hash_key, sizeof(temp)); 49962306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci memcpy(efx->rx_indir_table, rx_indir_table, 50262306a36Sopenharmony_ci sizeof(efx->rx_indir_table)); 50362306a36Sopenharmony_ci ef4_farch_rx_push_indir_table(efx); 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/************************************************************************** 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * EEPROM/flash 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci ************************************************************************** 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci#define FALCON_SPI_MAX_LEN sizeof(ef4_oword_t) 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int falcon_spi_poll(struct ef4_nic *efx) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci ef4_oword_t reg; 51962306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_EE_SPI_HCMD); 52062306a36Sopenharmony_ci return EF4_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* Wait for SPI command completion */ 52462306a36Sopenharmony_cistatic int falcon_spi_wait(struct ef4_nic *efx) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci /* Most commands will finish quickly, so we start polling at 52762306a36Sopenharmony_ci * very short intervals. Sometimes the command may have to 52862306a36Sopenharmony_ci * wait for VPD or expansion ROM access outside of our 52962306a36Sopenharmony_ci * control, so we allow up to 100 ms. */ 53062306a36Sopenharmony_ci unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); 53162306a36Sopenharmony_ci int i; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 53462306a36Sopenharmony_ci if (!falcon_spi_poll(efx)) 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci udelay(10); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci for (;;) { 54062306a36Sopenharmony_ci if (!falcon_spi_poll(efx)) 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci if (time_after_eq(jiffies, timeout)) { 54362306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 54462306a36Sopenharmony_ci "timed out waiting for SPI\n"); 54562306a36Sopenharmony_ci return -ETIMEDOUT; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int 55262306a36Sopenharmony_cifalcon_spi_cmd(struct ef4_nic *efx, const struct falcon_spi_device *spi, 55362306a36Sopenharmony_ci unsigned int command, int address, 55462306a36Sopenharmony_ci const void *in, void *out, size_t len) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci bool addressed = (address >= 0); 55762306a36Sopenharmony_ci bool reading = (out != NULL); 55862306a36Sopenharmony_ci ef4_oword_t reg; 55962306a36Sopenharmony_ci int rc; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Input validation */ 56262306a36Sopenharmony_ci if (len > FALCON_SPI_MAX_LEN) 56362306a36Sopenharmony_ci return -EINVAL; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Check that previous command is not still running */ 56662306a36Sopenharmony_ci rc = falcon_spi_poll(efx); 56762306a36Sopenharmony_ci if (rc) 56862306a36Sopenharmony_ci return rc; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* Program address register, if we have an address */ 57162306a36Sopenharmony_ci if (addressed) { 57262306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); 57362306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_EE_SPI_HADR); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* Program data register, if we have data */ 57762306a36Sopenharmony_ci if (in != NULL) { 57862306a36Sopenharmony_ci memcpy(®, in, len); 57962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_EE_SPI_HDATA); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Issue read/write command */ 58362306a36Sopenharmony_ci EF4_POPULATE_OWORD_7(reg, 58462306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_CMD_EN, 1, 58562306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, 58662306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_DABCNT, len, 58762306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_READ, reading, 58862306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_DUBCNT, 0, 58962306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_ADBCNT, 59062306a36Sopenharmony_ci (addressed ? spi->addr_len : 0), 59162306a36Sopenharmony_ci FRF_AB_EE_SPI_HCMD_ENC, command); 59262306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_EE_SPI_HCMD); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Wait for read/write to complete */ 59562306a36Sopenharmony_ci rc = falcon_spi_wait(efx); 59662306a36Sopenharmony_ci if (rc) 59762306a36Sopenharmony_ci return rc; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* Read data */ 60062306a36Sopenharmony_ci if (out != NULL) { 60162306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_EE_SPI_HDATA); 60262306a36Sopenharmony_ci memcpy(out, ®, len); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic inline u8 60962306a36Sopenharmony_cifalcon_spi_munge_command(const struct falcon_spi_device *spi, 61062306a36Sopenharmony_ci const u8 command, const unsigned int address) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci return command | (((address >> 8) & spi->munge_address) << 3); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int 61662306a36Sopenharmony_cifalcon_spi_read(struct ef4_nic *efx, const struct falcon_spi_device *spi, 61762306a36Sopenharmony_ci loff_t start, size_t len, size_t *retlen, u8 *buffer) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci size_t block_len, pos = 0; 62062306a36Sopenharmony_ci unsigned int command; 62162306a36Sopenharmony_ci int rc = 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci while (pos < len) { 62462306a36Sopenharmony_ci block_len = min(len - pos, FALCON_SPI_MAX_LEN); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci command = falcon_spi_munge_command(spi, SPI_READ, start + pos); 62762306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, 62862306a36Sopenharmony_ci buffer + pos, block_len); 62962306a36Sopenharmony_ci if (rc) 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci pos += block_len; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Avoid locking up the system */ 63462306a36Sopenharmony_ci cond_resched(); 63562306a36Sopenharmony_ci if (signal_pending(current)) { 63662306a36Sopenharmony_ci rc = -EINTR; 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (retlen) 64262306a36Sopenharmony_ci *retlen = pos; 64362306a36Sopenharmony_ci return rc; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistruct falcon_mtd_partition { 64962306a36Sopenharmony_ci struct ef4_mtd_partition common; 65062306a36Sopenharmony_ci const struct falcon_spi_device *spi; 65162306a36Sopenharmony_ci size_t offset; 65262306a36Sopenharmony_ci}; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci#define to_falcon_mtd_partition(mtd) \ 65562306a36Sopenharmony_ci container_of(mtd, struct falcon_mtd_partition, common.mtd) 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic size_t 65862306a36Sopenharmony_cifalcon_spi_write_limit(const struct falcon_spi_device *spi, size_t start) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci return min(FALCON_SPI_MAX_LEN, 66162306a36Sopenharmony_ci (spi->block_size - (start & (spi->block_size - 1)))); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/* Wait up to 10 ms for buffered write completion */ 66562306a36Sopenharmony_cistatic int 66662306a36Sopenharmony_cifalcon_spi_wait_write(struct ef4_nic *efx, const struct falcon_spi_device *spi) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); 66962306a36Sopenharmony_ci u8 status; 67062306a36Sopenharmony_ci int rc; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci for (;;) { 67362306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, 67462306a36Sopenharmony_ci &status, sizeof(status)); 67562306a36Sopenharmony_ci if (rc) 67662306a36Sopenharmony_ci return rc; 67762306a36Sopenharmony_ci if (!(status & SPI_STATUS_NRDY)) 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci if (time_after_eq(jiffies, timeout)) { 68062306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 68162306a36Sopenharmony_ci "SPI write timeout on device %d" 68262306a36Sopenharmony_ci " last status=0x%02x\n", 68362306a36Sopenharmony_ci spi->device_id, status); 68462306a36Sopenharmony_ci return -ETIMEDOUT; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int 69162306a36Sopenharmony_cifalcon_spi_write(struct ef4_nic *efx, const struct falcon_spi_device *spi, 69262306a36Sopenharmony_ci loff_t start, size_t len, size_t *retlen, const u8 *buffer) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci u8 verify_buffer[FALCON_SPI_MAX_LEN]; 69562306a36Sopenharmony_ci size_t block_len, pos = 0; 69662306a36Sopenharmony_ci unsigned int command; 69762306a36Sopenharmony_ci int rc = 0; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci while (pos < len) { 70062306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); 70162306a36Sopenharmony_ci if (rc) 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci block_len = min(len - pos, 70562306a36Sopenharmony_ci falcon_spi_write_limit(spi, start + pos)); 70662306a36Sopenharmony_ci command = falcon_spi_munge_command(spi, SPI_WRITE, start + pos); 70762306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, command, start + pos, 70862306a36Sopenharmony_ci buffer + pos, NULL, block_len); 70962306a36Sopenharmony_ci if (rc) 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci rc = falcon_spi_wait_write(efx, spi); 71362306a36Sopenharmony_ci if (rc) 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci command = falcon_spi_munge_command(spi, SPI_READ, start + pos); 71762306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, command, start + pos, 71862306a36Sopenharmony_ci NULL, verify_buffer, block_len); 71962306a36Sopenharmony_ci if (memcmp(verify_buffer, buffer + pos, block_len)) { 72062306a36Sopenharmony_ci rc = -EIO; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci pos += block_len; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Avoid locking up the system */ 72762306a36Sopenharmony_ci cond_resched(); 72862306a36Sopenharmony_ci if (signal_pending(current)) { 72962306a36Sopenharmony_ci rc = -EINTR; 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (retlen) 73562306a36Sopenharmony_ci *retlen = pos; 73662306a36Sopenharmony_ci return rc; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int 74062306a36Sopenharmony_cifalcon_spi_slow_wait(struct falcon_mtd_partition *part, bool uninterruptible) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci const struct falcon_spi_device *spi = part->spi; 74362306a36Sopenharmony_ci struct ef4_nic *efx = part->common.mtd.priv; 74462306a36Sopenharmony_ci u8 status; 74562306a36Sopenharmony_ci int rc, i; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* Wait up to 4s for flash/EEPROM to finish a slow operation. */ 74862306a36Sopenharmony_ci for (i = 0; i < 40; i++) { 74962306a36Sopenharmony_ci __set_current_state(uninterruptible ? 75062306a36Sopenharmony_ci TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); 75162306a36Sopenharmony_ci schedule_timeout(HZ / 10); 75262306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, 75362306a36Sopenharmony_ci &status, sizeof(status)); 75462306a36Sopenharmony_ci if (rc) 75562306a36Sopenharmony_ci return rc; 75662306a36Sopenharmony_ci if (!(status & SPI_STATUS_NRDY)) 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci if (signal_pending(current)) 75962306a36Sopenharmony_ci return -EINTR; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci pr_err("%s: timed out waiting for %s\n", 76262306a36Sopenharmony_ci part->common.name, part->common.dev_type_name); 76362306a36Sopenharmony_ci return -ETIMEDOUT; 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic int 76762306a36Sopenharmony_cifalcon_spi_unlock(struct ef4_nic *efx, const struct falcon_spi_device *spi) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | 77062306a36Sopenharmony_ci SPI_STATUS_BP0); 77162306a36Sopenharmony_ci u8 status; 77262306a36Sopenharmony_ci int rc; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, 77562306a36Sopenharmony_ci &status, sizeof(status)); 77662306a36Sopenharmony_ci if (rc) 77762306a36Sopenharmony_ci return rc; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!(status & unlock_mask)) 78062306a36Sopenharmony_ci return 0; /* already unlocked */ 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); 78362306a36Sopenharmony_ci if (rc) 78462306a36Sopenharmony_ci return rc; 78562306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); 78662306a36Sopenharmony_ci if (rc) 78762306a36Sopenharmony_ci return rc; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci status &= ~unlock_mask; 79062306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, 79162306a36Sopenharmony_ci NULL, sizeof(status)); 79262306a36Sopenharmony_ci if (rc) 79362306a36Sopenharmony_ci return rc; 79462306a36Sopenharmony_ci rc = falcon_spi_wait_write(efx, spi); 79562306a36Sopenharmony_ci if (rc) 79662306a36Sopenharmony_ci return rc; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci#define FALCON_SPI_VERIFY_BUF_LEN 16 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int 80462306a36Sopenharmony_cifalcon_spi_erase(struct falcon_mtd_partition *part, loff_t start, size_t len) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci const struct falcon_spi_device *spi = part->spi; 80762306a36Sopenharmony_ci struct ef4_nic *efx = part->common.mtd.priv; 80862306a36Sopenharmony_ci unsigned pos, block_len; 80962306a36Sopenharmony_ci u8 empty[FALCON_SPI_VERIFY_BUF_LEN]; 81062306a36Sopenharmony_ci u8 buffer[FALCON_SPI_VERIFY_BUF_LEN]; 81162306a36Sopenharmony_ci int rc; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (len != spi->erase_size) 81462306a36Sopenharmony_ci return -EINVAL; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (spi->erase_command == 0) 81762306a36Sopenharmony_ci return -EOPNOTSUPP; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci rc = falcon_spi_unlock(efx, spi); 82062306a36Sopenharmony_ci if (rc) 82162306a36Sopenharmony_ci return rc; 82262306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); 82362306a36Sopenharmony_ci if (rc) 82462306a36Sopenharmony_ci return rc; 82562306a36Sopenharmony_ci rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, 82662306a36Sopenharmony_ci NULL, 0); 82762306a36Sopenharmony_ci if (rc) 82862306a36Sopenharmony_ci return rc; 82962306a36Sopenharmony_ci rc = falcon_spi_slow_wait(part, false); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Verify the entire region has been wiped */ 83262306a36Sopenharmony_ci memset(empty, 0xff, sizeof(empty)); 83362306a36Sopenharmony_ci for (pos = 0; pos < len; pos += block_len) { 83462306a36Sopenharmony_ci block_len = min(len - pos, sizeof(buffer)); 83562306a36Sopenharmony_ci rc = falcon_spi_read(efx, spi, start + pos, block_len, 83662306a36Sopenharmony_ci NULL, buffer); 83762306a36Sopenharmony_ci if (rc) 83862306a36Sopenharmony_ci return rc; 83962306a36Sopenharmony_ci if (memcmp(empty, buffer, block_len)) 84062306a36Sopenharmony_ci return -EIO; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* Avoid locking up the system */ 84362306a36Sopenharmony_ci cond_resched(); 84462306a36Sopenharmony_ci if (signal_pending(current)) 84562306a36Sopenharmony_ci return -EINTR; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci return rc; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void falcon_mtd_rename(struct ef4_mtd_partition *part) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct ef4_nic *efx = part->mtd.priv; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci snprintf(part->name, sizeof(part->name), "%s %s", 85662306a36Sopenharmony_ci efx->name, part->type_name); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic int falcon_mtd_read(struct mtd_info *mtd, loff_t start, 86062306a36Sopenharmony_ci size_t len, size_t *retlen, u8 *buffer) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd); 86362306a36Sopenharmony_ci struct ef4_nic *efx = mtd->priv; 86462306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 86562306a36Sopenharmony_ci int rc; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci rc = mutex_lock_interruptible(&nic_data->spi_lock); 86862306a36Sopenharmony_ci if (rc) 86962306a36Sopenharmony_ci return rc; 87062306a36Sopenharmony_ci rc = falcon_spi_read(efx, part->spi, part->offset + start, 87162306a36Sopenharmony_ci len, retlen, buffer); 87262306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 87362306a36Sopenharmony_ci return rc; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd); 87962306a36Sopenharmony_ci struct ef4_nic *efx = mtd->priv; 88062306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 88162306a36Sopenharmony_ci int rc; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci rc = mutex_lock_interruptible(&nic_data->spi_lock); 88462306a36Sopenharmony_ci if (rc) 88562306a36Sopenharmony_ci return rc; 88662306a36Sopenharmony_ci rc = falcon_spi_erase(part, part->offset + start, len); 88762306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 88862306a36Sopenharmony_ci return rc; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int falcon_mtd_write(struct mtd_info *mtd, loff_t start, 89262306a36Sopenharmony_ci size_t len, size_t *retlen, const u8 *buffer) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd); 89562306a36Sopenharmony_ci struct ef4_nic *efx = mtd->priv; 89662306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 89762306a36Sopenharmony_ci int rc; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci rc = mutex_lock_interruptible(&nic_data->spi_lock); 90062306a36Sopenharmony_ci if (rc) 90162306a36Sopenharmony_ci return rc; 90262306a36Sopenharmony_ci rc = falcon_spi_write(efx, part->spi, part->offset + start, 90362306a36Sopenharmony_ci len, retlen, buffer); 90462306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 90562306a36Sopenharmony_ci return rc; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic int falcon_mtd_sync(struct mtd_info *mtd) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd); 91162306a36Sopenharmony_ci struct ef4_nic *efx = mtd->priv; 91262306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 91362306a36Sopenharmony_ci int rc; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci mutex_lock(&nic_data->spi_lock); 91662306a36Sopenharmony_ci rc = falcon_spi_slow_wait(part, true); 91762306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 91862306a36Sopenharmony_ci return rc; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic int falcon_mtd_probe(struct ef4_nic *efx) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 92462306a36Sopenharmony_ci struct falcon_mtd_partition *parts; 92562306a36Sopenharmony_ci struct falcon_spi_device *spi; 92662306a36Sopenharmony_ci size_t n_parts; 92762306a36Sopenharmony_ci int rc = -ENODEV; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci ASSERT_RTNL(); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* Allocate space for maximum number of partitions */ 93262306a36Sopenharmony_ci parts = kcalloc(2, sizeof(*parts), GFP_KERNEL); 93362306a36Sopenharmony_ci if (!parts) 93462306a36Sopenharmony_ci return -ENOMEM; 93562306a36Sopenharmony_ci n_parts = 0; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci spi = &nic_data->spi_flash; 93862306a36Sopenharmony_ci if (falcon_spi_present(spi) && spi->size > FALCON_FLASH_BOOTCODE_START) { 93962306a36Sopenharmony_ci parts[n_parts].spi = spi; 94062306a36Sopenharmony_ci parts[n_parts].offset = FALCON_FLASH_BOOTCODE_START; 94162306a36Sopenharmony_ci parts[n_parts].common.dev_type_name = "flash"; 94262306a36Sopenharmony_ci parts[n_parts].common.type_name = "sfc_flash_bootrom"; 94362306a36Sopenharmony_ci parts[n_parts].common.mtd.type = MTD_NORFLASH; 94462306a36Sopenharmony_ci parts[n_parts].common.mtd.flags = MTD_CAP_NORFLASH; 94562306a36Sopenharmony_ci parts[n_parts].common.mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; 94662306a36Sopenharmony_ci parts[n_parts].common.mtd.erasesize = spi->erase_size; 94762306a36Sopenharmony_ci n_parts++; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci spi = &nic_data->spi_eeprom; 95162306a36Sopenharmony_ci if (falcon_spi_present(spi) && spi->size > FALCON_EEPROM_BOOTCONFIG_START) { 95262306a36Sopenharmony_ci parts[n_parts].spi = spi; 95362306a36Sopenharmony_ci parts[n_parts].offset = FALCON_EEPROM_BOOTCONFIG_START; 95462306a36Sopenharmony_ci parts[n_parts].common.dev_type_name = "EEPROM"; 95562306a36Sopenharmony_ci parts[n_parts].common.type_name = "sfc_bootconfig"; 95662306a36Sopenharmony_ci parts[n_parts].common.mtd.type = MTD_RAM; 95762306a36Sopenharmony_ci parts[n_parts].common.mtd.flags = MTD_CAP_RAM; 95862306a36Sopenharmony_ci parts[n_parts].common.mtd.size = 95962306a36Sopenharmony_ci min(spi->size, FALCON_EEPROM_BOOTCONFIG_END) - 96062306a36Sopenharmony_ci FALCON_EEPROM_BOOTCONFIG_START; 96162306a36Sopenharmony_ci parts[n_parts].common.mtd.erasesize = spi->erase_size; 96262306a36Sopenharmony_ci n_parts++; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci rc = ef4_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts)); 96662306a36Sopenharmony_ci if (rc) 96762306a36Sopenharmony_ci kfree(parts); 96862306a36Sopenharmony_ci return rc; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci#endif /* CONFIG_SFC_FALCON_MTD */ 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/************************************************************************** 97462306a36Sopenharmony_ci * 97562306a36Sopenharmony_ci * XMAC operations 97662306a36Sopenharmony_ci * 97762306a36Sopenharmony_ci ************************************************************************** 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci/* Configure the XAUI driver that is an output from Falcon */ 98162306a36Sopenharmony_cistatic void falcon_setup_xaui(struct ef4_nic *efx) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci ef4_oword_t sdctl, txdrv; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Move the XAUI into low power, unless there is no PHY, in 98662306a36Sopenharmony_ci * which case the XAUI will have to drive a cable. */ 98762306a36Sopenharmony_ci if (efx->phy_type == PHY_TYPE_NONE) 98862306a36Sopenharmony_ci return; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci ef4_reado(efx, &sdctl, FR_AB_XX_SD_CTL); 99162306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF); 99262306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF); 99362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF); 99462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF); 99562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF); 99662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF); 99762306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF); 99862306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF); 99962306a36Sopenharmony_ci ef4_writeo(efx, &sdctl, FR_AB_XX_SD_CTL); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci EF4_POPULATE_OWORD_8(txdrv, 100262306a36Sopenharmony_ci FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF, 100362306a36Sopenharmony_ci FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF, 100462306a36Sopenharmony_ci FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF, 100562306a36Sopenharmony_ci FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF, 100662306a36Sopenharmony_ci FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF, 100762306a36Sopenharmony_ci FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF, 100862306a36Sopenharmony_ci FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF, 100962306a36Sopenharmony_ci FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF); 101062306a36Sopenharmony_ci ef4_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ciint falcon_reset_xaui(struct ef4_nic *efx) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 101662306a36Sopenharmony_ci ef4_oword_t reg; 101762306a36Sopenharmony_ci int count; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Don't fetch MAC statistics over an XMAC reset */ 102062306a36Sopenharmony_ci WARN_ON(nic_data->stats_disable_count == 0); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Start reset sequence */ 102362306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); 102462306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XX_PWR_RST); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Wait up to 10 ms for completion, then reinitialise */ 102762306a36Sopenharmony_ci for (count = 0; count < 1000; count++) { 102862306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_PWR_RST); 102962306a36Sopenharmony_ci if (EF4_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 && 103062306a36Sopenharmony_ci EF4_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) { 103162306a36Sopenharmony_ci falcon_setup_xaui(efx); 103262306a36Sopenharmony_ci return 0; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci udelay(10); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 103762306a36Sopenharmony_ci "timed out waiting for XAUI/XGXS reset\n"); 103862306a36Sopenharmony_ci return -ETIMEDOUT; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic void falcon_ack_status_intr(struct ef4_nic *efx) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 104462306a36Sopenharmony_ci ef4_oword_t reg; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if ((ef4_nic_rev(efx) != EF4_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) 104762306a36Sopenharmony_ci return; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* We expect xgmii faults if the wireside link is down */ 105062306a36Sopenharmony_ci if (!efx->link_state.up) 105162306a36Sopenharmony_ci return; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* We can only use this interrupt to signal the negative edge of 105462306a36Sopenharmony_ci * xaui_align [we have to poll the positive edge]. */ 105562306a36Sopenharmony_ci if (nic_data->xmac_poll_required) 105662306a36Sopenharmony_ci return; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic bool falcon_xgxs_link_ok(struct ef4_nic *efx) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci ef4_oword_t reg; 106462306a36Sopenharmony_ci bool align_done, link_ok = false; 106562306a36Sopenharmony_ci int sync_status; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* Read link status */ 106862306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_CORE_STAT); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci align_done = EF4_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE); 107162306a36Sopenharmony_ci sync_status = EF4_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT); 107262306a36Sopenharmony_ci if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES)) 107362306a36Sopenharmony_ci link_ok = true; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Clear link status ready for next read */ 107662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES); 107762306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES); 107862306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); 107962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XX_CORE_STAT); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci return link_ok; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic bool falcon_xmac_link_ok(struct ef4_nic *efx) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci /* 108762306a36Sopenharmony_ci * Check MAC's XGXS link status except when using XGMII loopback 108862306a36Sopenharmony_ci * which bypasses the XGXS block. 108962306a36Sopenharmony_ci * If possible, check PHY's XGXS link status except when using 109062306a36Sopenharmony_ci * MAC loopback. 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_ci return (efx->loopback_mode == LOOPBACK_XGMII || 109362306a36Sopenharmony_ci falcon_xgxs_link_ok(efx)) && 109462306a36Sopenharmony_ci (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) || 109562306a36Sopenharmony_ci LOOPBACK_INTERNAL(efx) || 109662306a36Sopenharmony_ci ef4_mdio_phyxgxs_lane_sync(efx)); 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic void falcon_reconfigure_xmac_core(struct ef4_nic *efx) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci unsigned int max_frame_len; 110262306a36Sopenharmony_ci ef4_oword_t reg; 110362306a36Sopenharmony_ci bool rx_fc = !!(efx->link_state.fc & EF4_FC_RX); 110462306a36Sopenharmony_ci bool tx_fc = !!(efx->link_state.fc & EF4_FC_TX); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Configure MAC - cut-thru mode is hard wired on */ 110762306a36Sopenharmony_ci EF4_POPULATE_OWORD_3(reg, 110862306a36Sopenharmony_ci FRF_AB_XM_RX_JUMBO_MODE, 1, 110962306a36Sopenharmony_ci FRF_AB_XM_TX_STAT_EN, 1, 111062306a36Sopenharmony_ci FRF_AB_XM_RX_STAT_EN, 1); 111162306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_GLB_CFG); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* Configure TX */ 111462306a36Sopenharmony_ci EF4_POPULATE_OWORD_6(reg, 111562306a36Sopenharmony_ci FRF_AB_XM_TXEN, 1, 111662306a36Sopenharmony_ci FRF_AB_XM_TX_PRMBL, 1, 111762306a36Sopenharmony_ci FRF_AB_XM_AUTO_PAD, 1, 111862306a36Sopenharmony_ci FRF_AB_XM_TXCRC, 1, 111962306a36Sopenharmony_ci FRF_AB_XM_FCNTL, tx_fc, 112062306a36Sopenharmony_ci FRF_AB_XM_IPG, 0x3); 112162306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_TX_CFG); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* Configure RX */ 112462306a36Sopenharmony_ci EF4_POPULATE_OWORD_5(reg, 112562306a36Sopenharmony_ci FRF_AB_XM_RXEN, 1, 112662306a36Sopenharmony_ci FRF_AB_XM_AUTO_DEPAD, 0, 112762306a36Sopenharmony_ci FRF_AB_XM_ACPT_ALL_MCAST, 1, 112862306a36Sopenharmony_ci FRF_AB_XM_ACPT_ALL_UCAST, !efx->unicast_filter, 112962306a36Sopenharmony_ci FRF_AB_XM_PASS_CRC_ERR, 1); 113062306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_RX_CFG); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* Set frame length */ 113362306a36Sopenharmony_ci max_frame_len = EF4_MAX_FRAME_LEN(efx->net_dev->mtu); 113462306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); 113562306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_RX_PARAM); 113662306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 113762306a36Sopenharmony_ci FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len, 113862306a36Sopenharmony_ci FRF_AB_XM_TX_JUMBO_MODE, 1); 113962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_TX_PARAM); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 114262306a36Sopenharmony_ci FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ 114362306a36Sopenharmony_ci FRF_AB_XM_DIS_FCNTL, !rx_fc); 114462306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_FC); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* Set MAC address */ 114762306a36Sopenharmony_ci memcpy(®, &efx->net_dev->dev_addr[0], 4); 114862306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_ADR_LO); 114962306a36Sopenharmony_ci memcpy(®, &efx->net_dev->dev_addr[4], 2); 115062306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_ADR_HI); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void falcon_reconfigure_xgxs_core(struct ef4_nic *efx) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci ef4_oword_t reg; 115662306a36Sopenharmony_ci bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS); 115762306a36Sopenharmony_ci bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI); 115862306a36Sopenharmony_ci bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII); 115962306a36Sopenharmony_ci bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* XGXS block is flaky and will need to be reset if moving 116262306a36Sopenharmony_ci * into our out of XGMII, XGXS or XAUI loopbacks. */ 116362306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_CORE_STAT); 116462306a36Sopenharmony_ci old_xgxs_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN); 116562306a36Sopenharmony_ci old_xgmii_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_SD_CTL); 116862306a36Sopenharmony_ci old_xaui_loopback = EF4_OWORD_FIELD(reg, FRF_AB_XX_LPBKA); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* The PHY driver may have turned XAUI off */ 117162306a36Sopenharmony_ci if ((xgxs_loopback != old_xgxs_loopback) || 117262306a36Sopenharmony_ci (xaui_loopback != old_xaui_loopback) || 117362306a36Sopenharmony_ci (xgmii_loopback != old_xgmii_loopback)) 117462306a36Sopenharmony_ci falcon_reset_xaui(efx); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_CORE_STAT); 117762306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG, 117862306a36Sopenharmony_ci (xgxs_loopback || xaui_loopback) ? 117962306a36Sopenharmony_ci FFE_AB_XX_FORCE_SIG_ALL_LANES : 0); 118062306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback); 118162306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback); 118262306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XX_CORE_STAT); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XX_SD_CTL); 118562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback); 118662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback); 118762306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback); 118862306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback); 118962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XX_SD_CTL); 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ 119462306a36Sopenharmony_cistatic bool falcon_xmac_link_ok_retry(struct ef4_nic *efx, int tries) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci bool mac_up = falcon_xmac_link_ok(efx); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || 119962306a36Sopenharmony_ci ef4_phy_mode_disabled(efx->phy_mode)) 120062306a36Sopenharmony_ci /* XAUI link is expected to be down */ 120162306a36Sopenharmony_ci return mac_up; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci falcon_stop_nic_stats(efx); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci while (!mac_up && tries) { 120662306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, "bashing xaui\n"); 120762306a36Sopenharmony_ci falcon_reset_xaui(efx); 120862306a36Sopenharmony_ci udelay(200); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci mac_up = falcon_xmac_link_ok(efx); 121162306a36Sopenharmony_ci --tries; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci falcon_start_nic_stats(efx); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci return mac_up; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic bool falcon_xmac_check_fault(struct ef4_nic *efx) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci return !falcon_xmac_link_ok_retry(efx, 5); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic int falcon_reconfigure_xmac(struct ef4_nic *efx) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci ef4_farch_filter_sync_rx_mode(efx); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci falcon_reconfigure_xgxs_core(efx); 123162306a36Sopenharmony_ci falcon_reconfigure_xmac_core(efx); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci falcon_reconfigure_mac_wrapper(efx); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5); 123662306a36Sopenharmony_ci falcon_ack_status_intr(efx); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci return 0; 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_cistatic void falcon_poll_xmac(struct ef4_nic *efx) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* We expect xgmii faults if the wireside link is down */ 124662306a36Sopenharmony_ci if (!efx->link_state.up || !nic_data->xmac_poll_required) 124762306a36Sopenharmony_ci return; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); 125062306a36Sopenharmony_ci falcon_ack_status_intr(efx); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci/************************************************************************** 125462306a36Sopenharmony_ci * 125562306a36Sopenharmony_ci * MAC wrapper 125662306a36Sopenharmony_ci * 125762306a36Sopenharmony_ci ************************************************************************** 125862306a36Sopenharmony_ci */ 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic void falcon_push_multicast_hash(struct ef4_nic *efx) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci union ef4_multicast_hash *mc_hash = &efx->multicast_hash; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ef4_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); 126762306a36Sopenharmony_ci ef4_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic void falcon_reset_macs(struct ef4_nic *efx) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 127362306a36Sopenharmony_ci ef4_oword_t reg, mac_ctrl; 127462306a36Sopenharmony_ci int count; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (ef4_nic_rev(efx) < EF4_REV_FALCON_B0) { 127762306a36Sopenharmony_ci /* It's not safe to use GLB_CTL_REG to reset the 127862306a36Sopenharmony_ci * macs, so instead use the internal MAC resets 127962306a36Sopenharmony_ci */ 128062306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); 128162306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_XM_GLB_CFG); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci for (count = 0; count < 10000; count++) { 128462306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_XM_GLB_CFG); 128562306a36Sopenharmony_ci if (EF4_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == 128662306a36Sopenharmony_ci 0) 128762306a36Sopenharmony_ci return; 128862306a36Sopenharmony_ci udelay(10); 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 129262306a36Sopenharmony_ci "timed out waiting for XMAC core reset\n"); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* Mac stats will fail whist the TX fifo is draining */ 129662306a36Sopenharmony_ci WARN_ON(nic_data->stats_disable_count == 0); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci ef4_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); 129962306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); 130062306a36Sopenharmony_ci ef4_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GLB_CTL); 130362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); 130462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1); 130562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1); 130662306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_GLB_CTL); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci count = 0; 130962306a36Sopenharmony_ci while (1) { 131062306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_GLB_CTL); 131162306a36Sopenharmony_ci if (!EF4_OWORD_FIELD(reg, FRF_AB_RST_XGTX) && 131262306a36Sopenharmony_ci !EF4_OWORD_FIELD(reg, FRF_AB_RST_XGRX) && 131362306a36Sopenharmony_ci !EF4_OWORD_FIELD(reg, FRF_AB_RST_EM)) { 131462306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 131562306a36Sopenharmony_ci "Completed MAC reset after %d loops\n", 131662306a36Sopenharmony_ci count); 131762306a36Sopenharmony_ci break; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci if (count > 20) { 132062306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "MAC reset failed\n"); 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci count++; 132462306a36Sopenharmony_ci udelay(10); 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* Ensure the correct MAC is selected before statistics 132862306a36Sopenharmony_ci * are re-enabled by the caller */ 132962306a36Sopenharmony_ci ef4_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci falcon_setup_xaui(efx); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic void falcon_drain_tx_fifo(struct ef4_nic *efx) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci ef4_oword_t reg; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if ((ef4_nic_rev(efx) < EF4_REV_FALCON_B0) || 133962306a36Sopenharmony_ci (efx->loopback_mode != LOOPBACK_NONE)) 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_MAC_CTRL); 134362306a36Sopenharmony_ci /* There is no point in draining more than once */ 134462306a36Sopenharmony_ci if (EF4_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN)) 134562306a36Sopenharmony_ci return; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci falcon_reset_macs(efx); 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic void falcon_deconfigure_mac_wrapper(struct ef4_nic *efx) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci ef4_oword_t reg; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (ef4_nic_rev(efx) < EF4_REV_FALCON_B0) 135562306a36Sopenharmony_ci return; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Isolate the MAC -> RX */ 135862306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AZ_RX_CFG); 135962306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); 136062306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AZ_RX_CFG); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* Isolate TX -> MAC */ 136362306a36Sopenharmony_ci falcon_drain_tx_fifo(efx); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic void falcon_reconfigure_mac_wrapper(struct ef4_nic *efx) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct ef4_link_state *link_state = &efx->link_state; 136962306a36Sopenharmony_ci ef4_oword_t reg; 137062306a36Sopenharmony_ci int link_speed, isolate; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci isolate = !!READ_ONCE(efx->reset_pending); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci switch (link_state->speed) { 137562306a36Sopenharmony_ci case 10000: link_speed = 3; break; 137662306a36Sopenharmony_ci case 1000: link_speed = 2; break; 137762306a36Sopenharmony_ci case 100: link_speed = 1; break; 137862306a36Sopenharmony_ci default: link_speed = 0; break; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* MAC_LINK_STATUS controls MAC backpressure but doesn't work 138262306a36Sopenharmony_ci * as advertised. Disable to ensure packets are not 138362306a36Sopenharmony_ci * indefinitely held and TX queue can be flushed at any point 138462306a36Sopenharmony_ci * while the link is down. */ 138562306a36Sopenharmony_ci EF4_POPULATE_OWORD_5(reg, 138662306a36Sopenharmony_ci FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */, 138762306a36Sopenharmony_ci FRF_AB_MAC_BCAD_ACPT, 1, 138862306a36Sopenharmony_ci FRF_AB_MAC_UC_PROM, !efx->unicast_filter, 138962306a36Sopenharmony_ci FRF_AB_MAC_LINK_STATUS, 1, /* always set */ 139062306a36Sopenharmony_ci FRF_AB_MAC_SPEED, link_speed); 139162306a36Sopenharmony_ci /* On B0, MAC backpressure can be disabled and packets get 139262306a36Sopenharmony_ci * discarded. */ 139362306a36Sopenharmony_ci if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) { 139462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 139562306a36Sopenharmony_ci !link_state->up || isolate); 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MAC_CTRL); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* Restore the multicast hash registers. */ 140162306a36Sopenharmony_ci falcon_push_multicast_hash(efx); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AZ_RX_CFG); 140462306a36Sopenharmony_ci /* Enable XOFF signal from RX FIFO (we enabled it during NIC 140562306a36Sopenharmony_ci * initialisation but it may read back as 0) */ 140662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); 140762306a36Sopenharmony_ci /* Unisolate the MAC -> RX */ 140862306a36Sopenharmony_ci if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) 140962306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate); 141062306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AZ_RX_CFG); 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic void falcon_stats_request(struct ef4_nic *efx) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 141662306a36Sopenharmony_ci ef4_oword_t reg; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci WARN_ON(nic_data->stats_pending); 141962306a36Sopenharmony_ci WARN_ON(nic_data->stats_disable_count); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci FALCON_XMAC_STATS_DMA_FLAG(efx) = 0; 142262306a36Sopenharmony_ci nic_data->stats_pending = true; 142362306a36Sopenharmony_ci wmb(); /* ensure done flag is clear */ 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* Initiate DMA transfer of stats */ 142662306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 142762306a36Sopenharmony_ci FRF_AB_MAC_STAT_DMA_CMD, 1, 142862306a36Sopenharmony_ci FRF_AB_MAC_STAT_DMA_ADR, 142962306a36Sopenharmony_ci efx->stats_buffer.dma_addr); 143062306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MAC_STAT_DMA); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic void falcon_stats_complete(struct ef4_nic *efx) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!nic_data->stats_pending) 144062306a36Sopenharmony_ci return; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci nic_data->stats_pending = false; 144362306a36Sopenharmony_ci if (FALCON_XMAC_STATS_DMA_FLAG(efx)) { 144462306a36Sopenharmony_ci rmb(); /* read the done flag before the stats */ 144562306a36Sopenharmony_ci ef4_nic_update_stats(falcon_stat_desc, FALCON_STAT_COUNT, 144662306a36Sopenharmony_ci falcon_stat_mask, nic_data->stats, 144762306a36Sopenharmony_ci efx->stats_buffer.addr, true); 144862306a36Sopenharmony_ci } else { 144962306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 145062306a36Sopenharmony_ci "timed out waiting for statistics\n"); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_cistatic void falcon_stats_timer_func(struct timer_list *t) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct falcon_nic_data *nic_data = from_timer(nic_data, t, 145762306a36Sopenharmony_ci stats_timer); 145862306a36Sopenharmony_ci struct ef4_nic *efx = nic_data->efx; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci spin_lock(&efx->stats_lock); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci falcon_stats_complete(efx); 146362306a36Sopenharmony_ci if (nic_data->stats_disable_count == 0) 146462306a36Sopenharmony_ci falcon_stats_request(efx); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci spin_unlock(&efx->stats_lock); 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistatic bool falcon_loopback_link_poll(struct ef4_nic *efx) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci struct ef4_link_state old_state = efx->link_state; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 147462306a36Sopenharmony_ci WARN_ON(!LOOPBACK_INTERNAL(efx)); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci efx->link_state.fd = true; 147762306a36Sopenharmony_ci efx->link_state.fc = efx->wanted_fc; 147862306a36Sopenharmony_ci efx->link_state.up = true; 147962306a36Sopenharmony_ci efx->link_state.speed = 10000; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci return !ef4_link_state_equal(&efx->link_state, &old_state); 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_cistatic int falcon_reconfigure_port(struct ef4_nic *efx) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci int rc; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci WARN_ON(ef4_nic_rev(efx) > EF4_REV_FALCON_B0); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* Poll the PHY link state *before* reconfiguring it. This means we 149162306a36Sopenharmony_ci * will pick up the correct speed (in loopback) to select the correct 149262306a36Sopenharmony_ci * MAC. 149362306a36Sopenharmony_ci */ 149462306a36Sopenharmony_ci if (LOOPBACK_INTERNAL(efx)) 149562306a36Sopenharmony_ci falcon_loopback_link_poll(efx); 149662306a36Sopenharmony_ci else 149762306a36Sopenharmony_ci efx->phy_op->poll(efx); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci falcon_stop_nic_stats(efx); 150062306a36Sopenharmony_ci falcon_deconfigure_mac_wrapper(efx); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci falcon_reset_macs(efx); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci efx->phy_op->reconfigure(efx); 150562306a36Sopenharmony_ci rc = falcon_reconfigure_xmac(efx); 150662306a36Sopenharmony_ci BUG_ON(rc); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci falcon_start_nic_stats(efx); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* Synchronise efx->link_state with the kernel */ 151162306a36Sopenharmony_ci ef4_link_status_changed(efx); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci/* TX flow control may automatically turn itself off if the link 151762306a36Sopenharmony_ci * partner (intermittently) stops responding to pause frames. There 151862306a36Sopenharmony_ci * isn't any indication that this has happened, so the best we do is 151962306a36Sopenharmony_ci * leave it up to the user to spot this and fix it by cycling transmit 152062306a36Sopenharmony_ci * flow control on this end. 152162306a36Sopenharmony_ci */ 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic void falcon_a1_prepare_enable_fc_tx(struct ef4_nic *efx) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci /* Schedule a reset to recover */ 152662306a36Sopenharmony_ci ef4_schedule_reset(efx, RESET_TYPE_INVISIBLE); 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic void falcon_b0_prepare_enable_fc_tx(struct ef4_nic *efx) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci /* Recover by resetting the EM block */ 153262306a36Sopenharmony_ci falcon_stop_nic_stats(efx); 153362306a36Sopenharmony_ci falcon_drain_tx_fifo(efx); 153462306a36Sopenharmony_ci falcon_reconfigure_xmac(efx); 153562306a36Sopenharmony_ci falcon_start_nic_stats(efx); 153662306a36Sopenharmony_ci} 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci/************************************************************************** 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * PHY access via GMII 154162306a36Sopenharmony_ci * 154262306a36Sopenharmony_ci ************************************************************************** 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci/* Wait for GMII access to complete */ 154662306a36Sopenharmony_cistatic int falcon_gmii_wait(struct ef4_nic *efx) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci ef4_oword_t md_stat; 154962306a36Sopenharmony_ci int count; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* wait up to 50ms - taken max from datasheet */ 155262306a36Sopenharmony_ci for (count = 0; count < 5000; count++) { 155362306a36Sopenharmony_ci ef4_reado(efx, &md_stat, FR_AB_MD_STAT); 155462306a36Sopenharmony_ci if (EF4_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { 155562306a36Sopenharmony_ci if (EF4_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || 155662306a36Sopenharmony_ci EF4_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { 155762306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 155862306a36Sopenharmony_ci "error from GMII access " 155962306a36Sopenharmony_ci EF4_OWORD_FMT"\n", 156062306a36Sopenharmony_ci EF4_OWORD_VAL(md_stat)); 156162306a36Sopenharmony_ci return -EIO; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci return 0; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci udelay(10); 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "timed out waiting for GMII\n"); 156862306a36Sopenharmony_ci return -ETIMEDOUT; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci/* Write an MDIO register of a PHY connected to Falcon. */ 157262306a36Sopenharmony_cistatic int falcon_mdio_write(struct net_device *net_dev, 157362306a36Sopenharmony_ci int prtad, int devad, u16 addr, u16 value) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 157662306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 157762306a36Sopenharmony_ci ef4_oword_t reg; 157862306a36Sopenharmony_ci int rc; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci netif_vdbg(efx, hw, efx->net_dev, 158162306a36Sopenharmony_ci "writing MDIO %d register %d.%d with 0x%04x\n", 158262306a36Sopenharmony_ci prtad, devad, addr, value); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci mutex_lock(&nic_data->mdio_lock); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci /* Check MDIO not currently being accessed */ 158762306a36Sopenharmony_ci rc = falcon_gmii_wait(efx); 158862306a36Sopenharmony_ci if (rc) 158962306a36Sopenharmony_ci goto out; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* Write the address/ID register */ 159262306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); 159362306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_PHY_ADR); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, 159662306a36Sopenharmony_ci FRF_AB_MD_DEV_ADR, devad); 159762306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_ID); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* Write data */ 160062306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value); 160162306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_TXD); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 160462306a36Sopenharmony_ci FRF_AB_MD_WRC, 1, 160562306a36Sopenharmony_ci FRF_AB_MD_GC, 0); 160662306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_CS); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* Wait for data to be written */ 160962306a36Sopenharmony_ci rc = falcon_gmii_wait(efx); 161062306a36Sopenharmony_ci if (rc) { 161162306a36Sopenharmony_ci /* Abort the write operation */ 161262306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 161362306a36Sopenharmony_ci FRF_AB_MD_WRC, 0, 161462306a36Sopenharmony_ci FRF_AB_MD_GC, 1); 161562306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_CS); 161662306a36Sopenharmony_ci udelay(10); 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ciout: 162062306a36Sopenharmony_ci mutex_unlock(&nic_data->mdio_lock); 162162306a36Sopenharmony_ci return rc; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/* Read an MDIO register of a PHY connected to Falcon. */ 162562306a36Sopenharmony_cistatic int falcon_mdio_read(struct net_device *net_dev, 162662306a36Sopenharmony_ci int prtad, int devad, u16 addr) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 162962306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 163062306a36Sopenharmony_ci ef4_oword_t reg; 163162306a36Sopenharmony_ci int rc; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci mutex_lock(&nic_data->mdio_lock); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci /* Check MDIO not currently being accessed */ 163662306a36Sopenharmony_ci rc = falcon_gmii_wait(efx); 163762306a36Sopenharmony_ci if (rc) 163862306a36Sopenharmony_ci goto out; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); 164162306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_PHY_ADR); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, 164462306a36Sopenharmony_ci FRF_AB_MD_DEV_ADR, devad); 164562306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_ID); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* Request data to be read */ 164862306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0); 164962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_CS); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* Wait for data to become available */ 165262306a36Sopenharmony_ci rc = falcon_gmii_wait(efx); 165362306a36Sopenharmony_ci if (rc == 0) { 165462306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AB_MD_RXD); 165562306a36Sopenharmony_ci rc = EF4_OWORD_FIELD(reg, FRF_AB_MD_RXD); 165662306a36Sopenharmony_ci netif_vdbg(efx, hw, efx->net_dev, 165762306a36Sopenharmony_ci "read from MDIO %d register %d.%d, got %04x\n", 165862306a36Sopenharmony_ci prtad, devad, addr, rc); 165962306a36Sopenharmony_ci } else { 166062306a36Sopenharmony_ci /* Abort the read operation */ 166162306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(reg, 166262306a36Sopenharmony_ci FRF_AB_MD_RIC, 0, 166362306a36Sopenharmony_ci FRF_AB_MD_GC, 1); 166462306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AB_MD_CS); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 166762306a36Sopenharmony_ci "read from MDIO %d register %d.%d, got error %d\n", 166862306a36Sopenharmony_ci prtad, devad, addr, rc); 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ciout: 167262306a36Sopenharmony_ci mutex_unlock(&nic_data->mdio_lock); 167362306a36Sopenharmony_ci return rc; 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci/* This call is responsible for hooking in the MAC and PHY operations */ 167762306a36Sopenharmony_cistatic int falcon_probe_port(struct ef4_nic *efx) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 168062306a36Sopenharmony_ci int rc; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci switch (efx->phy_type) { 168362306a36Sopenharmony_ci case PHY_TYPE_SFX7101: 168462306a36Sopenharmony_ci efx->phy_op = &falcon_sfx7101_phy_ops; 168562306a36Sopenharmony_ci break; 168662306a36Sopenharmony_ci case PHY_TYPE_QT2022C2: 168762306a36Sopenharmony_ci case PHY_TYPE_QT2025C: 168862306a36Sopenharmony_ci efx->phy_op = &falcon_qt202x_phy_ops; 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci case PHY_TYPE_TXC43128: 169162306a36Sopenharmony_ci efx->phy_op = &falcon_txc_phy_ops; 169262306a36Sopenharmony_ci break; 169362306a36Sopenharmony_ci default: 169462306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n", 169562306a36Sopenharmony_ci efx->phy_type); 169662306a36Sopenharmony_ci return -ENODEV; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci /* Fill out MDIO structure and loopback modes */ 170062306a36Sopenharmony_ci mutex_init(&nic_data->mdio_lock); 170162306a36Sopenharmony_ci efx->mdio.mdio_read = falcon_mdio_read; 170262306a36Sopenharmony_ci efx->mdio.mdio_write = falcon_mdio_write; 170362306a36Sopenharmony_ci rc = efx->phy_op->probe(efx); 170462306a36Sopenharmony_ci if (rc != 0) 170562306a36Sopenharmony_ci return rc; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* Initial assumption */ 170862306a36Sopenharmony_ci efx->link_state.speed = 10000; 170962306a36Sopenharmony_ci efx->link_state.fd = true; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ 171262306a36Sopenharmony_ci if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) 171362306a36Sopenharmony_ci efx->wanted_fc = EF4_FC_RX | EF4_FC_TX; 171462306a36Sopenharmony_ci else 171562306a36Sopenharmony_ci efx->wanted_fc = EF4_FC_RX; 171662306a36Sopenharmony_ci if (efx->mdio.mmds & MDIO_DEVS_AN) 171762306a36Sopenharmony_ci efx->wanted_fc |= EF4_FC_AUTO; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci /* Allocate buffer for stats */ 172062306a36Sopenharmony_ci rc = ef4_nic_alloc_buffer(efx, &efx->stats_buffer, 172162306a36Sopenharmony_ci FALCON_MAC_STATS_SIZE, GFP_KERNEL); 172262306a36Sopenharmony_ci if (rc) 172362306a36Sopenharmony_ci return rc; 172462306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 172562306a36Sopenharmony_ci "stats buffer at %llx (virt %p phys %llx)\n", 172662306a36Sopenharmony_ci (u64)efx->stats_buffer.dma_addr, 172762306a36Sopenharmony_ci efx->stats_buffer.addr, 172862306a36Sopenharmony_ci (u64)virt_to_phys(efx->stats_buffer.addr)); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci return 0; 173162306a36Sopenharmony_ci} 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_cistatic void falcon_remove_port(struct ef4_nic *efx) 173462306a36Sopenharmony_ci{ 173562306a36Sopenharmony_ci efx->phy_op->remove(efx); 173662306a36Sopenharmony_ci ef4_nic_free_buffer(efx, &efx->stats_buffer); 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci/* Global events are basically PHY events */ 174062306a36Sopenharmony_cistatic bool 174162306a36Sopenharmony_cifalcon_handle_global_event(struct ef4_channel *channel, ef4_qword_t *event) 174262306a36Sopenharmony_ci{ 174362306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 174462306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || 174762306a36Sopenharmony_ci EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || 174862306a36Sopenharmony_ci EF4_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) 174962306a36Sopenharmony_ci /* Ignored */ 175062306a36Sopenharmony_ci return true; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if ((ef4_nic_rev(efx) == EF4_REV_FALCON_B0) && 175362306a36Sopenharmony_ci EF4_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { 175462306a36Sopenharmony_ci nic_data->xmac_poll_required = true; 175562306a36Sopenharmony_ci return true; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1 ? 175962306a36Sopenharmony_ci EF4_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : 176062306a36Sopenharmony_ci EF4_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { 176162306a36Sopenharmony_ci netif_err(efx, rx_err, efx->net_dev, 176262306a36Sopenharmony_ci "channel %d seen global RX_RESET event. Resetting.\n", 176362306a36Sopenharmony_ci channel->channel); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci atomic_inc(&efx->rx_reset); 176662306a36Sopenharmony_ci ef4_schedule_reset(efx, EF4_WORKAROUND_6555(efx) ? 176762306a36Sopenharmony_ci RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); 176862306a36Sopenharmony_ci return true; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci return false; 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci/************************************************************************** 177562306a36Sopenharmony_ci * 177662306a36Sopenharmony_ci * Falcon test code 177762306a36Sopenharmony_ci * 177862306a36Sopenharmony_ci **************************************************************************/ 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_cistatic int 178162306a36Sopenharmony_cifalcon_read_nvram(struct ef4_nic *efx, struct falcon_nvconfig *nvconfig_out) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 178462306a36Sopenharmony_ci struct falcon_nvconfig *nvconfig; 178562306a36Sopenharmony_ci struct falcon_spi_device *spi; 178662306a36Sopenharmony_ci void *region; 178762306a36Sopenharmony_ci int rc, magic_num, struct_ver; 178862306a36Sopenharmony_ci __le16 *word, *limit; 178962306a36Sopenharmony_ci u32 csum; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (falcon_spi_present(&nic_data->spi_flash)) 179262306a36Sopenharmony_ci spi = &nic_data->spi_flash; 179362306a36Sopenharmony_ci else if (falcon_spi_present(&nic_data->spi_eeprom)) 179462306a36Sopenharmony_ci spi = &nic_data->spi_eeprom; 179562306a36Sopenharmony_ci else 179662306a36Sopenharmony_ci return -EINVAL; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); 179962306a36Sopenharmony_ci if (!region) 180062306a36Sopenharmony_ci return -ENOMEM; 180162306a36Sopenharmony_ci nvconfig = region + FALCON_NVCONFIG_OFFSET; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci mutex_lock(&nic_data->spi_lock); 180462306a36Sopenharmony_ci rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); 180562306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 180662306a36Sopenharmony_ci if (rc) { 180762306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "Failed to read %s\n", 180862306a36Sopenharmony_ci falcon_spi_present(&nic_data->spi_flash) ? 180962306a36Sopenharmony_ci "flash" : "EEPROM"); 181062306a36Sopenharmony_ci rc = -EIO; 181162306a36Sopenharmony_ci goto out; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci magic_num = le16_to_cpu(nvconfig->board_magic_num); 181562306a36Sopenharmony_ci struct_ver = le16_to_cpu(nvconfig->board_struct_ver); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci rc = -EINVAL; 181862306a36Sopenharmony_ci if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) { 181962306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 182062306a36Sopenharmony_ci "NVRAM bad magic 0x%x\n", magic_num); 182162306a36Sopenharmony_ci goto out; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci if (struct_ver < 2) { 182462306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 182562306a36Sopenharmony_ci "NVRAM has ancient version 0x%x\n", struct_ver); 182662306a36Sopenharmony_ci goto out; 182762306a36Sopenharmony_ci } else if (struct_ver < 4) { 182862306a36Sopenharmony_ci word = &nvconfig->board_magic_num; 182962306a36Sopenharmony_ci limit = (__le16 *) (nvconfig + 1); 183062306a36Sopenharmony_ci } else { 183162306a36Sopenharmony_ci word = region; 183262306a36Sopenharmony_ci limit = region + FALCON_NVCONFIG_END; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci for (csum = 0; word < limit; ++word) 183562306a36Sopenharmony_ci csum += le16_to_cpu(*word); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if (~csum & 0xffff) { 183862306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 183962306a36Sopenharmony_ci "NVRAM has incorrect checksum\n"); 184062306a36Sopenharmony_ci goto out; 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci rc = 0; 184462306a36Sopenharmony_ci if (nvconfig_out) 184562306a36Sopenharmony_ci memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig)); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci out: 184862306a36Sopenharmony_ci kfree(region); 184962306a36Sopenharmony_ci return rc; 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic int falcon_test_nvram(struct ef4_nic *efx) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci return falcon_read_nvram(efx, NULL); 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_cistatic const struct ef4_farch_register_test falcon_b0_register_tests[] = { 185862306a36Sopenharmony_ci { FR_AZ_ADR_REGION, 185962306a36Sopenharmony_ci EF4_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, 186062306a36Sopenharmony_ci { FR_AZ_RX_CFG, 186162306a36Sopenharmony_ci EF4_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, 186262306a36Sopenharmony_ci { FR_AZ_TX_CFG, 186362306a36Sopenharmony_ci EF4_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, 186462306a36Sopenharmony_ci { FR_AZ_TX_RESERVED, 186562306a36Sopenharmony_ci EF4_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, 186662306a36Sopenharmony_ci { FR_AB_MAC_CTRL, 186762306a36Sopenharmony_ci EF4_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, 186862306a36Sopenharmony_ci { FR_AZ_SRM_TX_DC_CFG, 186962306a36Sopenharmony_ci EF4_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, 187062306a36Sopenharmony_ci { FR_AZ_RX_DC_CFG, 187162306a36Sopenharmony_ci EF4_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, 187262306a36Sopenharmony_ci { FR_AZ_RX_DC_PF_WM, 187362306a36Sopenharmony_ci EF4_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, 187462306a36Sopenharmony_ci { FR_BZ_DP_CTRL, 187562306a36Sopenharmony_ci EF4_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, 187662306a36Sopenharmony_ci { FR_AB_GM_CFG2, 187762306a36Sopenharmony_ci EF4_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, 187862306a36Sopenharmony_ci { FR_AB_GMF_CFG0, 187962306a36Sopenharmony_ci EF4_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, 188062306a36Sopenharmony_ci { FR_AB_XM_GLB_CFG, 188162306a36Sopenharmony_ci EF4_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, 188262306a36Sopenharmony_ci { FR_AB_XM_TX_CFG, 188362306a36Sopenharmony_ci EF4_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, 188462306a36Sopenharmony_ci { FR_AB_XM_RX_CFG, 188562306a36Sopenharmony_ci EF4_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, 188662306a36Sopenharmony_ci { FR_AB_XM_RX_PARAM, 188762306a36Sopenharmony_ci EF4_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, 188862306a36Sopenharmony_ci { FR_AB_XM_FC, 188962306a36Sopenharmony_ci EF4_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, 189062306a36Sopenharmony_ci { FR_AB_XM_ADR_LO, 189162306a36Sopenharmony_ci EF4_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, 189262306a36Sopenharmony_ci { FR_AB_XX_SD_CTL, 189362306a36Sopenharmony_ci EF4_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, 189462306a36Sopenharmony_ci}; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_cistatic int 189762306a36Sopenharmony_cifalcon_b0_test_chip(struct ef4_nic *efx, struct ef4_self_tests *tests) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci enum reset_type reset_method = RESET_TYPE_INVISIBLE; 190062306a36Sopenharmony_ci int rc, rc2; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 190362306a36Sopenharmony_ci if (efx->loopback_modes) { 190462306a36Sopenharmony_ci /* We need the 312 clock from the PHY to test the XMAC 190562306a36Sopenharmony_ci * registers, so move into XGMII loopback if available */ 190662306a36Sopenharmony_ci if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) 190762306a36Sopenharmony_ci efx->loopback_mode = LOOPBACK_XGMII; 190862306a36Sopenharmony_ci else 190962306a36Sopenharmony_ci efx->loopback_mode = __ffs(efx->loopback_modes); 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci __ef4_reconfigure_port(efx); 191262306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci ef4_reset_down(efx, reset_method); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci tests->registers = 191762306a36Sopenharmony_ci ef4_farch_test_registers(efx, falcon_b0_register_tests, 191862306a36Sopenharmony_ci ARRAY_SIZE(falcon_b0_register_tests)) 191962306a36Sopenharmony_ci ? -1 : 1; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci rc = falcon_reset_hw(efx, reset_method); 192262306a36Sopenharmony_ci rc2 = ef4_reset_up(efx, reset_method, rc == 0); 192362306a36Sopenharmony_ci return rc ? rc : rc2; 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci/************************************************************************** 192762306a36Sopenharmony_ci * 192862306a36Sopenharmony_ci * Device reset 192962306a36Sopenharmony_ci * 193062306a36Sopenharmony_ci ************************************************************************** 193162306a36Sopenharmony_ci */ 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_cistatic enum reset_type falcon_map_reset_reason(enum reset_type reason) 193462306a36Sopenharmony_ci{ 193562306a36Sopenharmony_ci switch (reason) { 193662306a36Sopenharmony_ci case RESET_TYPE_RX_RECOVERY: 193762306a36Sopenharmony_ci case RESET_TYPE_DMA_ERROR: 193862306a36Sopenharmony_ci case RESET_TYPE_TX_SKIP: 193962306a36Sopenharmony_ci /* These can occasionally occur due to hardware bugs. 194062306a36Sopenharmony_ci * We try to reset without disrupting the link. 194162306a36Sopenharmony_ci */ 194262306a36Sopenharmony_ci return RESET_TYPE_INVISIBLE; 194362306a36Sopenharmony_ci default: 194462306a36Sopenharmony_ci return RESET_TYPE_ALL; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci} 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_cistatic int falcon_map_reset_flags(u32 *flags) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci enum { 195162306a36Sopenharmony_ci FALCON_RESET_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | 195262306a36Sopenharmony_ci ETH_RESET_OFFLOAD | ETH_RESET_MAC), 195362306a36Sopenharmony_ci FALCON_RESET_ALL = FALCON_RESET_INVISIBLE | ETH_RESET_PHY, 195462306a36Sopenharmony_ci FALCON_RESET_WORLD = FALCON_RESET_ALL | ETH_RESET_IRQ, 195562306a36Sopenharmony_ci }; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci if ((*flags & FALCON_RESET_WORLD) == FALCON_RESET_WORLD) { 195862306a36Sopenharmony_ci *flags &= ~FALCON_RESET_WORLD; 195962306a36Sopenharmony_ci return RESET_TYPE_WORLD; 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci if ((*flags & FALCON_RESET_ALL) == FALCON_RESET_ALL) { 196362306a36Sopenharmony_ci *flags &= ~FALCON_RESET_ALL; 196462306a36Sopenharmony_ci return RESET_TYPE_ALL; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if ((*flags & FALCON_RESET_INVISIBLE) == FALCON_RESET_INVISIBLE) { 196862306a36Sopenharmony_ci *flags &= ~FALCON_RESET_INVISIBLE; 196962306a36Sopenharmony_ci return RESET_TYPE_INVISIBLE; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci return -EINVAL; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci/* Resets NIC to known state. This routine must be called in process 197662306a36Sopenharmony_ci * context and is allowed to sleep. */ 197762306a36Sopenharmony_cistatic int __falcon_reset_hw(struct ef4_nic *efx, enum reset_type method) 197862306a36Sopenharmony_ci{ 197962306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 198062306a36Sopenharmony_ci ef4_oword_t glb_ctl_reg_ker; 198162306a36Sopenharmony_ci int rc; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, "performing %s hardware reset\n", 198462306a36Sopenharmony_ci RESET_TYPE(method)); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* Initiate device reset */ 198762306a36Sopenharmony_ci if (method == RESET_TYPE_WORLD) { 198862306a36Sopenharmony_ci rc = pci_save_state(efx->pci_dev); 198962306a36Sopenharmony_ci if (rc) { 199062306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 199162306a36Sopenharmony_ci "failed to backup PCI state of primary " 199262306a36Sopenharmony_ci "function prior to hardware reset\n"); 199362306a36Sopenharmony_ci goto fail1; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci if (ef4_nic_is_dual_func(efx)) { 199662306a36Sopenharmony_ci rc = pci_save_state(nic_data->pci_dev2); 199762306a36Sopenharmony_ci if (rc) { 199862306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 199962306a36Sopenharmony_ci "failed to backup PCI state of " 200062306a36Sopenharmony_ci "secondary function prior to " 200162306a36Sopenharmony_ci "hardware reset\n"); 200262306a36Sopenharmony_ci goto fail2; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(glb_ctl_reg_ker, 200762306a36Sopenharmony_ci FRF_AB_EXT_PHY_RST_DUR, 200862306a36Sopenharmony_ci FFE_AB_EXT_PHY_RST_DUR_10240US, 200962306a36Sopenharmony_ci FRF_AB_SWRST, 1); 201062306a36Sopenharmony_ci } else { 201162306a36Sopenharmony_ci EF4_POPULATE_OWORD_7(glb_ctl_reg_ker, 201262306a36Sopenharmony_ci /* exclude PHY from "invisible" reset */ 201362306a36Sopenharmony_ci FRF_AB_EXT_PHY_RST_CTL, 201462306a36Sopenharmony_ci method == RESET_TYPE_INVISIBLE, 201562306a36Sopenharmony_ci /* exclude EEPROM/flash and PCIe */ 201662306a36Sopenharmony_ci FRF_AB_PCIE_CORE_RST_CTL, 1, 201762306a36Sopenharmony_ci FRF_AB_PCIE_NSTKY_RST_CTL, 1, 201862306a36Sopenharmony_ci FRF_AB_PCIE_SD_RST_CTL, 1, 201962306a36Sopenharmony_ci FRF_AB_EE_RST_CTL, 1, 202062306a36Sopenharmony_ci FRF_AB_EXT_PHY_RST_DUR, 202162306a36Sopenharmony_ci FFE_AB_EXT_PHY_RST_DUR_10240US, 202262306a36Sopenharmony_ci FRF_AB_SWRST, 1); 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci ef4_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, "waiting for hardware reset\n"); 202762306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 20); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci /* Restore PCI configuration if needed */ 203062306a36Sopenharmony_ci if (method == RESET_TYPE_WORLD) { 203162306a36Sopenharmony_ci if (ef4_nic_is_dual_func(efx)) 203262306a36Sopenharmony_ci pci_restore_state(nic_data->pci_dev2); 203362306a36Sopenharmony_ci pci_restore_state(efx->pci_dev); 203462306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 203562306a36Sopenharmony_ci "successfully restored PCI config\n"); 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci /* Assert that reset complete */ 203962306a36Sopenharmony_ci ef4_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); 204062306a36Sopenharmony_ci if (EF4_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) { 204162306a36Sopenharmony_ci rc = -ETIMEDOUT; 204262306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 204362306a36Sopenharmony_ci "timed out waiting for hardware reset\n"); 204462306a36Sopenharmony_ci goto fail3; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n"); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci return 0; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci /* pci_save_state() and pci_restore_state() MUST be called in pairs */ 205162306a36Sopenharmony_cifail2: 205262306a36Sopenharmony_ci pci_restore_state(efx->pci_dev); 205362306a36Sopenharmony_cifail1: 205462306a36Sopenharmony_cifail3: 205562306a36Sopenharmony_ci return rc; 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cistatic int falcon_reset_hw(struct ef4_nic *efx, enum reset_type method) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 206162306a36Sopenharmony_ci int rc; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci mutex_lock(&nic_data->spi_lock); 206462306a36Sopenharmony_ci rc = __falcon_reset_hw(efx, method); 206562306a36Sopenharmony_ci mutex_unlock(&nic_data->spi_lock); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci return rc; 206862306a36Sopenharmony_ci} 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_cistatic void falcon_monitor(struct ef4_nic *efx) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci bool link_changed; 207362306a36Sopenharmony_ci int rc; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci BUG_ON(!mutex_is_locked(&efx->mac_lock)); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci rc = falcon_board(efx)->type->monitor(efx); 207862306a36Sopenharmony_ci if (rc) { 207962306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 208062306a36Sopenharmony_ci "Board sensor %s; shutting down PHY\n", 208162306a36Sopenharmony_ci (rc == -ERANGE) ? "reported fault" : "failed"); 208262306a36Sopenharmony_ci efx->phy_mode |= PHY_MODE_LOW_POWER; 208362306a36Sopenharmony_ci rc = __ef4_reconfigure_port(efx); 208462306a36Sopenharmony_ci WARN_ON(rc); 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (LOOPBACK_INTERNAL(efx)) 208862306a36Sopenharmony_ci link_changed = falcon_loopback_link_poll(efx); 208962306a36Sopenharmony_ci else 209062306a36Sopenharmony_ci link_changed = efx->phy_op->poll(efx); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci if (link_changed) { 209362306a36Sopenharmony_ci falcon_stop_nic_stats(efx); 209462306a36Sopenharmony_ci falcon_deconfigure_mac_wrapper(efx); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci falcon_reset_macs(efx); 209762306a36Sopenharmony_ci rc = falcon_reconfigure_xmac(efx); 209862306a36Sopenharmony_ci BUG_ON(rc); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci falcon_start_nic_stats(efx); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci ef4_link_status_changed(efx); 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci falcon_poll_xmac(efx); 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci/* Zeroes out the SRAM contents. This routine must be called in 210962306a36Sopenharmony_ci * process context and is allowed to sleep. 211062306a36Sopenharmony_ci */ 211162306a36Sopenharmony_cistatic int falcon_reset_sram(struct ef4_nic *efx) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci ef4_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker; 211462306a36Sopenharmony_ci int count; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* Set the SRAM wake/sleep GPIO appropriately. */ 211762306a36Sopenharmony_ci ef4_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); 211862306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1); 211962306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1); 212062306a36Sopenharmony_ci ef4_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci /* Initiate SRAM reset */ 212362306a36Sopenharmony_ci EF4_POPULATE_OWORD_2(srm_cfg_reg_ker, 212462306a36Sopenharmony_ci FRF_AZ_SRM_INIT_EN, 1, 212562306a36Sopenharmony_ci FRF_AZ_SRM_NB_SZ, 0); 212662306a36Sopenharmony_ci ef4_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci /* Wait for SRAM reset to complete */ 212962306a36Sopenharmony_ci count = 0; 213062306a36Sopenharmony_ci do { 213162306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 213262306a36Sopenharmony_ci "waiting for SRAM reset (attempt %d)...\n", count); 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci /* SRAM reset is slow; expect around 16ms */ 213562306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 50); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* Check for reset complete */ 213862306a36Sopenharmony_ci ef4_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); 213962306a36Sopenharmony_ci if (!EF4_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) { 214062306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 214162306a36Sopenharmony_ci "SRAM reset complete\n"); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci return 0; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci } while (++count < 20); /* wait up to 0.4 sec */ 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n"); 214862306a36Sopenharmony_ci return -ETIMEDOUT; 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic void falcon_spi_device_init(struct ef4_nic *efx, 215262306a36Sopenharmony_ci struct falcon_spi_device *spi_device, 215362306a36Sopenharmony_ci unsigned int device_id, u32 device_type) 215462306a36Sopenharmony_ci{ 215562306a36Sopenharmony_ci if (device_type != 0) { 215662306a36Sopenharmony_ci spi_device->device_id = device_id; 215762306a36Sopenharmony_ci spi_device->size = 215862306a36Sopenharmony_ci 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE); 215962306a36Sopenharmony_ci spi_device->addr_len = 216062306a36Sopenharmony_ci SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN); 216162306a36Sopenharmony_ci spi_device->munge_address = (spi_device->size == 1 << 9 && 216262306a36Sopenharmony_ci spi_device->addr_len == 1); 216362306a36Sopenharmony_ci spi_device->erase_command = 216462306a36Sopenharmony_ci SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD); 216562306a36Sopenharmony_ci spi_device->erase_size = 216662306a36Sopenharmony_ci 1 << SPI_DEV_TYPE_FIELD(device_type, 216762306a36Sopenharmony_ci SPI_DEV_TYPE_ERASE_SIZE); 216862306a36Sopenharmony_ci spi_device->block_size = 216962306a36Sopenharmony_ci 1 << SPI_DEV_TYPE_FIELD(device_type, 217062306a36Sopenharmony_ci SPI_DEV_TYPE_BLOCK_SIZE); 217162306a36Sopenharmony_ci } else { 217262306a36Sopenharmony_ci spi_device->size = 0; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci} 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci/* Extract non-volatile configuration */ 217762306a36Sopenharmony_cistatic int falcon_probe_nvconfig(struct ef4_nic *efx) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 218062306a36Sopenharmony_ci struct falcon_nvconfig *nvconfig; 218162306a36Sopenharmony_ci int rc; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); 218462306a36Sopenharmony_ci if (!nvconfig) 218562306a36Sopenharmony_ci return -ENOMEM; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci rc = falcon_read_nvram(efx, nvconfig); 218862306a36Sopenharmony_ci if (rc) 218962306a36Sopenharmony_ci goto out; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci efx->phy_type = nvconfig->board_v2.port0_phy_type; 219262306a36Sopenharmony_ci efx->mdio.prtad = nvconfig->board_v2.port0_phy_addr; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { 219562306a36Sopenharmony_ci falcon_spi_device_init( 219662306a36Sopenharmony_ci efx, &nic_data->spi_flash, FFE_AB_SPI_DEVICE_FLASH, 219762306a36Sopenharmony_ci le32_to_cpu(nvconfig->board_v3 219862306a36Sopenharmony_ci .spi_device_type[FFE_AB_SPI_DEVICE_FLASH])); 219962306a36Sopenharmony_ci falcon_spi_device_init( 220062306a36Sopenharmony_ci efx, &nic_data->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM, 220162306a36Sopenharmony_ci le32_to_cpu(nvconfig->board_v3 220262306a36Sopenharmony_ci .spi_device_type[FFE_AB_SPI_DEVICE_EEPROM])); 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci /* Read the MAC addresses */ 220662306a36Sopenharmony_ci ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n", 220962306a36Sopenharmony_ci efx->phy_type, efx->mdio.prtad); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci rc = falcon_probe_board(efx, 221262306a36Sopenharmony_ci le16_to_cpu(nvconfig->board_v2.board_revision)); 221362306a36Sopenharmony_ciout: 221462306a36Sopenharmony_ci kfree(nvconfig); 221562306a36Sopenharmony_ci return rc; 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_cistatic int falcon_dimension_resources(struct ef4_nic *efx) 221962306a36Sopenharmony_ci{ 222062306a36Sopenharmony_ci efx->rx_dc_base = 0x20000; 222162306a36Sopenharmony_ci efx->tx_dc_base = 0x26000; 222262306a36Sopenharmony_ci return 0; 222362306a36Sopenharmony_ci} 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci/* Probe all SPI devices on the NIC */ 222662306a36Sopenharmony_cistatic void falcon_probe_spi_devices(struct ef4_nic *efx) 222762306a36Sopenharmony_ci{ 222862306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 222962306a36Sopenharmony_ci ef4_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; 223062306a36Sopenharmony_ci int boot_dev; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci ef4_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL); 223362306a36Sopenharmony_ci ef4_reado(efx, &nic_stat, FR_AB_NIC_STAT); 223462306a36Sopenharmony_ci ef4_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (EF4_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) { 223762306a36Sopenharmony_ci boot_dev = (EF4_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ? 223862306a36Sopenharmony_ci FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM); 223962306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "Booted from %s\n", 224062306a36Sopenharmony_ci boot_dev == FFE_AB_SPI_DEVICE_FLASH ? 224162306a36Sopenharmony_ci "flash" : "EEPROM"); 224262306a36Sopenharmony_ci } else { 224362306a36Sopenharmony_ci /* Disable VPD and set clock dividers to safe 224462306a36Sopenharmony_ci * values for initial programming. */ 224562306a36Sopenharmony_ci boot_dev = -1; 224662306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 224762306a36Sopenharmony_ci "Booted from internal ASIC settings;" 224862306a36Sopenharmony_ci " setting SPI config\n"); 224962306a36Sopenharmony_ci EF4_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0, 225062306a36Sopenharmony_ci /* 125 MHz / 7 ~= 20 MHz */ 225162306a36Sopenharmony_ci FRF_AB_EE_SF_CLOCK_DIV, 7, 225262306a36Sopenharmony_ci /* 125 MHz / 63 ~= 2 MHz */ 225362306a36Sopenharmony_ci FRF_AB_EE_EE_CLOCK_DIV, 63); 225462306a36Sopenharmony_ci ef4_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci mutex_init(&nic_data->spi_lock); 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci if (boot_dev == FFE_AB_SPI_DEVICE_FLASH) 226062306a36Sopenharmony_ci falcon_spi_device_init(efx, &nic_data->spi_flash, 226162306a36Sopenharmony_ci FFE_AB_SPI_DEVICE_FLASH, 226262306a36Sopenharmony_ci default_flash_type); 226362306a36Sopenharmony_ci if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM) 226462306a36Sopenharmony_ci falcon_spi_device_init(efx, &nic_data->spi_eeprom, 226562306a36Sopenharmony_ci FFE_AB_SPI_DEVICE_EEPROM, 226662306a36Sopenharmony_ci large_eeprom_type); 226762306a36Sopenharmony_ci} 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_cistatic unsigned int falcon_a1_mem_map_size(struct ef4_nic *efx) 227062306a36Sopenharmony_ci{ 227162306a36Sopenharmony_ci return 0x20000; 227262306a36Sopenharmony_ci} 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_cistatic unsigned int falcon_b0_mem_map_size(struct ef4_nic *efx) 227562306a36Sopenharmony_ci{ 227662306a36Sopenharmony_ci /* Map everything up to and including the RSS indirection table. 227762306a36Sopenharmony_ci * The PCI core takes care of mapping the MSI-X tables. 227862306a36Sopenharmony_ci */ 227962306a36Sopenharmony_ci return FR_BZ_RX_INDIRECTION_TBL + 228062306a36Sopenharmony_ci FR_BZ_RX_INDIRECTION_TBL_STEP * FR_BZ_RX_INDIRECTION_TBL_ROWS; 228162306a36Sopenharmony_ci} 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_cistatic int falcon_probe_nic(struct ef4_nic *efx) 228462306a36Sopenharmony_ci{ 228562306a36Sopenharmony_ci struct falcon_nic_data *nic_data; 228662306a36Sopenharmony_ci struct falcon_board *board; 228762306a36Sopenharmony_ci int rc; 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci efx->primary = efx; /* only one usable function per controller */ 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* Allocate storage for hardware specific data */ 229262306a36Sopenharmony_ci nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); 229362306a36Sopenharmony_ci if (!nic_data) 229462306a36Sopenharmony_ci return -ENOMEM; 229562306a36Sopenharmony_ci efx->nic_data = nic_data; 229662306a36Sopenharmony_ci nic_data->efx = efx; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci rc = -ENODEV; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (ef4_farch_fpga_ver(efx) != 0) { 230162306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 230262306a36Sopenharmony_ci "Falcon FPGA not supported\n"); 230362306a36Sopenharmony_ci goto fail1; 230462306a36Sopenharmony_ci } 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1) { 230762306a36Sopenharmony_ci ef4_oword_t nic_stat; 230862306a36Sopenharmony_ci struct pci_dev *dev; 230962306a36Sopenharmony_ci u8 pci_rev = efx->pci_dev->revision; 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci if ((pci_rev == 0xff) || (pci_rev == 0)) { 231262306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 231362306a36Sopenharmony_ci "Falcon rev A0 not supported\n"); 231462306a36Sopenharmony_ci goto fail1; 231562306a36Sopenharmony_ci } 231662306a36Sopenharmony_ci ef4_reado(efx, &nic_stat, FR_AB_NIC_STAT); 231762306a36Sopenharmony_ci if (EF4_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { 231862306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 231962306a36Sopenharmony_ci "Falcon rev A1 1G not supported\n"); 232062306a36Sopenharmony_ci goto fail1; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci if (EF4_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { 232362306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 232462306a36Sopenharmony_ci "Falcon rev A1 PCI-X not supported\n"); 232562306a36Sopenharmony_ci goto fail1; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci dev = pci_dev_get(efx->pci_dev); 232962306a36Sopenharmony_ci while ((dev = pci_get_device(PCI_VENDOR_ID_SOLARFLARE, 233062306a36Sopenharmony_ci PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1, 233162306a36Sopenharmony_ci dev))) { 233262306a36Sopenharmony_ci if (dev->bus == efx->pci_dev->bus && 233362306a36Sopenharmony_ci dev->devfn == efx->pci_dev->devfn + 1) { 233462306a36Sopenharmony_ci nic_data->pci_dev2 = dev; 233562306a36Sopenharmony_ci break; 233662306a36Sopenharmony_ci } 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci if (!nic_data->pci_dev2) { 233962306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 234062306a36Sopenharmony_ci "failed to find secondary function\n"); 234162306a36Sopenharmony_ci rc = -ENODEV; 234262306a36Sopenharmony_ci goto fail2; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci } 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci /* Now we can reset the NIC */ 234762306a36Sopenharmony_ci rc = __falcon_reset_hw(efx, RESET_TYPE_ALL); 234862306a36Sopenharmony_ci if (rc) { 234962306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n"); 235062306a36Sopenharmony_ci goto fail3; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci /* Allocate memory for INT_KER */ 235462306a36Sopenharmony_ci rc = ef4_nic_alloc_buffer(efx, &efx->irq_status, sizeof(ef4_oword_t), 235562306a36Sopenharmony_ci GFP_KERNEL); 235662306a36Sopenharmony_ci if (rc) 235762306a36Sopenharmony_ci goto fail4; 235862306a36Sopenharmony_ci BUG_ON(efx->irq_status.dma_addr & 0x0f); 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 236162306a36Sopenharmony_ci "INT_KER at %llx (virt %p phys %llx)\n", 236262306a36Sopenharmony_ci (u64)efx->irq_status.dma_addr, 236362306a36Sopenharmony_ci efx->irq_status.addr, 236462306a36Sopenharmony_ci (u64)virt_to_phys(efx->irq_status.addr)); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci falcon_probe_spi_devices(efx); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci /* Read in the non-volatile configuration */ 236962306a36Sopenharmony_ci rc = falcon_probe_nvconfig(efx); 237062306a36Sopenharmony_ci if (rc) { 237162306a36Sopenharmony_ci if (rc == -EINVAL) 237262306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "NVRAM is invalid\n"); 237362306a36Sopenharmony_ci goto fail5; 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci efx->max_channels = (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1 ? 4 : 237762306a36Sopenharmony_ci EF4_MAX_CHANNELS); 237862306a36Sopenharmony_ci efx->max_tx_channels = efx->max_channels; 237962306a36Sopenharmony_ci efx->timer_quantum_ns = 4968; /* 621 cycles */ 238062306a36Sopenharmony_ci efx->timer_max_ns = efx->type->timer_period_max * 238162306a36Sopenharmony_ci efx->timer_quantum_ns; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci /* Initialise I2C adapter */ 238462306a36Sopenharmony_ci board = falcon_board(efx); 238562306a36Sopenharmony_ci board->i2c_adap.owner = THIS_MODULE; 238662306a36Sopenharmony_ci board->i2c_data = falcon_i2c_bit_operations; 238762306a36Sopenharmony_ci board->i2c_data.data = efx; 238862306a36Sopenharmony_ci board->i2c_adap.algo_data = &board->i2c_data; 238962306a36Sopenharmony_ci board->i2c_adap.dev.parent = &efx->pci_dev->dev; 239062306a36Sopenharmony_ci strscpy(board->i2c_adap.name, "SFC4000 GPIO", 239162306a36Sopenharmony_ci sizeof(board->i2c_adap.name)); 239262306a36Sopenharmony_ci rc = i2c_bit_add_bus(&board->i2c_adap); 239362306a36Sopenharmony_ci if (rc) 239462306a36Sopenharmony_ci goto fail5; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci rc = falcon_board(efx)->type->init(efx); 239762306a36Sopenharmony_ci if (rc) { 239862306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 239962306a36Sopenharmony_ci "failed to initialise board\n"); 240062306a36Sopenharmony_ci goto fail6; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci nic_data->stats_disable_count = 1; 240462306a36Sopenharmony_ci timer_setup(&nic_data->stats_timer, falcon_stats_timer_func, 0); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci return 0; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci fail6: 240962306a36Sopenharmony_ci i2c_del_adapter(&board->i2c_adap); 241062306a36Sopenharmony_ci memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); 241162306a36Sopenharmony_ci fail5: 241262306a36Sopenharmony_ci ef4_nic_free_buffer(efx, &efx->irq_status); 241362306a36Sopenharmony_ci fail4: 241462306a36Sopenharmony_ci fail3: 241562306a36Sopenharmony_ci if (nic_data->pci_dev2) { 241662306a36Sopenharmony_ci pci_dev_put(nic_data->pci_dev2); 241762306a36Sopenharmony_ci nic_data->pci_dev2 = NULL; 241862306a36Sopenharmony_ci } 241962306a36Sopenharmony_ci fail2: 242062306a36Sopenharmony_ci fail1: 242162306a36Sopenharmony_ci kfree(efx->nic_data); 242262306a36Sopenharmony_ci return rc; 242362306a36Sopenharmony_ci} 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_cistatic void falcon_init_rx_cfg(struct ef4_nic *efx) 242662306a36Sopenharmony_ci{ 242762306a36Sopenharmony_ci /* RX control FIFO thresholds (32 entries) */ 242862306a36Sopenharmony_ci const unsigned ctrl_xon_thr = 20; 242962306a36Sopenharmony_ci const unsigned ctrl_xoff_thr = 25; 243062306a36Sopenharmony_ci ef4_oword_t reg; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci ef4_reado(efx, ®, FR_AZ_RX_CFG); 243362306a36Sopenharmony_ci if (ef4_nic_rev(efx) <= EF4_REV_FALCON_A1) { 243462306a36Sopenharmony_ci /* Data FIFO size is 5.5K. The RX DMA engine only 243562306a36Sopenharmony_ci * supports scattering for user-mode queues, but will 243662306a36Sopenharmony_ci * split DMA writes at intervals of RX_USR_BUF_SIZE 243762306a36Sopenharmony_ci * (32-byte units) even for kernel-mode queues. We 243862306a36Sopenharmony_ci * set it to be so large that that never happens. 243962306a36Sopenharmony_ci */ 244062306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0); 244162306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE, 244262306a36Sopenharmony_ci (3 * 4096) >> 5); 244362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8); 244462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8); 244562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr); 244662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr); 244762306a36Sopenharmony_ci } else { 244862306a36Sopenharmony_ci /* Data FIFO size is 80K; register fields moved */ 244962306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0); 245062306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE, 245162306a36Sopenharmony_ci EF4_RX_USR_BUF_SIZE >> 5); 245262306a36Sopenharmony_ci /* Send XON and XOFF at ~3 * max MTU away from empty/full */ 245362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8); 245462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8); 245562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr); 245662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); 245762306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci /* Enable hash insertion. This is broken for the 246062306a36Sopenharmony_ci * 'Falcon' hash so also select Toeplitz TCP/IPv4 and 246162306a36Sopenharmony_ci * IPv4 hashes. */ 246262306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_INSRT_HDR, 1); 246362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_ALG, 1); 246462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_BZ_RX_IP_HASH, 1); 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci /* Always enable XOFF signal from RX FIFO. We enable 246762306a36Sopenharmony_ci * or disable transmission of pause frames at the MAC. */ 246862306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); 246962306a36Sopenharmony_ci ef4_writeo(efx, ®, FR_AZ_RX_CFG); 247062306a36Sopenharmony_ci} 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci/* This call performs hardware-specific global initialisation, such as 247362306a36Sopenharmony_ci * defining the descriptor cache sizes and number of RSS channels. 247462306a36Sopenharmony_ci * It does not set up any buffers, descriptor rings or event queues. 247562306a36Sopenharmony_ci */ 247662306a36Sopenharmony_cistatic int falcon_init_nic(struct ef4_nic *efx) 247762306a36Sopenharmony_ci{ 247862306a36Sopenharmony_ci ef4_oword_t temp; 247962306a36Sopenharmony_ci int rc; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci /* Use on-chip SRAM */ 248262306a36Sopenharmony_ci ef4_reado(efx, &temp, FR_AB_NIC_STAT); 248362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); 248462306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_AB_NIC_STAT); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci rc = falcon_reset_sram(efx); 248762306a36Sopenharmony_ci if (rc) 248862306a36Sopenharmony_ci return rc; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci /* Clear the parity enables on the TX data fifos as 249162306a36Sopenharmony_ci * they produce false parity errors because of timing issues 249262306a36Sopenharmony_ci */ 249362306a36Sopenharmony_ci if (EF4_WORKAROUND_5129(efx)) { 249462306a36Sopenharmony_ci ef4_reado(efx, &temp, FR_AZ_CSR_SPARE); 249562306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); 249662306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_AZ_CSR_SPARE); 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci if (EF4_WORKAROUND_7244(efx)) { 250062306a36Sopenharmony_ci ef4_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); 250162306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); 250262306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8); 250362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8); 250462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8); 250562306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci /* XXX This is documented only for Falcon A0/A1 */ 250962306a36Sopenharmony_ci /* Setup RX. Wait for descriptor is broken and must 251062306a36Sopenharmony_ci * be disabled. RXDP recovery shouldn't be needed, but is. 251162306a36Sopenharmony_ci */ 251262306a36Sopenharmony_ci ef4_reado(efx, &temp, FR_AA_RX_SELF_RST); 251362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1); 251462306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1); 251562306a36Sopenharmony_ci if (EF4_WORKAROUND_5583(efx)) 251662306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); 251762306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_AA_RX_SELF_RST); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 252062306a36Sopenharmony_ci * descriptors (which is bad). 252162306a36Sopenharmony_ci */ 252262306a36Sopenharmony_ci ef4_reado(efx, &temp, FR_AZ_TX_CFG); 252362306a36Sopenharmony_ci EF4_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); 252462306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_AZ_TX_CFG); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci falcon_init_rx_cfg(efx); 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci if (ef4_nic_rev(efx) >= EF4_REV_FALCON_B0) { 252962306a36Sopenharmony_ci falcon_b0_rx_push_rss_config(efx, false, efx->rx_indir_table); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci /* Set destination of both TX and RX Flush events */ 253262306a36Sopenharmony_ci EF4_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); 253362306a36Sopenharmony_ci ef4_writeo(efx, &temp, FR_BZ_DP_CTRL); 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci ef4_farch_init_common(efx); 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci return 0; 253962306a36Sopenharmony_ci} 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_cistatic void falcon_remove_nic(struct ef4_nic *efx) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 254462306a36Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci board->type->fini(efx); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci /* Remove I2C adapter and clear it in preparation for a retry */ 254962306a36Sopenharmony_ci i2c_del_adapter(&board->i2c_adap); 255062306a36Sopenharmony_ci memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci ef4_nic_free_buffer(efx, &efx->irq_status); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci __falcon_reset_hw(efx, RESET_TYPE_ALL); 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci /* Release the second function after the reset */ 255762306a36Sopenharmony_ci if (nic_data->pci_dev2) { 255862306a36Sopenharmony_ci pci_dev_put(nic_data->pci_dev2); 255962306a36Sopenharmony_ci nic_data->pci_dev2 = NULL; 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci /* Tear down the private nic state */ 256362306a36Sopenharmony_ci kfree(efx->nic_data); 256462306a36Sopenharmony_ci efx->nic_data = NULL; 256562306a36Sopenharmony_ci} 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_cistatic size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 *names) 256862306a36Sopenharmony_ci{ 256962306a36Sopenharmony_ci return ef4_nic_describe_stats(falcon_stat_desc, FALCON_STAT_COUNT, 257062306a36Sopenharmony_ci falcon_stat_mask, names); 257162306a36Sopenharmony_ci} 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic size_t falcon_update_nic_stats(struct ef4_nic *efx, u64 *full_stats, 257462306a36Sopenharmony_ci struct rtnl_link_stats64 *core_stats) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 257762306a36Sopenharmony_ci u64 *stats = nic_data->stats; 257862306a36Sopenharmony_ci ef4_oword_t cnt; 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci if (!nic_data->stats_disable_count) { 258162306a36Sopenharmony_ci ef4_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); 258262306a36Sopenharmony_ci stats[FALCON_STAT_rx_nodesc_drop_cnt] += 258362306a36Sopenharmony_ci EF4_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci if (nic_data->stats_pending && 258662306a36Sopenharmony_ci FALCON_XMAC_STATS_DMA_FLAG(efx)) { 258762306a36Sopenharmony_ci nic_data->stats_pending = false; 258862306a36Sopenharmony_ci rmb(); /* read the done flag before the stats */ 258962306a36Sopenharmony_ci ef4_nic_update_stats( 259062306a36Sopenharmony_ci falcon_stat_desc, FALCON_STAT_COUNT, 259162306a36Sopenharmony_ci falcon_stat_mask, 259262306a36Sopenharmony_ci stats, efx->stats_buffer.addr, true); 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci /* Update derived statistic */ 259662306a36Sopenharmony_ci ef4_update_diff_stat(&stats[FALCON_STAT_rx_bad_bytes], 259762306a36Sopenharmony_ci stats[FALCON_STAT_rx_bytes] - 259862306a36Sopenharmony_ci stats[FALCON_STAT_rx_good_bytes] - 259962306a36Sopenharmony_ci stats[FALCON_STAT_rx_control] * 64); 260062306a36Sopenharmony_ci ef4_update_sw_stats(efx, stats); 260162306a36Sopenharmony_ci } 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (full_stats) 260462306a36Sopenharmony_ci memcpy(full_stats, stats, sizeof(u64) * FALCON_STAT_COUNT); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci if (core_stats) { 260762306a36Sopenharmony_ci core_stats->rx_packets = stats[FALCON_STAT_rx_packets]; 260862306a36Sopenharmony_ci core_stats->tx_packets = stats[FALCON_STAT_tx_packets]; 260962306a36Sopenharmony_ci core_stats->rx_bytes = stats[FALCON_STAT_rx_bytes]; 261062306a36Sopenharmony_ci core_stats->tx_bytes = stats[FALCON_STAT_tx_bytes]; 261162306a36Sopenharmony_ci core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt] + 261262306a36Sopenharmony_ci stats[GENERIC_STAT_rx_nodesc_trunc] + 261362306a36Sopenharmony_ci stats[GENERIC_STAT_rx_noskb_drops]; 261462306a36Sopenharmony_ci core_stats->multicast = stats[FALCON_STAT_rx_multicast]; 261562306a36Sopenharmony_ci core_stats->rx_length_errors = 261662306a36Sopenharmony_ci stats[FALCON_STAT_rx_gtjumbo] + 261762306a36Sopenharmony_ci stats[FALCON_STAT_rx_length_error]; 261862306a36Sopenharmony_ci core_stats->rx_crc_errors = stats[FALCON_STAT_rx_bad]; 261962306a36Sopenharmony_ci core_stats->rx_frame_errors = stats[FALCON_STAT_rx_align_error]; 262062306a36Sopenharmony_ci core_stats->rx_fifo_errors = stats[FALCON_STAT_rx_overflow]; 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci core_stats->rx_errors = (core_stats->rx_length_errors + 262362306a36Sopenharmony_ci core_stats->rx_crc_errors + 262462306a36Sopenharmony_ci core_stats->rx_frame_errors + 262562306a36Sopenharmony_ci stats[FALCON_STAT_rx_symbol_error]); 262662306a36Sopenharmony_ci } 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci return FALCON_STAT_COUNT; 262962306a36Sopenharmony_ci} 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_civoid falcon_start_nic_stats(struct ef4_nic *efx) 263262306a36Sopenharmony_ci{ 263362306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 263662306a36Sopenharmony_ci if (--nic_data->stats_disable_count == 0) 263762306a36Sopenharmony_ci falcon_stats_request(efx); 263862306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 263962306a36Sopenharmony_ci} 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci/* We don't acutally pull stats on falcon. Wait 10ms so that 264262306a36Sopenharmony_ci * they arrive when we call this just after start_stats 264362306a36Sopenharmony_ci */ 264462306a36Sopenharmony_cistatic void falcon_pull_nic_stats(struct ef4_nic *efx) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci msleep(10); 264762306a36Sopenharmony_ci} 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_civoid falcon_stop_nic_stats(struct ef4_nic *efx) 265062306a36Sopenharmony_ci{ 265162306a36Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 265262306a36Sopenharmony_ci int i; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci might_sleep(); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 265762306a36Sopenharmony_ci ++nic_data->stats_disable_count; 265862306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci del_timer_sync(&nic_data->stats_timer); 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci /* Wait enough time for the most recent transfer to 266362306a36Sopenharmony_ci * complete. */ 266462306a36Sopenharmony_ci for (i = 0; i < 4 && nic_data->stats_pending; i++) { 266562306a36Sopenharmony_ci if (FALCON_XMAC_STATS_DMA_FLAG(efx)) 266662306a36Sopenharmony_ci break; 266762306a36Sopenharmony_ci msleep(1); 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 267162306a36Sopenharmony_ci falcon_stats_complete(efx); 267262306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 267362306a36Sopenharmony_ci} 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_cistatic void falcon_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) 267662306a36Sopenharmony_ci{ 267762306a36Sopenharmony_ci falcon_board(efx)->type->set_id_led(efx, mode); 267862306a36Sopenharmony_ci} 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci/************************************************************************** 268162306a36Sopenharmony_ci * 268262306a36Sopenharmony_ci * Wake on LAN 268362306a36Sopenharmony_ci * 268462306a36Sopenharmony_ci ************************************************************************** 268562306a36Sopenharmony_ci */ 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_cistatic void falcon_get_wol(struct ef4_nic *efx, struct ethtool_wolinfo *wol) 268862306a36Sopenharmony_ci{ 268962306a36Sopenharmony_ci wol->supported = 0; 269062306a36Sopenharmony_ci wol->wolopts = 0; 269162306a36Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 269262306a36Sopenharmony_ci} 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_cistatic int falcon_set_wol(struct ef4_nic *efx, u32 type) 269562306a36Sopenharmony_ci{ 269662306a36Sopenharmony_ci if (type != 0) 269762306a36Sopenharmony_ci return -EINVAL; 269862306a36Sopenharmony_ci return 0; 269962306a36Sopenharmony_ci} 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci/************************************************************************** 270262306a36Sopenharmony_ci * 270362306a36Sopenharmony_ci * Revision-dependent attributes used by efx.c and nic.c 270462306a36Sopenharmony_ci * 270562306a36Sopenharmony_ci ************************************************************************** 270662306a36Sopenharmony_ci */ 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ciconst struct ef4_nic_type falcon_a1_nic_type = { 270962306a36Sopenharmony_ci .mem_bar = EF4_MEM_BAR, 271062306a36Sopenharmony_ci .mem_map_size = falcon_a1_mem_map_size, 271162306a36Sopenharmony_ci .probe = falcon_probe_nic, 271262306a36Sopenharmony_ci .remove = falcon_remove_nic, 271362306a36Sopenharmony_ci .init = falcon_init_nic, 271462306a36Sopenharmony_ci .dimension_resources = falcon_dimension_resources, 271562306a36Sopenharmony_ci .fini = falcon_irq_ack_a1, 271662306a36Sopenharmony_ci .monitor = falcon_monitor, 271762306a36Sopenharmony_ci .map_reset_reason = falcon_map_reset_reason, 271862306a36Sopenharmony_ci .map_reset_flags = falcon_map_reset_flags, 271962306a36Sopenharmony_ci .reset = falcon_reset_hw, 272062306a36Sopenharmony_ci .probe_port = falcon_probe_port, 272162306a36Sopenharmony_ci .remove_port = falcon_remove_port, 272262306a36Sopenharmony_ci .handle_global_event = falcon_handle_global_event, 272362306a36Sopenharmony_ci .fini_dmaq = ef4_farch_fini_dmaq, 272462306a36Sopenharmony_ci .prepare_flush = falcon_prepare_flush, 272562306a36Sopenharmony_ci .finish_flush = ef4_port_dummy_op_void, 272662306a36Sopenharmony_ci .prepare_flr = ef4_port_dummy_op_void, 272762306a36Sopenharmony_ci .finish_flr = ef4_farch_finish_flr, 272862306a36Sopenharmony_ci .describe_stats = falcon_describe_nic_stats, 272962306a36Sopenharmony_ci .update_stats = falcon_update_nic_stats, 273062306a36Sopenharmony_ci .start_stats = falcon_start_nic_stats, 273162306a36Sopenharmony_ci .pull_stats = falcon_pull_nic_stats, 273262306a36Sopenharmony_ci .stop_stats = falcon_stop_nic_stats, 273362306a36Sopenharmony_ci .set_id_led = falcon_set_id_led, 273462306a36Sopenharmony_ci .push_irq_moderation = falcon_push_irq_moderation, 273562306a36Sopenharmony_ci .reconfigure_port = falcon_reconfigure_port, 273662306a36Sopenharmony_ci .prepare_enable_fc_tx = falcon_a1_prepare_enable_fc_tx, 273762306a36Sopenharmony_ci .reconfigure_mac = falcon_reconfigure_xmac, 273862306a36Sopenharmony_ci .check_mac_fault = falcon_xmac_check_fault, 273962306a36Sopenharmony_ci .get_wol = falcon_get_wol, 274062306a36Sopenharmony_ci .set_wol = falcon_set_wol, 274162306a36Sopenharmony_ci .resume_wol = ef4_port_dummy_op_void, 274262306a36Sopenharmony_ci .test_nvram = falcon_test_nvram, 274362306a36Sopenharmony_ci .irq_enable_master = ef4_farch_irq_enable_master, 274462306a36Sopenharmony_ci .irq_test_generate = ef4_farch_irq_test_generate, 274562306a36Sopenharmony_ci .irq_disable_non_ev = ef4_farch_irq_disable_master, 274662306a36Sopenharmony_ci .irq_handle_msi = ef4_farch_msi_interrupt, 274762306a36Sopenharmony_ci .irq_handle_legacy = falcon_legacy_interrupt_a1, 274862306a36Sopenharmony_ci .tx_probe = ef4_farch_tx_probe, 274962306a36Sopenharmony_ci .tx_init = ef4_farch_tx_init, 275062306a36Sopenharmony_ci .tx_remove = ef4_farch_tx_remove, 275162306a36Sopenharmony_ci .tx_write = ef4_farch_tx_write, 275262306a36Sopenharmony_ci .tx_limit_len = ef4_farch_tx_limit_len, 275362306a36Sopenharmony_ci .rx_push_rss_config = dummy_rx_push_rss_config, 275462306a36Sopenharmony_ci .rx_probe = ef4_farch_rx_probe, 275562306a36Sopenharmony_ci .rx_init = ef4_farch_rx_init, 275662306a36Sopenharmony_ci .rx_remove = ef4_farch_rx_remove, 275762306a36Sopenharmony_ci .rx_write = ef4_farch_rx_write, 275862306a36Sopenharmony_ci .rx_defer_refill = ef4_farch_rx_defer_refill, 275962306a36Sopenharmony_ci .ev_probe = ef4_farch_ev_probe, 276062306a36Sopenharmony_ci .ev_init = ef4_farch_ev_init, 276162306a36Sopenharmony_ci .ev_fini = ef4_farch_ev_fini, 276262306a36Sopenharmony_ci .ev_remove = ef4_farch_ev_remove, 276362306a36Sopenharmony_ci .ev_process = ef4_farch_ev_process, 276462306a36Sopenharmony_ci .ev_read_ack = ef4_farch_ev_read_ack, 276562306a36Sopenharmony_ci .ev_test_generate = ef4_farch_ev_test_generate, 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci /* We don't expose the filter table on Falcon A1 as it is not 276862306a36Sopenharmony_ci * mapped into function 0, but these implementations still 276962306a36Sopenharmony_ci * work with a degenerate case of all tables set to size 0. 277062306a36Sopenharmony_ci */ 277162306a36Sopenharmony_ci .filter_table_probe = ef4_farch_filter_table_probe, 277262306a36Sopenharmony_ci .filter_table_restore = ef4_farch_filter_table_restore, 277362306a36Sopenharmony_ci .filter_table_remove = ef4_farch_filter_table_remove, 277462306a36Sopenharmony_ci .filter_insert = ef4_farch_filter_insert, 277562306a36Sopenharmony_ci .filter_remove_safe = ef4_farch_filter_remove_safe, 277662306a36Sopenharmony_ci .filter_get_safe = ef4_farch_filter_get_safe, 277762306a36Sopenharmony_ci .filter_clear_rx = ef4_farch_filter_clear_rx, 277862306a36Sopenharmony_ci .filter_count_rx_used = ef4_farch_filter_count_rx_used, 277962306a36Sopenharmony_ci .filter_get_rx_id_limit = ef4_farch_filter_get_rx_id_limit, 278062306a36Sopenharmony_ci .filter_get_rx_ids = ef4_farch_filter_get_rx_ids, 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD 278362306a36Sopenharmony_ci .mtd_probe = falcon_mtd_probe, 278462306a36Sopenharmony_ci .mtd_rename = falcon_mtd_rename, 278562306a36Sopenharmony_ci .mtd_read = falcon_mtd_read, 278662306a36Sopenharmony_ci .mtd_erase = falcon_mtd_erase, 278762306a36Sopenharmony_ci .mtd_write = falcon_mtd_write, 278862306a36Sopenharmony_ci .mtd_sync = falcon_mtd_sync, 278962306a36Sopenharmony_ci#endif 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci .revision = EF4_REV_FALCON_A1, 279262306a36Sopenharmony_ci .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, 279362306a36Sopenharmony_ci .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, 279462306a36Sopenharmony_ci .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER, 279562306a36Sopenharmony_ci .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER, 279662306a36Sopenharmony_ci .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER, 279762306a36Sopenharmony_ci .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), 279862306a36Sopenharmony_ci .rx_buffer_padding = 0x24, 279962306a36Sopenharmony_ci .can_rx_scatter = false, 280062306a36Sopenharmony_ci .max_interrupt_mode = EF4_INT_MODE_MSI, 280162306a36Sopenharmony_ci .timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH, 280262306a36Sopenharmony_ci .offload_features = NETIF_F_IP_CSUM, 280362306a36Sopenharmony_ci}; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ciconst struct ef4_nic_type falcon_b0_nic_type = { 280662306a36Sopenharmony_ci .mem_bar = EF4_MEM_BAR, 280762306a36Sopenharmony_ci .mem_map_size = falcon_b0_mem_map_size, 280862306a36Sopenharmony_ci .probe = falcon_probe_nic, 280962306a36Sopenharmony_ci .remove = falcon_remove_nic, 281062306a36Sopenharmony_ci .init = falcon_init_nic, 281162306a36Sopenharmony_ci .dimension_resources = falcon_dimension_resources, 281262306a36Sopenharmony_ci .fini = ef4_port_dummy_op_void, 281362306a36Sopenharmony_ci .monitor = falcon_monitor, 281462306a36Sopenharmony_ci .map_reset_reason = falcon_map_reset_reason, 281562306a36Sopenharmony_ci .map_reset_flags = falcon_map_reset_flags, 281662306a36Sopenharmony_ci .reset = falcon_reset_hw, 281762306a36Sopenharmony_ci .probe_port = falcon_probe_port, 281862306a36Sopenharmony_ci .remove_port = falcon_remove_port, 281962306a36Sopenharmony_ci .handle_global_event = falcon_handle_global_event, 282062306a36Sopenharmony_ci .fini_dmaq = ef4_farch_fini_dmaq, 282162306a36Sopenharmony_ci .prepare_flush = falcon_prepare_flush, 282262306a36Sopenharmony_ci .finish_flush = ef4_port_dummy_op_void, 282362306a36Sopenharmony_ci .prepare_flr = ef4_port_dummy_op_void, 282462306a36Sopenharmony_ci .finish_flr = ef4_farch_finish_flr, 282562306a36Sopenharmony_ci .describe_stats = falcon_describe_nic_stats, 282662306a36Sopenharmony_ci .update_stats = falcon_update_nic_stats, 282762306a36Sopenharmony_ci .start_stats = falcon_start_nic_stats, 282862306a36Sopenharmony_ci .pull_stats = falcon_pull_nic_stats, 282962306a36Sopenharmony_ci .stop_stats = falcon_stop_nic_stats, 283062306a36Sopenharmony_ci .set_id_led = falcon_set_id_led, 283162306a36Sopenharmony_ci .push_irq_moderation = falcon_push_irq_moderation, 283262306a36Sopenharmony_ci .reconfigure_port = falcon_reconfigure_port, 283362306a36Sopenharmony_ci .prepare_enable_fc_tx = falcon_b0_prepare_enable_fc_tx, 283462306a36Sopenharmony_ci .reconfigure_mac = falcon_reconfigure_xmac, 283562306a36Sopenharmony_ci .check_mac_fault = falcon_xmac_check_fault, 283662306a36Sopenharmony_ci .get_wol = falcon_get_wol, 283762306a36Sopenharmony_ci .set_wol = falcon_set_wol, 283862306a36Sopenharmony_ci .resume_wol = ef4_port_dummy_op_void, 283962306a36Sopenharmony_ci .test_chip = falcon_b0_test_chip, 284062306a36Sopenharmony_ci .test_nvram = falcon_test_nvram, 284162306a36Sopenharmony_ci .irq_enable_master = ef4_farch_irq_enable_master, 284262306a36Sopenharmony_ci .irq_test_generate = ef4_farch_irq_test_generate, 284362306a36Sopenharmony_ci .irq_disable_non_ev = ef4_farch_irq_disable_master, 284462306a36Sopenharmony_ci .irq_handle_msi = ef4_farch_msi_interrupt, 284562306a36Sopenharmony_ci .irq_handle_legacy = ef4_farch_legacy_interrupt, 284662306a36Sopenharmony_ci .tx_probe = ef4_farch_tx_probe, 284762306a36Sopenharmony_ci .tx_init = ef4_farch_tx_init, 284862306a36Sopenharmony_ci .tx_remove = ef4_farch_tx_remove, 284962306a36Sopenharmony_ci .tx_write = ef4_farch_tx_write, 285062306a36Sopenharmony_ci .tx_limit_len = ef4_farch_tx_limit_len, 285162306a36Sopenharmony_ci .rx_push_rss_config = falcon_b0_rx_push_rss_config, 285262306a36Sopenharmony_ci .rx_probe = ef4_farch_rx_probe, 285362306a36Sopenharmony_ci .rx_init = ef4_farch_rx_init, 285462306a36Sopenharmony_ci .rx_remove = ef4_farch_rx_remove, 285562306a36Sopenharmony_ci .rx_write = ef4_farch_rx_write, 285662306a36Sopenharmony_ci .rx_defer_refill = ef4_farch_rx_defer_refill, 285762306a36Sopenharmony_ci .ev_probe = ef4_farch_ev_probe, 285862306a36Sopenharmony_ci .ev_init = ef4_farch_ev_init, 285962306a36Sopenharmony_ci .ev_fini = ef4_farch_ev_fini, 286062306a36Sopenharmony_ci .ev_remove = ef4_farch_ev_remove, 286162306a36Sopenharmony_ci .ev_process = ef4_farch_ev_process, 286262306a36Sopenharmony_ci .ev_read_ack = ef4_farch_ev_read_ack, 286362306a36Sopenharmony_ci .ev_test_generate = ef4_farch_ev_test_generate, 286462306a36Sopenharmony_ci .filter_table_probe = ef4_farch_filter_table_probe, 286562306a36Sopenharmony_ci .filter_table_restore = ef4_farch_filter_table_restore, 286662306a36Sopenharmony_ci .filter_table_remove = ef4_farch_filter_table_remove, 286762306a36Sopenharmony_ci .filter_update_rx_scatter = ef4_farch_filter_update_rx_scatter, 286862306a36Sopenharmony_ci .filter_insert = ef4_farch_filter_insert, 286962306a36Sopenharmony_ci .filter_remove_safe = ef4_farch_filter_remove_safe, 287062306a36Sopenharmony_ci .filter_get_safe = ef4_farch_filter_get_safe, 287162306a36Sopenharmony_ci .filter_clear_rx = ef4_farch_filter_clear_rx, 287262306a36Sopenharmony_ci .filter_count_rx_used = ef4_farch_filter_count_rx_used, 287362306a36Sopenharmony_ci .filter_get_rx_id_limit = ef4_farch_filter_get_rx_id_limit, 287462306a36Sopenharmony_ci .filter_get_rx_ids = ef4_farch_filter_get_rx_ids, 287562306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 287662306a36Sopenharmony_ci .filter_rfs_insert = ef4_farch_filter_rfs_insert, 287762306a36Sopenharmony_ci .filter_rfs_expire_one = ef4_farch_filter_rfs_expire_one, 287862306a36Sopenharmony_ci#endif 287962306a36Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD 288062306a36Sopenharmony_ci .mtd_probe = falcon_mtd_probe, 288162306a36Sopenharmony_ci .mtd_rename = falcon_mtd_rename, 288262306a36Sopenharmony_ci .mtd_read = falcon_mtd_read, 288362306a36Sopenharmony_ci .mtd_erase = falcon_mtd_erase, 288462306a36Sopenharmony_ci .mtd_write = falcon_mtd_write, 288562306a36Sopenharmony_ci .mtd_sync = falcon_mtd_sync, 288662306a36Sopenharmony_ci#endif 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci .revision = EF4_REV_FALCON_B0, 288962306a36Sopenharmony_ci .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, 289062306a36Sopenharmony_ci .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, 289162306a36Sopenharmony_ci .buf_tbl_base = FR_BZ_BUF_FULL_TBL, 289262306a36Sopenharmony_ci .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, 289362306a36Sopenharmony_ci .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, 289462306a36Sopenharmony_ci .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), 289562306a36Sopenharmony_ci .rx_prefix_size = FS_BZ_RX_PREFIX_SIZE, 289662306a36Sopenharmony_ci .rx_hash_offset = FS_BZ_RX_PREFIX_HASH_OFST, 289762306a36Sopenharmony_ci .rx_buffer_padding = 0, 289862306a36Sopenharmony_ci .can_rx_scatter = true, 289962306a36Sopenharmony_ci .max_interrupt_mode = EF4_INT_MODE_MSIX, 290062306a36Sopenharmony_ci .timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH, 290162306a36Sopenharmony_ci .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, 290262306a36Sopenharmony_ci .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, 290362306a36Sopenharmony_ci}; 2904