Commit d312bad4 authored by David S. Miller's avatar David S. Miller

Merge branch 'txgbe'

Mengyuan Lou says:

====================
net: WangXun txgbe/ngbe ethernet driver

This patch series adds support for WangXun NICS, to initialize
interface from software to firmware.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2e0de636 02338c48
...@@ -24,6 +24,7 @@ config LIBWX ...@@ -24,6 +24,7 @@ config LIBWX
config NGBE config NGBE
tristate "Wangxun(R) GbE PCI Express adapters support" tristate "Wangxun(R) GbE PCI Express adapters support"
depends on PCI depends on PCI
select LIBWX
help help
This driver supports Wangxun(R) GbE PCI Express family of This driver supports Wangxun(R) GbE PCI Express family of
adapters. adapters.
......
This diff is collapsed.
...@@ -5,6 +5,15 @@ ...@@ -5,6 +5,15 @@
#define _WX_HW_H_ #define _WX_HW_H_
int wx_check_flash_load(struct wx_hw *hw, u32 check_bit); int wx_check_flash_load(struct wx_hw *hw, u32 check_bit);
void wx_control_hw(struct wx_hw *wxhw, bool drv);
int wx_mng_present(struct wx_hw *wxhw);
int wx_host_interface_command(struct wx_hw *wxhw, u32 *buffer,
u32 length, u32 timeout, bool return_data);
int wx_read_ee_hostif(struct wx_hw *wxhw, u16 offset, u16 *data);
int wx_read_ee_hostif_buffer(struct wx_hw *wxhw,
u16 offset, u16 words, u16 *data);
int wx_reset_hostif(struct wx_hw *wxhw);
void wx_init_eeprom_params(struct wx_hw *wxhw);
void wx_get_mac_addr(struct wx_hw *wxhw, u8 *mac_addr); void wx_get_mac_addr(struct wx_hw *wxhw, u8 *mac_addr);
int wx_set_rar(struct wx_hw *wxhw, u32 index, u8 *addr, u64 pools, u32 enable_addr); int wx_set_rar(struct wx_hw *wxhw, u32 index, u8 *addr, u64 pools, u32 enable_addr);
int wx_clear_rar(struct wx_hw *wxhw, u32 index); int wx_clear_rar(struct wx_hw *wxhw, u32 index);
...@@ -13,6 +22,7 @@ void wx_disable_rx(struct wx_hw *wxhw); ...@@ -13,6 +22,7 @@ void wx_disable_rx(struct wx_hw *wxhw);
int wx_disable_pcie_master(struct wx_hw *wxhw); int wx_disable_pcie_master(struct wx_hw *wxhw);
int wx_stop_adapter(struct wx_hw *wxhw); int wx_stop_adapter(struct wx_hw *wxhw);
void wx_reset_misc(struct wx_hw *wxhw); void wx_reset_misc(struct wx_hw *wxhw);
int wx_get_pcie_msix_counts(struct wx_hw *wxhw, u16 *msix_count, u16 max_msix_count);
int wx_sw_init(struct wx_hw *wxhw); int wx_sw_init(struct wx_hw *wxhw);
#endif /* _WX_HW_H_ */ #endif /* _WX_HW_H_ */
...@@ -14,11 +14,20 @@ ...@@ -14,11 +14,20 @@
#define WX_WOL_SUP 0x4000 #define WX_WOL_SUP 0x4000
#define WX_WOL_MASK 0x4000 #define WX_WOL_MASK 0x4000
/* MSI-X capability fields masks */
#define WX_PCIE_MSIX_TBL_SZ_MASK 0x7FF
#define WX_PCI_LINK_STATUS 0xB2
/**************** Global Registers ****************************/ /**************** Global Registers ****************************/
/* chip control Registers */ /* chip control Registers */
#define WX_MIS_PWR 0x10000 #define WX_MIS_PWR 0x10000
#define WX_MIS_RST 0x1000C #define WX_MIS_RST 0x1000C
#define WX_MIS_RST_LAN_RST(_i) BIT((_i) + 1) #define WX_MIS_RST_LAN_RST(_i) BIT((_i) + 1)
#define WX_MIS_RST_SW_RST BIT(0)
#define WX_MIS_ST 0x10028
#define WX_MIS_ST_MNG_INIT_DN BIT(0)
#define WX_MIS_SWSM 0x1002C
#define WX_MIS_SWSM_SMBI BIT(0)
#define WX_MIS_RST_ST 0x10030 #define WX_MIS_RST_ST 0x10030
#define WX_MIS_RST_ST_RST_INI_SHIFT 8 #define WX_MIS_RST_ST_RST_INI_SHIFT 8
#define WX_MIS_RST_ST_RST_INIT (0xFF << WX_MIS_RST_ST_RST_INI_SHIFT) #define WX_MIS_RST_ST_RST_INIT (0xFF << WX_MIS_RST_ST_RST_INI_SHIFT)
...@@ -51,6 +60,11 @@ ...@@ -51,6 +60,11 @@
#define WX_TS_ALARM_ST_DALARM BIT(1) #define WX_TS_ALARM_ST_DALARM BIT(1)
#define WX_TS_ALARM_ST_ALARM BIT(0) #define WX_TS_ALARM_ST_ALARM BIT(0)
/************************* Port Registers ************************************/
/* port cfg Registers */
#define WX_CFG_PORT_CTL 0x14400
#define WX_CFG_PORT_CTL_DRV_LOAD BIT(3)
/*********************** Transmit DMA registers **************************/ /*********************** Transmit DMA registers **************************/
/* transmit global control */ /* transmit global control */
#define WX_TDM_CTL 0x18000 #define WX_TDM_CTL 0x18000
...@@ -107,6 +121,15 @@ ...@@ -107,6 +121,15 @@
#define WX_PSR_MAC_SWC_IDX 0x16210 #define WX_PSR_MAC_SWC_IDX 0x16210
#define WX_CLEAR_VMDQ_ALL 0xFFFFFFFFU #define WX_CLEAR_VMDQ_ALL 0xFFFFFFFFU
/************************************** MNG ********************************/
#define WX_MNG_SWFW_SYNC 0x1E008
#define WX_MNG_SWFW_SYNC_SW_MB BIT(2)
#define WX_MNG_SWFW_SYNC_SW_FLASH BIT(3)
#define WX_MNG_MBOX 0x1E100
#define WX_MNG_MBOX_CTL 0x1E044
#define WX_MNG_MBOX_CTL_SWRDY BIT(0)
#define WX_MNG_MBOX_CTL_FWRDY BIT(2)
/************************************* ETH MAC *****************************/ /************************************* ETH MAC *****************************/
#define WX_MAC_TX_CFG 0x11000 #define WX_MAC_TX_CFG 0x11000
#define WX_MAC_TX_CFG_TE BIT(0) #define WX_MAC_TX_CFG_TE BIT(0)
...@@ -144,6 +167,70 @@ ...@@ -144,6 +167,70 @@
/* Number of 80 microseconds we wait for PCI Express master disable */ /* Number of 80 microseconds we wait for PCI Express master disable */
#define WX_PCI_MASTER_DISABLE_TIMEOUT 80000 #define WX_PCI_MASTER_DISABLE_TIMEOUT 80000
/****************** Manageablility Host Interface defines ********************/
#define WX_HI_MAX_BLOCK_BYTE_LENGTH 256 /* Num of bytes in range */
#define WX_HI_COMMAND_TIMEOUT 1000 /* Process HI command limit */
#define FW_READ_SHADOW_RAM_CMD 0x31
#define FW_READ_SHADOW_RAM_LEN 0x6
#define FW_DEFAULT_CHECKSUM 0xFF /* checksum always 0xFF */
#define FW_NVM_DATA_OFFSET 3
#define FW_MAX_READ_BUFFER_SIZE 244
#define FW_RESET_CMD 0xDF
#define FW_RESET_LEN 0x2
#define FW_CEM_HDR_LEN 0x4
#define FW_CEM_CMD_RESERVED 0X0
#define FW_CEM_MAX_RETRIES 3
#define FW_CEM_RESP_STATUS_SUCCESS 0x1
#define WX_SW_REGION_PTR 0x1C
/* Host Interface Command Structures */
struct wx_hic_hdr {
u8 cmd;
u8 buf_len;
union {
u8 cmd_resv;
u8 ret_status;
} cmd_or_resp;
u8 checksum;
};
struct wx_hic_hdr2_req {
u8 cmd;
u8 buf_lenh;
u8 buf_lenl;
u8 checksum;
};
struct wx_hic_hdr2_rsp {
u8 cmd;
u8 buf_lenl;
u8 buf_lenh_status; /* 7-5: high bits of buf_len, 4-0: status */
u8 checksum;
};
union wx_hic_hdr2 {
struct wx_hic_hdr2_req req;
struct wx_hic_hdr2_rsp rsp;
};
/* These need to be dword aligned */
struct wx_hic_read_shadow_ram {
union wx_hic_hdr2 hdr;
u32 address;
u16 length;
u16 pad2;
u16 data;
u16 pad3;
};
struct wx_hic_reset {
struct wx_hic_hdr hdr;
u16 lan_id;
u16 reset_type;
};
/* Bus parameters */ /* Bus parameters */
struct wx_bus_info { struct wx_bus_info {
u8 func; u8 func;
...@@ -172,20 +259,43 @@ struct wx_mac_info { ...@@ -172,20 +259,43 @@ struct wx_mac_info {
u32 num_rar_entries; u32 num_rar_entries;
u32 max_tx_queues; u32 max_tx_queues;
u32 max_rx_queues; u32 max_rx_queues;
u16 max_msix_vectors;
struct wx_thermal_sensor_data sensor; struct wx_thermal_sensor_data sensor;
}; };
enum wx_eeprom_type {
wx_eeprom_uninitialized = 0,
wx_eeprom_spi,
wx_flash,
wx_eeprom_none /* No NVM support */
};
struct wx_eeprom_info {
enum wx_eeprom_type type;
u32 semaphore_delay;
u16 word_size;
u16 sw_region_offset;
};
struct wx_addr_filter_info { struct wx_addr_filter_info {
u32 num_mc_addrs; u32 num_mc_addrs;
u32 mta_in_use; u32 mta_in_use;
bool user_set_promisc; bool user_set_promisc;
}; };
enum wx_reset_type {
WX_LAN_RESET = 0,
WX_SW_RESET,
WX_GLOBAL_RESET
};
struct wx_hw { struct wx_hw {
u8 __iomem *hw_addr; u8 __iomem *hw_addr;
struct pci_dev *pdev; struct pci_dev *pdev;
struct wx_bus_info bus; struct wx_bus_info bus;
struct wx_mac_info mac; struct wx_mac_info mac;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl; struct wx_addr_filter_info addr_ctrl;
u16 device_id; u16 device_id;
u16 vendor_id; u16 vendor_id;
...@@ -195,6 +305,7 @@ struct wx_hw { ...@@ -195,6 +305,7 @@ struct wx_hw {
u16 oem_ssid; u16 oem_ssid;
u16 oem_svid; u16 oem_svid;
bool adapter_stopped; bool adapter_stopped;
enum wx_reset_type reset_type;
}; };
#define WX_INTR_ALL (~0ULL) #define WX_INTR_ALL (~0ULL)
...@@ -202,6 +313,10 @@ struct wx_hw { ...@@ -202,6 +313,10 @@ struct wx_hw {
/* register operations */ /* register operations */
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg))) #define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define rd32(a, reg) readl((a)->hw_addr + (reg)) #define rd32(a, reg) readl((a)->hw_addr + (reg))
#define rd32a(a, reg, offset) ( \
rd32((a), (reg) + ((offset) << 2)))
#define wr32a(a, reg, off, val) \
wr32((a), (reg) + ((off) << 2), (val))
static inline u32 static inline u32
rd32m(struct wx_hw *wxhw, u32 reg, u32 mask) rd32m(struct wx_hw *wxhw, u32 reg, u32 mask)
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
obj-$(CONFIG_NGBE) += ngbe.o obj-$(CONFIG_NGBE) += ngbe.o
ngbe-objs := ngbe_main.o ngbe-objs := ngbe_main.o ngbe_hw.o
...@@ -11,12 +11,67 @@ ...@@ -11,12 +11,67 @@
#define NGBE_MAX_RX_QUEUES (NGBE_MAX_FDIR_INDICES + 1) #define NGBE_MAX_RX_QUEUES (NGBE_MAX_FDIR_INDICES + 1)
#define NGBE_MAX_TX_QUEUES (NGBE_MAX_FDIR_INDICES + 1) #define NGBE_MAX_TX_QUEUES (NGBE_MAX_FDIR_INDICES + 1)
#define NGBE_ETH_LENGTH_OF_ADDRESS 6
#define NGBE_MAX_MSIX_VECTORS 0x09
#define NGBE_RAR_ENTRIES 32
/* TX/RX descriptor defines */
#define NGBE_DEFAULT_TXD 512 /* default ring size */
#define NGBE_DEFAULT_TX_WORK 256
#define NGBE_MAX_TXD 8192
#define NGBE_MIN_TXD 128
#define NGBE_DEFAULT_RXD 512 /* default ring size */
#define NGBE_DEFAULT_RX_WORK 256
#define NGBE_MAX_RXD 8192
#define NGBE_MIN_RXD 128
#define NGBE_MAC_STATE_DEFAULT 0x1
#define NGBE_MAC_STATE_MODIFIED 0x2
#define NGBE_MAC_STATE_IN_USE 0x4
struct ngbe_mac_addr {
u8 addr[ETH_ALEN];
u16 state; /* bitmask */
u64 pools;
};
/* board specific private data structure */ /* board specific private data structure */
struct ngbe_adapter { struct ngbe_adapter {
u8 __iomem *io_addr; /* Mainly for iounmap use */ u8 __iomem *io_addr; /* Mainly for iounmap use */
/* OS defined structs */ /* OS defined structs */
struct net_device *netdev; struct net_device *netdev;
struct pci_dev *pdev; struct pci_dev *pdev;
/* structs defined in ngbe_hw.h */
struct ngbe_hw hw;
struct ngbe_mac_addr *mac_table;
u16 msg_enable;
/* Tx fast path data */
int num_tx_queues;
u16 tx_itr_setting;
u16 tx_work_limit;
/* Rx fast path data */
int num_rx_queues;
u16 rx_itr_setting;
u16 rx_work_limit;
int num_q_vectors; /* current number of q_vectors for device */
int max_q_vectors; /* upper limit of q_vectors for device */
u32 tx_ring_count;
u32 rx_ring_count;
#define NGBE_MAX_RETA_ENTRIES 128
u8 rss_indir_tbl[NGBE_MAX_RETA_ENTRIES];
#define NGBE_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
u32 *rss_key;
u32 wol;
u16 bd_number;
}; };
extern char ngbe_driver_name[]; extern char ngbe_driver_name[];
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */
#include <linux/etherdevice.h>
#include <linux/iopoll.h>
#include <linux/pci.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "ngbe_type.h"
#include "ngbe_hw.h"
#include "ngbe.h"
int ngbe_eeprom_chksum_hostif(struct ngbe_hw *hw)
{
struct wx_hic_read_shadow_ram buffer;
struct wx_hw *wxhw = &hw->wxhw;
int status;
int tmp;
buffer.hdr.req.cmd = NGBE_FW_EEPROM_CHECKSUM_CMD;
buffer.hdr.req.buf_lenh = 0;
buffer.hdr.req.buf_lenl = 0;
buffer.hdr.req.checksum = NGBE_FW_CMD_DEFAULT_CHECKSUM;
/* convert offset from words to bytes */
buffer.address = 0;
/* one word */
buffer.length = 0;
status = wx_host_interface_command(wxhw, (u32 *)&buffer, sizeof(buffer),
WX_HI_COMMAND_TIMEOUT, false);
if (status < 0)
return status;
tmp = rd32a(wxhw, WX_MNG_MBOX, 1);
if (tmp == NGBE_FW_CMD_ST_PASS)
return 0;
return -EIO;
}
static int ngbe_reset_misc(struct ngbe_hw *hw)
{
struct wx_hw *wxhw = &hw->wxhw;
wx_reset_misc(wxhw);
if (hw->mac_type == ngbe_mac_type_rgmii)
wr32(wxhw, NGBE_MDIO_CLAUSE_SELECT, 0xF);
if (hw->gpio_ctrl) {
/* gpio0 is used to power on/off control*/
wr32(wxhw, NGBE_GPIO_DDR, 0x1);
wr32(wxhw, NGBE_GPIO_DR, NGBE_GPIO_DR_0);
}
return 0;
}
/**
* ngbe_reset_hw - Perform hardware reset
* @hw: pointer to hardware structure
*
* Resets the hardware by resetting the transmit and receive units, masks
* and clears all interrupts, perform a PHY reset, and perform a link (MAC)
* reset.
**/
int ngbe_reset_hw(struct ngbe_hw *hw)
{
struct wx_hw *wxhw = &hw->wxhw;
int status = 0;
u32 reset = 0;
/* Call adapter stop to disable tx/rx and clear interrupts */
status = wx_stop_adapter(wxhw);
if (status != 0)
return status;
reset = WX_MIS_RST_LAN_RST(wxhw->bus.func);
wr32(wxhw, WX_MIS_RST, reset | rd32(wxhw, WX_MIS_RST));
ngbe_reset_misc(hw);
/* Store the permanent mac address */
wx_get_mac_addr(wxhw, wxhw->mac.perm_addr);
/* reset num_rar_entries to 128 */
wxhw->mac.num_rar_entries = NGBE_RAR_ENTRIES;
wx_init_rx_addrs(wxhw);
pci_set_master(wxhw->pdev);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* WangXun Gigabit PCI Express Linux driver
* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd.
*/
#ifndef _NGBE_HW_H_
#define _NGBE_HW_H_
int ngbe_eeprom_chksum_hostif(struct ngbe_hw *hw);
int ngbe_reset_hw(struct ngbe_hw *hw);
#endif /* _NGBE_HW_H_ */
...@@ -8,11 +8,6 @@ ...@@ -8,11 +8,6 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
/************ NGBE_register.h ************/ /************ NGBE_register.h ************/
/* Vendor ID */
#ifndef PCI_VENDOR_ID_WANGXUN
#define PCI_VENDOR_ID_WANGXUN 0x8088
#endif
/* Device IDs */ /* Device IDs */
#define NGBE_DEV_ID_EM_WX1860AL_W 0x0100 #define NGBE_DEV_ID_EM_WX1860AL_W 0x0100
#define NGBE_DEV_ID_EM_WX1860A2 0x0101 #define NGBE_DEV_ID_EM_WX1860A2 0x0101
...@@ -47,4 +42,98 @@ ...@@ -47,4 +42,98 @@
#define NGBE_WOL_SUP 0x4000 #define NGBE_WOL_SUP 0x4000
#define NGBE_WOL_MASK 0x4000 #define NGBE_WOL_MASK 0x4000
/**************** EM Registers ****************************/
/* chip control Registers */
#define NGBE_MIS_PRB_CTL 0x10010
/* FMGR Registers */
#define NGBE_SPI_ILDR_STATUS 0x10120
#define NGBE_SPI_ILDR_STATUS_PERST BIT(0) /* PCIE_PERST is done */
#define NGBE_SPI_ILDR_STATUS_PWRRST BIT(1) /* Power on reset is done */
#define NGBE_SPI_ILDR_STATUS_LAN_SW_RST(_i) BIT((_i) + 9) /* lan soft reset done */
/* Checksum and EEPROM pointers */
#define NGBE_CALSUM_COMMAND 0xE9
#define NGBE_CALSUM_CAP_STATUS 0x10224
#define NGBE_EEPROM_VERSION_STORE_REG 0x1022C
#define NGBE_SAN_MAC_ADDR_PTR 0x18
#define NGBE_DEVICE_CAPS 0x1C
#define NGBE_EEPROM_VERSION_L 0x1D
#define NGBE_EEPROM_VERSION_H 0x1E
/* Media-dependent registers. */
#define NGBE_MDIO_CLAUSE_SELECT 0x11220
/* GPIO Registers */
#define NGBE_GPIO_DR 0x14800
#define NGBE_GPIO_DDR 0x14804
/*GPIO bit */
#define NGBE_GPIO_DR_0 BIT(0) /* SDP0 Data Value */
#define NGBE_GPIO_DR_1 BIT(1) /* SDP1 Data Value */
#define NGBE_GPIO_DDR_0 BIT(0) /* SDP0 IO direction */
#define NGBE_GPIO_DDR_1 BIT(1) /* SDP1 IO direction */
/* Wake up registers */
#define NGBE_PSR_WKUP_CTL 0x15B80
/* Wake Up Filter Control Bit */
#define NGBE_PSR_WKUP_CTL_LNKC BIT(0) /* Link Status Change Wakeup Enable*/
#define NGBE_PSR_WKUP_CTL_MAG BIT(1) /* Magic Packet Wakeup Enable */
#define NGBE_PSR_WKUP_CTL_EX BIT(2) /* Directed Exact Wakeup Enable */
#define NGBE_PSR_WKUP_CTL_MC BIT(3) /* Directed Multicast Wakeup Enable*/
#define NGBE_PSR_WKUP_CTL_BC BIT(4) /* Broadcast Wakeup Enable */
#define NGBE_PSR_WKUP_CTL_ARP BIT(5) /* ARP Request Packet Wakeup Enable*/
#define NGBE_PSR_WKUP_CTL_IPV4 BIT(6) /* Directed IPv4 Pkt Wakeup Enable */
#define NGBE_PSR_WKUP_CTL_IPV6 BIT(7) /* Directed IPv6 Pkt Wakeup Enable */
#define NGBE_FW_EEPROM_CHECKSUM_CMD 0xE9
#define NGBE_FW_NVM_DATA_OFFSET 3
#define NGBE_FW_CMD_DEFAULT_CHECKSUM 0xFF /* checksum always 0xFF */
#define NGBE_FW_CMD_ST_PASS 0x80658383
#define NGBE_FW_CMD_ST_FAIL 0x70657376
enum ngbe_phy_type {
ngbe_phy_unknown = 0,
ngbe_phy_none,
ngbe_phy_internal,
ngbe_phy_m88e1512,
ngbe_phy_m88e1512_sfi,
ngbe_phy_m88e1512_unknown,
ngbe_phy_yt8521s,
ngbe_phy_yt8521s_sfi,
ngbe_phy_internal_yt8521s_sfi,
ngbe_phy_generic
};
enum ngbe_media_type {
ngbe_media_type_unknown = 0,
ngbe_media_type_fiber,
ngbe_media_type_copper,
ngbe_media_type_backplane,
};
enum ngbe_mac_type {
ngbe_mac_type_unknown = 0,
ngbe_mac_type_mdi,
ngbe_mac_type_rgmii
};
struct ngbe_phy_info {
enum ngbe_phy_type type;
enum ngbe_media_type media_type;
u32 addr;
u32 id;
bool reset_if_overtemp;
};
struct ngbe_hw {
struct wx_hw wxhw;
struct ngbe_phy_info phy;
enum ngbe_mac_type mac_type;
bool wol_enabled;
bool ncsi_enabled;
bool gpio_ctrl;
};
#endif /* _NGBE_TYPE_H_ */ #endif /* _NGBE_TYPE_H_ */
...@@ -35,6 +35,7 @@ struct txgbe_adapter { ...@@ -35,6 +35,7 @@ struct txgbe_adapter {
struct txgbe_hw hw; struct txgbe_hw hw;
u16 msg_enable; u16 msg_enable;
struct txgbe_mac_addr *mac_table; struct txgbe_mac_addr *mac_table;
char eeprom_id[32];
}; };
extern char txgbe_driver_name[]; extern char txgbe_driver_name[];
......
...@@ -44,6 +44,218 @@ static void txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw) ...@@ -44,6 +44,218 @@ static void txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw)
wr32(wxhw, WX_TS_DALARM_THRE, 614); wr32(wxhw, WX_TS_DALARM_THRE, 614);
} }
/**
* txgbe_read_pba_string - Reads part number string from EEPROM
* @hw: pointer to hardware structure
* @pba_num: stores the part number string from the EEPROM
* @pba_num_size: part number string buffer length
*
* Reads the part number string from the EEPROM.
**/
int txgbe_read_pba_string(struct txgbe_hw *hw, u8 *pba_num, u32 pba_num_size)
{
u16 pba_ptr, offset, length, data;
struct wx_hw *wxhw = &hw->wxhw;
int ret_val;
if (!pba_num) {
wx_err(wxhw, "PBA string buffer was null\n");
return -EINVAL;
}
ret_val = wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + TXGBE_PBANUM0_PTR,
&data);
if (ret_val != 0) {
wx_err(wxhw, "NVM Read Error\n");
return ret_val;
}
ret_val = wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + TXGBE_PBANUM1_PTR,
&pba_ptr);
if (ret_val != 0) {
wx_err(wxhw, "NVM Read Error\n");
return ret_val;
}
/* if data is not ptr guard the PBA must be in legacy format which
* means pba_ptr is actually our second data word for the PBA number
* and we can decode it into an ascii string
*/
if (data != TXGBE_PBANUM_PTR_GUARD) {
wx_err(wxhw, "NVM PBA number is not stored as string\n");
/* we will need 11 characters to store the PBA */
if (pba_num_size < 11) {
wx_err(wxhw, "PBA string buffer too small\n");
return -ENOMEM;
}
/* extract hex string from data and pba_ptr */
pba_num[0] = (data >> 12) & 0xF;
pba_num[1] = (data >> 8) & 0xF;
pba_num[2] = (data >> 4) & 0xF;
pba_num[3] = data & 0xF;
pba_num[4] = (pba_ptr >> 12) & 0xF;
pba_num[5] = (pba_ptr >> 8) & 0xF;
pba_num[6] = '-';
pba_num[7] = 0;
pba_num[8] = (pba_ptr >> 4) & 0xF;
pba_num[9] = pba_ptr & 0xF;
/* put a null character on the end of our string */
pba_num[10] = '\0';
/* switch all the data but the '-' to hex char */
for (offset = 0; offset < 10; offset++) {
if (pba_num[offset] < 0xA)
pba_num[offset] += '0';
else if (pba_num[offset] < 0x10)
pba_num[offset] += 'A' - 0xA;
}
return 0;
}
ret_val = wx_read_ee_hostif(wxhw, pba_ptr, &length);
if (ret_val != 0) {
wx_err(wxhw, "NVM Read Error\n");
return ret_val;
}
if (length == 0xFFFF || length == 0) {
wx_err(wxhw, "NVM PBA number section invalid length\n");
return -EINVAL;
}
/* check if pba_num buffer is big enough */
if (pba_num_size < (((u32)length * 2) - 1)) {
wx_err(wxhw, "PBA string buffer too small\n");
return -ENOMEM;
}
/* trim pba length from start of string */
pba_ptr++;
length--;
for (offset = 0; offset < length; offset++) {
ret_val = wx_read_ee_hostif(wxhw, pba_ptr + offset, &data);
if (ret_val != 0) {
wx_err(wxhw, "NVM Read Error\n");
return ret_val;
}
pba_num[offset * 2] = (u8)(data >> 8);
pba_num[(offset * 2) + 1] = (u8)(data & 0xFF);
}
pba_num[offset * 2] = '\0';
return 0;
}
/**
* txgbe_calc_eeprom_checksum - Calculates and returns the checksum
* @hw: pointer to hardware structure
* @checksum: pointer to cheksum
*
* Returns a negative error code on error
**/
static int txgbe_calc_eeprom_checksum(struct txgbe_hw *hw, u16 *checksum)
{
struct wx_hw *wxhw = &hw->wxhw;
u16 *eeprom_ptrs = NULL;
u32 buffer_size = 0;
u16 *buffer = NULL;
u16 *local_buffer;
int status;
u16 i;
wx_init_eeprom_params(wxhw);
if (!buffer) {
eeprom_ptrs = kvmalloc_array(TXGBE_EEPROM_LAST_WORD, sizeof(u16),
GFP_KERNEL);
if (!eeprom_ptrs)
return -ENOMEM;
/* Read pointer area */
status = wx_read_ee_hostif_buffer(wxhw, 0,
TXGBE_EEPROM_LAST_WORD,
eeprom_ptrs);
if (status != 0) {
wx_err(wxhw, "Failed to read EEPROM image\n");
return status;
}
local_buffer = eeprom_ptrs;
} else {
if (buffer_size < TXGBE_EEPROM_LAST_WORD)
return -EFAULT;
local_buffer = buffer;
}
for (i = 0; i < TXGBE_EEPROM_LAST_WORD; i++)
if (i != wxhw->eeprom.sw_region_offset + TXGBE_EEPROM_CHECKSUM)
*checksum += local_buffer[i];
*checksum = TXGBE_EEPROM_SUM - *checksum;
if (*checksum < 0)
return -EINVAL;
if (eeprom_ptrs)
kvfree(eeprom_ptrs);
return 0;
}
/**
* txgbe_validate_eeprom_checksum - Validate EEPROM checksum
* @hw: pointer to hardware structure
* @checksum_val: calculated checksum
*
* Performs checksum calculation and validates the EEPROM checksum. If the
* caller does not need checksum_val, the value can be NULL.
**/
int txgbe_validate_eeprom_checksum(struct txgbe_hw *hw, u16 *checksum_val)
{
struct wx_hw *wxhw = &hw->wxhw;
u16 read_checksum = 0;
u16 checksum;
int status;
/* Read the first word from the EEPROM. If this times out or fails, do
* not continue or we could be in for a very long wait while every
* EEPROM read fails
*/
status = wx_read_ee_hostif(wxhw, 0, &checksum);
if (status) {
wx_err(wxhw, "EEPROM read failed\n");
return status;
}
checksum = 0;
status = txgbe_calc_eeprom_checksum(hw, &checksum);
if (status != 0)
return status;
status = wx_read_ee_hostif(wxhw, wxhw->eeprom.sw_region_offset +
TXGBE_EEPROM_CHECKSUM, &read_checksum);
if (status != 0)
return status;
/* Verify read checksum from EEPROM is the same as
* calculated checksum
*/
if (read_checksum != checksum) {
status = -EIO;
wx_err(wxhw, "Invalid EEPROM checksum\n");
}
/* If the user cares, return the calculated checksum */
if (checksum_val)
*checksum_val = checksum;
return status;
}
static void txgbe_reset_misc(struct txgbe_hw *hw) static void txgbe_reset_misc(struct txgbe_hw *hw)
{ {
struct wx_hw *wxhw = &hw->wxhw; struct wx_hw *wxhw = &hw->wxhw;
...@@ -63,7 +275,6 @@ static void txgbe_reset_misc(struct txgbe_hw *hw) ...@@ -63,7 +275,6 @@ static void txgbe_reset_misc(struct txgbe_hw *hw)
int txgbe_reset_hw(struct txgbe_hw *hw) int txgbe_reset_hw(struct txgbe_hw *hw)
{ {
struct wx_hw *wxhw = &hw->wxhw; struct wx_hw *wxhw = &hw->wxhw;
u32 reset = 0;
int status; int status;
/* Call adapter stop to disable tx/rx and clear interrupts */ /* Call adapter stop to disable tx/rx and clear interrupts */
...@@ -71,10 +282,10 @@ int txgbe_reset_hw(struct txgbe_hw *hw) ...@@ -71,10 +282,10 @@ int txgbe_reset_hw(struct txgbe_hw *hw)
if (status != 0) if (status != 0)
return status; return status;
reset = WX_MIS_RST_LAN_RST(wxhw->bus.func); if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
wr32(wxhw, WX_MIS_RST, reset | rd32(wxhw, WX_MIS_RST)); ((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP)))
wx_reset_hostif(wxhw);
WX_WRITE_FLUSH(wxhw);
usleep_range(10, 100); usleep_range(10, 100);
status = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wxhw->bus.func)); status = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wxhw->bus.func));
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#ifndef _TXGBE_HW_H_ #ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_ #define _TXGBE_HW_H_
int txgbe_read_pba_string(struct txgbe_hw *hw, u8 *pba_num, u32 pba_num_size);
int txgbe_validate_eeprom_checksum(struct txgbe_hw *hw, u16 *checksum_val);
int txgbe_reset_hw(struct txgbe_hw *hw); int txgbe_reset_hw(struct txgbe_hw *hw);
#endif /* _TXGBE_HW_H_ */ #endif /* _TXGBE_HW_H_ */
...@@ -158,6 +158,14 @@ static int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 poo ...@@ -158,6 +158,14 @@ static int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 poo
return -ENOMEM; return -ENOMEM;
} }
static void txgbe_up_complete(struct txgbe_adapter *adapter)
{
struct txgbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
wx_control_hw(wxhw, true);
}
static void txgbe_reset(struct txgbe_adapter *adapter) static void txgbe_reset(struct txgbe_adapter *adapter)
{ {
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
...@@ -270,6 +278,10 @@ static int txgbe_sw_init(struct txgbe_adapter *adapter) ...@@ -270,6 +278,10 @@ static int txgbe_sw_init(struct txgbe_adapter *adapter)
**/ **/
static int txgbe_open(struct net_device *netdev) static int txgbe_open(struct net_device *netdev)
{ {
struct txgbe_adapter *adapter = netdev_priv(netdev);
txgbe_up_complete(adapter);
return 0; return 0;
} }
...@@ -301,6 +313,7 @@ static int txgbe_close(struct net_device *netdev) ...@@ -301,6 +313,7 @@ static int txgbe_close(struct net_device *netdev)
struct txgbe_adapter *adapter = netdev_priv(netdev); struct txgbe_adapter *adapter = netdev_priv(netdev);
txgbe_down(adapter); txgbe_down(adapter);
wx_control_hw(&adapter->hw.wxhw, false);
return 0; return 0;
} }
...@@ -309,6 +322,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) ...@@ -309,6 +322,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{ {
struct txgbe_adapter *adapter = pci_get_drvdata(pdev); struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct txgbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
netif_device_detach(netdev); netif_device_detach(netdev);
...@@ -317,6 +332,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) ...@@ -317,6 +332,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
txgbe_close_suspend(adapter); txgbe_close_suspend(adapter);
rtnl_unlock(); rtnl_unlock();
wx_control_hw(wxhw, false);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
...@@ -393,6 +410,12 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -393,6 +410,12 @@ static int txgbe_probe(struct pci_dev *pdev,
struct net_device *netdev; struct net_device *netdev;
int err, expected_gts; int err, expected_gts;
u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0;
u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0;
u16 build = 0, major = 0, patch = 0;
u8 part_str[TXGBE_PBANUM_LENGTH];
u32 etrack_id = 0;
err = pci_enable_device_mem(pdev); err = pci_enable_device_mem(pdev);
if (err) if (err)
return err; return err;
...@@ -457,6 +480,12 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -457,6 +480,12 @@ static int txgbe_probe(struct pci_dev *pdev,
if (err) if (err)
goto err_free_mac_table; goto err_free_mac_table;
err = wx_mng_present(wxhw);
if (err) {
dev_err(&pdev->dev, "Management capability is not present\n");
goto err_free_mac_table;
}
err = txgbe_reset_hw(hw); err = txgbe_reset_hw(hw);
if (err) { if (err) {
dev_err(&pdev->dev, "HW Init failed: %d\n", err); dev_err(&pdev->dev, "HW Init failed: %d\n", err);
...@@ -465,12 +494,59 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -465,12 +494,59 @@ static int txgbe_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HIGHDMA;
/* make sure the EEPROM is good */
err = txgbe_validate_eeprom_checksum(hw, NULL);
if (err != 0) {
dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
wr32(wxhw, WX_MIS_RST, WX_MIS_RST_SW_RST);
err = -EIO;
goto err_free_mac_table;
}
eth_hw_addr_set(netdev, wxhw->mac.perm_addr); eth_hw_addr_set(netdev, wxhw->mac.perm_addr);
txgbe_mac_set_default_filter(adapter, wxhw->mac.perm_addr); txgbe_mac_set_default_filter(adapter, wxhw->mac.perm_addr);
/* Save off EEPROM version number and Option Rom version which
* together make a unique identify for the eeprom
*/
wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_H,
&eeprom_verh);
wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_L,
&eeprom_verl);
etrack_id = (eeprom_verh << 16) | eeprom_verl;
wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + TXGBE_ISCSI_BOOT_CONFIG,
&offset);
/* Make sure offset to SCSI block is valid */
if (!(offset == 0x0) && !(offset == 0xffff)) {
wx_read_ee_hostif(wxhw, offset + 0x84, &eeprom_cfg_blkh);
wx_read_ee_hostif(wxhw, offset + 0x83, &eeprom_cfg_blkl);
/* Only display Option Rom if exist */
if (eeprom_cfg_blkl && eeprom_cfg_blkh) {
major = eeprom_cfg_blkl >> 8;
build = (eeprom_cfg_blkl << 8) | (eeprom_cfg_blkh >> 8);
patch = eeprom_cfg_blkh & 0x00ff;
snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
"0x%08x, %d.%d.%d", etrack_id, major, build,
patch);
} else {
snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
"0x%08x", etrack_id);
}
} else {
snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
"0x%08x", etrack_id);
}
err = register_netdev(netdev); err = register_netdev(netdev);
if (err) if (err)
goto err_free_mac_table; goto err_release_hw;
pci_set_drvdata(pdev, adapter); pci_set_drvdata(pdev, adapter);
...@@ -488,10 +564,17 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -488,10 +564,17 @@ static int txgbe_probe(struct pci_dev *pdev,
else else
dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n"); dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n");
/* First try to read PBA as a string */
err = txgbe_read_pba_string(hw, part_str, TXGBE_PBANUM_LENGTH);
if (err)
strncpy(part_str, "Unknown", TXGBE_PBANUM_LENGTH);
netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr); netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr);
return 0; return 0;
err_release_hw:
wx_control_hw(wxhw, false);
err_free_mac_table: err_free_mac_table:
kfree(adapter->mac_table); kfree(adapter->mac_table);
err_pci_release_regions: err_pci_release_regions:
......
...@@ -53,6 +53,20 @@ ...@@ -53,6 +53,20 @@
#define TXGBE_TS_CTL 0x10300 #define TXGBE_TS_CTL 0x10300
#define TXGBE_TS_CTL_EVAL_MD BIT(31) #define TXGBE_TS_CTL_EVAL_MD BIT(31)
/* Part Number String Length */
#define TXGBE_PBANUM_LENGTH 32
/* Checksum and EEPROM pointers */
#define TXGBE_EEPROM_LAST_WORD 0x800
#define TXGBE_EEPROM_CHECKSUM 0x2F
#define TXGBE_EEPROM_SUM 0xBABA
#define TXGBE_EEPROM_VERSION_L 0x1D
#define TXGBE_EEPROM_VERSION_H 0x1E
#define TXGBE_ISCSI_BOOT_CONFIG 0x07
#define TXGBE_PBANUM0_PTR 0x05
#define TXGBE_PBANUM1_PTR 0x06
#define TXGBE_PBANUM_PTR_GUARD 0xFAFA
struct txgbe_hw { struct txgbe_hw {
struct wx_hw wxhw; struct wx_hw wxhw;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment