aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/wangxun/Kconfig6
-rw-r--r--drivers/net/ethernet/wangxun/Makefile1
-rw-r--r--drivers/net/ethernet/wangxun/libwx/Makefile7
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.c475
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.h18
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_type.h237
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/Makefile3
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe.h22
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c99
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h9
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_main.c382
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_type.h33
12 files changed, 1273 insertions, 19 deletions
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index f5d43d8c9629..565fa826b056 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -16,6 +16,11 @@ config NET_VENDOR_WANGXUN
if NET_VENDOR_WANGXUN
+config LIBWX
+ tristate
+ help
+ Common library for Wangxun(R) Ethernet drivers.
+
config NGBE
tristate "Wangxun(R) GbE PCI Express adapters support"
depends on PCI
@@ -32,6 +37,7 @@ config NGBE
config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
+ select LIBWX
help
This driver supports Wangxun(R) 10GbE PCI Express family of
adapters.
diff --git a/drivers/net/ethernet/wangxun/Makefile b/drivers/net/ethernet/wangxun/Makefile
index ac3fb06b233c..ca19311dbe38 100644
--- a/drivers/net/ethernet/wangxun/Makefile
+++ b/drivers/net/ethernet/wangxun/Makefile
@@ -3,5 +3,6 @@
# Makefile for the Wangxun network device drivers.
#
+obj-$(CONFIG_LIBWX) += libwx/
obj-$(CONFIG_TXGBE) += txgbe/
obj-$(CONFIG_NGBE) += ngbe/
diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
new file mode 100644
index 000000000000..1ed5e23af944
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
@@ -0,0 +1,7 @@
+# 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
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
new file mode 100644
index 000000000000..8dbbac862f27
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -0,0 +1,475 @@
+// 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");
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
new file mode 100644
index 000000000000..58a943dc76c1
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -0,0 +1,18 @@
+/* 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_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
new file mode 100644
index 000000000000..790497cec603
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -0,0 +1,237 @@
+/* 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_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile
index 431303ca75b4..78484c58b78b 100644
--- a/drivers/net/ethernet/wangxun/txgbe/Makefile
+++ b/drivers/net/ethernet/wangxun/txgbe/Makefile
@@ -6,4 +6,5 @@
obj-$(CONFIG_TXGBE) += txgbe.o
-txgbe-objs := txgbe_main.o
+txgbe-objs := txgbe_main.o \
+ txgbe_hw.o
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe.h b/drivers/net/ethernet/wangxun/txgbe/txgbe.h
index 38ddbde0ed0f..52e350f9a7d9 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe.h
@@ -4,19 +4,37 @@
#ifndef _TXGBE_H_
#define _TXGBE_H_
-#include "txgbe_type.h"
-
#define TXGBE_MAX_FDIR_INDICES 63
#define TXGBE_MAX_RX_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 */
struct txgbe_adapter {
u8 __iomem *io_addr; /* Mainly for iounmap use */
/* OS defined structs */
struct net_device *netdev;
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[];
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
new file mode 100644
index 000000000000..c7c92c0ec561
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
@@ -0,0 +1,99 @@
+// 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;
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
new file mode 100644
index 000000000000..155f18ea4b8c
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
@@ -0,0 +1,9 @@
+/* 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_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index d3b9f73ecba4..adfa4e7d0d52 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -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 "txgbe_type.h"
+#include "txgbe_hw.h"
#include "txgbe.h"
char txgbe_driver_name[] = "txgbe";
@@ -30,6 +35,276 @@ static const struct pci_device_id txgbe_pci_tbl[] = {
#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)
{
struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
@@ -37,6 +312,11 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
netif_device_detach(netdev);
+ rtnl_lock();
+ if (netif_running(netdev))
+ txgbe_close_suspend(adapter);
+ rtnl_unlock();
+
pci_disable_device(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
* @pdev: PCI device information struct
@@ -67,8 +388,10 @@ static int txgbe_probe(struct pci_dev *pdev,
const struct pci_device_id __always_unused *ent)
{
struct txgbe_adapter *adapter = NULL;
+ struct txgbe_hw *hw = NULL;
+ struct wx_hw *wxhw = NULL;
struct net_device *netdev;
- int err;
+ int err, expected_gts;
err = pci_enable_device_mem(pdev);
if (err)
@@ -107,6 +430,9 @@ static int txgbe_probe(struct pci_dev *pdev,
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
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,
pci_resource_start(pdev, 0),
@@ -116,12 +442,58 @@ static int txgbe_probe(struct pci_dev *pdev,
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;
+ 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);
+ /* 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;
+err_free_mac_table:
+ kfree(adapter->mac_table);
err_pci_release_regions:
pci_disable_pcie_error_reporting(pdev);
pci_release_selected_regions(pdev,
@@ -142,9 +514,17 @@ err_pci_disable_dev:
**/
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_select_bars(pdev, IORESOURCE_MEM));
+ kfree(adapter->mac_table);
+
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index b2e329f50bae..4082d3b76709 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -4,15 +4,6 @@
#ifndef _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 */
#define TXGBE_DEV_ID_SP1000 0x1001
#define TXGBE_DEV_ID_WX1820 0x2001
@@ -42,16 +33,28 @@
#define TXGBE_ID_WX1820_MAC_SGMII 0x2060
#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*/
#define TXGBE_ID_SFI_XAUI 0x50
/* Revision ID */
#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_ */