Commit 92c7076e authored by David S. Miller's avatar David S. Miller

Merge branch 'txgbe'

Jiawen Wu says:

====================
net: WangXun txgbe ethernet driver

This patch series adds support for WangXun 10 gigabit NIC, to initialize
hardware, set mac address, and register netdev.

Change log:
v6: address comments:
    Jakub Kicinski: check with scripts/kernel-doc
v5: address comments:
    Jakub Kicinski: clean build with W=1 C=1
v4: address comments:
    Andrew Lunn: https://lore.kernel.org/all/YzXROBtztWopeeaA@lunn.ch/
v3: address comments:
    Andrew Lunn: remove hw function ops, reorder functions, use BIT(n)
                 for register bit offset, move the same code of txgbe
                 and ngbe to libwx
v2: address comments:
    Andrew Lunn: https://lore.kernel.org/netdev/YvRhld5rD%2FxgITEg@lunn.ch/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 957ed5e7 d21d2c7f
...@@ -16,6 +16,11 @@ config NET_VENDOR_WANGXUN ...@@ -16,6 +16,11 @@ config NET_VENDOR_WANGXUN
if NET_VENDOR_WANGXUN if NET_VENDOR_WANGXUN
config LIBWX
tristate
help
Common library for Wangxun(R) Ethernet drivers.
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
...@@ -32,6 +37,7 @@ config NGBE ...@@ -32,6 +37,7 @@ config NGBE
config TXGBE config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support" tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI depends on PCI
select LIBWX
help help
This driver supports Wangxun(R) 10GbE PCI Express family of This driver supports Wangxun(R) 10GbE PCI Express family of
adapters. adapters.
......
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
# Makefile for the Wangxun network device drivers. # Makefile for the Wangxun network device drivers.
# #
obj-$(CONFIG_LIBWX) += libwx/
obj-$(CONFIG_TXGBE) += txgbe/ obj-$(CONFIG_TXGBE) += txgbe/
obj-$(CONFIG_NGBE) += ngbe/ obj-$(CONFIG_NGBE) += ngbe/
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd.
#
obj-$(CONFIG_LIBWX) += libwx.o
libwx-objs := wx_hw.o
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/iopoll.h>
#include <linux/pci.h>
#include "wx_type.h"
#include "wx_hw.h"
static void wx_intr_disable(struct wx_hw *wxhw, u64 qmask)
{
u32 mask;
mask = (qmask & 0xFFFFFFFF);
if (mask)
wr32(wxhw, WX_PX_IMS(0), mask);
if (wxhw->mac.type == wx_mac_sp) {
mask = (qmask >> 32);
if (mask)
wr32(wxhw, WX_PX_IMS(1), mask);
}
}
/* cmd_addr is used for some special command:
* 1. to be sector address, when implemented erase sector command
* 2. to be flash address when implemented read, write flash address
*/
static int wx_fmgr_cmd_op(struct wx_hw *wxhw, u32 cmd, u32 cmd_addr)
{
u32 cmd_val = 0, val = 0;
cmd_val = WX_SPI_CMD_CMD(cmd) |
WX_SPI_CMD_CLK(WX_SPI_CLK_DIV) |
cmd_addr;
wr32(wxhw, WX_SPI_CMD, cmd_val);
return read_poll_timeout(rd32, val, (val & 0x1), 10, 100000,
false, wxhw, WX_SPI_STATUS);
}
static int wx_flash_read_dword(struct wx_hw *wxhw, u32 addr, u32 *data)
{
int ret = 0;
ret = wx_fmgr_cmd_op(wxhw, WX_SPI_CMD_READ_DWORD, addr);
if (ret < 0)
return ret;
*data = rd32(wxhw, WX_SPI_DATA);
return ret;
}
int wx_check_flash_load(struct wx_hw *hw, u32 check_bit)
{
u32 reg = 0;
int err = 0;
/* if there's flash existing */
if (!(rd32(hw, WX_SPI_STATUS) &
WX_SPI_STATUS_FLASH_BYPASS)) {
/* wait hw load flash done */
err = read_poll_timeout(rd32, reg, !(reg & check_bit), 20000, 2000000,
false, hw, WX_SPI_ILDR_STATUS);
if (err < 0)
wx_err(hw, "Check flash load timeout.\n");
}
return err;
}
EXPORT_SYMBOL(wx_check_flash_load);
/**
* wx_get_mac_addr - Generic get MAC address
* @wxhw: pointer to hardware structure
* @mac_addr: Adapter MAC address
*
* Reads the adapter's MAC address from first Receive Address Register (RAR0)
* A reset of the adapter must be performed prior to calling this function
* in order for the MAC address to have been loaded from the EEPROM into RAR0
**/
void wx_get_mac_addr(struct wx_hw *wxhw, u8 *mac_addr)
{
u32 rar_high;
u32 rar_low;
u16 i;
wr32(wxhw, WX_PSR_MAC_SWC_IDX, 0);
rar_high = rd32(wxhw, WX_PSR_MAC_SWC_AD_H);
rar_low = rd32(wxhw, WX_PSR_MAC_SWC_AD_L);
for (i = 0; i < 2; i++)
mac_addr[i] = (u8)(rar_high >> (1 - i) * 8);
for (i = 0; i < 4; i++)
mac_addr[i + 2] = (u8)(rar_low >> (3 - i) * 8);
}
EXPORT_SYMBOL(wx_get_mac_addr);
/**
* wx_set_rar - Set Rx address register
* @wxhw: pointer to hardware structure
* @index: Receive address register to write
* @addr: Address to put into receive address register
* @pools: VMDq "set" or "pool" index
* @enable_addr: set flag that address is active
*
* Puts an ethernet address into a receive address register.
**/
int wx_set_rar(struct wx_hw *wxhw, u32 index, u8 *addr, u64 pools,
u32 enable_addr)
{
u32 rar_entries = wxhw->mac.num_rar_entries;
u32 rar_low, rar_high;
/* Make sure we are using a valid rar index range */
if (index >= rar_entries) {
wx_err(wxhw, "RAR index %d is out of range.\n", index);
return -EINVAL;
}
/* select the MAC address */
wr32(wxhw, WX_PSR_MAC_SWC_IDX, index);
/* setup VMDq pool mapping */
wr32(wxhw, WX_PSR_MAC_SWC_VM_L, pools & 0xFFFFFFFF);
if (wxhw->mac.type == wx_mac_sp)
wr32(wxhw, WX_PSR_MAC_SWC_VM_H, pools >> 32);
/* HW expects these in little endian so we reverse the byte
* order from network order (big endian) to little endian
*
* Some parts put the VMDq setting in the extra RAH bits,
* so save everything except the lower 16 bits that hold part
* of the address and the address valid bit.
*/
rar_low = ((u32)addr[5] |
((u32)addr[4] << 8) |
((u32)addr[3] << 16) |
((u32)addr[2] << 24));
rar_high = ((u32)addr[1] |
((u32)addr[0] << 8));
if (enable_addr != 0)
rar_high |= WX_PSR_MAC_SWC_AD_H_AV;
wr32(wxhw, WX_PSR_MAC_SWC_AD_L, rar_low);
wr32m(wxhw, WX_PSR_MAC_SWC_AD_H,
(WX_PSR_MAC_SWC_AD_H_AD(~0) |
WX_PSR_MAC_SWC_AD_H_ADTYPE(~0) |
WX_PSR_MAC_SWC_AD_H_AV),
rar_high);
return 0;
}
EXPORT_SYMBOL(wx_set_rar);
/**
* wx_clear_rar - Remove Rx address register
* @wxhw: pointer to hardware structure
* @index: Receive address register to write
*
* Clears an ethernet address from a receive address register.
**/
int wx_clear_rar(struct wx_hw *wxhw, u32 index)
{
u32 rar_entries = wxhw->mac.num_rar_entries;
/* Make sure we are using a valid rar index range */
if (index >= rar_entries) {
wx_err(wxhw, "RAR index %d is out of range.\n", index);
return -EINVAL;
}
/* Some parts put the VMDq setting in the extra RAH bits,
* so save everything except the lower 16 bits that hold part
* of the address and the address valid bit.
*/
wr32(wxhw, WX_PSR_MAC_SWC_IDX, index);
wr32(wxhw, WX_PSR_MAC_SWC_VM_L, 0);
wr32(wxhw, WX_PSR_MAC_SWC_VM_H, 0);
wr32(wxhw, WX_PSR_MAC_SWC_AD_L, 0);
wr32m(wxhw, WX_PSR_MAC_SWC_AD_H,
(WX_PSR_MAC_SWC_AD_H_AD(~0) |
WX_PSR_MAC_SWC_AD_H_ADTYPE(~0) |
WX_PSR_MAC_SWC_AD_H_AV),
0);
return 0;
}
EXPORT_SYMBOL(wx_clear_rar);
/**
* wx_clear_vmdq - Disassociate a VMDq pool index from a rx address
* @wxhw: pointer to hardware struct
* @rar: receive address register index to disassociate
* @vmdq: VMDq pool index to remove from the rar
**/
static int wx_clear_vmdq(struct wx_hw *wxhw, u32 rar, u32 __maybe_unused vmdq)
{
u32 rar_entries = wxhw->mac.num_rar_entries;
u32 mpsar_lo, mpsar_hi;
/* Make sure we are using a valid rar index range */
if (rar >= rar_entries) {
wx_err(wxhw, "RAR index %d is out of range.\n", rar);
return -EINVAL;
}
wr32(wxhw, WX_PSR_MAC_SWC_IDX, rar);
mpsar_lo = rd32(wxhw, WX_PSR_MAC_SWC_VM_L);
mpsar_hi = rd32(wxhw, WX_PSR_MAC_SWC_VM_H);
if (!mpsar_lo && !mpsar_hi)
return 0;
/* was that the last pool using this rar? */
if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
wx_clear_rar(wxhw, rar);
return 0;
}
/**
* wx_init_uta_tables - Initialize the Unicast Table Array
* @wxhw: pointer to hardware structure
**/
static void wx_init_uta_tables(struct wx_hw *wxhw)
{
int i;
wx_dbg(wxhw, " Clearing UTA\n");
for (i = 0; i < 128; i++)
wr32(wxhw, WX_PSR_UC_TBL(i), 0);
}
/**
* wx_init_rx_addrs - Initializes receive address filters.
* @wxhw: pointer to hardware structure
*
* Places the MAC address in receive address register 0 and clears the rest
* of the receive address registers. Clears the multicast table. Assumes
* the receiver is in reset when the routine is called.
**/
void wx_init_rx_addrs(struct wx_hw *wxhw)
{
u32 rar_entries = wxhw->mac.num_rar_entries;
u32 psrctl;
int i;
/* If the current mac address is valid, assume it is a software override
* to the permanent address.
* Otherwise, use the permanent address from the eeprom.
*/
if (!is_valid_ether_addr(wxhw->mac.addr)) {
/* Get the MAC address from the RAR0 for later reference */
wx_get_mac_addr(wxhw, wxhw->mac.addr);
wx_dbg(wxhw, "Keeping Current RAR0 Addr = %pM\n", wxhw->mac.addr);
} else {
/* Setup the receive address. */
wx_dbg(wxhw, "Overriding MAC Address in RAR[0]\n");
wx_dbg(wxhw, "New MAC Addr = %pM\n", wxhw->mac.addr);
wx_set_rar(wxhw, 0, wxhw->mac.addr, 0, WX_PSR_MAC_SWC_AD_H_AV);
if (wxhw->mac.type == wx_mac_sp) {
/* clear VMDq pool/queue selection for RAR 0 */
wx_clear_vmdq(wxhw, 0, WX_CLEAR_VMDQ_ALL);
}
}
/* Zero out the other receive addresses. */
wx_dbg(wxhw, "Clearing RAR[1-%d]\n", rar_entries - 1);
for (i = 1; i < rar_entries; i++) {
wr32(wxhw, WX_PSR_MAC_SWC_IDX, i);
wr32(wxhw, WX_PSR_MAC_SWC_AD_L, 0);
wr32(wxhw, WX_PSR_MAC_SWC_AD_H, 0);
}
/* Clear the MTA */
wxhw->addr_ctrl.mta_in_use = 0;
psrctl = rd32(wxhw, WX_PSR_CTL);
psrctl &= ~(WX_PSR_CTL_MO | WX_PSR_CTL_MFE);
psrctl |= wxhw->mac.mc_filter_type << WX_PSR_CTL_MO_SHIFT;
wr32(wxhw, WX_PSR_CTL, psrctl);
wx_dbg(wxhw, " Clearing MTA\n");
for (i = 0; i < wxhw->mac.mcft_size; i++)
wr32(wxhw, WX_PSR_MC_TBL(i), 0);
wx_init_uta_tables(wxhw);
}
EXPORT_SYMBOL(wx_init_rx_addrs);
void wx_disable_rx(struct wx_hw *wxhw)
{
u32 pfdtxgswc;
u32 rxctrl;
rxctrl = rd32(wxhw, WX_RDB_PB_CTL);
if (rxctrl & WX_RDB_PB_CTL_RXEN) {
pfdtxgswc = rd32(wxhw, WX_PSR_CTL);
if (pfdtxgswc & WX_PSR_CTL_SW_EN) {
pfdtxgswc &= ~WX_PSR_CTL_SW_EN;
wr32(wxhw, WX_PSR_CTL, pfdtxgswc);
wxhw->mac.set_lben = true;
} else {
wxhw->mac.set_lben = false;
}
rxctrl &= ~WX_RDB_PB_CTL_RXEN;
wr32(wxhw, WX_RDB_PB_CTL, rxctrl);
if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
/* disable mac receiver */
wr32m(wxhw, WX_MAC_RX_CFG,
WX_MAC_RX_CFG_RE, 0);
}
}
}
EXPORT_SYMBOL(wx_disable_rx);
/**
* wx_disable_pcie_master - Disable PCI-express master access
* @wxhw: pointer to hardware structure
*
* Disables PCI-Express master access and verifies there are no pending
* requests.
**/
int wx_disable_pcie_master(struct wx_hw *wxhw)
{
int status = 0;
u32 val;
/* Always set this bit to ensure any future transactions are blocked */
pci_clear_master(wxhw->pdev);
/* Exit if master requests are blocked */
if (!(rd32(wxhw, WX_PX_TRANSACTION_PENDING)))
return 0;
/* Poll for master request bit to clear */
status = read_poll_timeout(rd32, val, !val, 100, WX_PCI_MASTER_DISABLE_TIMEOUT,
false, wxhw, WX_PX_TRANSACTION_PENDING);
if (status < 0)
wx_err(wxhw, "PCIe transaction pending bit did not clear.\n");
return status;
}
EXPORT_SYMBOL(wx_disable_pcie_master);
/**
* wx_stop_adapter - Generic stop Tx/Rx units
* @wxhw: pointer to hardware structure
*
* Sets the adapter_stopped flag within wx_hw struct. Clears interrupts,
* disables transmit and receive units. The adapter_stopped flag is used by
* the shared code and drivers to determine if the adapter is in a stopped
* state and should not touch the hardware.
**/
int wx_stop_adapter(struct wx_hw *wxhw)
{
u16 i;
/* Set the adapter_stopped flag so other driver functions stop touching
* the hardware
*/
wxhw->adapter_stopped = true;
/* Disable the receive unit */
wx_disable_rx(wxhw);
/* Set interrupt mask to stop interrupts from being generated */
wx_intr_disable(wxhw, WX_INTR_ALL);
/* Clear any pending interrupts, flush previous writes */
wr32(wxhw, WX_PX_MISC_IC, 0xffffffff);
wr32(wxhw, WX_BME_CTL, 0x3);
/* Disable the transmit unit. Each queue must be disabled. */
for (i = 0; i < wxhw->mac.max_tx_queues; i++) {
wr32m(wxhw, WX_PX_TR_CFG(i),
WX_PX_TR_CFG_SWFLSH | WX_PX_TR_CFG_ENABLE,
WX_PX_TR_CFG_SWFLSH);
}
/* Disable the receive unit by stopping each queue */
for (i = 0; i < wxhw->mac.max_rx_queues; i++) {
wr32m(wxhw, WX_PX_RR_CFG(i),
WX_PX_RR_CFG_RR_EN, 0);
}
/* flush all queues disables */
WX_WRITE_FLUSH(wxhw);
/* Prevent the PCI-E bus from hanging by disabling PCI-E master
* access and verify no pending requests
*/
return wx_disable_pcie_master(wxhw);
}
EXPORT_SYMBOL(wx_stop_adapter);
void wx_reset_misc(struct wx_hw *wxhw)
{
int i;
/* receive packets that size > 2048 */
wr32m(wxhw, WX_MAC_RX_CFG, WX_MAC_RX_CFG_JE, WX_MAC_RX_CFG_JE);
/* clear counters on read */
wr32m(wxhw, WX_MMC_CONTROL,
WX_MMC_CONTROL_RSTONRD, WX_MMC_CONTROL_RSTONRD);
wr32m(wxhw, WX_MAC_RX_FLOW_CTRL,
WX_MAC_RX_FLOW_CTRL_RFE, WX_MAC_RX_FLOW_CTRL_RFE);
wr32(wxhw, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
wr32m(wxhw, WX_MIS_RST_ST,
WX_MIS_RST_ST_RST_INIT, 0x1E00);
/* errata 4: initialize mng flex tbl and wakeup flex tbl*/
wr32(wxhw, WX_PSR_MNG_FLEX_SEL, 0);
for (i = 0; i < 16; i++) {
wr32(wxhw, WX_PSR_MNG_FLEX_DW_L(i), 0);
wr32(wxhw, WX_PSR_MNG_FLEX_DW_H(i), 0);
wr32(wxhw, WX_PSR_MNG_FLEX_MSK(i), 0);
}
wr32(wxhw, WX_PSR_LAN_FLEX_SEL, 0);
for (i = 0; i < 16; i++) {
wr32(wxhw, WX_PSR_LAN_FLEX_DW_L(i), 0);
wr32(wxhw, WX_PSR_LAN_FLEX_DW_H(i), 0);
wr32(wxhw, WX_PSR_LAN_FLEX_MSK(i), 0);
}
/* set pause frame dst mac addr */
wr32(wxhw, WX_RDB_PFCMACDAL, 0xC2000001);
wr32(wxhw, WX_RDB_PFCMACDAH, 0x0180);
}
EXPORT_SYMBOL(wx_reset_misc);
int wx_sw_init(struct wx_hw *wxhw)
{
struct pci_dev *pdev = wxhw->pdev;
u32 ssid = 0;
int err = 0;
wxhw->vendor_id = pdev->vendor;
wxhw->device_id = pdev->device;
wxhw->revision_id = pdev->revision;
wxhw->oem_svid = pdev->subsystem_vendor;
wxhw->oem_ssid = pdev->subsystem_device;
wxhw->bus.device = PCI_SLOT(pdev->devfn);
wxhw->bus.func = PCI_FUNC(pdev->devfn);
if (wxhw->oem_svid == PCI_VENDOR_ID_WANGXUN) {
wxhw->subsystem_vendor_id = pdev->subsystem_vendor;
wxhw->subsystem_device_id = pdev->subsystem_device;
} else {
err = wx_flash_read_dword(wxhw, 0xfffdc, &ssid);
if (!err)
wxhw->subsystem_device_id = swab16((u16)ssid);
return err;
}
return 0;
}
EXPORT_SYMBOL(wx_sw_init);
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
#ifndef _WX_HW_H_
#define _WX_HW_H_
int wx_check_flash_load(struct wx_hw *hw, u32 check_bit);
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);
void wx_init_rx_addrs(struct wx_hw *wxhw);
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_sw_init(struct wx_hw *wxhw);
#endif /* _WX_HW_H_ */
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
#ifndef _WX_TYPE_H_
#define _WX_TYPE_H_
/* Vendor ID */
#ifndef PCI_VENDOR_ID_WANGXUN
#define PCI_VENDOR_ID_WANGXUN 0x8088
#endif
#define WX_NCSI_SUP 0x8000
#define WX_NCSI_MASK 0x8000
#define WX_WOL_SUP 0x4000
#define WX_WOL_MASK 0x4000
/**************** 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_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)
/* FMGR Registers */
#define WX_SPI_CMD 0x10104
#define WX_SPI_CMD_READ_DWORD 0x1
#define WX_SPI_CLK_DIV 0x3
#define WX_SPI_CMD_CMD(_v) (((_v) & 0x7) << 28)
#define WX_SPI_CMD_CLK(_v) (((_v) & 0x7) << 25)
#define WX_SPI_CMD_ADDR(_v) (((_v) & 0xFFFFFF))
#define WX_SPI_DATA 0x10108
#define WX_SPI_DATA_BYPASS BIT(31)
#define WX_SPI_DATA_STATUS(_v) (((_v) & 0xFF) << 16)
#define WX_SPI_DATA_OP_DONE BIT(0)
#define WX_SPI_STATUS 0x1010C
#define WX_SPI_STATUS_OPDONE BIT(0)
#define WX_SPI_STATUS_FLASH_BYPASS BIT(31)
#define WX_SPI_ILDR_STATUS 0x10120
/* Sensors for PVT(Process Voltage Temperature) */
#define WX_TS_EN 0x10304
#define WX_TS_EN_ENA BIT(0)
#define WX_TS_ALARM_THRE 0x1030C
#define WX_TS_DALARM_THRE 0x10310
#define WX_TS_INT_EN 0x10314
#define WX_TS_INT_EN_DALARM_INT_EN BIT(1)
#define WX_TS_INT_EN_ALARM_INT_EN BIT(0)
#define WX_TS_ALARM_ST 0x10318
#define WX_TS_ALARM_ST_DALARM BIT(1)
#define WX_TS_ALARM_ST_ALARM BIT(0)
/*********************** Transmit DMA registers **************************/
/* transmit global control */
#define WX_TDM_CTL 0x18000
/* TDM CTL BIT */
#define WX_TDM_CTL_TE BIT(0) /* Transmit Enable */
/***************************** RDB registers *********************************/
/* receive packet buffer */
#define WX_RDB_PB_CTL 0x19000
#define WX_RDB_PB_CTL_RXEN BIT(31) /* Enable Receiver */
#define WX_RDB_PB_CTL_DISABLED BIT(0)
/* statistic */
#define WX_RDB_PFCMACDAL 0x19210
#define WX_RDB_PFCMACDAH 0x19214
/******************************* PSR Registers *******************************/
/* psr control */
#define WX_PSR_CTL 0x15000
/* Header split receive */
#define WX_PSR_CTL_SW_EN BIT(18)
#define WX_PSR_CTL_RSC_ACK BIT(17)
#define WX_PSR_CTL_RSC_DIS BIT(16)
#define WX_PSR_CTL_PCSD BIT(13)
#define WX_PSR_CTL_IPPCSE BIT(12)
#define WX_PSR_CTL_BAM BIT(10)
#define WX_PSR_CTL_UPE BIT(9)
#define WX_PSR_CTL_MPE BIT(8)
#define WX_PSR_CTL_MFE BIT(7)
#define WX_PSR_CTL_MO_SHIFT 5
#define WX_PSR_CTL_MO (0x3 << WX_PSR_CTL_MO_SHIFT)
#define WX_PSR_CTL_TPE BIT(4)
/* mcasst/ucast overflow tbl */
#define WX_PSR_MC_TBL(_i) (0x15200 + ((_i) * 4))
#define WX_PSR_UC_TBL(_i) (0x15400 + ((_i) * 4))
/* Management */
#define WX_PSR_MNG_FLEX_SEL 0x1582C
#define WX_PSR_MNG_FLEX_DW_L(_i) (0x15A00 + ((_i) * 16))
#define WX_PSR_MNG_FLEX_DW_H(_i) (0x15A04 + ((_i) * 16))
#define WX_PSR_MNG_FLEX_MSK(_i) (0x15A08 + ((_i) * 16))
#define WX_PSR_LAN_FLEX_SEL 0x15B8C
#define WX_PSR_LAN_FLEX_DW_L(_i) (0x15C00 + ((_i) * 16))
#define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16))
#define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16))
/* mac switcher */
#define WX_PSR_MAC_SWC_AD_L 0x16200
#define WX_PSR_MAC_SWC_AD_H 0x16204
#define WX_PSR_MAC_SWC_AD_H_AD(v) (((v) & 0xFFFF))
#define WX_PSR_MAC_SWC_AD_H_ADTYPE(v) (((v) & 0x1) << 30)
#define WX_PSR_MAC_SWC_AD_H_AV BIT(31)
#define WX_PSR_MAC_SWC_VM_L 0x16208
#define WX_PSR_MAC_SWC_VM_H 0x1620C
#define WX_PSR_MAC_SWC_IDX 0x16210
#define WX_CLEAR_VMDQ_ALL 0xFFFFFFFFU
/************************************* ETH MAC *****************************/
#define WX_MAC_TX_CFG 0x11000
#define WX_MAC_TX_CFG_TE BIT(0)
#define WX_MAC_RX_CFG 0x11004
#define WX_MAC_RX_CFG_RE BIT(0)
#define WX_MAC_RX_CFG_JE BIT(8)
#define WX_MAC_PKT_FLT 0x11008
#define WX_MAC_PKT_FLT_PR BIT(0) /* promiscuous mode */
#define WX_MAC_RX_FLOW_CTRL 0x11090
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
#define WX_MMC_CONTROL 0x11800
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
/********************************* BAR registers ***************************/
/* Interrupt Registers */
#define WX_BME_CTL 0x12020
#define WX_PX_MISC_IC 0x100
#define WX_PX_IMS(_i) (0x140 + (_i) * 4)
#define WX_PX_TRANSACTION_PENDING 0x168
/* transmit DMA Registers */
#define WX_PX_TR_CFG(_i) (0x03010 + ((_i) * 0x40))
/* Transmit Config masks */
#define WX_PX_TR_CFG_ENABLE BIT(0) /* Ena specific Tx Queue */
#define WX_PX_TR_CFG_TR_SIZE_SHIFT 1 /* tx desc number per ring */
#define WX_PX_TR_CFG_SWFLSH BIT(26) /* Tx Desc. wr-bk flushing */
#define WX_PX_TR_CFG_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */
#define WX_PX_TR_CFG_THRE_SHIFT 8
/* Receive DMA Registers */
#define WX_PX_RR_CFG(_i) (0x01010 + ((_i) * 0x40))
/* PX_RR_CFG bit definitions */
#define WX_PX_RR_CFG_RR_EN BIT(0)
/* Number of 80 microseconds we wait for PCI Express master disable */
#define WX_PCI_MASTER_DISABLE_TIMEOUT 80000
/* Bus parameters */
struct wx_bus_info {
u8 func;
u16 device;
};
struct wx_thermal_sensor_data {
s16 temp;
s16 alarm_thresh;
s16 dalarm_thresh;
};
enum wx_mac_type {
wx_mac_unknown = 0,
wx_mac_sp,
wx_mac_em
};
struct wx_mac_info {
enum wx_mac_type type;
bool set_lben;
u8 addr[ETH_ALEN];
u8 perm_addr[ETH_ALEN];
s32 mc_filter_type;
u32 mcft_size;
u32 num_rar_entries;
u32 max_tx_queues;
u32 max_rx_queues;
struct wx_thermal_sensor_data sensor;
};
struct wx_addr_filter_info {
u32 num_mc_addrs;
u32 mta_in_use;
bool user_set_promisc;
};
struct wx_hw {
u8 __iomem *hw_addr;
struct pci_dev *pdev;
struct wx_bus_info bus;
struct wx_mac_info mac;
struct wx_addr_filter_info addr_ctrl;
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
u16 subsystem_vendor_id;
u8 revision_id;
u16 oem_ssid;
u16 oem_svid;
bool adapter_stopped;
};
#define WX_INTR_ALL (~0ULL)
/* register operations */
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define rd32(a, reg) readl((a)->hw_addr + (reg))
static inline u32
rd32m(struct wx_hw *wxhw, u32 reg, u32 mask)
{
u32 val;
val = rd32(wxhw, reg);
return val & mask;
}
static inline void
wr32m(struct wx_hw *wxhw, u32 reg, u32 mask, u32 field)
{
u32 val;
val = rd32(wxhw, reg);
val = ((val & ~mask) | (field & mask));
wr32(wxhw, reg, val);
}
/* On some domestic CPU platforms, sometimes IO is not synchronized with
* flushing memory, here use readl() to flush PCI read and write.
*/
#define WX_WRITE_FLUSH(H) rd32(H, WX_MIS_PWR)
#define wx_err(wxhw, fmt, arg...) \
dev_err(&(wxhw)->pdev->dev, fmt, ##arg)
#define wx_dbg(wxhw, fmt, arg...) \
dev_dbg(&(wxhw)->pdev->dev, fmt, ##arg)
#endif /* _WX_TYPE_H_ */
...@@ -6,4 +6,5 @@ ...@@ -6,4 +6,5 @@
obj-$(CONFIG_TXGBE) += txgbe.o obj-$(CONFIG_TXGBE) += txgbe.o
txgbe-objs := txgbe_main.o txgbe-objs := txgbe_main.o \
txgbe_hw.o
...@@ -4,19 +4,37 @@ ...@@ -4,19 +4,37 @@
#ifndef _TXGBE_H_ #ifndef _TXGBE_H_
#define _TXGBE_H_ #define _TXGBE_H_
#include "txgbe_type.h"
#define TXGBE_MAX_FDIR_INDICES 63 #define TXGBE_MAX_FDIR_INDICES 63
#define TXGBE_MAX_RX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1) #define TXGBE_MAX_RX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
#define TXGBE_MAX_TX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1) #define TXGBE_MAX_TX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
#define TXGBE_SP_MAX_TX_QUEUES 128
#define TXGBE_SP_MAX_RX_QUEUES 128
#define TXGBE_SP_RAR_ENTRIES 128
#define TXGBE_SP_MC_TBL_SIZE 128
struct txgbe_mac_addr {
u8 addr[ETH_ALEN];
u16 state; /* bitmask */
u64 pools;
};
#define TXGBE_MAC_STATE_DEFAULT 0x1
#define TXGBE_MAC_STATE_MODIFIED 0x2
#define TXGBE_MAC_STATE_IN_USE 0x4
/* board specific private data structure */ /* board specific private data structure */
struct txgbe_adapter { struct txgbe_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 txgbe_type.h */
struct txgbe_hw hw;
u16 msg_enable;
struct txgbe_mac_addr *mac_table;
}; };
extern char txgbe_driver_name[]; extern char txgbe_driver_name[];
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/string.h>
#include <linux/iopoll.h>
#include <linux/types.h>
#include <linux/pci.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_hw.h"
#include "txgbe.h"
/**
* txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
* @hw: pointer to hardware structure
*
* Inits the thermal sensor thresholds according to the NVM map
* and save off the threshold and location values into mac.thermal_sensor_data
**/
static void txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw)
{
struct wx_hw *wxhw = &hw->wxhw;
struct wx_thermal_sensor_data *data = &wxhw->mac.sensor;
memset(data, 0, sizeof(struct wx_thermal_sensor_data));
/* Only support thermal sensors attached to SP physical port 0 */
if (wxhw->bus.func)
return;
wr32(wxhw, TXGBE_TS_CTL, TXGBE_TS_CTL_EVAL_MD);
wr32(wxhw, WX_TS_INT_EN,
WX_TS_INT_EN_ALARM_INT_EN | WX_TS_INT_EN_DALARM_INT_EN);
wr32(wxhw, WX_TS_EN, WX_TS_EN_ENA);
data->alarm_thresh = 100;
wr32(wxhw, WX_TS_ALARM_THRE, 677);
data->dalarm_thresh = 90;
wr32(wxhw, WX_TS_DALARM_THRE, 614);
}
static void txgbe_reset_misc(struct txgbe_hw *hw)
{
struct wx_hw *wxhw = &hw->wxhw;
wx_reset_misc(wxhw);
txgbe_init_thermal_sensor_thresh(hw);
}
/**
* txgbe_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 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 */
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));
WX_WRITE_FLUSH(wxhw);
usleep_range(10, 100);
status = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wxhw->bus.func));
if (status != 0)
return status;
txgbe_reset_misc(hw);
/* Store the permanent mac address */
wx_get_mac_addr(wxhw, wxhw->mac.perm_addr);
/* Store MAC address from RAR0, clear receive address registers, and
* clear the multicast table. Also reset num_rar_entries to 128,
* since we modify this value when programming the SAN MAC address.
*/
wxhw->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;
wx_init_rx_addrs(wxhw);
pci_set_master(wxhw->pdev);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
#ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_
int txgbe_reset_hw(struct txgbe_hw *hw);
#endif /* _TXGBE_HW_H_ */
...@@ -8,7 +8,12 @@ ...@@ -8,7 +8,12 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/ip.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_hw.h"
#include "txgbe.h" #include "txgbe.h"
char txgbe_driver_name[] = "txgbe"; char txgbe_driver_name[] = "txgbe";
...@@ -30,6 +35,276 @@ static const struct pci_device_id txgbe_pci_tbl[] = { ...@@ -30,6 +35,276 @@ static const struct pci_device_id txgbe_pci_tbl[] = {
#define DEFAULT_DEBUG_LEVEL_SHIFT 3 #define DEFAULT_DEBUG_LEVEL_SHIFT 3
static void txgbe_check_minimum_link(struct txgbe_adapter *adapter)
{
struct pci_dev *pdev;
pdev = adapter->pdev;
pcie_print_link_status(pdev);
}
/**
* txgbe_enumerate_functions - Get the number of ports this device has
* @adapter: adapter structure
*
* This function enumerates the phsyical functions co-located on a single slot,
* in order to determine how many ports a device has. This is most useful in
* determining the required GT/s of PCIe bandwidth necessary for optimal
* performance.
**/
static int txgbe_enumerate_functions(struct txgbe_adapter *adapter)
{
struct pci_dev *entry, *pdev = adapter->pdev;
int physfns = 0;
list_for_each_entry(entry, &pdev->bus->devices, bus_list) {
/* When the devices on the bus don't all match our device ID,
* we can't reliably determine the correct number of
* functions. This can occur if a function has been direct
* attached to a virtual machine using VT-d.
*/
if (entry->vendor != pdev->vendor ||
entry->device != pdev->device)
return -EINVAL;
physfns++;
}
return physfns;
}
static void txgbe_sync_mac_table(struct txgbe_adapter *adapter)
{
struct txgbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
int i;
for (i = 0; i < wxhw->mac.num_rar_entries; i++) {
if (adapter->mac_table[i].state & TXGBE_MAC_STATE_MODIFIED) {
if (adapter->mac_table[i].state & TXGBE_MAC_STATE_IN_USE) {
wx_set_rar(wxhw, i,
adapter->mac_table[i].addr,
adapter->mac_table[i].pools,
WX_PSR_MAC_SWC_AD_H_AV);
} else {
wx_clear_rar(wxhw, i);
}
adapter->mac_table[i].state &= ~(TXGBE_MAC_STATE_MODIFIED);
}
}
}
/* this function destroys the first RAR entry */
static void txgbe_mac_set_default_filter(struct txgbe_adapter *adapter,
u8 *addr)
{
struct wx_hw *wxhw = &adapter->hw.wxhw;
memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
adapter->mac_table[0].pools = 1ULL;
adapter->mac_table[0].state = (TXGBE_MAC_STATE_DEFAULT |
TXGBE_MAC_STATE_IN_USE);
wx_set_rar(wxhw, 0, adapter->mac_table[0].addr,
adapter->mac_table[0].pools,
WX_PSR_MAC_SWC_AD_H_AV);
}
static void txgbe_flush_sw_mac_table(struct txgbe_adapter *adapter)
{
struct wx_hw *wxhw = &adapter->hw.wxhw;
u32 i;
for (i = 0; i < wxhw->mac.num_rar_entries; i++) {
adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
adapter->mac_table[i].pools = 0;
}
txgbe_sync_mac_table(adapter);
}
static int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 pool)
{
struct wx_hw *wxhw = &adapter->hw.wxhw;
u32 i;
if (is_zero_ether_addr(addr))
return -EINVAL;
/* search table for addr, if found, set to 0 and sync */
for (i = 0; i < wxhw->mac.num_rar_entries; i++) {
if (ether_addr_equal(addr, adapter->mac_table[i].addr)) {
if (adapter->mac_table[i].pools & (1ULL << pool)) {
adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
adapter->mac_table[i].pools &= ~(1ULL << pool);
txgbe_sync_mac_table(adapter);
}
return 0;
}
if (adapter->mac_table[i].pools != (1 << pool))
continue;
if (!ether_addr_equal(addr, adapter->mac_table[i].addr))
continue;
adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
adapter->mac_table[i].pools = 0;
txgbe_sync_mac_table(adapter);
return 0;
}
return -ENOMEM;
}
static void txgbe_reset(struct txgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct txgbe_hw *hw = &adapter->hw;
u8 old_addr[ETH_ALEN];
int err;
err = txgbe_reset_hw(hw);
if (err != 0)
dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
/* do not flush user set addresses */
memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len);
txgbe_flush_sw_mac_table(adapter);
txgbe_mac_set_default_filter(adapter, old_addr);
}
static void txgbe_disable_device(struct txgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct wx_hw *wxhw = &adapter->hw.wxhw;
wx_disable_pcie_master(wxhw);
/* disable receives */
wx_disable_rx(wxhw);
netif_carrier_off(netdev);
netif_tx_disable(netdev);
if (wxhw->bus.func < 2)
wr32m(wxhw, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wxhw->bus.func), 0);
else
dev_err(&adapter->pdev->dev,
"%s: invalid bus lan id %d\n",
__func__, wxhw->bus.func);
if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
/* disable mac transmiter */
wr32m(wxhw, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
}
/* Disable the Tx DMA engine */
wr32m(wxhw, WX_TDM_CTL, WX_TDM_CTL_TE, 0);
}
static void txgbe_down(struct txgbe_adapter *adapter)
{
txgbe_disable_device(adapter);
txgbe_reset(adapter);
}
/**
* txgbe_sw_init - Initialize general software structures (struct txgbe_adapter)
* @adapter: board private structure to initialize
**/
static int txgbe_sw_init(struct txgbe_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct txgbe_hw *hw = &adapter->hw;
struct wx_hw *wxhw = &hw->wxhw;
int err;
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;
}
switch (wxhw->device_id) {
case TXGBE_DEV_ID_SP1000:
case TXGBE_DEV_ID_WX1820:
wxhw->mac.type = wx_mac_sp;
break;
default:
wxhw->mac.type = wx_mac_unknown;
break;
}
wxhw->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;
wxhw->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES;
wxhw->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES;
wxhw->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE;
adapter->mac_table = kcalloc(wxhw->mac.num_rar_entries,
sizeof(struct txgbe_mac_addr),
GFP_KERNEL);
if (!adapter->mac_table) {
netif_err(adapter, probe, adapter->netdev,
"mac_table allocation failed\n");
return -ENOMEM;
}
return 0;
}
/**
* txgbe_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 txgbe_open(struct net_device *netdev)
{
return 0;
}
/**
* txgbe_close_suspend - actions necessary to both suspend and close flows
* @adapter: the private adapter struct
*
* This function should contain the necessary work common to both suspending
* and closing of the device.
*/
static void txgbe_close_suspend(struct txgbe_adapter *adapter)
{
txgbe_disable_device(adapter);
}
/**
* txgbe_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 txgbe_close(struct net_device *netdev)
{
struct txgbe_adapter *adapter = netdev_priv(netdev);
txgbe_down(adapter);
return 0;
}
static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) 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);
...@@ -37,6 +312,11 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) ...@@ -37,6 +312,11 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
netif_device_detach(netdev); netif_device_detach(netdev);
rtnl_lock();
if (netif_running(netdev))
txgbe_close_suspend(adapter);
rtnl_unlock();
pci_disable_device(pdev); pci_disable_device(pdev);
} }
...@@ -52,6 +332,47 @@ static void txgbe_shutdown(struct pci_dev *pdev) ...@@ -52,6 +332,47 @@ static void txgbe_shutdown(struct pci_dev *pdev)
} }
} }
static netdev_tx_t txgbe_xmit_frame(struct sk_buff *skb,
struct net_device *netdev)
{
return NETDEV_TX_OK;
}
/**
* txgbe_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 txgbe_set_mac(struct net_device *netdev, void *p)
{
struct txgbe_adapter *adapter = netdev_priv(netdev);
struct wx_hw *wxhw = &adapter->hw.wxhw;
struct sockaddr *addr = p;
int retval;
retval = eth_prepare_mac_addr_change(netdev, addr);
if (retval)
return retval;
txgbe_del_mac_filter(adapter, wxhw->mac.addr, 0);
eth_hw_addr_set(netdev, addr->sa_data);
memcpy(wxhw->mac.addr, addr->sa_data, netdev->addr_len);
txgbe_mac_set_default_filter(adapter, wxhw->mac.addr);
return 0;
}
static const struct net_device_ops txgbe_netdev_ops = {
.ndo_open = txgbe_open,
.ndo_stop = txgbe_close,
.ndo_start_xmit = txgbe_xmit_frame,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = txgbe_set_mac,
};
/** /**
* txgbe_probe - Device Initialization Routine * txgbe_probe - Device Initialization Routine
* @pdev: PCI device information struct * @pdev: PCI device information struct
...@@ -67,8 +388,10 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -67,8 +388,10 @@ static int txgbe_probe(struct pci_dev *pdev,
const struct pci_device_id __always_unused *ent) const struct pci_device_id __always_unused *ent)
{ {
struct txgbe_adapter *adapter = NULL; struct txgbe_adapter *adapter = NULL;
struct txgbe_hw *hw = NULL;
struct wx_hw *wxhw = NULL;
struct net_device *netdev; struct net_device *netdev;
int err; int err, expected_gts;
err = pci_enable_device_mem(pdev); err = pci_enable_device_mem(pdev);
if (err) if (err)
...@@ -107,6 +430,9 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -107,6 +430,9 @@ static int txgbe_probe(struct pci_dev *pdev,
adapter = netdev_priv(netdev); adapter = netdev_priv(netdev);
adapter->netdev = netdev; adapter->netdev = netdev;
adapter->pdev = pdev; adapter->pdev = pdev;
hw = &adapter->hw;
wxhw = &hw->wxhw;
adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
adapter->io_addr = devm_ioremap(&pdev->dev, adapter->io_addr = devm_ioremap(&pdev->dev,
pci_resource_start(pdev, 0), pci_resource_start(pdev, 0),
...@@ -116,12 +442,58 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -116,12 +442,58 @@ static int txgbe_probe(struct pci_dev *pdev,
goto err_pci_release_regions; goto err_pci_release_regions;
} }
netdev->netdev_ops = &txgbe_netdev_ops;
/* setup the private structure */
err = txgbe_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, TXGBE_SPI_ILDR_STATUS_PERST);
if (err)
goto err_free_mac_table;
err = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_PWRRST);
if (err)
goto err_free_mac_table;
err = txgbe_reset_hw(hw);
if (err) {
dev_err(&pdev->dev, "HW Init failed: %d\n", err);
goto err_free_mac_table;
}
netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HIGHDMA;
eth_hw_addr_set(netdev, wxhw->mac.perm_addr);
txgbe_mac_set_default_filter(adapter, wxhw->mac.perm_addr);
err = register_netdev(netdev);
if (err)
goto err_free_mac_table;
pci_set_drvdata(pdev, adapter); pci_set_drvdata(pdev, adapter);
/* calculate the expected PCIe bandwidth required for optimal
* performance. Note that some older parts will never have enough
* bandwidth due to being older generation PCIe parts. We clamp these
* parts to ensure that no warning is displayed, as this could confuse
* users otherwise.
*/
expected_gts = txgbe_enumerate_functions(adapter) * 10;
/* don't check link if we failed to enumerate functions */
if (expected_gts > 0)
txgbe_check_minimum_link(adapter);
else
dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n");
netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr);
return 0; return 0;
err_free_mac_table:
kfree(adapter->mac_table);
err_pci_release_regions: err_pci_release_regions:
pci_disable_pcie_error_reporting(pdev); pci_disable_pcie_error_reporting(pdev);
pci_release_selected_regions(pdev, pci_release_selected_regions(pdev,
...@@ -142,9 +514,17 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -142,9 +514,17 @@ static int txgbe_probe(struct pci_dev *pdev,
**/ **/
static void txgbe_remove(struct pci_dev *pdev) static void txgbe_remove(struct pci_dev *pdev)
{ {
struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev;
netdev = adapter->netdev;
unregister_netdev(netdev);
pci_release_selected_regions(pdev, pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM)); pci_select_bars(pdev, IORESOURCE_MEM));
kfree(adapter->mac_table);
pci_disable_pcie_error_reporting(pdev); pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
......
...@@ -4,15 +4,6 @@ ...@@ -4,15 +4,6 @@
#ifndef _TXGBE_TYPE_H_ #ifndef _TXGBE_TYPE_H_
#define _TXGBE_TYPE_H_ #define _TXGBE_TYPE_H_
#include <linux/types.h>
#include <linux/netdevice.h>
/************ txgbe_register.h ************/
/* Vendor ID */
#ifndef PCI_VENDOR_ID_WANGXUN
#define PCI_VENDOR_ID_WANGXUN 0x8088
#endif
/* Device IDs */ /* Device IDs */
#define TXGBE_DEV_ID_SP1000 0x1001 #define TXGBE_DEV_ID_SP1000 0x1001
#define TXGBE_DEV_ID_WX1820 0x2001 #define TXGBE_DEV_ID_WX1820 0x2001
...@@ -42,16 +33,28 @@ ...@@ -42,16 +33,28 @@
#define TXGBE_ID_WX1820_MAC_SGMII 0x2060 #define TXGBE_ID_WX1820_MAC_SGMII 0x2060
#define TXGBE_ID_MAC_SGMII 0x60 #define TXGBE_ID_MAC_SGMII 0x60
#define TXGBE_NCSI_SUP 0x8000
#define TXGBE_NCSI_MASK 0x8000
#define TXGBE_WOL_SUP 0x4000
#define TXGBE_WOL_MASK 0x4000
#define TXGBE_DEV_MASK 0xf0
/* Combined interface*/ /* Combined interface*/
#define TXGBE_ID_SFI_XAUI 0x50 #define TXGBE_ID_SFI_XAUI 0x50
/* Revision ID */ /* Revision ID */
#define TXGBE_SP_MPW 1 #define TXGBE_SP_MPW 1
/**************** SP Registers ****************************/
/* chip control Registers */
#define TXGBE_MIS_PRB_CTL 0x10010
#define TXGBE_MIS_PRB_CTL_LAN_UP(_i) BIT(1 - (_i))
/* FMGR Registers */
#define TXGBE_SPI_ILDR_STATUS 0x10120
#define TXGBE_SPI_ILDR_STATUS_PERST BIT(0) /* PCIE_PERST is done */
#define TXGBE_SPI_ILDR_STATUS_PWRRST BIT(1) /* Power on reset is done */
#define TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(_i) BIT((_i) + 9) /* lan soft reset done */
/* Sensors for PVT(Process Voltage Temperature) */
#define TXGBE_TS_CTL 0x10300
#define TXGBE_TS_CTL_EVAL_MD BIT(31)
struct txgbe_hw {
struct wx_hw wxhw;
};
#endif /* _TXGBE_TYPE_H_ */ #endif /* _TXGBE_TYPE_H_ */
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