net: txgbe: Store PCI info

Get PCI config space info, set LAN id and check flash status.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiawen Wu 2022-10-27 14:11:14 +08:00 committed by David S. Miller
parent 957ed5e712
commit a34b3e6ed8
9 changed files with 280 additions and 10 deletions

View File

@ -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.

View File

@ -3,5 +3,6 @@
# Makefile for the Wangxun network device drivers.
#
obj-$(CONFIG_LIBWX) += libwx/
obj-$(CONFIG_TXGBE) += txgbe/
obj-$(CONFIG_NGBE) += ngbe/

View File

@ -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

View File

@ -0,0 +1,88 @@
// 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");

View File

@ -0,0 +1,10 @@
/* 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_ */

View File

@ -0,0 +1,54 @@
/* 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_ */

View File

@ -17,6 +17,10 @@ struct txgbe_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
/* structs defined in txgbe_type.h */
struct txgbe_hw hw;
u16 msg_enable;
};
extern char txgbe_driver_name[];

View File

@ -9,6 +9,8 @@
#include <linux/aer.h>
#include <linux/etherdevice.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "txgbe.h"
char txgbe_driver_name[] = "txgbe";
@ -30,6 +32,69 @@ 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;
}
/**
* 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)
{
struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
@ -67,8 +132,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 +174,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,10 +186,39 @@ static int txgbe_probe(struct pci_dev *pdev,
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;
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;
err_pci_release_regions:

View File

@ -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
@ -54,4 +45,14 @@
/* Revision ID */
#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_ */