Commit a34b3e6e authored by Jiawen Wu's avatar Jiawen Wu Committed by David S. Miller

net: txgbe: Store PCI info

Get PCI config space info, set LAN id and check flash status.
Signed-off-by: default avatarJiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 957ed5e7
...@@ -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/iopoll.h>
#include <linux/pci.h>
#include "wx_type.h"
#include "wx_hw.h"
/* 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);
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);
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
/* 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
/* Bus parameters */
struct wx_bus_info {
u8 func;
u16 device;
};
struct wx_hw {
u8 __iomem *hw_addr;
struct pci_dev *pdev;
struct wx_bus_info bus;
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
u16 subsystem_vendor_id;
u8 revision_id;
u16 oem_ssid;
u16 oem_svid;
};
/* register operations */
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define rd32(a, reg) readl((a)->hw_addr + (reg))
#define wx_err(wxhw, fmt, arg...) \
dev_err(&(wxhw)->pdev->dev, fmt, ##arg)
#endif /* _WX_TYPE_H_ */
...@@ -17,6 +17,10 @@ struct txgbe_adapter { ...@@ -17,6 +17,10 @@ struct txgbe_adapter {
/* 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;
}; };
extern char txgbe_driver_name[]; extern char txgbe_driver_name[];
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "txgbe.h" #include "txgbe.h"
char txgbe_driver_name[] = "txgbe"; char txgbe_driver_name[] = "txgbe";
...@@ -30,6 +32,69 @@ static const struct pci_device_id txgbe_pci_tbl[] = { ...@@ -30,6 +32,69 @@ 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;
}
/**
* 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;
}
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);
...@@ -67,8 +132,10 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -67,8 +132,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 +174,9 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -107,6 +174,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,10 +186,39 @@ static int txgbe_probe(struct pci_dev *pdev, ...@@ -116,10 +186,39 @@ static int txgbe_probe(struct pci_dev *pdev,
goto err_pci_release_regions; goto err_pci_release_regions;
} }
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
/* setup the private structure */
err = txgbe_sw_init(adapter);
if (err)
goto err_pci_release_regions;
/* 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_pci_release_regions;
err = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_PWRRST);
if (err)
goto err_pci_release_regions;
netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HIGHDMA;
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");
return 0; return 0;
err_pci_release_regions: err_pci_release_regions:
......
...@@ -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
...@@ -54,4 +45,14 @@ ...@@ -54,4 +45,14 @@
/* Revision ID */ /* Revision ID */
#define TXGBE_SP_MPW 1 #define TXGBE_SP_MPW 1
/**************** SP Registers ****************************/
/* 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 */
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