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
config NGBE
tristate "Wangxun(R) GbE PCI Express adapters support"
depends on PCI
select LIBWX
help
This driver supports Wangxun(R) GbE PCI Express family of
adapters.
......
......@@ -73,6 +73,434 @@ int wx_check_flash_load(struct wx_hw *hw, u32 check_bit)
}
EXPORT_SYMBOL(wx_check_flash_load);
void wx_control_hw(struct wx_hw *wxhw, bool drv)
{
if (drv) {
/* Let firmware know the driver has taken over */
wr32m(wxhw, WX_CFG_PORT_CTL,
WX_CFG_PORT_CTL_DRV_LOAD, WX_CFG_PORT_CTL_DRV_LOAD);
} else {
/* Let firmware take over control of hw */
wr32m(wxhw, WX_CFG_PORT_CTL,
WX_CFG_PORT_CTL_DRV_LOAD, 0);
}
}
EXPORT_SYMBOL(wx_control_hw);
/**
* wx_mng_present - returns 0 when management capability is present
* @wxhw: pointer to hardware structure
*/
int wx_mng_present(struct wx_hw *wxhw)
{
u32 fwsm;
fwsm = rd32(wxhw, WX_MIS_ST);
if (fwsm & WX_MIS_ST_MNG_INIT_DN)
return 0;
else
return -EACCES;
}
EXPORT_SYMBOL(wx_mng_present);
/* Software lock to be held while software semaphore is being accessed. */
static DEFINE_MUTEX(wx_sw_sync_lock);
/**
* wx_release_sw_sync - Release SW semaphore
* @wxhw: pointer to hardware structure
* @mask: Mask to specify which semaphore to release
*
* Releases the SW semaphore for the specified
* function (CSR, PHY0, PHY1, EEPROM, Flash)
**/
static void wx_release_sw_sync(struct wx_hw *wxhw, u32 mask)
{
mutex_lock(&wx_sw_sync_lock);
wr32m(wxhw, WX_MNG_SWFW_SYNC, mask, 0);
mutex_unlock(&wx_sw_sync_lock);
}
/**
* wx_acquire_sw_sync - Acquire SW semaphore
* @wxhw: pointer to hardware structure
* @mask: Mask to specify which semaphore to acquire
*
* Acquires the SW semaphore for the specified
* function (CSR, PHY0, PHY1, EEPROM, Flash)
**/
static int wx_acquire_sw_sync(struct wx_hw *wxhw, u32 mask)
{
u32 sem = 0;
int ret = 0;
mutex_lock(&wx_sw_sync_lock);
ret = read_poll_timeout(rd32, sem, !(sem & mask),
5000, 2000000, false, wxhw, WX_MNG_SWFW_SYNC);
if (!ret) {
sem |= mask;
wr32(wxhw, WX_MNG_SWFW_SYNC, sem);
} else {
wx_err(wxhw, "SW Semaphore not granted: 0x%x.\n", sem);
}
mutex_unlock(&wx_sw_sync_lock);
return ret;
}
/**
* wx_host_interface_command - Issue command to manageability block
* @wxhw: pointer to the HW structure
* @buffer: contains the command to write and where the return status will
* be placed
* @length: length of buffer, must be multiple of 4 bytes
* @timeout: time in ms to wait for command completion
* @return_data: read and return data from the buffer (true) or not (false)
* Needed because FW structures are big endian and decoding of
* these fields can be 8 bit or 16 bit based on command. Decoding
* is not easily understood without making a table of commands.
* So we will leave this up to the caller to read back the data
* in these cases.
**/
int wx_host_interface_command(struct wx_hw *wxhw, u32 *buffer,
u32 length, u32 timeout, bool return_data)
{
u32 hdr_size = sizeof(struct wx_hic_hdr);
u32 hicr, i, bi, buf[64] = {};
int status = 0;
u32 dword_len;
u16 buf_len;
if (length == 0 || length > WX_HI_MAX_BLOCK_BYTE_LENGTH) {
wx_err(wxhw, "Buffer length failure buffersize=%d.\n", length);
return -EINVAL;
}
status = wx_acquire_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_MB);
if (status != 0)
return status;
/* Calculate length in DWORDs. We must be DWORD aligned */
if ((length % (sizeof(u32))) != 0) {
wx_err(wxhw, "Buffer length failure, not aligned to dword");
status = -EINVAL;
goto rel_out;
}
dword_len = length >> 2;
/* The device driver writes the relevant command block
* into the ram area.
*/
for (i = 0; i < dword_len; i++) {
wr32a(wxhw, WX_MNG_MBOX, i, (__force u32)cpu_to_le32(buffer[i]));
/* write flush */
buf[i] = rd32a(wxhw, WX_MNG_MBOX, i);
}
/* Setting this bit tells the ARC that a new command is pending. */
wr32m(wxhw, WX_MNG_MBOX_CTL,
WX_MNG_MBOX_CTL_SWRDY, WX_MNG_MBOX_CTL_SWRDY);
status = read_poll_timeout(rd32, hicr, hicr & WX_MNG_MBOX_CTL_FWRDY, 1000,
timeout * 1000, false, wxhw, WX_MNG_MBOX_CTL);
if (status)
goto rel_out;
/* Check command completion */
if (status) {
wx_dbg(wxhw, "Command has failed with no status valid.\n");
buf[0] = rd32(wxhw, WX_MNG_MBOX);
if ((buffer[0] & 0xff) != (~buf[0] >> 24)) {
status = -EINVAL;
goto rel_out;
}
if ((buf[0] & 0xff0000) >> 16 == 0x80) {
wx_dbg(wxhw, "It's unknown cmd.\n");
status = -EINVAL;
goto rel_out;
}
wx_dbg(wxhw, "write value:\n");
for (i = 0; i < dword_len; i++)
wx_dbg(wxhw, "%x ", buffer[i]);
wx_dbg(wxhw, "read value:\n");
for (i = 0; i < dword_len; i++)
wx_dbg(wxhw, "%x ", buf[i]);
}
if (!return_data)
goto rel_out;
/* Calculate length in DWORDs */
dword_len = hdr_size >> 2;
/* first pull in the header so we know the buffer length */
for (bi = 0; bi < dword_len; bi++) {
buffer[bi] = rd32a(wxhw, WX_MNG_MBOX, bi);
le32_to_cpus(&buffer[bi]);
}
/* If there is any thing in data position pull it in */
buf_len = ((struct wx_hic_hdr *)buffer)->buf_len;
if (buf_len == 0)
goto rel_out;
if (length < buf_len + hdr_size) {
wx_err(wxhw, "Buffer not large enough for reply message.\n");
status = -EFAULT;
goto rel_out;
}
/* Calculate length in DWORDs, add 3 for odd lengths */
dword_len = (buf_len + 3) >> 2;
/* Pull in the rest of the buffer (bi is where we left off) */
for (; bi <= dword_len; bi++) {
buffer[bi] = rd32a(wxhw, WX_MNG_MBOX, bi);
le32_to_cpus(&buffer[bi]);
}
rel_out:
wx_release_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_MB);
return status;
}
EXPORT_SYMBOL(wx_host_interface_command);
/**
* wx_read_ee_hostif_data - Read EEPROM word using a host interface cmd
* assuming that the semaphore is already obtained.
* @wxhw: pointer to hardware structure
* @offset: offset of word in the EEPROM to read
* @data: word read from the EEPROM
*
* Reads a 16 bit word from the EEPROM using the hostif.
**/
static int wx_read_ee_hostif_data(struct wx_hw *wxhw, u16 offset, u16 *data)
{
struct wx_hic_read_shadow_ram buffer;
int status;
buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
buffer.hdr.req.buf_lenh = 0;
buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
/* convert offset from words to bytes */
buffer.address = (__force u32)cpu_to_be32(offset * 2);
/* one word */
buffer.length = (__force u16)cpu_to_be16(sizeof(u16));
status = wx_host_interface_command(wxhw, (u32 *)&buffer, sizeof(buffer),
WX_HI_COMMAND_TIMEOUT, false);
if (status != 0)
return status;
*data = (u16)rd32a(wxhw, WX_MNG_MBOX, FW_NVM_DATA_OFFSET);
return status;
}
/**
* wx_read_ee_hostif - Read EEPROM word using a host interface cmd
* @wxhw: pointer to hardware structure
* @offset: offset of word in the EEPROM to read
* @data: word read from the EEPROM
*
* Reads a 16 bit word from the EEPROM using the hostif.
**/
int wx_read_ee_hostif(struct wx_hw *wxhw, u16 offset, u16 *data)
{
int status = 0;
status = wx_acquire_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_FLASH);
if (status == 0) {
status = wx_read_ee_hostif_data(wxhw, offset, data);
wx_release_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_FLASH);
}
return status;
}
EXPORT_SYMBOL(wx_read_ee_hostif);
/**
* wx_read_ee_hostif_buffer- Read EEPROM word(s) using hostif
* @wxhw: pointer to hardware structure
* @offset: offset of word in the EEPROM to read
* @words: number of words
* @data: word(s) read from the EEPROM
*
* Reads a 16 bit word(s) from the EEPROM using the hostif.
**/
int wx_read_ee_hostif_buffer(struct wx_hw *wxhw,
u16 offset, u16 words, u16 *data)
{
struct wx_hic_read_shadow_ram buffer;
u32 current_word = 0;
u16 words_to_read;
u32 value = 0;
int status;
u32 i;
/* Take semaphore for the entire operation. */
status = wx_acquire_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_FLASH);
if (status != 0)
return status;
while (words) {
if (words > FW_MAX_READ_BUFFER_SIZE / 2)
words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
else
words_to_read = words;
buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
buffer.hdr.req.buf_lenh = 0;
buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
/* convert offset from words to bytes */
buffer.address = (__force u32)cpu_to_be32((offset + current_word) * 2);
buffer.length = (__force u16)cpu_to_be16(words_to_read * 2);
status = wx_host_interface_command(wxhw, (u32 *)&buffer,
sizeof(buffer),
WX_HI_COMMAND_TIMEOUT,
false);
if (status != 0) {
wx_err(wxhw, "Host interface command failed\n");
goto out;
}
for (i = 0; i < words_to_read; i++) {
u32 reg = WX_MNG_MBOX + (FW_NVM_DATA_OFFSET << 2) + 2 * i;
value = rd32(wxhw, reg);
data[current_word] = (u16)(value & 0xffff);
current_word++;
i++;
if (i < words_to_read) {
value >>= 16;
data[current_word] = (u16)(value & 0xffff);
current_word++;
}
}
words -= words_to_read;
}
out:
wx_release_sw_sync(wxhw, WX_MNG_SWFW_SYNC_SW_FLASH);
return status;
}
EXPORT_SYMBOL(wx_read_ee_hostif_buffer);
/**
* wx_calculate_checksum - Calculate checksum for buffer
* @buffer: pointer to EEPROM
* @length: size of EEPROM to calculate a checksum for
* Calculates the checksum for some buffer on a specified length. The
* checksum calculated is returned.
**/
static u8 wx_calculate_checksum(u8 *buffer, u32 length)
{
u8 sum = 0;
u32 i;
if (!buffer)
return 0;
for (i = 0; i < length; i++)
sum += buffer[i];
return (u8)(0 - sum);
}
/**
* wx_reset_hostif - send reset cmd to fw
* @wxhw: pointer to hardware structure
*
* Sends reset cmd to firmware through the manageability
* block.
**/
int wx_reset_hostif(struct wx_hw *wxhw)
{
struct wx_hic_reset reset_cmd;
int ret_val = 0;
int i;
reset_cmd.hdr.cmd = FW_RESET_CMD;
reset_cmd.hdr.buf_len = FW_RESET_LEN;
reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
reset_cmd.lan_id = wxhw->bus.func;
reset_cmd.reset_type = (u16)wxhw->reset_type;
reset_cmd.hdr.checksum = 0;
reset_cmd.hdr.checksum = wx_calculate_checksum((u8 *)&reset_cmd,
(FW_CEM_HDR_LEN +
reset_cmd.hdr.buf_len));
for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
ret_val = wx_host_interface_command(wxhw, (u32 *)&reset_cmd,
sizeof(reset_cmd),
WX_HI_COMMAND_TIMEOUT,
true);
if (ret_val != 0)
continue;
if (reset_cmd.hdr.cmd_or_resp.ret_status ==
FW_CEM_RESP_STATUS_SUCCESS)
ret_val = 0;
else
ret_val = -EFAULT;
break;
}
return ret_val;
}
EXPORT_SYMBOL(wx_reset_hostif);
/**
* wx_init_eeprom_params - Initialize EEPROM params
* @wxhw: pointer to hardware structure
*
* Initializes the EEPROM parameters wx_eeprom_info within the
* wx_hw struct in order to set up EEPROM access.
**/
void wx_init_eeprom_params(struct wx_hw *wxhw)
{
struct wx_eeprom_info *eeprom = &wxhw->eeprom;
u16 eeprom_size;
u16 data = 0x80;
if (eeprom->type == wx_eeprom_uninitialized) {
eeprom->semaphore_delay = 10;
eeprom->type = wx_eeprom_none;
if (!(rd32(wxhw, WX_SPI_STATUS) &
WX_SPI_STATUS_FLASH_BYPASS)) {
eeprom->type = wx_flash;
eeprom_size = 4096;
eeprom->word_size = eeprom_size >> 1;
wx_dbg(wxhw, "Eeprom params: type = %d, size = %d\n",
eeprom->type, eeprom->word_size);
}
}
if (wxhw->mac.type == wx_mac_sp) {
if (wx_read_ee_hostif(wxhw, WX_SW_REGION_PTR, &data)) {
wx_err(wxhw, "NVM Read Error\n");
return;
}
data = data >> 1;
}
eeprom->sw_region_offset = data;
}
EXPORT_SYMBOL(wx_init_eeprom_params);
/**
* wx_get_mac_addr - Generic get MAC address
* @wxhw: pointer to hardware structure
......@@ -443,6 +871,41 @@ void wx_reset_misc(struct wx_hw *wxhw)
}
EXPORT_SYMBOL(wx_reset_misc);
/**
* wx_get_pcie_msix_counts - Gets MSI-X vector count
* @wxhw: pointer to hardware structure
* @msix_count: number of MSI interrupts that can be obtained
* @max_msix_count: number of MSI interrupts that mac need
*
* Read PCIe configuration space, and get the MSI-X vector count from
* the capabilities table.
**/
int wx_get_pcie_msix_counts(struct wx_hw *wxhw, u16 *msix_count, u16 max_msix_count)
{
struct pci_dev *pdev = wxhw->pdev;
struct device *dev = &pdev->dev;
int pos;
*msix_count = 1;
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
if (!pos) {
dev_err(dev, "Unable to find MSI-X Capabilities\n");
return -EINVAL;
}
pci_read_config_word(pdev,
pos + PCI_MSIX_FLAGS,
msix_count);
*msix_count &= WX_PCIE_MSIX_TBL_SZ_MASK;
/* MSI-X count is zero-based in HW */
*msix_count += 1;
if (*msix_count > max_msix_count)
*msix_count = max_msix_count;
return 0;
}
EXPORT_SYMBOL(wx_get_pcie_msix_counts);
int wx_sw_init(struct wx_hw *wxhw)
{
struct pci_dev *pdev = wxhw->pdev;
......
......@@ -5,6 +5,15 @@
#define _WX_HW_H_
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);
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);
......@@ -13,6 +22,7 @@ void wx_disable_rx(struct wx_hw *wxhw);
int wx_disable_pcie_master(struct wx_hw *wxhw);
int wx_stop_adapter(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);
#endif /* _WX_HW_H_ */
......@@ -14,11 +14,20 @@
#define WX_WOL_SUP 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 ****************************/
/* chip control Registers */
#define WX_MIS_PWR 0x10000
#define WX_MIS_RST 0x1000C
#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_RST_INI_SHIFT 8
#define WX_MIS_RST_ST_RST_INIT (0xFF << WX_MIS_RST_ST_RST_INI_SHIFT)
......@@ -51,6 +60,11 @@
#define WX_TS_ALARM_ST_DALARM BIT(1)
#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 global control */
#define WX_TDM_CTL 0x18000
......@@ -107,6 +121,15 @@
#define WX_PSR_MAC_SWC_IDX 0x16210
#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 *****************************/
#define WX_MAC_TX_CFG 0x11000
#define WX_MAC_TX_CFG_TE BIT(0)
......@@ -144,6 +167,70 @@
/* Number of 80 microseconds we wait for PCI Express master disable */
#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 */
struct wx_bus_info {
u8 func;
......@@ -172,20 +259,43 @@ struct wx_mac_info {
u32 num_rar_entries;
u32 max_tx_queues;
u32 max_rx_queues;
u16 max_msix_vectors;
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 {
u32 num_mc_addrs;
u32 mta_in_use;
bool user_set_promisc;
};
enum wx_reset_type {
WX_LAN_RESET = 0,
WX_SW_RESET,
WX_GLOBAL_RESET
};
struct wx_hw {
u8 __iomem *hw_addr;
struct pci_dev *pdev;
struct wx_bus_info bus;
struct wx_mac_info mac;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
u16 device_id;
u16 vendor_id;
......@@ -195,6 +305,7 @@ struct wx_hw {
u16 oem_ssid;
u16 oem_svid;
bool adapter_stopped;
enum wx_reset_type reset_type;
};
#define WX_INTR_ALL (~0ULL)
......@@ -202,6 +313,10 @@ struct wx_hw {
/* register operations */
#define wr32(a, reg, value) writel((value), ((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
rd32m(struct wx_hw *wxhw, u32 reg, u32 mask)
......
......@@ -6,4 +6,4 @@
obj-$(CONFIG_NGBE) += ngbe.o
ngbe-objs := ngbe_main.o
ngbe-objs := ngbe_main.o ngbe_hw.o
......@@ -11,12 +11,67 @@
#define NGBE_MAX_RX_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 */
struct ngbe_adapter {
u8 __iomem *io_addr; /* Mainly for iounmap use */
/* OS defined structs */
struct net_device *netdev;
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[];
......
// 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,7 +8,12 @@
#include <linux/string.h>
#include <linux/aer.h>
#include <linux/etherdevice.h>
#include <net/ip.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "ngbe_type.h"
#include "ngbe_hw.h"
#include "ngbe.h"
char ngbe_driver_name[] = "ngbe";
......@@ -34,6 +39,247 @@ static const struct pci_device_id ngbe_pci_tbl[] = {
{ .device = 0 }
};
static void ngbe_mac_set_default_filter(struct ngbe_adapter *adapter, u8 *addr)
{
struct ngbe_hw *hw = &adapter->hw;
memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
adapter->mac_table[0].pools = 1ULL;
adapter->mac_table[0].state = (NGBE_MAC_STATE_DEFAULT |
NGBE_MAC_STATE_IN_USE);
wx_set_rar(&hw->wxhw, 0, adapter->mac_table[0].addr,
adapter->mac_table[0].pools,
WX_PSR_MAC_SWC_AD_H_AV);
}
/**
* ngbe_init_type_code - Initialize the shared code
* @hw: pointer to hardware structure
**/
static void ngbe_init_type_code(struct ngbe_hw *hw)
{
int wol_mask = 0, ncsi_mask = 0;
struct wx_hw *wxhw = &hw->wxhw;
u16 type_mask = 0;
wxhw->mac.type = wx_mac_em;
type_mask = (u16)(wxhw->subsystem_device_id & NGBE_OEM_MASK);
ncsi_mask = wxhw->subsystem_device_id & NGBE_NCSI_MASK;
wol_mask = wxhw->subsystem_device_id & NGBE_WOL_MASK;
switch (type_mask) {
case NGBE_SUBID_M88E1512_SFP:
case NGBE_SUBID_LY_M88E1512_SFP:
hw->phy.type = ngbe_phy_m88e1512_sfi;
break;
case NGBE_SUBID_M88E1512_RJ45:
hw->phy.type = ngbe_phy_m88e1512;
break;
case NGBE_SUBID_M88E1512_MIX:
hw->phy.type = ngbe_phy_m88e1512_unknown;
break;
case NGBE_SUBID_YT8521S_SFP:
case NGBE_SUBID_YT8521S_SFP_GPIO:
case NGBE_SUBID_LY_YT8521S_SFP:
hw->phy.type = ngbe_phy_yt8521s_sfi;
break;
case NGBE_SUBID_INTERNAL_YT8521S_SFP:
case NGBE_SUBID_INTERNAL_YT8521S_SFP_GPIO:
hw->phy.type = ngbe_phy_internal_yt8521s_sfi;
break;
case NGBE_SUBID_RGMII_FPGA:
case NGBE_SUBID_OCP_CARD:
fallthrough;
default:
hw->phy.type = ngbe_phy_internal;
break;
}
if (hw->phy.type == ngbe_phy_internal ||
hw->phy.type == ngbe_phy_internal_yt8521s_sfi)
hw->mac_type = ngbe_mac_type_mdi;
else
hw->mac_type = ngbe_mac_type_rgmii;
hw->wol_enabled = (wol_mask == NGBE_WOL_SUP) ? 1 : 0;
hw->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK ||
type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;
switch (type_mask) {
case NGBE_SUBID_LY_YT8521S_SFP:
case NGBE_SUBID_LY_M88E1512_SFP:
case NGBE_SUBID_YT8521S_SFP_GPIO:
case NGBE_SUBID_INTERNAL_YT8521S_SFP_GPIO:
hw->gpio_ctrl = 1;
break;
default:
hw->gpio_ctrl = 0;
break;
}
}
/**
* ngbe_init_rss_key - Initialize adapter RSS key
* @adapter: device handle
*
* Allocates and initializes the RSS key if it is not allocated.
**/
static inline int ngbe_init_rss_key(struct ngbe_adapter *adapter)
{
u32 *rss_key;
if (!adapter->rss_key) {
rss_key = kzalloc(NGBE_RSS_KEY_SIZE, GFP_KERNEL);
if (unlikely(!rss_key))
return -ENOMEM;
netdev_rss_key_fill(rss_key, NGBE_RSS_KEY_SIZE);
adapter->rss_key = rss_key;
}
return 0;
}
/**
* ngbe_sw_init - Initialize general software structures
* @adapter: board private structure to initialize
**/
static int ngbe_sw_init(struct ngbe_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct ngbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
u16 msix_count = 0;
int err = 0;
wxhw->hw_addr = adapter->io_addr;
wxhw->pdev = pdev;
/* PCI config space info */
err = wx_sw_init(wxhw);
if (err < 0) {
netif_err(adapter, probe, adapter->netdev,
"Read of internal subsystem device id failed\n");
return err;
}
/* mac type, phy type , oem type */
ngbe_init_type_code(hw);
wxhw->mac.max_rx_queues = NGBE_MAX_RX_QUEUES;
wxhw->mac.max_tx_queues = NGBE_MAX_TX_QUEUES;
wxhw->mac.num_rar_entries = NGBE_RAR_ENTRIES;
/* Set common capability flags and settings */
adapter->max_q_vectors = NGBE_MAX_MSIX_VECTORS;
err = wx_get_pcie_msix_counts(wxhw, &msix_count, NGBE_MAX_MSIX_VECTORS);
if (err)
dev_err(&pdev->dev, "Do not support MSI-X\n");
wxhw->mac.max_msix_vectors = msix_count;
adapter->mac_table = kcalloc(wxhw->mac.num_rar_entries,
sizeof(struct ngbe_mac_addr),
GFP_KERNEL);
if (!adapter->mac_table) {
dev_err(&pdev->dev, "mac_table allocation failed: %d\n", err);
return -ENOMEM;
}
if (ngbe_init_rss_key(adapter))
return -ENOMEM;
/* enable itr by default in dynamic mode */
adapter->rx_itr_setting = 1;
adapter->tx_itr_setting = 1;
/* set default ring sizes */
adapter->tx_ring_count = NGBE_DEFAULT_TXD;
adapter->rx_ring_count = NGBE_DEFAULT_RXD;
/* set default work limits */
adapter->tx_work_limit = NGBE_DEFAULT_TX_WORK;
adapter->rx_work_limit = NGBE_DEFAULT_RX_WORK;
return 0;
}
static void ngbe_down(struct ngbe_adapter *adapter)
{
netif_carrier_off(adapter->netdev);
netif_tx_disable(adapter->netdev);
};
/**
* ngbe_open - Called when a network interface is made active
* @netdev: network interface device structure
*
* Returns 0 on success, negative value on failure
*
* The open entry point is called when a network interface is made
* active by the system (IFF_UP).
**/
static int ngbe_open(struct net_device *netdev)
{
struct ngbe_adapter *adapter = netdev_priv(netdev);
struct ngbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
wx_control_hw(wxhw, true);
return 0;
}
/**
* ngbe_close - Disables a network interface
* @netdev: network interface device structure
*
* Returns 0, this is not allowed to fail
*
* The close entry point is called when an interface is de-activated
* by the OS. The hardware is still under the drivers control, but
* needs to be disabled. A global MAC reset is issued to stop the
* hardware, and all transmit and receive resources are freed.
**/
static int ngbe_close(struct net_device *netdev)
{
struct ngbe_adapter *adapter = netdev_priv(netdev);
ngbe_down(adapter);
wx_control_hw(&adapter->hw.wxhw, false);
return 0;
}
static netdev_tx_t ngbe_xmit_frame(struct sk_buff *skb,
struct net_device *netdev)
{
return NETDEV_TX_OK;
}
/**
* ngbe_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
*
* Returns 0 on success, negative on failure
**/
static int ngbe_set_mac(struct net_device *netdev, void *p)
{
struct ngbe_adapter *adapter = netdev_priv(netdev);
struct wx_hw *wxhw = &adapter->hw.wxhw;
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
eth_hw_addr_set(netdev, addr->sa_data);
memcpy(wxhw->mac.addr, addr->sa_data, netdev->addr_len);
ngbe_mac_set_default_filter(adapter, wxhw->mac.addr);
return 0;
}
static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct ngbe_adapter *adapter = pci_get_drvdata(pdev);
......@@ -41,13 +287,22 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
netif_device_detach(netdev);
rtnl_lock();
if (netif_running(netdev))
ngbe_down(adapter);
rtnl_unlock();
wx_control_hw(&adapter->hw.wxhw, false);
pci_disable_device(pdev);
}
static void ngbe_shutdown(struct pci_dev *pdev)
{
struct ngbe_adapter *adapter = pci_get_drvdata(pdev);
bool wake;
wake = !!adapter->wol;
ngbe_dev_shutdown(pdev, &wake);
if (system_state == SYSTEM_POWER_OFF) {
......@@ -56,6 +311,14 @@ static void ngbe_shutdown(struct pci_dev *pdev)
}
}
static const struct net_device_ops ngbe_netdev_ops = {
.ndo_open = ngbe_open,
.ndo_stop = ngbe_close,
.ndo_start_xmit = ngbe_xmit_frame,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ngbe_set_mac,
};
/**
* ngbe_probe - Device Initialization Routine
* @pdev: PCI device information struct
......@@ -71,7 +334,14 @@ static int ngbe_probe(struct pci_dev *pdev,
const struct pci_device_id __always_unused *ent)
{
struct ngbe_adapter *adapter = NULL;
struct ngbe_hw *hw = NULL;
struct wx_hw *wxhw = NULL;
struct net_device *netdev;
u32 e2rom_cksum_cap = 0;
static int func_nums;
u16 e2rom_ver = 0;
u32 etrack_id = 0;
u32 saved_ver = 0;
int err;
err = pci_enable_device_mem(pdev);
......@@ -111,6 +381,9 @@ static int ngbe_probe(struct pci_dev *pdev,
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
hw = &adapter->hw;
wxhw = &hw->wxhw;
adapter->msg_enable = BIT(3) - 1;
adapter->io_addr = devm_ioremap(&pdev->dev,
pci_resource_start(pdev, 0),
......@@ -120,12 +393,101 @@ static int ngbe_probe(struct pci_dev *pdev,
goto err_pci_release_regions;
}
netdev->netdev_ops = &ngbe_netdev_ops;
netdev->features |= NETIF_F_HIGHDMA;
adapter->bd_number = func_nums;
/* setup the private structure */
err = ngbe_sw_init(adapter);
if (err)
goto err_free_mac_table;
/* check if flash load is done after hw power up */
err = wx_check_flash_load(wxhw, NGBE_SPI_ILDR_STATUS_PERST);
if (err)
goto err_free_mac_table;
err = wx_check_flash_load(wxhw, NGBE_SPI_ILDR_STATUS_PWRRST);
if (err)
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 = ngbe_reset_hw(hw);
if (err) {
dev_err(&pdev->dev, "HW Init failed: %d\n", err);
goto err_free_mac_table;
}
if (wxhw->bus.func == 0) {
wr32(wxhw, NGBE_CALSUM_CAP_STATUS, 0x0);
wr32(wxhw, NGBE_EEPROM_VERSION_STORE_REG, 0x0);
} else {
e2rom_cksum_cap = rd32(wxhw, NGBE_CALSUM_CAP_STATUS);
saved_ver = rd32(wxhw, NGBE_EEPROM_VERSION_STORE_REG);
}
wx_init_eeprom_params(wxhw);
if (wxhw->bus.func == 0 || e2rom_cksum_cap == 0) {
/* make sure the EEPROM is ready */
err = ngbe_eeprom_chksum_hostif(hw);
if (err) {
dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
err = -EIO;
goto err_free_mac_table;
}
}
adapter->wol = 0;
if (hw->wol_enabled)
adapter->wol = NGBE_PSR_WKUP_CTL_MAG;
hw->wol_enabled = !!(adapter->wol);
wr32(wxhw, NGBE_PSR_WKUP_CTL, adapter->wol);
device_set_wakeup_enable(&pdev->dev, adapter->wol);
/* Save off EEPROM version number and Option Rom version which
* together make a unique identify for the eeprom
*/
if (saved_ver) {
etrack_id = saved_ver;
} else {
wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_H,
&e2rom_ver);
etrack_id = e2rom_ver << 16;
wx_read_ee_hostif(wxhw,
wxhw->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_L,
&e2rom_ver);
etrack_id |= e2rom_ver;
wr32(wxhw, NGBE_EEPROM_VERSION_STORE_REG, etrack_id);
}
eth_hw_addr_set(netdev, wxhw->mac.perm_addr);
ngbe_mac_set_default_filter(adapter, wxhw->mac.perm_addr);
err = register_netdev(netdev);
if (err)
goto err_register;
pci_set_drvdata(pdev, adapter);
netif_info(adapter, probe, netdev,
"PHY: %s, PBA No: Wang Xun GbE Family Controller\n",
hw->phy.type == ngbe_phy_internal ? "Internal" : "External");
netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr);
return 0;
err_register:
wx_control_hw(wxhw, false);
err_free_mac_table:
kfree(adapter->mac_table);
err_pci_release_regions:
pci_disable_pcie_error_reporting(pdev);
pci_release_selected_regions(pdev,
......@@ -146,9 +508,15 @@ static int ngbe_probe(struct pci_dev *pdev,
**/
static void ngbe_remove(struct pci_dev *pdev)
{
struct ngbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev;
netdev = adapter->netdev;
unregister_netdev(netdev);
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
kfree(adapter->mac_table);
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
......
......@@ -8,11 +8,6 @@
#include <linux/netdevice.h>
/************ NGBE_register.h ************/
/* Vendor ID */
#ifndef PCI_VENDOR_ID_WANGXUN
#define PCI_VENDOR_ID_WANGXUN 0x8088
#endif
/* Device IDs */
#define NGBE_DEV_ID_EM_WX1860AL_W 0x0100
#define NGBE_DEV_ID_EM_WX1860A2 0x0101
......@@ -47,4 +42,98 @@
#define NGBE_WOL_SUP 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_ */
......@@ -35,6 +35,7 @@ struct txgbe_adapter {
struct txgbe_hw hw;
u16 msg_enable;
struct txgbe_mac_addr *mac_table;
char eeprom_id[32];
};
extern char txgbe_driver_name[];
......
......@@ -44,6 +44,218 @@ static void txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw)
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)
{
struct wx_hw *wxhw = &hw->wxhw;
......@@ -63,7 +275,6 @@ static void txgbe_reset_misc(struct txgbe_hw *hw)
int txgbe_reset_hw(struct txgbe_hw *hw)
{
struct wx_hw *wxhw = &hw->wxhw;
u32 reset = 0;
int status;
/* Call adapter stop to disable tx/rx and clear interrupts */
......@@ -71,10 +282,10 @@ int txgbe_reset_hw(struct txgbe_hw *hw)
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));
if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP)))
wx_reset_hostif(wxhw);
WX_WRITE_FLUSH(wxhw);
usleep_range(10, 100);
status = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wxhw->bus.func));
......
......@@ -4,6 +4,8 @@
#ifndef _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);
#endif /* _TXGBE_HW_H_ */
......@@ -158,6 +158,14 @@ static int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 poo
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)
{
struct net_device *netdev = adapter->netdev;
......@@ -270,6 +278,10 @@ static int txgbe_sw_init(struct txgbe_adapter *adapter)
**/
static int txgbe_open(struct net_device *netdev)
{
struct txgbe_adapter *adapter = netdev_priv(netdev);
txgbe_up_complete(adapter);
return 0;
}
......@@ -301,6 +313,7 @@ static int txgbe_close(struct net_device *netdev)
struct txgbe_adapter *adapter = netdev_priv(netdev);
txgbe_down(adapter);
wx_control_hw(&adapter->hw.wxhw, false);
return 0;
}
......@@ -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 net_device *netdev = adapter->netdev;
struct txgbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
netif_device_detach(netdev);
......@@ -317,6 +332,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
txgbe_close_suspend(adapter);
rtnl_unlock();
wx_control_hw(wxhw, false);
pci_disable_device(pdev);
}
......@@ -393,6 +410,12 @@ static int txgbe_probe(struct pci_dev *pdev,
struct net_device *netdev;
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);
if (err)
return err;
......@@ -457,6 +480,12 @@ static int txgbe_probe(struct pci_dev *pdev,
if (err)
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);
if (err) {
dev_err(&pdev->dev, "HW Init failed: %d\n", err);
......@@ -465,12 +494,59 @@ static int txgbe_probe(struct pci_dev *pdev,
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);
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);
if (err)
goto err_free_mac_table;
goto err_release_hw;
pci_set_drvdata(pdev, adapter);
......@@ -488,10 +564,17 @@ static int txgbe_probe(struct pci_dev *pdev,
else
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);
return 0;
err_release_hw:
wx_control_hw(wxhw, false);
err_free_mac_table:
kfree(adapter->mac_table);
err_pci_release_regions:
......
......@@ -53,6 +53,20 @@
#define TXGBE_TS_CTL 0x10300
#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 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