net: wangxun: ngbe: support wangxun 1GbE driver
add support for wangxun 1GbE driver, source files and functions are the same as wangxun oob ngbe-1.2.5.3. Signed-off-by: Duanqiang Wen <duanqiangwen@net-swift.com>
This commit is contained in:
parent
2ae9cf86d2
commit
467b4bd334
|
@ -181,6 +181,7 @@ source "drivers/net/ethernet/toshiba/Kconfig"
|
|||
source "drivers/net/ethernet/tundra/Kconfig"
|
||||
source "drivers/net/ethernet/via/Kconfig"
|
||||
source "drivers/net/ethernet/wiznet/Kconfig"
|
||||
source "drivers/net/ethernet/wangxun/Kconfig"
|
||||
source "drivers/net/ethernet/xilinx/Kconfig"
|
||||
source "drivers/net/ethernet/xircom/Kconfig"
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/
|
|||
obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/
|
||||
obj-$(CONFIG_NET_VENDOR_VIA) += via/
|
||||
obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
|
||||
obj-$(CONFIG_NET_VENDOR_WANGXUN) += wangxun/
|
||||
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
|
||||
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
|
||||
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Wangxun network device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_WANGXUN
|
||||
bool "Wangxun devices"
|
||||
default y
|
||||
help
|
||||
If you have a network (Ethernet) card from Wangxun(R), say Y.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about Wangxun(R) cards. If you say Y, you will
|
||||
be asked for your specific card in the following questions.
|
||||
|
||||
if NET_VENDOR_WANGXUN
|
||||
|
||||
config NGBE
|
||||
tristate "Wangxun(R) GbE PCI Express adapters support"
|
||||
depends on PCI
|
||||
help
|
||||
This driver supports Wangxun(R) GbE PCI Express family of
|
||||
adapters.
|
||||
|
||||
More specific information on configuring the driver is in
|
||||
<file:Documentation/networking/device_drivers/ethernet/wangxun/ngbe.rst>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called ngbe.
|
||||
|
||||
endif # NET_VENDOR_WANGXUN
|
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the Wangxun network device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NGBE) += ngbe/
|
|
@ -0,0 +1,16 @@
|
|||
obj-$(CONFIG_NGBE) += ngbe.o
|
||||
|
||||
ngbe-objs := ngbe_main.o \
|
||||
ngbe_hw.o \
|
||||
ngbe_phy.o \
|
||||
ngbe_ethtool.o \
|
||||
ngbe_lib.o \
|
||||
ngbe_mbx.o \
|
||||
ngbe_sriov.o \
|
||||
ngbe_pcierr.o \
|
||||
ngbe_param.o \
|
||||
ngbe_procfs.o \
|
||||
ngbe_ptp.o \
|
||||
ngbe_sysfs.o \
|
||||
ngbe_debugfs.o \
|
||||
ngbe_kcompat.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,778 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ngbe.h"
|
||||
|
||||
#ifdef HAVE_NGBE_DEBUG_FS
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static struct dentry *ngbe_dbg_root;
|
||||
static int ngbe_data_mode;
|
||||
|
||||
#define NGBE_DATA_FUNC(dm) ((dm) & ~0xFFFF)
|
||||
#define NGBE_DATA_ARGS(dm) ((dm) & 0xFFFF)
|
||||
enum ngbe_data_func {
|
||||
NGBE_FUNC_NONE = (0 << 16),
|
||||
NGBE_FUNC_DUMP_BAR = (1 << 16),
|
||||
NGBE_FUNC_DUMP_RDESC = (2 << 16),
|
||||
NGBE_FUNC_DUMP_TDESC = (3 << 16),
|
||||
NGBE_FUNC_FLASH_READ = (4 << 16),
|
||||
NGBE_FUNC_FLASH_WRITE = (5 << 16),
|
||||
};
|
||||
|
||||
/**
|
||||
* data operation
|
||||
**/
|
||||
static ssize_t
|
||||
ngbe_simple_read_from_pcibar(struct ngbe_adapter *adapter, int res,
|
||||
void __user *buf, size_t size, loff_t *ppos)
|
||||
{
|
||||
loff_t pos = *ppos;
|
||||
u32 miss, len, limit = pci_resource_len(adapter->pdev, res);
|
||||
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
|
||||
limit = (pos + size <= limit ? pos + size : limit);
|
||||
for (miss = 0; pos < limit && !miss; buf += len, pos += len) {
|
||||
u32 val = 0, reg = round_down(pos, 4);
|
||||
u32 off = pos - reg;
|
||||
|
||||
len = (reg + 4 <= limit ? 4 - off : 4 - off - (limit - reg - 4));
|
||||
val = ngbe_rd32(adapter->io_addr + reg);
|
||||
miss = copy_to_user(buf, &val + off, len);
|
||||
}
|
||||
|
||||
size = pos - *ppos - miss;
|
||||
*ppos += size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_simple_read_from_flash(struct ngbe_adapter *adapter,
|
||||
void __user *buf, size_t size, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
loff_t pos = *ppos;
|
||||
size_t ret = 0;
|
||||
loff_t rpos, rtail;
|
||||
void __user *to = buf;
|
||||
size_t available = adapter->hw.flash.dword_size << 2;
|
||||
|
||||
if (pos < 0)
|
||||
return -EINVAL;
|
||||
if (pos >= available || !size)
|
||||
return 0;
|
||||
if (size > available - pos)
|
||||
size = available - pos;
|
||||
|
||||
rpos = round_up(pos, 4);
|
||||
rtail = round_down(pos + size, 4);
|
||||
if (rtail < rpos)
|
||||
return 0;
|
||||
|
||||
to += rpos - pos;
|
||||
while (rpos <= rtail) {
|
||||
u32 value = ngbe_rd32(adapter->io_addr + rpos);
|
||||
if (hw->flash.ops.write_buffer(hw, rpos>>2, 1, &value)) {
|
||||
ret = size;
|
||||
break;
|
||||
}
|
||||
if (4 == copy_to_user(to, &value, 4)) {
|
||||
ret = size;
|
||||
break;
|
||||
}
|
||||
to += 4;
|
||||
rpos += 4;
|
||||
}
|
||||
|
||||
if (ret == size)
|
||||
return -EFAULT;
|
||||
size -= ret;
|
||||
*ppos = pos + size;
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_simple_write_to_flash(struct ngbe_adapter *adapter,
|
||||
const void __user *from, size_t size, loff_t *ppos, size_t available)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_dbg_data_ops_read(struct file *filp, char __user *buffer,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
u32 func = NGBE_DATA_FUNC(ngbe_data_mode);
|
||||
|
||||
rmb();
|
||||
|
||||
switch (func) {
|
||||
case NGBE_FUNC_DUMP_BAR: {
|
||||
u32 bar = NGBE_DATA_ARGS(ngbe_data_mode);
|
||||
|
||||
return ngbe_simple_read_from_pcibar(adapter, bar, buffer, size,
|
||||
ppos);
|
||||
}
|
||||
case NGBE_FUNC_FLASH_READ: {
|
||||
return ngbe_simple_read_from_flash(adapter, buffer, size, ppos);
|
||||
}
|
||||
case NGBE_FUNC_DUMP_RDESC: {
|
||||
struct ngbe_ring *ring;
|
||||
u32 queue = NGBE_DATA_ARGS(ngbe_data_mode);
|
||||
|
||||
if (queue >= adapter->num_rx_queues)
|
||||
return 0;
|
||||
queue += VMDQ_P(0) * adapter->queues_per_pool;
|
||||
ring = adapter->rx_ring[queue];
|
||||
|
||||
return simple_read_from_buffer(buffer, size, ppos,
|
||||
ring->desc, ring->size);
|
||||
}
|
||||
case NGBE_FUNC_DUMP_TDESC: {
|
||||
struct ngbe_ring *ring;
|
||||
u32 queue = NGBE_DATA_ARGS(ngbe_data_mode);
|
||||
|
||||
if (queue >= adapter->num_tx_queues)
|
||||
return 0;
|
||||
queue += VMDQ_P(0) * adapter->queues_per_pool;
|
||||
ring = adapter->tx_ring[queue];
|
||||
|
||||
return simple_read_from_buffer(buffer, size, ppos,
|
||||
ring->desc, ring->size);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_dbg_data_ops_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
u32 func = NGBE_DATA_FUNC(ngbe_data_mode);
|
||||
|
||||
rmb();
|
||||
|
||||
switch (func) {
|
||||
case NGBE_FUNC_FLASH_WRITE: {
|
||||
u32 size = NGBE_DATA_ARGS(ngbe_data_mode);
|
||||
|
||||
if (size > adapter->hw.flash.dword_size << 2)
|
||||
size = adapter->hw.flash.dword_size << 2;
|
||||
|
||||
return ngbe_simple_write_to_flash(adapter, buffer, size, ppos, size);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
static struct file_operations ngbe_dbg_data_ops_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = ngbe_dbg_data_ops_read,
|
||||
.write = ngbe_dbg_data_ops_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* reg_ops operation
|
||||
**/
|
||||
static char ngbe_dbg_reg_ops_buf[256] = "";
|
||||
static ssize_t
|
||||
ngbe_dbg_reg_ops_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
/* don't allow partial reads */
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
buf = kasprintf(GFP_KERNEL, "%s: mode=0x%08x\n%s\n",
|
||||
adapter->netdev->name, ngbe_data_mode,
|
||||
ngbe_dbg_reg_ops_buf);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count < strlen(buf)) {
|
||||
kfree(buf);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
|
||||
|
||||
kfree(buf);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_dbg_reg_ops_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
char *pc = ngbe_dbg_reg_ops_buf;
|
||||
int len;
|
||||
|
||||
/* don't allow partial writes */
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
if (count >= sizeof(ngbe_dbg_reg_ops_buf))
|
||||
return -ENOSPC;
|
||||
|
||||
len = simple_write_to_buffer(ngbe_dbg_reg_ops_buf,
|
||||
sizeof(ngbe_dbg_reg_ops_buf)-1,
|
||||
ppos,
|
||||
buffer,
|
||||
count);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
pc[len] = '\0';
|
||||
|
||||
if (strncmp(pc, "dump", 4) == 0) {
|
||||
u32 mode = 0;
|
||||
u16 args;
|
||||
|
||||
pc += 4;
|
||||
pc += strspn(pc, " \t");
|
||||
|
||||
if (!strncmp(pc, "bar", 3)) {
|
||||
pc += 3;
|
||||
mode = NGBE_FUNC_DUMP_BAR;
|
||||
} else if (!strncmp(pc, "rdesc", 5)) {
|
||||
pc += 5;
|
||||
mode = NGBE_FUNC_DUMP_RDESC;
|
||||
} else if (!strncmp(pc, "tdesc", 5)) {
|
||||
pc += 5;
|
||||
mode = NGBE_FUNC_DUMP_TDESC;
|
||||
} else {
|
||||
ngbe_dump(adapter);
|
||||
}
|
||||
|
||||
if (mode && 1 == sscanf(pc, "%hu", &args)) {
|
||||
mode |= args;
|
||||
}
|
||||
|
||||
ngbe_data_mode = mode;
|
||||
} else if (strncmp(pc, "flash", 4) == 0) {
|
||||
u32 mode = 0;
|
||||
u16 args;
|
||||
|
||||
pc += 5;
|
||||
pc += strspn(pc, " \t");
|
||||
if (!strncmp(pc, "read", 3)) {
|
||||
pc += 4;
|
||||
mode = NGBE_FUNC_FLASH_READ;
|
||||
} else if (!strncmp(pc, "write", 5)) {
|
||||
pc += 5;
|
||||
mode = NGBE_FUNC_FLASH_WRITE;
|
||||
}
|
||||
|
||||
if (mode && 1 == sscanf(pc, "%hu", &args)) {
|
||||
mode |= args;
|
||||
}
|
||||
|
||||
ngbe_data_mode = mode;
|
||||
} else if (strncmp(ngbe_dbg_reg_ops_buf, "write", 5) == 0) {
|
||||
u32 reg, value;
|
||||
int cnt;
|
||||
cnt = sscanf(&ngbe_dbg_reg_ops_buf[5], "%x %x", ®, &value);
|
||||
if (cnt == 2) {
|
||||
wr32(&adapter->hw, reg, value);
|
||||
e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
|
||||
} else {
|
||||
e_dev_info("write <reg> <value>\n");
|
||||
}
|
||||
} else if (strncmp(ngbe_dbg_reg_ops_buf, "read", 4) == 0) {
|
||||
u32 reg, value;
|
||||
int cnt;
|
||||
cnt = sscanf(&ngbe_dbg_reg_ops_buf[4], "%x", ®);
|
||||
if (cnt == 1) {
|
||||
value = rd32(&adapter->hw, reg);
|
||||
e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
|
||||
} else {
|
||||
e_dev_info("read <reg>\n");
|
||||
}
|
||||
} else {
|
||||
e_dev_info("Unknown command %s\n", ngbe_dbg_reg_ops_buf);
|
||||
e_dev_info("Available commands:\n");
|
||||
e_dev_info(" read <reg>\n");
|
||||
e_dev_info(" write <reg> <value>\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ngbe_dbg_reg_ops_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = ngbe_dbg_reg_ops_read,
|
||||
.write = ngbe_dbg_reg_ops_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* netdev_ops operation
|
||||
**/
|
||||
static char ngbe_dbg_netdev_ops_buf[256] = "";
|
||||
static ssize_t
|
||||
ngbe_dbg_netdev_ops_read(struct file *filp,
|
||||
char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
/* don't allow partial reads */
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
buf = kasprintf(GFP_KERNEL, "%s: mode=0x%08x\n%s\n",
|
||||
adapter->netdev->name, ngbe_data_mode,
|
||||
ngbe_dbg_netdev_ops_buf);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count < strlen(buf)) {
|
||||
kfree(buf);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
|
||||
|
||||
kfree(buf);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ngbe_dbg_netdev_ops_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ngbe_adapter *adapter = filp->private_data;
|
||||
int len;
|
||||
|
||||
/* don't allow partial writes */
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
if (count >= sizeof(ngbe_dbg_netdev_ops_buf))
|
||||
return -ENOSPC;
|
||||
|
||||
len = simple_write_to_buffer(ngbe_dbg_netdev_ops_buf,
|
||||
sizeof(ngbe_dbg_netdev_ops_buf)-1,
|
||||
ppos,
|
||||
buffer,
|
||||
count);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
ngbe_dbg_netdev_ops_buf[len] = '\0';
|
||||
|
||||
if (strncmp(ngbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
|
||||
#if defined(HAVE_TX_TIMEOUT_TXQUEUE)
|
||||
adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev, 0);
|
||||
#elif defined(HAVE_NET_DEVICE_OPS)
|
||||
adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev);
|
||||
#else
|
||||
adapter->netdev->tx_timeout(adapter->netdev);
|
||||
#endif /* HAVE_NET_DEVICE_OPS */
|
||||
e_dev_info("tx_timeout called\n");
|
||||
} else {
|
||||
e_dev_info("Unknown command: %s\n", ngbe_dbg_netdev_ops_buf);
|
||||
e_dev_info("Available commands:\n");
|
||||
e_dev_info(" tx_timeout\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations ngbe_dbg_netdev_ops_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = ngbe_dbg_netdev_ops_read,
|
||||
.write = ngbe_dbg_netdev_ops_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* ngbe_dbg_adapter_init - setup the debugfs directory for the adapter
|
||||
* @adapter: the adapter that is starting up
|
||||
**/
|
||||
void ngbe_dbg_adapter_init(struct ngbe_adapter *adapter)
|
||||
{
|
||||
const char *name = pci_name(adapter->pdev);
|
||||
struct dentry *pfile;
|
||||
|
||||
adapter->ngbe_dbg_adapter = debugfs_create_dir(name, ngbe_dbg_root);
|
||||
if (!adapter->ngbe_dbg_adapter) {
|
||||
e_dev_err("debugfs entry for %s failed\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
pfile = debugfs_create_file("data", 0600,
|
||||
adapter->ngbe_dbg_adapter, adapter,
|
||||
&ngbe_dbg_data_ops_fops);
|
||||
if (!pfile)
|
||||
e_dev_err("debugfs netdev_ops for %s failed\n", name);
|
||||
|
||||
pfile = debugfs_create_file("reg_ops", 0600,
|
||||
adapter->ngbe_dbg_adapter, adapter,
|
||||
&ngbe_dbg_reg_ops_fops);
|
||||
if (!pfile)
|
||||
e_dev_err("debugfs reg_ops for %s failed\n", name);
|
||||
|
||||
pfile = debugfs_create_file("netdev_ops", 0600,
|
||||
adapter->ngbe_dbg_adapter, adapter,
|
||||
&ngbe_dbg_netdev_ops_fops);
|
||||
if (!pfile)
|
||||
e_dev_err("debugfs netdev_ops for %s failed\n", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_dbg_adapter_exit - clear out the adapter's debugfs entries
|
||||
* @pf: the pf that is stopping
|
||||
**/
|
||||
void ngbe_dbg_adapter_exit(struct ngbe_adapter *adapter)
|
||||
{
|
||||
if (adapter->ngbe_dbg_adapter)
|
||||
debugfs_remove_recursive(adapter->ngbe_dbg_adapter);
|
||||
adapter->ngbe_dbg_adapter = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_dbg_init - start up debugfs for the driver
|
||||
**/
|
||||
void ngbe_dbg_init(void)
|
||||
{
|
||||
ngbe_dbg_root = debugfs_create_dir(ngbe_driver_name, NULL);
|
||||
if (ngbe_dbg_root == NULL)
|
||||
pr_err("init of debugfs failed\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_dbg_exit - clean out the driver's debugfs entries
|
||||
**/
|
||||
void ngbe_dbg_exit(void)
|
||||
{
|
||||
debugfs_remove_recursive(ngbe_dbg_root);
|
||||
}
|
||||
|
||||
#endif /* HAVE_NGBE_DEBUG_FS */
|
||||
|
||||
struct ngbe_reg_info {
|
||||
u32 offset;
|
||||
u32 length;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static struct ngbe_reg_info ngbe_reg_info_tbl[] = {
|
||||
|
||||
/* General Registers */
|
||||
{NGBE_CFG_PORT_CTL, 1, "CTRL"},
|
||||
{NGBE_CFG_PORT_ST, 1, "STATUS"},
|
||||
|
||||
/* RX Registers */
|
||||
{NGBE_PX_RR_CFG(0), 1, "SRRCTL"},
|
||||
{NGBE_PX_RR_RP(0), 1, "RDH"},
|
||||
{NGBE_PX_RR_WP(0), 1, "RDT"},
|
||||
{NGBE_PX_RR_CFG(0), 1, "RXDCTL"},
|
||||
{NGBE_PX_RR_BAL(0), 1, "RDBAL"},
|
||||
{NGBE_PX_RR_BAH(0), 1, "RDBAH"},
|
||||
|
||||
/* TX Registers */
|
||||
{NGBE_PX_TR_BAL(0), 1, "TDBAL"},
|
||||
{NGBE_PX_TR_BAH(0), 1, "TDBAH"},
|
||||
{NGBE_PX_TR_RP(0), 1, "TDH"},
|
||||
{NGBE_PX_TR_WP(0), 1, "TDT"},
|
||||
{NGBE_PX_TR_CFG(0), 1, "TXDCTL"},
|
||||
|
||||
/* MACVLAN */
|
||||
{NGBE_PSR_MAC_SWC_VM, 128, "PSR_MAC_SWC_VM"},
|
||||
{NGBE_PSR_MAC_SWC_AD_L, 32, "PSR_MAC_SWC_AD"},
|
||||
{NGBE_PSR_VLAN_TBL(0), 128, "PSR_VLAN_TBL"},
|
||||
|
||||
/* List Terminator */
|
||||
{ .name = NULL }
|
||||
};
|
||||
|
||||
/**
|
||||
* ngbe_regdump - register printout routine
|
||||
**/
|
||||
static void
|
||||
ngbe_regdump(struct ngbe_hw *hw, struct ngbe_reg_info *reg_info)
|
||||
{
|
||||
#if 0
|
||||
int i, n = 0;
|
||||
u32 buffer[32*8];
|
||||
|
||||
switch (reg_info->offset) {
|
||||
case NGBE_PSR_MAC_SWC_AD_L:
|
||||
for (i = 0; i < reg_info->length; i++) {
|
||||
wr32(hw, NGBE_PSR_MAC_SWC_IDX, i);
|
||||
buffer[n++] =
|
||||
rd32(hw, NGBE_PSR_MAC_SWC_AD_H);
|
||||
buffer[n++] =
|
||||
rd32(hw, NGBE_PSR_MAC_SWC_AD_L);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (i = 0; i < reg_info->length; i++) {
|
||||
buffer[n++] = rd32(hw,
|
||||
reg_info->offset + 4*i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; n && i < 32; i++) {
|
||||
pr_info("%-20s[%02x-%02x]", reg_info->name, i*8, i*8 + 7);
|
||||
for (j = 0; n && j < 8; j++, n--)
|
||||
pr_cont(" %08x", buffer[i*8 + j]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
BUG_ON(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_dump - Print registers, tx-rings and rx-rings
|
||||
**/
|
||||
void ngbe_dump(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
struct ngbe_reg_info *reg_info;
|
||||
int n = 0;
|
||||
struct ngbe_ring *tx_ring;
|
||||
struct ngbe_tx_buffer *tx_buffer;
|
||||
union ngbe_tx_desc *tx_desc;
|
||||
struct my_u0 { u64 a; u64 b; } *u0;
|
||||
struct ngbe_ring *rx_ring;
|
||||
#ifndef CONFIG_NGBE_DISABLE_PACKET_SPLIT
|
||||
union ngbe_rx_desc *rx_desc;
|
||||
struct ngbe_rx_buffer *rx_buffer_info;
|
||||
u32 staterr;
|
||||
#endif
|
||||
int i = 0;
|
||||
|
||||
if (!netif_msg_hw(adapter))
|
||||
return;
|
||||
|
||||
/* Print Registers */
|
||||
dev_info(&adapter->pdev->dev, "Register Dump\n");
|
||||
pr_info(" Register Name Value\n");
|
||||
for (reg_info = ngbe_reg_info_tbl; reg_info->name; reg_info++) {
|
||||
ngbe_regdump(hw, reg_info);
|
||||
}
|
||||
|
||||
/* Print TX Ring Summary */
|
||||
if (!netdev || !netif_running(netdev))
|
||||
return;
|
||||
|
||||
dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
|
||||
pr_info(" %s %s %s %s\n",
|
||||
"Queue [NTU] [NTC] [bi(ntc)->dma ]",
|
||||
"leng", "ntw", "timestamp");
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
tx_buffer = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
|
||||
pr_info(" %5d %5X %5X %016llX %08X %p %016llX\n",
|
||||
n, tx_ring->next_to_use, tx_ring->next_to_clean,
|
||||
(u64)dma_unmap_addr(tx_buffer, dma),
|
||||
dma_unmap_len(tx_buffer, len),
|
||||
tx_buffer->next_to_watch,
|
||||
(u64)tx_buffer->time_stamp);
|
||||
}
|
||||
|
||||
/* Print TX Rings */
|
||||
if (!netif_msg_tx_done(adapter))
|
||||
goto rx_ring_summary;
|
||||
|
||||
dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
|
||||
|
||||
/* Transmit Descriptor Formats
|
||||
*
|
||||
* Transmit Descriptor (Read)
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | Buffer Address [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 |PAYLEN |POPTS|CC|IDX |STA |DCMD |DTYP |MAC |RSV |DTALEN |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 46 45 40 39 38 36 35 32 31 24 23 20 19 18 17 16 15 0
|
||||
*
|
||||
* Transmit Descriptor (Write-Back)
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | RSV [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 | RSV | STA | RSV |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 36 35 32 31 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
pr_info("------------------------------------\n");
|
||||
pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
|
||||
pr_info("------------------------------------\n");
|
||||
pr_info("%s%s %s %s %s %s\n",
|
||||
"T [desc] [address 63:0 ] ",
|
||||
"[PlPOIdStDDt Ln] [bi->dma ] ",
|
||||
"leng", "ntw", "timestamp", "bi->skb");
|
||||
|
||||
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
|
||||
tx_desc = NGBE_TX_DESC(tx_ring, i);
|
||||
tx_buffer = &tx_ring->tx_buffer_info[i];
|
||||
u0 = (struct my_u0 *)tx_desc;
|
||||
if (dma_unmap_len(tx_buffer, len) > 0) {
|
||||
pr_info("T [0x%03X] %016llX %016llX %016llX "
|
||||
"%08X %p %016llX %p",
|
||||
i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)dma_unmap_addr(tx_buffer, dma),
|
||||
dma_unmap_len(tx_buffer, len),
|
||||
tx_buffer->next_to_watch,
|
||||
(u64)tx_buffer->time_stamp,
|
||||
tx_buffer->skb);
|
||||
if (i == tx_ring->next_to_use &&
|
||||
i == tx_ring->next_to_clean)
|
||||
pr_cont(" NTC/U\n");
|
||||
else if (i == tx_ring->next_to_use)
|
||||
pr_cont(" NTU\n");
|
||||
else if (i == tx_ring->next_to_clean)
|
||||
pr_cont(" NTC\n");
|
||||
else
|
||||
pr_cont("\n");
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
tx_buffer->skb)
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS, 16, 1,
|
||||
tx_buffer->skb->data,
|
||||
dma_unmap_len(tx_buffer, len),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print RX Rings Summary */
|
||||
rx_ring_summary:
|
||||
dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
|
||||
pr_info("Queue [NTU] [NTC]\n");
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
pr_info("%5d %5X %5X\n",
|
||||
n, rx_ring->next_to_use, rx_ring->next_to_clean);
|
||||
}
|
||||
|
||||
/* Print RX Rings */
|
||||
if (!netif_msg_rx_status(adapter))
|
||||
return;
|
||||
|
||||
dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
|
||||
|
||||
/* Receive Descriptor Formats
|
||||
*
|
||||
* Receive Descriptor (Read)
|
||||
* 63 1 0
|
||||
* +-----------------------------------------------------+
|
||||
* 0 | Packet Buffer Address [63:1] |A0/NSE|
|
||||
* +----------------------------------------------+------+
|
||||
* 8 | Header Buffer Address [63:1] | DD |
|
||||
* +-----------------------------------------------------+
|
||||
*
|
||||
*
|
||||
* Receive Descriptor (Write-Back)
|
||||
*
|
||||
* 63 48 47 32 31 30 21 20 17 16 4 3 0
|
||||
* +------------------------------------------------------+
|
||||
* 0 |RSS / Frag Checksum|SPH| HDR_LEN |RSC- |Packet| RSS |
|
||||
* |/ RTT / PCoE_PARAM | | | CNT | Type | Type |
|
||||
* |/ Flow Dir Flt ID | | | | | |
|
||||
* +------------------------------------------------------+
|
||||
* 8 | VLAN Tag | Length |Extended Error| Xtnd Status/NEXTP |
|
||||
* +------------------------------------------------------+
|
||||
* 63 48 47 32 31 20 19 0
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_NGBE_DISABLE_PACKET_SPLIT
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
pr_info("------------------------------------\n");
|
||||
pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
|
||||
pr_info("------------------------------------\n");
|
||||
pr_info("%s%s%s",
|
||||
"R [desc] [ PktBuf A0] ",
|
||||
"[ HeadBuf DD] [bi->dma ] [bi->skb ] ",
|
||||
"<-- Adv Rx Read format\n");
|
||||
pr_info("%s%s%s",
|
||||
"RWB[desc] [PcsmIpSHl PtRs] ",
|
||||
"[vl er S cks ln] ---------------- [bi->skb ] ",
|
||||
"<-- Adv Rx Write-Back format\n");
|
||||
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
rx_buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
rx_desc = NGBE_RX_DESC(rx_ring, i);
|
||||
u0 = (struct my_u0 *)rx_desc;
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
if (staterr & NGBE_RXD_STAT_DD) {
|
||||
/* Descriptor Done */
|
||||
pr_info("RWB[0x%03X] %016llX "
|
||||
"%016llX ---------------- %p", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
rx_buffer_info->skb);
|
||||
} else {
|
||||
pr_info("R [0x%03X] %016llX "
|
||||
"%016llX %016llX %p", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)rx_buffer_info->page_dma,
|
||||
rx_buffer_info->skb);
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
rx_buffer_info->page_dma) {
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS, 16, 1,
|
||||
page_address(rx_buffer_info->page) +
|
||||
rx_buffer_info->page_offset,
|
||||
ngbe_rx_bufsz(rx_ring), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == rx_ring->next_to_use)
|
||||
pr_cont(" NTU\n");
|
||||
else if (i == rx_ring->next_to_clean)
|
||||
pr_cont(" NTC\n");
|
||||
else
|
||||
pr_cont("\n");
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
#ifndef _NGBE_HW_H_
|
||||
#define _NGBE_HW_H_
|
||||
|
||||
#define NGBE_EMC_INTERNAL_DATA 0x00
|
||||
#define NGBE_EMC_INTERNAL_THERM_LIMIT 0x20
|
||||
#define NGBE_EMC_DIODE1_DATA 0x01
|
||||
#define NGBE_EMC_DIODE1_THERM_LIMIT 0x19
|
||||
#define NGBE_EMC_DIODE2_DATA 0x23
|
||||
#define NGBE_EMC_DIODE2_THERM_LIMIT 0x1A
|
||||
#define NGBE_EMC_DIODE3_DATA 0x2A
|
||||
#define NGBE_EMC_DIODE3_THERM_LIMIT 0x30
|
||||
|
||||
#define SPI_CLK_DIV 3
|
||||
|
||||
#define SPI_CMD_ERASE_CHIP 4 // SPI erase chip command
|
||||
#define SPI_CMD_ERASE_SECTOR 3 // SPI erase sector command
|
||||
#define SPI_CMD_WRITE_DWORD 0 // SPI write a dword command
|
||||
#define SPI_CMD_READ_DWORD 1 // SPI read a dword command
|
||||
#define SPI_CMD_USER_CMD 5 // SPI user command
|
||||
|
||||
#define SPI_CLK_CMD_OFFSET 28 // SPI command field offset in Command register
|
||||
#define SPI_CLK_DIV_OFFSET 25 // SPI clock divide field offset in Command register
|
||||
|
||||
#define SPI_TIME_OUT_VALUE 10000
|
||||
#define SPI_SECTOR_SIZE (4 * 1024) // FLASH sector size is 64KB
|
||||
#define SPI_H_CMD_REG_ADDR 0x10104 // SPI Command register address
|
||||
#define SPI_H_DAT_REG_ADDR 0x10108 // SPI Data register address
|
||||
#define SPI_H_STA_REG_ADDR 0x1010c // SPI Status register address
|
||||
#define SPI_H_USR_CMD_REG_ADDR 0x10110 // SPI User Command register address
|
||||
#define SPI_CMD_CFG1_ADDR 0x10118 // Flash command configuration register 1
|
||||
#define MISC_RST_REG_ADDR 0x1000c // Misc reset register address
|
||||
#define MGR_FLASH_RELOAD_REG_ADDR 0x101a0 // MGR reload flash read
|
||||
|
||||
#define MAC_ADDR0_WORD0_OFFSET_1G 0x006000c // MAC Address for LAN0, stored in external FLASH
|
||||
#define MAC_ADDR0_WORD1_OFFSET_1G 0x0060014
|
||||
#define MAC_ADDR1_WORD0_OFFSET_1G 0x006800c // MAC Address for LAN1, stored in external FLASH
|
||||
#define MAC_ADDR1_WORD1_OFFSET_1G 0x0068014
|
||||
#define MAC_ADDR2_WORD0_OFFSET_1G 0x007000c // MAC Address for LAN2, stored in external FLASH
|
||||
#define MAC_ADDR2_WORD1_OFFSET_1G 0x0070014
|
||||
#define MAC_ADDR3_WORD0_OFFSET_1G 0x007800c // MAC Address for LAN3, stored in external FLASH
|
||||
#define MAC_ADDR3_WORD1_OFFSET_1G 0x0078014
|
||||
#define PRODUCT_SERIAL_NUM_OFFSET_1G 0x00f0000 // Product Serial Number, stored in external FLASH last sector
|
||||
|
||||
struct ngbe_hic_read_cab {
|
||||
union ngbe_hic_hdr2 hdr;
|
||||
union {
|
||||
u8 d8[252];
|
||||
u16 d16[126];
|
||||
u32 d32[63];
|
||||
} dbuf;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Packet Type decoding
|
||||
**/
|
||||
/* ngbe_dec_ptype.mac: outer mac */
|
||||
enum ngbe_dec_ptype_mac {
|
||||
NGBE_DEC_PTYPE_MAC_IP = 0,
|
||||
NGBE_DEC_PTYPE_MAC_L2 = 2,
|
||||
NGBE_DEC_PTYPE_MAC_FCOE = 3,
|
||||
};
|
||||
|
||||
/* ngbe_dec_ptype.[e]ip: outer&encaped ip */
|
||||
#define NGBE_DEC_PTYPE_IP_FRAG (0x4)
|
||||
enum ngbe_dec_ptype_ip {
|
||||
NGBE_DEC_PTYPE_IP_NONE = 0,
|
||||
NGBE_DEC_PTYPE_IP_IPV4 = 1,
|
||||
NGBE_DEC_PTYPE_IP_IPV6 = 2,
|
||||
NGBE_DEC_PTYPE_IP_FGV4 =
|
||||
(NGBE_DEC_PTYPE_IP_FRAG | NGBE_DEC_PTYPE_IP_IPV4),
|
||||
NGBE_DEC_PTYPE_IP_FGV6 =
|
||||
(NGBE_DEC_PTYPE_IP_FRAG | NGBE_DEC_PTYPE_IP_IPV6),
|
||||
};
|
||||
|
||||
/* ngbe_dec_ptype.etype: encaped type */
|
||||
enum ngbe_dec_ptype_etype {
|
||||
NGBE_DEC_PTYPE_ETYPE_NONE = 0,
|
||||
NGBE_DEC_PTYPE_ETYPE_IPIP = 1, /* IP+IP */
|
||||
NGBE_DEC_PTYPE_ETYPE_IG = 2, /* IP+GRE */
|
||||
NGBE_DEC_PTYPE_ETYPE_IGM = 3, /* IP+GRE+MAC */
|
||||
NGBE_DEC_PTYPE_ETYPE_IGMV = 4, /* IP+GRE+MAC+VLAN */
|
||||
};
|
||||
|
||||
/* ngbe_dec_ptype.proto: payload proto */
|
||||
enum ngbe_dec_ptype_prot {
|
||||
NGBE_DEC_PTYPE_PROT_NONE = 0,
|
||||
NGBE_DEC_PTYPE_PROT_UDP = 1,
|
||||
NGBE_DEC_PTYPE_PROT_TCP = 2,
|
||||
NGBE_DEC_PTYPE_PROT_SCTP = 3,
|
||||
NGBE_DEC_PTYPE_PROT_ICMP = 4,
|
||||
NGBE_DEC_PTYPE_PROT_TS = 5, /* time sync */
|
||||
};
|
||||
|
||||
/* ngbe_dec_ptype.layer: payload layer */
|
||||
enum ngbe_dec_ptype_layer {
|
||||
NGBE_DEC_PTYPE_LAYER_NONE = 0,
|
||||
NGBE_DEC_PTYPE_LAYER_PAY2 = 1,
|
||||
NGBE_DEC_PTYPE_LAYER_PAY3 = 2,
|
||||
NGBE_DEC_PTYPE_LAYER_PAY4 = 3,
|
||||
};
|
||||
|
||||
struct ngbe_dec_ptype {
|
||||
u32 ptype:8;
|
||||
u32 known:1;
|
||||
u32 mac:2; /* outer mac */
|
||||
u32 ip:3; /* outer ip*/
|
||||
u32 etype:3; /* encaped type */
|
||||
u32 eip:3; /* encaped ip */
|
||||
u32 prot:4; /* payload proto */
|
||||
u32 layer:3; /* payload layer */
|
||||
};
|
||||
typedef struct ngbe_dec_ptype ngbe_dptype;
|
||||
|
||||
|
||||
u16 ngbe_get_pcie_msix_count(struct ngbe_hw *hw);
|
||||
int ngbe_init_hw(struct ngbe_hw *hw);
|
||||
int ngbe_start_hw(struct ngbe_hw *hw);
|
||||
int ngbe_clear_hw_cntrs(struct ngbe_hw *hw);
|
||||
int ngbe_read_pba_string(struct ngbe_hw *hw, u8 *pba_num,
|
||||
u32 pba_num_size);
|
||||
int ngbe_get_mac_addr(struct ngbe_hw *hw, u8 *mac_addr);
|
||||
int ngbe_get_bus_info(struct ngbe_hw *hw);
|
||||
void ngbe_set_pci_config_data(struct ngbe_hw *hw, u16 link_status);
|
||||
void ngbe_set_lan_id_multi_port_pcie(struct ngbe_hw *hw);
|
||||
int ngbe_stop_adapter(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_led_on(struct ngbe_hw *hw, u32 index);
|
||||
int ngbe_led_off(struct ngbe_hw *hw, u32 index);
|
||||
|
||||
int ngbe_set_rar(struct ngbe_hw *hw, u32 index, u8 *addr, u64 pools,
|
||||
u32 enable_addr);
|
||||
int ngbe_clear_rar(struct ngbe_hw *hw, u32 index);
|
||||
int ngbe_init_rx_addrs(struct ngbe_hw *hw);
|
||||
int ngbe_update_mc_addr_list(struct ngbe_hw *hw, u8 *mc_addr_list,
|
||||
u32 mc_addr_count,
|
||||
ngbe_mc_addr_itr func, bool clear);
|
||||
int ngbe_update_uc_addr_list(struct ngbe_hw *hw, u8 *addr_list,
|
||||
u32 addr_count, ngbe_mc_addr_itr func);
|
||||
int ngbe_enable_mc(struct ngbe_hw *hw);
|
||||
int ngbe_disable_mc(struct ngbe_hw *hw);
|
||||
int ngbe_disable_sec_rx_path(struct ngbe_hw *hw);
|
||||
int ngbe_enable_sec_rx_path(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_fc_enable(struct ngbe_hw *hw);
|
||||
void ngbe_fc_autoneg(struct ngbe_hw *hw);
|
||||
int ngbe_setup_fc(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_validate_mac_addr(u8 *mac_addr);
|
||||
int ngbe_acquire_swfw_sync(struct ngbe_hw *hw, u32 mask);
|
||||
void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask);
|
||||
int ngbe_disable_pcie_master(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_set_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
|
||||
int ngbe_set_vmdq_san_mac(struct ngbe_hw *hw, u32 vmdq);
|
||||
int ngbe_clear_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
|
||||
int ngbe_insert_mac_addr(struct ngbe_hw *hw, u8 *addr, u32 vmdq);
|
||||
int ngbe_init_uta_tables(struct ngbe_hw *hw);
|
||||
int ngbe_set_vfta(struct ngbe_hw *hw, u32 vlan,
|
||||
u32 vind, bool vlan_on);
|
||||
int ngbe_set_vlvf(struct ngbe_hw *hw, u32 vlan, u32 vind,
|
||||
bool vlan_on, bool *vfta_changed);
|
||||
int ngbe_clear_vfta(struct ngbe_hw *hw);
|
||||
int ngbe_find_vlvf_slot(struct ngbe_hw *hw, u32 vlan);
|
||||
|
||||
void ngbe_set_mac_anti_spoofing(struct ngbe_hw *hw, bool enable, int pf);
|
||||
void ngbe_set_vlan_anti_spoofing(struct ngbe_hw *hw, bool enable, int vf);
|
||||
void ngbe_set_ethertype_anti_spoofing(struct ngbe_hw *hw,
|
||||
bool enable, int vf);
|
||||
int ngbe_get_device_caps(struct ngbe_hw *hw, u16 *device_caps);
|
||||
void ngbe_set_rxpba(struct ngbe_hw *hw, int num_pb, u32 headroom,
|
||||
int strategy);
|
||||
int ngbe_set_fw_drv_ver(struct ngbe_hw *hw, u8 maj, u8 min,
|
||||
u8 build, u8 ver);
|
||||
int ngbe_reset_hostif(struct ngbe_hw *hw);
|
||||
u8 ngbe_calculate_checksum(u8 *buffer, u32 length);
|
||||
int ngbe_host_interface_command(struct ngbe_hw *hw, u32 *buffer,
|
||||
u32 length, u32 timeout, bool return_data);
|
||||
|
||||
void ngbe_clear_tx_pending(struct ngbe_hw *hw);
|
||||
void ngbe_stop_mac_link_on_d3(struct ngbe_hw *hw);
|
||||
bool ngbe_mng_present(struct ngbe_hw *hw);
|
||||
bool ngbe_check_mng_access(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_get_thermal_sensor_data(struct ngbe_hw *hw);
|
||||
int ngbe_init_thermal_sensor_thresh(struct ngbe_hw *hw);
|
||||
void ngbe_enable_rx(struct ngbe_hw *hw);
|
||||
void ngbe_disable_rx(struct ngbe_hw *hw);
|
||||
int ngbe_setup_mac_link_multispeed_fiber(struct ngbe_hw *hw,
|
||||
u32 speed,
|
||||
bool autoneg_wait_to_complete);
|
||||
int ngbe_check_flash_load(struct ngbe_hw *hw, u32 check_bit);
|
||||
|
||||
/* @ngbe_api.h */
|
||||
void ngbe_atr_compute_perfect_hash(union ngbe_atr_input *input,
|
||||
union ngbe_atr_input *mask);
|
||||
u32 ngbe_atr_compute_sig_hash(union ngbe_atr_hash_dword input,
|
||||
union ngbe_atr_hash_dword common);
|
||||
|
||||
int ngbe_get_link_capabilities(struct ngbe_hw *hw,
|
||||
u32 *speed, bool *autoneg);
|
||||
enum ngbe_media_type ngbe_get_media_type(struct ngbe_hw *hw);
|
||||
void ngbe_disable_tx_laser_multispeed_fiber(struct ngbe_hw *hw);
|
||||
void ngbe_enable_tx_laser_multispeed_fiber(struct ngbe_hw *hw);
|
||||
void ngbe_flap_tx_laser_multispeed_fiber(struct ngbe_hw *hw);
|
||||
void ngbe_set_hard_rate_select_speed(struct ngbe_hw *hw,
|
||||
u32 speed);
|
||||
int ngbe_setup_mac_link(struct ngbe_hw *hw, u32 speed,
|
||||
bool autoneg_wait_to_complete);
|
||||
void ngbe_init_mac_link_ops(struct ngbe_hw *hw);
|
||||
int ngbe_reset_hw(struct ngbe_hw *hw);
|
||||
int ngbe_identify_phy(struct ngbe_hw *hw);
|
||||
void ngbe_init_ops_common(struct ngbe_hw *hw);
|
||||
int ngbe_enable_rx_dma(struct ngbe_hw *hw, u32 regval);
|
||||
void ngbe_init_ops(struct ngbe_hw *hw);
|
||||
int ngbe_setup_eee(struct ngbe_hw *hw, bool enable_eee);
|
||||
|
||||
int ngbe_init_flash_params(struct ngbe_hw *hw);
|
||||
int ngbe_read_flash_buffer(struct ngbe_hw *hw, u32 offset,
|
||||
u32 dwords, u32 *data);
|
||||
int ngbe_write_flash_buffer(struct ngbe_hw *hw, u32 offset,
|
||||
u32 dwords, u32 *data);
|
||||
|
||||
int ngbe_read_eeprom(struct ngbe_hw *hw,
|
||||
u16 offset, u16 *data);
|
||||
int ngbe_read_eeprom_buffer(struct ngbe_hw *hw, u16 offset,
|
||||
u16 words, u16 *data);
|
||||
int ngbe_init_eeprom_params(struct ngbe_hw *hw);
|
||||
int ngbe_update_eeprom_checksum(struct ngbe_hw *hw);
|
||||
int ngbe_calc_eeprom_checksum(struct ngbe_hw *hw);
|
||||
int ngbe_validate_eeprom_checksum(struct ngbe_hw *hw,
|
||||
u16 *checksum_val);
|
||||
int ngbe_upgrade_flash(struct ngbe_hw *hw, u32 region,
|
||||
const u8 *data, u32 size);
|
||||
int ngbe_write_ee_hostif_buffer(struct ngbe_hw *hw,
|
||||
u16 offset, u16 words, u16 *data);
|
||||
int ngbe_write_ee_hostif(struct ngbe_hw *hw, u16 offset,
|
||||
u16 data);
|
||||
int ngbe_write_ee_hostif32(struct ngbe_hw *hw, u16 offset,
|
||||
u32 data);
|
||||
|
||||
int ngbe_read_ee_hostif_buffer(struct ngbe_hw *hw,
|
||||
u16 offset, u16 words, u16 *data);
|
||||
int ngbe_read_ee_hostif(struct ngbe_hw *hw, u16 offset, u16 *data);
|
||||
|
||||
int ngbe_read_ee_hostif32(struct ngbe_hw *hw, u16 offset, u32 *data);
|
||||
|
||||
u32 ngbe_rd32_epcs(struct ngbe_hw *hw, u32 addr);
|
||||
void ngbe_wr32_epcs(struct ngbe_hw *hw, u32 addr, u32 data);
|
||||
void ngbe_wr32_ephy(struct ngbe_hw *hw, u32 addr, u32 data);
|
||||
int ngbe_upgrade_flash_hostif(struct ngbe_hw *hw, u32 region,
|
||||
const u8 *data, u32 size);
|
||||
|
||||
int ngbe_eepromcheck_cap(struct ngbe_hw *hw, u16 offset,
|
||||
u32 *data);
|
||||
int ngbe_phy_signal_set(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_flash_read_dword(struct ngbe_hw *hw, u32 addr, u32 *data);
|
||||
|
||||
int ngbe_is_lldp(struct ngbe_hw *hw);
|
||||
int ngbe_hic_write_lldp(struct ngbe_hw *hw, u32 open);
|
||||
|
||||
#endif /* _NGBE_HW_H_ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ngbe.h"
|
||||
#include "ngbe_sriov.h"
|
||||
|
||||
/**
|
||||
* ngbe_cache_ring_vmdq - Descriptor ring to register mapping for VMDq
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* Cache the descriptor ring offsets for VMDq to the assigned rings. It
|
||||
* will also try to cache the proper offsets if RSS/FCoE/SRIOV are enabled along
|
||||
* with VMDq.
|
||||
*
|
||||
**/
|
||||
static bool ngbe_cache_ring_vmdq(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
|
||||
//struct ngbe_ring_feature *rss = &adapter->ring_feature[RING_F_RSS];
|
||||
int i;
|
||||
u16 reg_idx;
|
||||
|
||||
/* only proceed if VMDq is enabled */
|
||||
if (!(adapter->flags & NGBE_FLAG_VMDQ_ENABLED))
|
||||
return false;
|
||||
|
||||
/* start at VMDq register offset for SR-IOV enabled setups */
|
||||
reg_idx = vmdq->offset;
|
||||
|
||||
for (i = 0; i < adapter->num_rx_queues; i++) {
|
||||
|
||||
/* If we are greater than indices move to next pool */
|
||||
adapter->rx_ring[i]->reg_idx = reg_idx + i;
|
||||
}
|
||||
|
||||
reg_idx = vmdq->offset;
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
|
||||
/* If we are greater than indices move to next pool */
|
||||
adapter->tx_ring[i]->reg_idx = reg_idx + i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_cache_ring_rss - Descriptor ring to register mapping for RSS
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* Cache the descriptor ring offsets for RSS, ATR, FCoE, and SR-IOV.
|
||||
*
|
||||
**/
|
||||
static bool ngbe_cache_ring_rss(struct ngbe_adapter *adapter)
|
||||
{
|
||||
u16 i, reg_i;
|
||||
|
||||
for (i = 0; i < adapter->num_rx_queues; i++)
|
||||
adapter->rx_ring[i]->reg_idx = i;
|
||||
|
||||
for (i = 0, reg_i = 0; i < adapter->num_tx_queues; i++, reg_i++)
|
||||
adapter->tx_ring[i]->reg_idx = reg_i;
|
||||
|
||||
for (i = 0; i < adapter->num_xdp_queues; i++, reg_i++)
|
||||
adapter->xdp_ring[i]->reg_idx = reg_i;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_cache_ring_register - Descriptor ring to register mapping
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* Once we know the feature-set enabled for the device, we'll cache
|
||||
* the register offset the descriptor ring is assigned to.
|
||||
*
|
||||
* Note, the order the various feature calls is important. It must start with
|
||||
* the "most" features enabled at the same time, then trickle down to the
|
||||
* least amount of features turned on at once.
|
||||
**/
|
||||
static void ngbe_cache_ring_register(struct ngbe_adapter *adapter)
|
||||
{
|
||||
if (ngbe_cache_ring_vmdq(adapter))
|
||||
return;
|
||||
|
||||
ngbe_cache_ring_rss(adapter);
|
||||
}
|
||||
|
||||
#define NGBE_RSS_64Q_MASK 0x3F
|
||||
#define NGBE_RSS_16Q_MASK 0xF
|
||||
#define NGBE_RSS_8Q_MASK 0x7
|
||||
#define NGBE_RSS_4Q_MASK 0x3
|
||||
#define NGBE_RSS_2Q_MASK 0x1
|
||||
#define NGBE_RSS_DISABLED_MASK 0x0
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_set_vmdq_queues: Allocate queues for VMDq devices
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* When VMDq (Virtual Machine Devices queue) is enabled, allocate queues
|
||||
* and VM pools where appropriate. If RSS is available, then also try and
|
||||
* enable RSS and map accordingly.
|
||||
*
|
||||
**/
|
||||
static bool ngbe_set_vmdq_queues(struct ngbe_adapter *adapter)
|
||||
{
|
||||
u16 vmdq_i = adapter->ring_feature[RING_F_VMDQ].limit;
|
||||
u16 vmdq_m = 0;
|
||||
u16 rss_i = adapter->ring_feature[RING_F_RSS].limit;
|
||||
u16 rss_m = NGBE_RSS_DISABLED_MASK;
|
||||
|
||||
/* only proceed if VMDq is enabled */
|
||||
if (!(adapter->flags & NGBE_FLAG_VMDQ_ENABLED))
|
||||
return false;
|
||||
|
||||
/* Add starting offset to total pool count */
|
||||
vmdq_i += adapter->ring_feature[RING_F_VMDQ].offset;
|
||||
|
||||
/* double check we are limited to maximum pools */
|
||||
vmdq_i = min_t(u16, NGBE_MAX_VMDQ_INDICES, vmdq_i);
|
||||
|
||||
/* when VMDQ on, disable RSS */
|
||||
rss_i = 1;
|
||||
|
||||
/* remove the starting offset from the pool count */
|
||||
vmdq_i -= adapter->ring_feature[RING_F_VMDQ].offset;
|
||||
|
||||
/* save features for later use */
|
||||
adapter->ring_feature[RING_F_VMDQ].indices = vmdq_i;
|
||||
adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
|
||||
|
||||
/* limit RSS based on user input and save for later use */
|
||||
adapter->ring_feature[RING_F_RSS].indices = rss_i;
|
||||
adapter->ring_feature[RING_F_RSS].mask = rss_m;
|
||||
|
||||
adapter->queues_per_pool = rss_i;
|
||||
adapter->num_rx_queues = vmdq_i * rss_i;
|
||||
|
||||
#ifdef HAVE_TX_MQ
|
||||
adapter->num_tx_queues = vmdq_i * rss_i;
|
||||
#else
|
||||
adapter->num_tx_queues = vmdq_i;
|
||||
#endif /* HAVE_TX_MQ */
|
||||
adapter->num_xdp_queues = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XDP_SUPPORT
|
||||
static int ngbe_xdp_queues(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int queues = min_t(int, NGBE_MAX_XDP_QS, nr_cpu_ids);
|
||||
|
||||
return adapter->xdp_prog ? queues : 0;
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* ngbe_set_rss_queues: Allocate queues for RSS
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* This is our "base" multiqueue mode. RSS (Receive Side Scaling) will try
|
||||
* to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
|
||||
*
|
||||
**/
|
||||
static bool ngbe_set_rss_queues(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_ring_feature *f;
|
||||
u16 rss_i;
|
||||
|
||||
/* set mask for 16 queue limit of RSS */
|
||||
f = &adapter->ring_feature[RING_F_RSS];
|
||||
rss_i = f->limit;
|
||||
|
||||
f->indices = rss_i;
|
||||
f->mask = NGBE_RSS_8Q_MASK;
|
||||
|
||||
adapter->num_rx_queues = rss_i;
|
||||
#ifdef HAVE_TX_MQ
|
||||
adapter->num_tx_queues = rss_i;
|
||||
#endif
|
||||
#ifdef HAVE_XDP_SUPPORT
|
||||
if (adapter->xdp_prog) {
|
||||
adapter->num_xdp_queues = min_t(int, ngbe_xdp_queues(adapter), rss_i);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* ngbe_set_num_queues: Allocate queues for device, feature dependent
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* This is the top level queue allocation routine. The order here is very
|
||||
* important, starting with the "most" number of features turned on at once,
|
||||
* and ending with the smallest set of features. This way large combinations
|
||||
* can be allocated if they're turned on, and smaller combinations are the
|
||||
* fallthrough conditions.
|
||||
*
|
||||
**/
|
||||
static void ngbe_set_num_queues(struct ngbe_adapter *adapter)
|
||||
{
|
||||
/* Start with base case */
|
||||
adapter->num_rx_queues = 1;
|
||||
adapter->num_tx_queues = 1;
|
||||
adapter->num_xdp_queues = 0;
|
||||
adapter->queues_per_pool = 1;
|
||||
|
||||
if (ngbe_set_vmdq_queues(adapter))
|
||||
return;
|
||||
|
||||
ngbe_set_rss_queues(adapter);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_acquire_msix_vectors - acquire MSI-X vectors
|
||||
* @adapter: board private structure
|
||||
*
|
||||
* Attempts to acquire a suitable range of MSI-X vector interrupts. Will
|
||||
* return a negative error code if unable to acquire MSI-X vectors for any
|
||||
* reason.
|
||||
*/
|
||||
static int ngbe_acquire_msix_vectors(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
int i, vectors, vector_threshold;
|
||||
|
||||
if (!(adapter->flags & NGBE_FLAG_MSIX_CAPABLE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* We start by asking for one vector per queue pair */
|
||||
vectors = max(adapter->num_rx_queues, adapter->num_tx_queues);
|
||||
vectors = max(vectors, adapter->num_xdp_queues);
|
||||
|
||||
/* It is easy to be greedy for MSI-X vectors. However, it really
|
||||
* doesn't do much good if we have a lot more vectors than CPUs. We'll
|
||||
* be somewhat conservative and only ask for (roughly) the same number
|
||||
* of vectors as there are CPUs.
|
||||
*/
|
||||
vectors = min_t(int, vectors, num_online_cpus());
|
||||
|
||||
/* Some vectors are necessary for non-queue interrupts */
|
||||
vectors += NON_Q_VECTORS;
|
||||
|
||||
/* Hardware can only support a maximum of hw.mac->max_msix_vectors.
|
||||
* With features such as RSS and VMDq, we can easily surpass the
|
||||
* number of Rx and Tx descriptor queues supported by our device.
|
||||
* Thus, we cap the maximum in the rare cases where the CPU count also
|
||||
* exceeds our vector limit
|
||||
*/
|
||||
vectors = min_t(int, vectors, hw->mac.max_msix_vectors);
|
||||
|
||||
/* We want a minimum of two MSI-X vectors for (1) a TxQ[0] + RxQ[0]
|
||||
* handler, and (2) an Other (Link Status Change, etc.) handler.
|
||||
*/
|
||||
vector_threshold = MIN_MSIX_COUNT;
|
||||
|
||||
/* we need to alloc (7vfs+1pf+1misc) or (8vfs+1misc) msix entries */
|
||||
if (adapter->flags2 & NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP) {
|
||||
vectors += adapter->ring_feature[RING_F_VMDQ].offset;
|
||||
}
|
||||
|
||||
adapter->msix_entries = kcalloc(vectors,
|
||||
sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (!adapter->msix_entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < vectors; i++)
|
||||
adapter->msix_entries[i].entry = i;
|
||||
|
||||
vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
|
||||
vector_threshold, vectors);
|
||||
if (vectors < 0) {
|
||||
/* A negative count of allocated vectors indicates an error in
|
||||
* acquiring within the specified range of MSI-X vectors */
|
||||
e_dev_warn("Failed to allocate MSI-X interrupts. Err: %d\n",
|
||||
vectors);
|
||||
|
||||
adapter->flags &= ~NGBE_FLAG_MSIX_ENABLED;
|
||||
kfree(adapter->msix_entries);
|
||||
adapter->msix_entries = NULL;
|
||||
|
||||
return vectors;
|
||||
}
|
||||
|
||||
if (adapter->flags2 & NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP) {
|
||||
if (vectors < 9) {
|
||||
adapter->flags2 &= ~NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP;
|
||||
e_dev_warn("Remain available irqs < 9. Disable MISC IRQ REMAP.\n");
|
||||
}
|
||||
else
|
||||
vectors -= adapter->ring_feature[RING_F_VMDQ].offset;
|
||||
}
|
||||
|
||||
/* we successfully allocated some number of vectors within our
|
||||
* requested range.
|
||||
*/
|
||||
adapter->flags |= NGBE_FLAG_MSIX_ENABLED;
|
||||
|
||||
/* Adjust for only the vectors we'll use, which is minimum
|
||||
* of max_q_vectors, or the number of vectors we were allocated.
|
||||
*/
|
||||
vectors -= NON_Q_VECTORS;
|
||||
adapter->num_q_vectors = min_t(int, vectors, adapter->max_q_vectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ngbe_add_ring(struct ngbe_ring *ring,
|
||||
struct ngbe_ring_container *head)
|
||||
{
|
||||
ring->next = head->ring;
|
||||
head->ring = ring;
|
||||
head->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_alloc_q_vector - Allocate memory for a single interrupt vector
|
||||
* @adapter: board private structure to initialize
|
||||
* @v_count: q_vectors allocated on adapter, used for ring interleaving
|
||||
* @v_idx: index of vector in adapter struct
|
||||
* @txr_count: total number of Tx rings to allocate
|
||||
* @txr_idx: index of first Tx ring to allocate
|
||||
* @rxr_count: total number of Rx rings to allocate
|
||||
* @rxr_idx: index of first Rx ring to allocate
|
||||
*
|
||||
* We allocate one q_vector. If allocation fails we return -ENOMEM.
|
||||
**/
|
||||
static int ngbe_alloc_q_vector(struct ngbe_adapter *adapter,
|
||||
unsigned int v_count, unsigned int v_idx,
|
||||
unsigned int txr_count, unsigned int txr_idx,
|
||||
unsigned int xdp_count, unsigned int xdp_idx,
|
||||
unsigned int rxr_count, unsigned int rxr_idx)
|
||||
{
|
||||
struct ngbe_q_vector *q_vector;
|
||||
struct ngbe_ring *ring;
|
||||
int node = -1;
|
||||
#ifdef HAVE_IRQ_AFFINITY_HINT
|
||||
int cpu = -1;
|
||||
u8 tcs = netdev_get_num_tc(adapter->netdev);
|
||||
#endif
|
||||
|
||||
int ring_count, size;
|
||||
|
||||
/* note this will allocate space for the ring structure as well! */
|
||||
ring_count = txr_count + rxr_count + xdp_count;
|
||||
size = sizeof(struct ngbe_q_vector) +
|
||||
(sizeof(struct ngbe_ring) * ring_count);
|
||||
|
||||
#ifdef HAVE_IRQ_AFFINITY_HINT
|
||||
/* customize cpu for Flow Director mapping */
|
||||
if ((tcs <= 1) && !(adapter->flags & NGBE_FLAG_VMDQ_ENABLED)) {
|
||||
u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
|
||||
if (rss_i > 1 && adapter->atr_sample_rate) {
|
||||
if (cpu_online(v_idx)) {
|
||||
cpu = v_idx;
|
||||
node = cpu_to_node(cpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/* allocate q_vector and rings */
|
||||
q_vector = kzalloc_node(size, GFP_KERNEL, node);
|
||||
if (!q_vector)
|
||||
q_vector = kzalloc(size, GFP_KERNEL);
|
||||
if (!q_vector)
|
||||
return -ENOMEM;
|
||||
|
||||
/* setup affinity mask and node */
|
||||
#ifdef HAVE_IRQ_AFFINITY_HINT
|
||||
if (cpu != -1)
|
||||
cpumask_set_cpu(cpu, &q_vector->affinity_mask);
|
||||
#endif
|
||||
q_vector->numa_node = node;
|
||||
|
||||
/* initialize CPU for DCA */
|
||||
q_vector->cpu = -1;
|
||||
|
||||
#ifndef NGBE_NO_LRO
|
||||
/* initialize LRO */
|
||||
__skb_queue_head_init(&q_vector->lrolist.active);
|
||||
|
||||
#endif
|
||||
/* initialize NAPI */
|
||||
#ifdef HAVE_NOT_NAPI_WEIGHT
|
||||
netif_napi_add(adapter->netdev, &q_vector->napi,
|
||||
ngbe_poll);
|
||||
#else
|
||||
netif_napi_add(adapter->netdev, &q_vector->napi,
|
||||
ngbe_poll, 64);
|
||||
#endif
|
||||
#ifndef HAVE_NETIF_NAPI_ADD_CALLS_NAPI_HASH_ADD
|
||||
#ifdef HAVE_NDO_BUSY_POLL
|
||||
napi_hash_add(&q_vector->napi);
|
||||
#endif
|
||||
#endif /*HAVE_NETIF_NAPI_ADD_CALLS_NAPI_HASH_ADD*/
|
||||
|
||||
#ifdef HAVE_NDO_BUSY_POLL
|
||||
/* initialize busy poll */
|
||||
atomic_set(&q_vector->state, NGBE_QV_STATE_DISABLE);
|
||||
|
||||
#endif
|
||||
/* tie q_vector and adapter together */
|
||||
adapter->q_vector[v_idx] = q_vector;
|
||||
q_vector->adapter = adapter;
|
||||
q_vector->v_idx = v_idx;
|
||||
|
||||
/* initialize work limits */
|
||||
q_vector->tx.work_limit = adapter->tx_work_limit;
|
||||
q_vector->rx.work_limit = adapter->rx_work_limit;
|
||||
|
||||
/* initialize pointer to rings */
|
||||
ring = q_vector->ring;
|
||||
|
||||
/* intialize ITR */
|
||||
if (txr_count && !rxr_count) {
|
||||
/* tx only vector */
|
||||
if (adapter->tx_itr_setting == 1)
|
||||
q_vector->itr = NGBE_7K_ITR;
|
||||
else
|
||||
q_vector->itr = adapter->tx_itr_setting;
|
||||
} else {
|
||||
/* rx or rx/tx vector */
|
||||
if (adapter->rx_itr_setting == 1)
|
||||
q_vector->itr = NGBE_7K_ITR;
|
||||
else
|
||||
q_vector->itr = adapter->rx_itr_setting;
|
||||
}
|
||||
|
||||
while (txr_count) {
|
||||
/* assign generic ring traits */
|
||||
ring->dev = pci_dev_to_dev(adapter->pdev);
|
||||
ring->netdev = adapter->netdev;
|
||||
|
||||
/* configure backlink on ring */
|
||||
ring->q_vector = q_vector;
|
||||
|
||||
/* update q_vector Tx values */
|
||||
ngbe_add_ring(ring, &q_vector->tx);
|
||||
|
||||
/* apply Tx specific ring traits */
|
||||
ring->count = adapter->tx_ring_count;
|
||||
if (adapter->num_vmdqs > 1)
|
||||
ring->queue_index =
|
||||
txr_idx % adapter->queues_per_pool;
|
||||
else
|
||||
ring->queue_index = txr_idx;
|
||||
clear_ring_xdp(ring);
|
||||
/* assign ring to adapter */
|
||||
adapter->tx_ring[txr_idx] = ring;
|
||||
|
||||
/* update count and index */
|
||||
txr_count--;
|
||||
txr_idx += v_count;
|
||||
|
||||
/* push pointer to next ring */
|
||||
ring++;
|
||||
}
|
||||
while (xdp_count) {
|
||||
/* assign generic ring traits */
|
||||
ring->dev = pci_dev_to_dev(adapter->pdev);
|
||||
ring->netdev = adapter->netdev;
|
||||
|
||||
/* configure backlink on ring */
|
||||
ring->q_vector = q_vector;
|
||||
|
||||
/* update q_vector Tx values */
|
||||
ngbe_add_ring(ring, &q_vector->tx);
|
||||
|
||||
/* apply Tx specific ring traits */
|
||||
ring->count = adapter->tx_ring_count;
|
||||
ring->queue_index = xdp_idx;
|
||||
set_ring_xdp(ring);
|
||||
|
||||
|
||||
/* assign ring to adapter */
|
||||
adapter->xdp_ring[xdp_idx] = ring;
|
||||
|
||||
/* update count and index */
|
||||
xdp_count--;
|
||||
xdp_idx += v_count;
|
||||
|
||||
/* push pointer to next ring */
|
||||
ring++;
|
||||
}
|
||||
while (rxr_count) {
|
||||
/* assign generic ring traits */
|
||||
ring->dev = pci_dev_to_dev(adapter->pdev);
|
||||
ring->netdev = adapter->netdev;
|
||||
|
||||
/* configure backlink on ring */
|
||||
ring->q_vector = q_vector;
|
||||
|
||||
/* update q_vector Rx values */
|
||||
ngbe_add_ring(ring, &q_vector->rx);
|
||||
|
||||
/* apply Rx specific ring traits */
|
||||
ring->count = adapter->rx_ring_count;
|
||||
if (adapter->num_vmdqs > 1)
|
||||
ring->queue_index =
|
||||
rxr_idx % adapter->queues_per_pool;
|
||||
else
|
||||
ring->queue_index = rxr_idx;
|
||||
|
||||
/* assign ring to adapter */
|
||||
adapter->rx_ring[rxr_idx] = ring;
|
||||
|
||||
/* update count and index */
|
||||
rxr_count--;
|
||||
rxr_idx += v_count;
|
||||
|
||||
/* push pointer to next ring */
|
||||
ring++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_free_q_vector - Free memory allocated for specific interrupt vector
|
||||
* @adapter: board private structure to initialize
|
||||
* @v_idx: Index of vector to be freed
|
||||
*
|
||||
* This function frees the memory allocated to the q_vector. In addition if
|
||||
* NAPI is enabled it will delete any references to the NAPI struct prior
|
||||
* to freeing the q_vector.
|
||||
**/
|
||||
static void ngbe_free_q_vector(struct ngbe_adapter *adapter, int v_idx)
|
||||
{
|
||||
struct ngbe_q_vector *q_vector = adapter->q_vector[v_idx];
|
||||
struct ngbe_ring *ring;
|
||||
|
||||
ngbe_for_each_ring(ring, q_vector->tx) {
|
||||
if (ring_is_xdp(ring))
|
||||
adapter->xdp_ring[ring->queue_index] = NULL;
|
||||
else
|
||||
adapter->tx_ring[ring->queue_index] = NULL;
|
||||
}
|
||||
#ifdef HAVE_XDP_SUPPORT
|
||||
if (static_key_enabled((struct static_key *)&ngbe_xdp_locking_key))
|
||||
static_branch_dec(&ngbe_xdp_locking_key);
|
||||
#endif
|
||||
|
||||
ngbe_for_each_ring(ring, q_vector->rx)
|
||||
adapter->rx_ring[ring->queue_index] = NULL;
|
||||
|
||||
adapter->q_vector[v_idx] = NULL;
|
||||
#ifdef HAVE_NDO_BUSY_POLL
|
||||
napi_hash_del(&q_vector->napi);
|
||||
#endif
|
||||
netif_napi_del(&q_vector->napi);
|
||||
#ifndef NGBE_NO_LRO
|
||||
__skb_queue_purge(&q_vector->lrolist.active);
|
||||
#endif
|
||||
kfree_rcu(q_vector, rcu);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_alloc_q_vectors - Allocate memory for interrupt vectors
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* We allocate one q_vector per queue interrupt. If allocation fails we
|
||||
* return -ENOMEM.
|
||||
**/
|
||||
static int ngbe_alloc_q_vectors(struct ngbe_adapter *adapter)
|
||||
{
|
||||
unsigned int q_vectors = adapter->num_q_vectors;
|
||||
unsigned int rxr_remaining = adapter->num_rx_queues;
|
||||
unsigned int txr_remaining = adapter->num_tx_queues;
|
||||
unsigned int xdp_remaining = adapter->num_xdp_queues;
|
||||
unsigned int rxr_idx = 0, txr_idx = 0, xdp_idx = 0, v_idx = 0;
|
||||
int err;
|
||||
|
||||
if (q_vectors >= (rxr_remaining + txr_remaining + xdp_remaining)) {
|
||||
for (; rxr_remaining; v_idx++) {
|
||||
err = ngbe_alloc_q_vector(adapter, q_vectors, v_idx,
|
||||
0, 0, 0, 0, 1, rxr_idx);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* update counts and index */
|
||||
rxr_remaining--;
|
||||
rxr_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; v_idx < q_vectors; v_idx++) {
|
||||
int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
|
||||
int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
|
||||
int xqpv = DIV_ROUND_UP(xdp_remaining, q_vectors - v_idx);
|
||||
err = ngbe_alloc_q_vector(adapter, q_vectors, v_idx,
|
||||
tqpv, txr_idx,
|
||||
xqpv, xdp_idx,
|
||||
rqpv, rxr_idx);
|
||||
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* update counts and index */
|
||||
rxr_remaining -= rqpv;
|
||||
txr_remaining -= tqpv;
|
||||
xdp_remaining -= xqpv;
|
||||
rxr_idx++;
|
||||
txr_idx++;
|
||||
xdp_idx++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
adapter->num_tx_queues = 0;
|
||||
adapter->num_rx_queues = 0;
|
||||
adapter->num_xdp_queues = 0;
|
||||
adapter->num_q_vectors = 0;
|
||||
|
||||
while (v_idx--)
|
||||
ngbe_free_q_vector(adapter, v_idx);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_free_q_vectors - Free memory allocated for interrupt vectors
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* This function frees the memory allocated to the q_vectors. In addition if
|
||||
* NAPI is enabled it will delete any references to the NAPI struct prior
|
||||
* to freeing the q_vector.
|
||||
**/
|
||||
static void ngbe_free_q_vectors(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int v_idx = adapter->num_q_vectors;
|
||||
|
||||
adapter->num_tx_queues = 0;
|
||||
adapter->num_rx_queues = 0;
|
||||
adapter->num_xdp_queues = 0;
|
||||
adapter->num_q_vectors = 0;
|
||||
|
||||
while (v_idx--)
|
||||
ngbe_free_q_vector(adapter, v_idx);
|
||||
}
|
||||
|
||||
void ngbe_reset_interrupt_capability(struct ngbe_adapter *adapter)
|
||||
{
|
||||
if (adapter->flags & NGBE_FLAG_MSIX_ENABLED) {
|
||||
adapter->flags &= ~NGBE_FLAG_MSIX_ENABLED;
|
||||
pci_disable_msix(adapter->pdev);
|
||||
kfree(adapter->msix_entries);
|
||||
adapter->msix_entries = NULL;
|
||||
} else if (adapter->flags & NGBE_FLAG_MSI_ENABLED) {
|
||||
adapter->flags &= ~NGBE_FLAG_MSI_ENABLED;
|
||||
pci_disable_msi(adapter->pdev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_set_interrupt_capability - set MSI-X or MSI if supported
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* Attempt to configure the interrupts using the best available
|
||||
* capabilities of the hardware and the kernel.
|
||||
**/
|
||||
void ngbe_set_interrupt_capability(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* We will try to get MSI-X interrupts first */
|
||||
if (!ngbe_acquire_msix_vectors(adapter))
|
||||
return;
|
||||
|
||||
/* At this point, we do not have MSI-X capabilities. We need to
|
||||
* reconfigure or disable various features which require MSI-X
|
||||
* capability.
|
||||
*/
|
||||
/* Disable VMDq support */
|
||||
e_dev_warn("Disabling VMQd support\n");
|
||||
adapter->flags &= ~NGBE_FLAG_VMDQ_ENABLED;
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
/* Disable SR-IOV support */
|
||||
e_dev_warn("Disabling SR-IOV support\n");
|
||||
ngbe_disable_sriov(adapter);
|
||||
if (adapter->flags2 & NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP)
|
||||
adapter->flags2 &= ~NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP;
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
/* Disable RSS */
|
||||
e_dev_warn("Disabling RSS support\n");
|
||||
adapter->ring_feature[RING_F_RSS].limit = 1;
|
||||
|
||||
/* recalculate number of queues now that many features have been
|
||||
* changed or disabled.
|
||||
*/
|
||||
ngbe_set_num_queues(adapter);
|
||||
adapter->num_q_vectors = 1;
|
||||
|
||||
if (!(adapter->flags & NGBE_FLAG_MSI_CAPABLE))
|
||||
return;
|
||||
|
||||
err = pci_enable_msi(adapter->pdev);
|
||||
if (err)
|
||||
e_dev_warn("Failed to allocate MSI interrupt, falling back to "
|
||||
"legacy. Error: %d\n",
|
||||
err);
|
||||
else
|
||||
adapter->flags |= NGBE_FLAG_MSI_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_init_interrupt_scheme - Determine proper interrupt scheme
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* We determine which interrupt scheme to use based on...
|
||||
* - Kernel support (MSI, MSI-X)
|
||||
* - which can be user-defined (via MODULE_PARAM)
|
||||
* - Hardware queue count (num_*_queues)
|
||||
* - defined by miscellaneous hardware support/features (RSS, etc.)
|
||||
**/
|
||||
int ngbe_init_interrupt_scheme(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* if assigned vfs >= 7, the PF queue irq remain seq 0 and misc irq move from
|
||||
* seq 1 to seq 8. it needs extra processions.
|
||||
*/
|
||||
if (adapter->num_vfs >= NGBE_MAX_VF_FUNCTIONS - 1) {
|
||||
adapter->flags2 |= NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP;
|
||||
adapter->irq_remap_offset = adapter->num_vfs;
|
||||
}
|
||||
|
||||
/* Number of supported queues */
|
||||
ngbe_set_num_queues(adapter);
|
||||
|
||||
/* Set interrupt mode */
|
||||
ngbe_set_interrupt_capability(adapter);
|
||||
|
||||
/* Allocate memory for queues */
|
||||
err = ngbe_alloc_q_vectors(adapter);
|
||||
if (err) {
|
||||
e_err(probe, "Unable to allocate memory for queue vectors\n");
|
||||
ngbe_reset_interrupt_capability(adapter);
|
||||
return err;
|
||||
}
|
||||
|
||||
ngbe_cache_ring_register(adapter);
|
||||
|
||||
set_bit(__NGBE_DOWN, &adapter->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
|
||||
* @adapter: board private structure to clear interrupt scheme on
|
||||
*
|
||||
* We go through and clear interrupt specific resources and reset the structure
|
||||
* to pre-load conditions
|
||||
**/
|
||||
void ngbe_clear_interrupt_scheme(struct ngbe_adapter *adapter)
|
||||
{
|
||||
ngbe_free_q_vectors(adapter);
|
||||
ngbe_reset_interrupt_capability(adapter);
|
||||
|
||||
/* remove this flags */
|
||||
if (adapter->flags2 & NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP) {
|
||||
adapter->flags2 &= ~NGBE_FLAG2_SRIOV_MISC_IRQ_REMAP;
|
||||
}
|
||||
}
|
||||
|
||||
void ngbe_tx_ctxtdesc(struct ngbe_ring *tx_ring, u32 vlan_macip_lens,
|
||||
u32 fcoe_sof_eof, u32 type_tucmd, u32 mss_l4len_idx)
|
||||
{
|
||||
struct ngbe_tx_context_desc *context_desc;
|
||||
u16 i = tx_ring->next_to_use;
|
||||
|
||||
context_desc = NGBE_TX_CTXTDESC(tx_ring, i);
|
||||
|
||||
i++;
|
||||
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
|
||||
|
||||
/* set bits to identify this as an advanced context descriptor */
|
||||
type_tucmd |= NGBE_TXD_DTYP_CTXT;
|
||||
context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
|
||||
context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof);
|
||||
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
|
||||
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,692 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ngbe_type.h"
|
||||
#include "ngbe.h"
|
||||
#include "ngbe_mbx.h"
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_read_mbx - Reads a message from the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to read
|
||||
*
|
||||
* returns SUCCESS if it successfuly read message from buffer
|
||||
**/
|
||||
int ngbe_read_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
/* limit read to size of mailbox */
|
||||
if (size > mbx->size)
|
||||
size = mbx->size;
|
||||
|
||||
err = hw->mbx.ops.read(hw, msg, size, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_write_mbx - Write a message to the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer
|
||||
**/
|
||||
int ngbe_write_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int err = 0;
|
||||
|
||||
if (size > mbx->size) {
|
||||
err = NGBE_ERR_MBX;
|
||||
ERROR_REPORT2(NGBE_ERROR_ARGUMENT,
|
||||
"Invalid mailbox message size %d", size);
|
||||
} else
|
||||
err = hw->mbx.ops.write(hw, msg, size, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_msg - checks to see if someone sent us mail
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
int ngbe_check_for_msg(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
err = hw->mbx.ops.check_for_msg(hw, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_ack - checks to see if someone sent us ACK
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
int ngbe_check_for_ack(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
err = hw->mbx.ops.check_for_ack(hw, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_rst - checks to see if other side has reset
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
int ngbe_check_for_rst(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
if (mbx->ops.check_for_rst)
|
||||
err = mbx->ops.check_for_rst(hw, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_poll_for_msg - Wait for message notification
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message notification
|
||||
**/
|
||||
static int ngbe_poll_for_msg(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int countdown = mbx->timeout;
|
||||
|
||||
if (!countdown || !mbx->ops.check_for_msg)
|
||||
goto out;
|
||||
|
||||
while (countdown && hw->mbx.ops.check_for_msg(hw, mbx_id)) {
|
||||
countdown--;
|
||||
if (!countdown)
|
||||
break;
|
||||
udelay(mbx->udelay);
|
||||
}
|
||||
|
||||
if (countdown == 0)
|
||||
ERROR_REPORT2(NGBE_ERROR_POLLING,
|
||||
"Polling for VF%d mailbox message timedout", mbx_id);
|
||||
|
||||
out:
|
||||
return countdown ? 0 : NGBE_ERR_MBX;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_poll_for_ack - Wait for message acknowledngbeent
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message acknowledngbeent
|
||||
**/
|
||||
static int ngbe_poll_for_ack(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int countdown = mbx->timeout;
|
||||
|
||||
if (!countdown || !mbx->ops.check_for_ack)
|
||||
goto out;
|
||||
|
||||
while (countdown && hw->mbx.ops.check_for_ack(hw, mbx_id)) {
|
||||
countdown--;
|
||||
if (!countdown)
|
||||
break;
|
||||
udelay(mbx->udelay);
|
||||
}
|
||||
|
||||
if (countdown == 0)
|
||||
ERROR_REPORT2(NGBE_ERROR_POLLING,
|
||||
"Polling for VF%d mailbox ack timedout", mbx_id);
|
||||
|
||||
out:
|
||||
return countdown ? 0 : NGBE_ERR_MBX;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_read_posted_mbx - Wait for message notification and receive message
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message notification and
|
||||
* copied it into the receive buffer.
|
||||
**/
|
||||
int ngbe_read_posted_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
if (!mbx->ops.read)
|
||||
goto out;
|
||||
|
||||
err = ngbe_poll_for_msg(hw, mbx_id);
|
||||
|
||||
/* if ack received read message, otherwise we timed out */
|
||||
if (!err)
|
||||
err = hw->mbx.ops.read(hw, msg, size, mbx_id);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_write_posted_mbx - Write a message to the mailbox, wait for ack
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer and
|
||||
* received an ack to that message within delay * timeout period
|
||||
**/
|
||||
int ngbe_write_posted_mbx(struct ngbe_hw *hw, u32 *msg, u16 size,
|
||||
u16 mbx_id)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
int err;
|
||||
|
||||
/* exit if either we can't write or there isn't a defined timeout */
|
||||
if (!mbx->timeout)
|
||||
return NGBE_ERR_MBX;
|
||||
|
||||
/* send msg */
|
||||
err = hw->mbx.ops.write(hw, msg, size, mbx_id);
|
||||
|
||||
/* if msg sent wait until we receive an ack */
|
||||
if (!err)
|
||||
err = ngbe_poll_for_ack(hw, mbx_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_init_mbx_ops - Initialize MB function pointers
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Setups up the mailbox read and write message function pointers
|
||||
**/
|
||||
void ngbe_init_mbx_ops(struct ngbe_hw *hw)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
|
||||
mbx->ops.read_posted = ngbe_read_posted_mbx;
|
||||
mbx->ops.write_posted = ngbe_write_posted_mbx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_read_v2p_mailbox - read v2p mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* This function is used to read the v2p mailbox without losing the read to
|
||||
* clear status bits.
|
||||
**/
|
||||
static u32 ngbe_read_v2p_mailbox(struct ngbe_hw *hw)
|
||||
{
|
||||
u32 v2p_mailbox = rd32(hw, NGBE_VXMAILBOX);
|
||||
|
||||
v2p_mailbox |= hw->mbx.v2p_mailbox;
|
||||
hw->mbx.v2p_mailbox |= v2p_mailbox & NGBE_VXMAILBOX_R2C_BITS;
|
||||
|
||||
return v2p_mailbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_bit_vf - Determine if a status bit was set
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: bitmask for bits to be tested and cleared
|
||||
*
|
||||
* This function is used to check for the read to clear bits within
|
||||
* the V2P mailbox.
|
||||
**/
|
||||
static int ngbe_check_for_bit_vf(struct ngbe_hw *hw, u32 mask)
|
||||
{
|
||||
u32 mailbox = ngbe_read_v2p_mailbox(hw);
|
||||
|
||||
hw->mbx.v2p_mailbox &= ~mask;
|
||||
|
||||
return (mailbox & mask ? 0 : NGBE_ERR_MBX);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_msg_vf - checks to see if the PF has sent mail
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the PF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static int ngbe_check_for_msg_vf(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
UNREFERENCED_PARAMETER(mbx_id);
|
||||
|
||||
/* read clear the pf sts bit */
|
||||
if (!ngbe_check_for_bit_vf(hw, NGBE_VXMAILBOX_PFSTS)) {
|
||||
err = 0;
|
||||
hw->mbx.stats.reqs++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_ack_vf - checks to see if the PF has ACK'd
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
|
||||
**/
|
||||
static int ngbe_check_for_ack_vf(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
UNREFERENCED_PARAMETER(mbx_id);
|
||||
|
||||
/* read clear the pf ack bit */
|
||||
if (!ngbe_check_for_bit_vf(hw, NGBE_VXMAILBOX_PFACK)) {
|
||||
err = 0;
|
||||
hw->mbx.stats.acks++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_rst_vf - checks to see if the PF has reset
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns true if the PF has set the reset done bit or else false
|
||||
**/
|
||||
static int ngbe_check_for_rst_vf(struct ngbe_hw *hw, u16 mbx_id)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
UNREFERENCED_PARAMETER(mbx_id);
|
||||
if (!ngbe_check_for_bit_vf(hw, (NGBE_VXMAILBOX_RSTD |
|
||||
NGBE_VXMAILBOX_RSTI))) {
|
||||
err = 0;
|
||||
hw->mbx.stats.rsts++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_obtain_mbx_lock_vf - obtain mailbox lock
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* return SUCCESS if we obtained the mailbox lock
|
||||
**/
|
||||
static int ngbe_obtain_mbx_lock_vf(struct ngbe_hw *hw)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
u32 mailbox;
|
||||
|
||||
/* Take ownership of the buffer */
|
||||
wr32(hw, NGBE_VXMAILBOX, NGBE_VXMAILBOX_VFU);
|
||||
|
||||
/* reserve mailbox for vf use */
|
||||
mailbox = ngbe_read_v2p_mailbox(hw);
|
||||
if (mailbox & NGBE_VXMAILBOX_VFU)
|
||||
err = 0;
|
||||
else
|
||||
ERROR_REPORT2(NGBE_ERROR_POLLING,
|
||||
"Failed to obtain mailbox lock for VF");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_write_mbx_vf - Write a message to the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer
|
||||
**/
|
||||
static int ngbe_write_mbx_vf(struct ngbe_hw *hw, u32 *msg, u16 size,
|
||||
u16 mbx_id)
|
||||
{
|
||||
int err;
|
||||
u16 i;
|
||||
|
||||
UNREFERENCED_PARAMETER(mbx_id);
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
err = ngbe_obtain_mbx_lock_vf(hw);
|
||||
if (err)
|
||||
goto out_no_write;
|
||||
|
||||
/* flush msg and acks as we are overwriting the message buffer */
|
||||
ngbe_check_for_msg_vf(hw, 0);
|
||||
ngbe_check_for_ack_vf(hw, 0);
|
||||
|
||||
/* copy the caller specified message to the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
wr32a(hw, NGBE_VXMBMEM, i, msg[i]);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_tx++;
|
||||
|
||||
/* Drop VFU and interrupt the PF to tell it a message has been sent */
|
||||
wr32(hw, NGBE_VXMAILBOX, NGBE_VXMAILBOX_REQ);
|
||||
|
||||
out_no_write:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_read_mbx_vf - Reads a message from the inbox intended for vf
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to read
|
||||
*
|
||||
* returns SUCCESS if it successfuly read message from buffer
|
||||
**/
|
||||
static int ngbe_read_mbx_vf(struct ngbe_hw *hw, u32 *msg, u16 size,
|
||||
u16 mbx_id)
|
||||
{
|
||||
int err = 0;
|
||||
u16 i;
|
||||
UNREFERENCED_PARAMETER(mbx_id);
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
err = ngbe_obtain_mbx_lock_vf(hw);
|
||||
if (err)
|
||||
goto out_no_read;
|
||||
|
||||
/* copy the message from the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
msg[i] = rd32a(hw, NGBE_VXMBMEM, i);
|
||||
|
||||
/* Acknowledge receipt and release mailbox, then we're done */
|
||||
wr32(hw, NGBE_VXMAILBOX, NGBE_VXMAILBOX_ACK);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_rx++;
|
||||
|
||||
out_no_read:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_init_mbx_params_vf - set initial values for vf mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Initializes the hw->mbx struct to correct values for vf mailbox
|
||||
*/
|
||||
void ngbe_init_mbx_params_vf(struct ngbe_hw *hw)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
|
||||
/* start mailbox as timed out and let the reset_hw call set the timeout
|
||||
* value to begin communications */
|
||||
mbx->timeout = 0;
|
||||
mbx->udelay = NGBE_VF_MBX_INIT_DELAY;
|
||||
|
||||
mbx->size = NGBE_VXMAILBOX_SIZE;
|
||||
|
||||
mbx->ops.read = ngbe_read_mbx_vf;
|
||||
mbx->ops.write = ngbe_write_mbx_vf;
|
||||
mbx->ops.read_posted = ngbe_read_posted_mbx;
|
||||
mbx->ops.write_posted = ngbe_write_posted_mbx;
|
||||
mbx->ops.check_for_msg = ngbe_check_for_msg_vf;
|
||||
mbx->ops.check_for_ack = ngbe_check_for_ack_vf;
|
||||
mbx->ops.check_for_rst = ngbe_check_for_rst_vf;
|
||||
|
||||
mbx->stats.msgs_tx = 0;
|
||||
mbx->stats.msgs_rx = 0;
|
||||
mbx->stats.reqs = 0;
|
||||
mbx->stats.acks = 0;
|
||||
mbx->stats.rsts = 0;
|
||||
}
|
||||
|
||||
static int ngbe_check_for_bit_pf(struct ngbe_hw *hw, u32 mask)
|
||||
{
|
||||
u32 mbvficr = rd32(hw, NGBE_MBVFICR);
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
if (mbvficr & mask) {
|
||||
err = 0;
|
||||
wr32(hw, NGBE_MBVFICR, mask);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_msg_pf - checks to see if the VF has sent mail
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static int ngbe_check_for_msg_pf(struct ngbe_hw *hw, u16 vf)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
u32 vf_bit = vf;
|
||||
|
||||
if (!ngbe_check_for_bit_pf(hw, NGBE_MBVFICR_VFREQ_VF1 << vf_bit)) {
|
||||
err = 0;
|
||||
hw->mbx.stats.reqs++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_ack_pf - checks to see if the VF has ACKed
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static int ngbe_check_for_ack_pf(struct ngbe_hw *hw, u16 vf)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
u32 vf_bit = vf;
|
||||
|
||||
if (!ngbe_check_for_bit_pf(hw, NGBE_MBVFICR_VFACK_VF1 << vf_bit)) {
|
||||
err = 0;
|
||||
hw->mbx.stats.acks++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_for_rst_pf - checks to see if the VF has reset
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static int ngbe_check_for_rst_pf(struct ngbe_hw *hw, u16 vf)
|
||||
{
|
||||
u32 vflre = 0;
|
||||
int err = NGBE_ERR_MBX;
|
||||
|
||||
vflre = rd32(hw, NGBE_VFLRE);
|
||||
|
||||
if (vflre & (1 << vf)) {
|
||||
err = 0;
|
||||
wr32(hw, NGBE_VFLREC, (1 << vf));
|
||||
hw->mbx.stats.rsts++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_obtain_mbx_lock_pf - obtain mailbox lock
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf: the VF index
|
||||
*
|
||||
* return SUCCESS if we obtained the mailbox lock
|
||||
**/
|
||||
static int ngbe_obtain_mbx_lock_pf(struct ngbe_hw *hw, u16 vf)
|
||||
{
|
||||
int err = NGBE_ERR_MBX;
|
||||
u32 mailbox;
|
||||
|
||||
/* Take ownership of the buffer */
|
||||
wr32(hw, NGBE_PXMAILBOX(vf), NGBE_PXMAILBOX_PFU);
|
||||
|
||||
/* reserve mailbox for vf use */
|
||||
mailbox = rd32(hw, NGBE_PXMAILBOX(vf));
|
||||
if (mailbox & NGBE_PXMAILBOX_PFU)
|
||||
err = 0;
|
||||
else
|
||||
ERROR_REPORT2(NGBE_ERROR_POLLING,
|
||||
"Failed to obtain mailbox lock for PF%d", vf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_write_mbx_pf - Places a message in the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @vf: the VF index
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer
|
||||
**/
|
||||
static int ngbe_write_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size,
|
||||
u16 vf)
|
||||
{
|
||||
int err;
|
||||
u16 i;
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
err = ngbe_obtain_mbx_lock_pf(hw, vf);
|
||||
if (err)
|
||||
goto out_no_write;
|
||||
|
||||
/* flush msg and acks as we are overwriting the message buffer */
|
||||
ngbe_check_for_msg_pf(hw, vf);
|
||||
ngbe_check_for_ack_pf(hw, vf);
|
||||
|
||||
/* copy the caller specified message to the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
wr32a(hw, NGBE_PXMBMEM(vf), i, msg[i]);
|
||||
|
||||
/* Interrupt VF to tell it a message has been sent and release buffer*/
|
||||
wr32(hw, NGBE_PXMAILBOX(vf), NGBE_PXMAILBOX_STS);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_tx++;
|
||||
|
||||
out_no_write:
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_read_mbx_pf - Read a message from the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @vf: the VF index
|
||||
*
|
||||
* This function copies a message from the mailbox buffer to the caller's
|
||||
* memory buffer. The presumption is that the caller knows that there was
|
||||
* a message due to a VF request so no polling for message is needed.
|
||||
**/
|
||||
static int ngbe_read_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size,
|
||||
u16 vf)
|
||||
{
|
||||
int err;
|
||||
u16 i;
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
err = ngbe_obtain_mbx_lock_pf(hw, vf);
|
||||
if (err)
|
||||
goto out_no_read;
|
||||
|
||||
/* copy the message to the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
msg[i] = rd32a(hw, NGBE_PXMBMEM(vf), i);
|
||||
|
||||
/* Acknowledge the message and release buffer */
|
||||
wr32(hw, NGBE_PXMAILBOX(vf), NGBE_PXMAILBOX_ACK);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_rx++;
|
||||
|
||||
out_no_read:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_init_mbx_params_pf - set initial values for pf mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Initializes the hw->mbx struct to correct values for pf mailbox
|
||||
*/
|
||||
void ngbe_init_mbx_params_pf(struct ngbe_hw *hw)
|
||||
{
|
||||
struct ngbe_mbx_info *mbx = &hw->mbx;
|
||||
|
||||
mbx->timeout = 0;
|
||||
mbx->udelay = 0;
|
||||
|
||||
mbx->size = NGBE_VXMAILBOX_SIZE;
|
||||
|
||||
mbx->ops.read = ngbe_read_mbx_pf;
|
||||
mbx->ops.write = ngbe_write_mbx_pf;
|
||||
mbx->ops.read_posted = ngbe_read_posted_mbx;
|
||||
mbx->ops.write_posted = ngbe_write_posted_mbx;
|
||||
mbx->ops.check_for_msg = ngbe_check_for_msg_pf;
|
||||
mbx->ops.check_for_ack = ngbe_check_for_ack_pf;
|
||||
mbx->ops.check_for_rst = ngbe_check_for_rst_pf;
|
||||
|
||||
mbx->stats.msgs_tx = 0;
|
||||
mbx->stats.msgs_rx = 0;
|
||||
mbx->stats.reqs = 0;
|
||||
mbx->stats.acks = 0;
|
||||
mbx->stats.rsts = 0;
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
#ifndef _NGBE_MBX_H_
|
||||
#define _NGBE_MBX_H_
|
||||
|
||||
#define NGBE_VXMAILBOX_SIZE (16)
|
||||
|
||||
/**
|
||||
* VF Registers
|
||||
**/
|
||||
#define NGBE_VXMAILBOX 0x00600
|
||||
#define NGBE_VXMAILBOX_REQ ((0x1) << 0) /* Request for PF Ready bit */
|
||||
#define NGBE_VXMAILBOX_ACK ((0x1) << 1) /* Ack PF message received */
|
||||
#define NGBE_VXMAILBOX_VFU ((0x1) << 2) /* VF owns the mailbox buffer */
|
||||
#define NGBE_VXMAILBOX_PFU ((0x1) << 3) /* PF owns the mailbox buffer */
|
||||
#define NGBE_VXMAILBOX_PFSTS ((0x1) << 4) /* PF wrote a message in the MB */
|
||||
#define NGBE_VXMAILBOX_PFACK ((0x1) << 5) /* PF ack the previous VF msg */
|
||||
#define NGBE_VXMAILBOX_RSTI ((0x1) << 6) /* PF has reset indication */
|
||||
#define NGBE_VXMAILBOX_RSTD ((0x1) << 7) /* PF has indicated reset done */
|
||||
#define NGBE_VXMAILBOX_R2C_BITS (NGBE_VXMAILBOX_RSTD | \
|
||||
NGBE_VXMAILBOX_PFSTS | NGBE_VXMAILBOX_PFACK)
|
||||
|
||||
#define NGBE_VXMBMEM 0x00C00 /* 16*4B */
|
||||
|
||||
/**
|
||||
* PF Registers
|
||||
**/
|
||||
#define NGBE_PXMAILBOX(i) (0x00600 + (4 * (i))) /* i=[0,7] */
|
||||
#define NGBE_PXMAILBOX_STS ((0x1) << 0) /* Initiate message send to VF */
|
||||
#define NGBE_PXMAILBOX_ACK ((0x1) << 1) /* Ack message recv'd from VF */
|
||||
#define NGBE_PXMAILBOX_VFU ((0x1) << 2) /* VF owns the mailbox buffer */
|
||||
#define NGBE_PXMAILBOX_PFU ((0x1) << 3) /* PF owns the mailbox buffer */
|
||||
#define NGBE_PXMAILBOX_RVFU ((0x1) << 4) /* Reset VFU - used when VF stuck*/
|
||||
|
||||
#define NGBE_PXMBMEM(i) (0x5000 + (64 * (i))) /* i=[0,7] */
|
||||
|
||||
#define NGBE_VFLRP(i) (0x00490 + (4 * (i))) /* i=[0,1] */
|
||||
#define NGBE_VFLRE 0x004A0
|
||||
#define NGBE_VFLREC 0x004A8
|
||||
|
||||
/* SR-IOV specific macros */
|
||||
#define NGBE_MBVFICR 0x00480
|
||||
|
||||
|
||||
|
||||
#define NGBE_MBVFICR_INDEX(vf) ((vf) >> 4)
|
||||
#define NGBE_MBVFICR_VFREQ_MASK (0x0000FFFF) /* bits for VF messages */
|
||||
#define NGBE_MBVFICR_VFREQ_VF1 (0x00000001) /* bit for VF 1 message */
|
||||
#define NGBE_MBVFICR_VFACK_MASK (0xFFFF0000) /* bits for VF acks */
|
||||
#define NGBE_MBVFICR_VFACK_VF1 (0x00010000) /* bit for VF 1 ack */
|
||||
|
||||
/**
|
||||
* Messages
|
||||
**/
|
||||
/* If it's a NGBE_VF_* msg then it originates in the VF and is sent to the
|
||||
* PF. The reverse is true if it is NGBE_PF_*.
|
||||
* Message ACK's are the value or'd with 0xF0000000
|
||||
*/
|
||||
#define NGBE_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with
|
||||
* this are the ACK */
|
||||
#define NGBE_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with
|
||||
* this are the NACK */
|
||||
#define NGBE_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still
|
||||
* clear to send requests */
|
||||
#define NGBE_VT_MSGINFO_SHIFT 16
|
||||
/* bits 23:16 are used for extra info for certain messages */
|
||||
#define NGBE_VT_MSGINFO_MASK (0xFF << NGBE_VT_MSGINFO_SHIFT)
|
||||
|
||||
/* definitions to support mailbox API version negotiation */
|
||||
|
||||
/*
|
||||
* each element denotes a version of the API; existing numbers may not
|
||||
* change; any additions must go at the end
|
||||
*/
|
||||
enum ngbe_pfvf_api_rev {
|
||||
ngbe_mbox_api_null,
|
||||
ngbe_mbox_api_10, /* API version 1.0, linux/freebsd VF driver */
|
||||
ngbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */
|
||||
ngbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */
|
||||
ngbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */
|
||||
ngbe_mbox_api_20, /* API version 2.0, solaris Phase1 VF driver */
|
||||
ngbe_mbox_api_unknown, /* indicates that API version is not known */
|
||||
};
|
||||
|
||||
/* mailbox API, legacy requests */
|
||||
#define NGBE_VF_RESET 0x01 /* VF requests reset */
|
||||
#define NGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */
|
||||
#define NGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
|
||||
#define NGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
|
||||
|
||||
/* mailbox API, version 1.0 VF requests */
|
||||
#define NGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
|
||||
#define NGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */
|
||||
#define NGBE_VF_API_NEGOTIATE 0x08 /* negotiate API version */
|
||||
|
||||
/* mailbox API, version 1.1 VF requests */
|
||||
#define NGBE_VF_GET_QUEUES 0x09 /* get queue configuration */
|
||||
|
||||
#define NGBE_NOFITY_VF_LINK_STATUS 0x01
|
||||
|
||||
/* mailbox API, version 1.2 VF requests */
|
||||
#define NGBE_VF_GET_RETA 0x0a /* VF request for RETA */
|
||||
#define NGBE_VF_GET_RSS_KEY 0x0b /* get RSS key */
|
||||
#define NGBE_VF_UPDATE_XCAST_MODE 0x0c
|
||||
#define NGBE_VF_BACKUP 0x8001 /* VF requests backup */
|
||||
|
||||
#define NGBE_VF_GET_LINK_STATUS 0x20 /* VF get link status from PF */
|
||||
|
||||
/* mode choices for IXGBE_VF_UPDATE_XCAST_MODE */
|
||||
enum ngbevf_xcast_modes {
|
||||
NGBEVF_XCAST_MODE_NONE = 0,
|
||||
NGBEVF_XCAST_MODE_MULTI,
|
||||
NGBEVF_XCAST_MODE_ALLMULTI,
|
||||
NGBEVF_XCAST_MODE_PROMISC,
|
||||
};
|
||||
|
||||
/* GET_QUEUES return data indices within the mailbox */
|
||||
#define NGBE_VF_TX_QUEUES 1 /* number of Tx queues supported */
|
||||
#define NGBE_VF_RX_QUEUES 2 /* number of Rx queues supported */
|
||||
#define NGBE_VF_TRANS_VLAN 3 /* Indication of port vlan */
|
||||
#define NGBE_VF_DEF_QUEUE 4 /* Default queue offset */
|
||||
|
||||
/* length of permanent address message returned from PF */
|
||||
#define NGBE_VF_PERMADDR_MSG_LEN 4
|
||||
/* word in permanent address message with the current multicast type */
|
||||
#define NGBE_VF_MC_TYPE_WORD 3
|
||||
|
||||
#define NGBE_PF_CONTROL_MSG 0x0100 /* PF control message */
|
||||
|
||||
/* mailbox API, version 2.0 VF requests */
|
||||
#define NGBE_VF_API_NEGOTIATE 0x08 /* negotiate API version */
|
||||
#define NGBE_VF_GET_QUEUES 0x09 /* get queue configuration */
|
||||
#define NGBE_VF_ENABLE_MACADDR 0x0A /* enable MAC address */
|
||||
#define NGBE_VF_DISABLE_MACADDR 0x0B /* disable MAC address */
|
||||
#define NGBE_VF_GET_MACADDRS 0x0C /* get all configured MAC addrs */
|
||||
#define NGBE_VF_SET_MCAST_PROMISC 0x0D /* enable multicast promiscuous */
|
||||
#define NGBE_VF_GET_MTU 0x0E /* get bounds on MTU */
|
||||
#define NGBE_VF_SET_MTU 0x0F /* set a specific MTU */
|
||||
|
||||
/* mailbox API, version 2.0 PF requests */
|
||||
#define NGBE_PF_TRANSPARENT_VLAN 0x0101 /* enable transparent vlan */
|
||||
|
||||
#define NGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
|
||||
#define NGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
|
||||
|
||||
int ngbe_read_mbx(struct ngbe_hw *, u32 *, u16, u16);
|
||||
int ngbe_write_mbx(struct ngbe_hw *, u32 *, u16, u16);
|
||||
int ngbe_read_posted_mbx(struct ngbe_hw *, u32 *, u16, u16);
|
||||
int ngbe_write_posted_mbx(struct ngbe_hw *, u32 *, u16, u16);
|
||||
int ngbe_check_for_msg(struct ngbe_hw *, u16);
|
||||
int ngbe_check_for_ack(struct ngbe_hw *, u16);
|
||||
int ngbe_check_for_rst(struct ngbe_hw *, u16);
|
||||
void ngbe_init_mbx_ops(struct ngbe_hw *hw);
|
||||
void ngbe_init_mbx_params_vf(struct ngbe_hw *);
|
||||
void ngbe_init_mbx_params_pf(struct ngbe_hw *);
|
||||
|
||||
#endif /* _NGBE_MBX_H_ */
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
/* glue for the OS independent part of ngbe
|
||||
* includes register access macros
|
||||
*/
|
||||
|
||||
#ifndef _NGBE_OSDEP_H_
|
||||
#define _NGBE_OSDEP_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/sched.h>
|
||||
#include "ngbe_kcompat.h"
|
||||
|
||||
#define NGBE_CPU_TO_BE16(_x) cpu_to_be16(_x)
|
||||
#define NGBE_BE16_TO_CPU(_x) be16_to_cpu(_x)
|
||||
#define NGBE_CPU_TO_BE32(_x) cpu_to_be32(_x)
|
||||
#define NGBE_BE32_TO_CPU(_x) be32_to_cpu(_x)
|
||||
|
||||
#define msec_delay(_x) msleep(_x)
|
||||
|
||||
#define usec_delay(_x) udelay(_x)
|
||||
|
||||
#define IOMEM __iomem
|
||||
|
||||
#define NGBE_NAME "ngbe"
|
||||
|
||||
/* #define DBG 1 */
|
||||
|
||||
#define DPRINTK(nlevel, klevel, fmt, args...) \
|
||||
((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
|
||||
printk(KERN_##klevel NGBE_NAME ": %s: %s: " fmt, \
|
||||
adapter->netdev->name, \
|
||||
__func__, ## args)))
|
||||
|
||||
#ifndef _WIN32
|
||||
#define ngbe_emerg(fmt, ...) printk(KERN_EMERG fmt, ## __VA_ARGS__)
|
||||
#define ngbe_alert(fmt, ...) printk(KERN_ALERT fmt, ## __VA_ARGS__)
|
||||
#define ngbe_crit(fmt, ...) printk(KERN_CRIT fmt, ## __VA_ARGS__)
|
||||
#define ngbe_error(fmt, ...) printk(KERN_ERR fmt, ## __VA_ARGS__)
|
||||
#define ngbe_warn(fmt, ...) printk(KERN_WARNING fmt, ## __VA_ARGS__)
|
||||
#define ngbe_notice(fmt, ...) printk(KERN_NOTICE fmt, ## __VA_ARGS__)
|
||||
#define ngbe_info(fmt, ...) printk(KERN_INFO fmt, ## __VA_ARGS__)
|
||||
#define ngbe_print(fmt, ...) printk(KERN_DEBUG fmt, ## __VA_ARGS__)
|
||||
#define ngbe_trace(fmt, ...) printk(KERN_INFO fmt, ## __VA_ARGS__)
|
||||
#else /* _WIN32 */
|
||||
#define ngbe_error(lvl, fmt, ...) \
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \
|
||||
"%s-error: %s@%d, " fmt, \
|
||||
"ngbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
#ifdef DBG
|
||||
#ifndef _WIN32
|
||||
#define ngbe_debug(fmt, ...) \
|
||||
printk(KERN_DEBUG \
|
||||
"%s-debug: %s@%d, " fmt, \
|
||||
"ngbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
#else /* _WIN32 */
|
||||
#define ngbe_debug(fmt, ...) \
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \
|
||||
"%s-debug: %s@%d, " fmt, \
|
||||
"ngbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
#endif /* _WIN32 */
|
||||
#else /* DBG */
|
||||
#define ngbe_debug(fmt, ...) do {} while (0)
|
||||
#endif /* DBG */
|
||||
|
||||
|
||||
#ifdef DBG
|
||||
#define ASSERT(_x) BUG_ON(!(_x))
|
||||
#define DEBUGOUT(S) printk(KERN_DEBUG S)
|
||||
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGOUT2(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGOUT3(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGOUT4(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGOUT5(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGOUT6(S, A...) printk(KERN_DEBUG S, ## A)
|
||||
#define DEBUGFUNC(fmt, ...) ngbe_debug(fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define ASSERT(_x) do {} while (0)
|
||||
#define DEBUGOUT(S) do {} while (0)
|
||||
#define DEBUGOUT1(S, A...) do {} while (0)
|
||||
#define DEBUGOUT2(S, A...) do {} while (0)
|
||||
#define DEBUGOUT3(S, A...) do {} while (0)
|
||||
#define DEBUGOUT4(S, A...) do {} while (0)
|
||||
#define DEBUGOUT5(S, A...) do {} while (0)
|
||||
#define DEBUGOUT6(S, A...) do {} while (0)
|
||||
#define DEBUGFUNC(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define NGBE_SFP_DETECT_RETRIES 2
|
||||
|
||||
struct ngbe_hw;
|
||||
struct ngbe_msg {
|
||||
u16 msg_enable;
|
||||
};
|
||||
struct net_device *ngbe_hw_to_netdev(const struct ngbe_hw *hw);
|
||||
struct ngbe_msg *ngbe_hw_to_msg(const struct ngbe_hw *hw);
|
||||
|
||||
#define hw_dbg(hw, format, arg...) \
|
||||
netdev_dbg(ngbe_hw_to_netdev(hw), format, ## arg)
|
||||
#define hw_err(hw, format, arg...) \
|
||||
netdev_err(ngbe_hw_to_netdev(hw), format, ## arg)
|
||||
#define e_dev_info(format, arg...) \
|
||||
dev_info(pci_dev_to_dev(adapter->pdev), format, ## arg)
|
||||
#define e_dev_warn(format, arg...) \
|
||||
dev_warn(pci_dev_to_dev(adapter->pdev), format, ## arg)
|
||||
#define e_dev_err(format, arg...) \
|
||||
dev_err(pci_dev_to_dev(adapter->pdev), format, ## arg)
|
||||
#define e_dev_notice(format, arg...) \
|
||||
dev_notice(pci_dev_to_dev(adapter->pdev), format, ## arg)
|
||||
#define e_dbg(msglvl, format, arg...) \
|
||||
netif_dbg(adapter, msglvl, adapter->netdev, format, ## arg)
|
||||
#define e_info(msglvl, format, arg...) \
|
||||
netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
|
||||
#define e_err(msglvl, format, arg...) \
|
||||
netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
|
||||
#define e_warn(msglvl, format, arg...) \
|
||||
netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
|
||||
#define e_crit(msglvl, format, arg...) \
|
||||
netif_crit(adapter, msglvl, adapter->netdev, format, ## arg)
|
||||
|
||||
#define NGBE_FAILED_READ_CFG_DWORD 0xffffffffU
|
||||
#define NGBE_FAILED_READ_CFG_WORD 0xffffU
|
||||
#define NGBE_FAILED_READ_CFG_BYTE 0xffU
|
||||
|
||||
extern u32 ngbe_read_reg(struct ngbe_hw *hw, u32 reg, bool quiet);
|
||||
extern u16 ngbe_read_pci_cfg_word(struct ngbe_hw *hw, u32 reg);
|
||||
extern void ngbe_write_pci_cfg_word(struct ngbe_hw *hw, u32 reg, u16 value);
|
||||
|
||||
#define NGBE_READ_PCIE_WORD ngbe_read_pci_cfg_word
|
||||
#define NGBE_WRITE_PCIE_WORD ngbe_write_pci_cfg_word
|
||||
#define NGBE_R32_Q(h, r) ngbe_read_reg(h, r, true)
|
||||
|
||||
#ifndef writeq
|
||||
#define writeq(val, addr) do { writel((u32) (val), addr); \
|
||||
writel((u32) (val >> 32), (addr + 4)); \
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
#define NGBE_EEPROM_GRANT_ATTEMPS 100
|
||||
#define NGBE_HTONL(_i) htonl(_i)
|
||||
#define NGBE_NTOHL(_i) ntohl(_i)
|
||||
#define NGBE_NTOHS(_i) ntohs(_i)
|
||||
#define NGBE_CPU_TO_LE32(_i) cpu_to_le32(_i)
|
||||
#define NGBE_LE32_TO_CPUS(_i) le32_to_cpus(_i)
|
||||
|
||||
enum {
|
||||
NGBE_ERROR_SOFTWARE,
|
||||
NGBE_ERROR_POLLING,
|
||||
NGBE_ERROR_INVALID_STATE,
|
||||
NGBE_ERROR_UNSUPPORTED,
|
||||
NGBE_ERROR_ARGUMENT,
|
||||
NGBE_ERROR_CAUTION,
|
||||
};
|
||||
|
||||
#define ERROR_REPORT(level, format, arg...) do { \
|
||||
switch (level) { \
|
||||
case NGBE_ERROR_SOFTWARE: \
|
||||
case NGBE_ERROR_CAUTION: \
|
||||
case NGBE_ERROR_POLLING: \
|
||||
netif_warn(ngbe_hw_to_msg(hw), drv, ngbe_hw_to_netdev(hw), \
|
||||
format, ## arg); \
|
||||
break; \
|
||||
case NGBE_ERROR_INVALID_STATE: \
|
||||
case NGBE_ERROR_UNSUPPORTED: \
|
||||
case NGBE_ERROR_ARGUMENT: \
|
||||
netif_err(ngbe_hw_to_msg(hw), hw, ngbe_hw_to_netdev(hw), \
|
||||
format, ## arg); \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ERROR_REPORT1 ERROR_REPORT
|
||||
#define ERROR_REPORT2 ERROR_REPORT
|
||||
#define ERROR_REPORT3 ERROR_REPORT
|
||||
|
||||
#define UNREFERENCED_XPARAMETER
|
||||
#define UNREFERENCED_1PARAMETER(_p) do { \
|
||||
uninitialized_var(_p); \
|
||||
} while (0)
|
||||
#define UNREFERENCED_2PARAMETER(_p, _q) do { \
|
||||
uninitialized_var(_p); \
|
||||
uninitialized_var(_q); \
|
||||
} while (0)
|
||||
#define UNREFERENCED_3PARAMETER(_p, _q, _r) do { \
|
||||
uninitialized_var(_p); \
|
||||
uninitialized_var(_q); \
|
||||
uninitialized_var(_r); \
|
||||
} while (0)
|
||||
#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s) do { \
|
||||
uninitialized_var(_p); \
|
||||
uninitialized_var(_q); \
|
||||
uninitialized_var(_r); \
|
||||
uninitialized_var(_s); \
|
||||
} while (0)
|
||||
#define UNREFERENCED_PARAMETER(_p) UNREFERENCED_1PARAMETER(_p)
|
||||
|
||||
#endif /* _NGBE_OSDEP_H_ */
|
|
@ -0,0 +1,932 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "ngbe.h"
|
||||
|
||||
/* This is the only thing that needs to be changed to adjust the
|
||||
* maximum number of ports that the driver can manage.
|
||||
*/
|
||||
#define NGBE_MAX_NIC 32
|
||||
#define OPTION_UNSET -1
|
||||
#define OPTION_DISABLED 0
|
||||
#define OPTION_ENABLED 1
|
||||
|
||||
#define STRINGIFY(foo) #foo /* magic for getting defines into strings */
|
||||
#define XSTRINGIFY(bar) STRINGIFY(bar)
|
||||
|
||||
/* All parameters are treated the same, as an integer array of values.
|
||||
* This macro just reduces the need to repeat the same declaration code
|
||||
* over and over (plus this helps to avoid typo bugs).
|
||||
*/
|
||||
|
||||
#define NGBE_PARAM_INIT { [0 ... NGBE_MAX_NIC] = OPTION_UNSET }
|
||||
#ifndef module_param_array
|
||||
/* Module Parameters are always initialized to -1, so that the driver
|
||||
* can tell the difference between no user specified value or the
|
||||
* user asking for the default value.
|
||||
* The true default values are loaded in when ngbe_check_options is called.
|
||||
*
|
||||
* This is a GCC extension to ANSI C.
|
||||
* See the item "Labelled Elements in Initializers" in the section
|
||||
* "Extensions to the C Language Family" of the GCC documentation.
|
||||
*/
|
||||
|
||||
#define NGBE_PARAM(X, desc) \
|
||||
static const int __devinitconst X[NGBE_MAX_NIC+1] = NGBE_PARAM_INIT; \
|
||||
MODULE_PARM(X, "1-" __MODULE_STRING(NGBE_MAX_NIC) "i"); \
|
||||
MODULE_PARM_DESC(X, desc);
|
||||
#else /* !module_param_array */
|
||||
#define NGBE_PARAM(X, desc) \
|
||||
static int __devinitdata X[NGBE_MAX_NIC+1] = NGBE_PARAM_INIT; \
|
||||
static unsigned int num_##X; \
|
||||
module_param_array_named(X, X, int, &num_##X, 0); \
|
||||
MODULE_PARM_DESC(X, desc);
|
||||
#endif /* module_param_array */
|
||||
|
||||
/* IntMode (Interrupt Mode)
|
||||
*
|
||||
* Valid Range: 0-2
|
||||
* - 0 - Legacy Interrupt
|
||||
* - 1 - MSI Interrupt
|
||||
* - 2 - MSI-X Interrupt(s)
|
||||
*
|
||||
* Default Value: 2
|
||||
*/
|
||||
NGBE_PARAM(InterruptType, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), "
|
||||
"default IntMode (deprecated)");
|
||||
NGBE_PARAM(IntMode, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), "
|
||||
"default 2");
|
||||
#define NGBE_INT_LEGACY 0
|
||||
#define NGBE_INT_MSI 1
|
||||
#define NGBE_INT_MSIX 2
|
||||
#define NGBE_DEFAULT_INT NGBE_INT_MSIX
|
||||
|
||||
/* MQ - Multiple Queue enable/disable
|
||||
*
|
||||
* Valid Range: 0, 1
|
||||
* - 0 - disables MQ
|
||||
* - 1 - enables MQ
|
||||
*
|
||||
* Default Value: 1
|
||||
*/
|
||||
|
||||
NGBE_PARAM(MQ, "Disable or enable Multiple Queues, default 1");
|
||||
|
||||
|
||||
/* RSS - Receive-Side Scaling (RSS) Descriptor Queues
|
||||
*
|
||||
* Valid Range: 0-64
|
||||
* - 0 - enables RSS and sets the Desc. Q's to min(64, num_online_cpus()).
|
||||
* - 1-64 - enables RSS and sets the Desc. Q's to the specified value.
|
||||
*
|
||||
* Default Value: 0
|
||||
*/
|
||||
|
||||
NGBE_PARAM(RSS, "Number of Receive-Side Scaling Descriptor Queues, "
|
||||
"default 0=number of cpus");
|
||||
|
||||
/* VMDQ - Virtual Machine Device Queues (VMDQ)
|
||||
*
|
||||
* Valid Range: 1-16
|
||||
* - 1 Disables VMDQ by allocating only a single queue.
|
||||
* - 2-16 - enables VMDQ and sets the Desc. Q's to the specified value.
|
||||
*
|
||||
* Default Value: 1
|
||||
*/
|
||||
|
||||
#define NGBE_DEFAULT_NUM_VMDQ 8
|
||||
|
||||
NGBE_PARAM(VMDQ, "Number of Virtual Machine Device Queues: 0/1 = disable, "
|
||||
"2-16 enable (default=" XSTRINGIFY(NGBE_DEFAULT_NUM_VMDQ) ")");
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
/* max_vfs - SR I/O Virtualization
|
||||
*
|
||||
* Valid Range: 0-63
|
||||
* - 0 Disables SR-IOV
|
||||
* - 1-63 - enables SR-IOV and sets the number of VFs enabled
|
||||
*
|
||||
* Default Value: 0
|
||||
*/
|
||||
|
||||
#define MAX_SRIOV_VFS 8
|
||||
|
||||
NGBE_PARAM(max_vfs, "Number of Virtual Functions: 0 = disable (default), "
|
||||
"1-" XSTRINGIFY(MAX_SRIOV_VFS) " = enable "
|
||||
"this many VFs");
|
||||
|
||||
/* VEPA - Set internal bridge to VEPA mode
|
||||
*
|
||||
* Valid Range: 0-1
|
||||
* - 0 Set bridge to VEB mode
|
||||
* - 1 Set bridge to VEPA mode
|
||||
*
|
||||
* Default Value: 0
|
||||
*/
|
||||
/*
|
||||
*Note:
|
||||
*=====
|
||||
* This provides ability to ensure VEPA mode on the internal bridge even if
|
||||
* the kernel does not support the netdev bridge setting operations.
|
||||
*/
|
||||
NGBE_PARAM(VEPA, "VEPA Bridge Mode: 0 = VEB (default), 1 = VEPA");
|
||||
#endif
|
||||
|
||||
/* Interrupt Throttle Rate (interrupts/sec)
|
||||
*
|
||||
* Valid Range: 980-500000 (0=off, 1=dynamic)
|
||||
*
|
||||
* Default Value: 1
|
||||
*/
|
||||
#define DEFAULT_ITR (NGBE_STATIC_ITR == 0) || \
|
||||
(NGBE_STATIC_ITR == 1)?NGBE_STATIC_ITR:(u16)((1000000/NGBE_STATIC_ITR) << 2)
|
||||
|
||||
NGBE_PARAM(InterruptThrottleRate, "Maximum interrupts per second, per vector, "
|
||||
"(0,1,980-500000), default 1");
|
||||
#define MAX_ITR NGBE_MAX_INT_RATE
|
||||
#define MIN_ITR NGBE_MIN_INT_RATE
|
||||
|
||||
#ifndef NGBE_NO_LLI
|
||||
|
||||
/* LLIPort (Low Latency Interrupt TCP Port)
|
||||
*
|
||||
* Valid Range: 0 - 65535
|
||||
*
|
||||
* Default Value: 0 (disabled)
|
||||
*/
|
||||
NGBE_PARAM(LLIPort, "Low Latency Interrupt TCP Port (0-65535)");
|
||||
|
||||
#define DEFAULT_LLIPORT 0
|
||||
#define MAX_LLIPORT 0xFFFF
|
||||
#define MIN_LLIPORT 0
|
||||
|
||||
|
||||
/* LLISize (Low Latency Interrupt on Packet Size)
|
||||
*
|
||||
* Valid Range: 0 - 1500
|
||||
*
|
||||
* Default Value: 0 (disabled)
|
||||
*/
|
||||
NGBE_PARAM(LLISize, "Low Latency Interrupt on Packet Size (0-1500)");
|
||||
|
||||
#define DEFAULT_LLISIZE 0
|
||||
#define MAX_LLISIZE 1500
|
||||
#define MIN_LLISIZE 0
|
||||
|
||||
/* LLIEType (Low Latency Interrupt Ethernet Type)
|
||||
*
|
||||
* Valid Range: 0 - 0x8fff
|
||||
*
|
||||
* Default Value: 0 (disabled)
|
||||
*/
|
||||
NGBE_PARAM(LLIEType, "Low Latency Interrupt Ethernet Protocol Type");
|
||||
|
||||
#define DEFAULT_LLIETYPE 0
|
||||
#define MAX_LLIETYPE 0x8fff
|
||||
#define MIN_LLIETYPE 0
|
||||
|
||||
/* LLIVLANP (Low Latency Interrupt on VLAN priority threshold)
|
||||
*
|
||||
* Valid Range: 0 - 7
|
||||
*
|
||||
* Default Value: 0 (disabled)
|
||||
*/
|
||||
NGBE_PARAM(LLIVLANP, "Low Latency Interrupt on VLAN priority threshold");
|
||||
|
||||
#define DEFAULT_LLIVLANP 0
|
||||
#define MAX_LLIVLANP 7
|
||||
#define MIN_LLIVLANP 0
|
||||
|
||||
#endif /* NGBE_NO_LLI */
|
||||
#ifdef HAVE_TX_MQ
|
||||
/* Software ATR packet sample rate
|
||||
*
|
||||
* Valid Range: 0-255 0 = off, 1-255 = rate of Tx packet inspection
|
||||
*
|
||||
* Default Value: 20
|
||||
*/
|
||||
NGBE_PARAM(AtrSampleRate, "Software ATR Tx packet sample rate");
|
||||
|
||||
#define NGBE_MAX_ATR_SAMPLE_RATE 255
|
||||
#define NGBE_MIN_ATR_SAMPLE_RATE 1
|
||||
#define NGBE_ATR_SAMPLE_RATE_OFF 0
|
||||
#define NGBE_DEFAULT_ATR_SAMPLE_RATE 20
|
||||
#endif /* HAVE_TX_MQ */
|
||||
|
||||
/* Enable/disable Large Receive Offload
|
||||
*
|
||||
* Valid Values: 0(off), 1(on)
|
||||
*
|
||||
* Default Value: 1
|
||||
*/
|
||||
NGBE_PARAM(LRO, "Large Receive Offload (0,1), default 1 = on");
|
||||
|
||||
/* Enable/disable support for DMA coalescing
|
||||
*
|
||||
* Valid Values: 0(off), 41 - 10000(on)
|
||||
*
|
||||
* Default Value: 0
|
||||
*/
|
||||
NGBE_PARAM(dmac_watchdog,
|
||||
"DMA coalescing watchdog in microseconds (0,41-10000),"
|
||||
"default 0 = off");
|
||||
|
||||
/* Rx buffer mode
|
||||
*
|
||||
* Valid Range: 0-1 0 = no header split, 1 = hdr split
|
||||
*
|
||||
* Default Value: 0
|
||||
*/
|
||||
NGBE_PARAM(RxBufferMode, "0=(default)no header split\n"
|
||||
"\t\t\t1=hdr split for recognized packet\n");
|
||||
|
||||
#define NGBE_RXBUFMODE_NO_HEADER_SPLIT 0
|
||||
#define NGBE_RXBUFMODE_HEADER_SPLIT 1
|
||||
#define NGBE_DEFAULT_RXBUFMODE NGBE_RXBUFMODE_NO_HEADER_SPLIT
|
||||
|
||||
|
||||
struct ngbe_option {
|
||||
enum { enable_option, range_option, list_option } type;
|
||||
const char *name;
|
||||
const char *err;
|
||||
const char *msg;
|
||||
int def;
|
||||
union {
|
||||
struct { /* range_option info */
|
||||
int min;
|
||||
int max;
|
||||
} r;
|
||||
struct { /* list_option info */
|
||||
int nr;
|
||||
const struct ngbe_opt_list {
|
||||
int i;
|
||||
char *str;
|
||||
} *p;
|
||||
} l;
|
||||
} arg;
|
||||
};
|
||||
|
||||
static int __devinit ngbe_validate_option(u32 *value,
|
||||
struct ngbe_option *opt)
|
||||
{
|
||||
int val = (int)*value;
|
||||
|
||||
if (val == OPTION_UNSET) {
|
||||
ngbe_info("ngbe: Invalid %s specified (%d), %s\n",
|
||||
opt->name, val, opt->err);
|
||||
*value = (u32)opt->def;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (opt->type) {
|
||||
case enable_option:
|
||||
switch (val) {
|
||||
case OPTION_ENABLED:
|
||||
ngbe_info("ngbe: %s Enabled\n", opt->name);
|
||||
return 0;
|
||||
case OPTION_DISABLED:
|
||||
ngbe_info("ngbe: %s Disabled\n", opt->name);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case range_option:
|
||||
if ((val >= opt->arg.r.min && val <= opt->arg.r.max) ||
|
||||
val == opt->def) {
|
||||
if (opt->msg)
|
||||
ngbe_info("ngbe: %s set to %d, %s\n",
|
||||
opt->name, val, opt->msg);
|
||||
else
|
||||
ngbe_info("ngbe: %s set to %d\n",
|
||||
opt->name, val);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case list_option: {
|
||||
int i;
|
||||
const struct ngbe_opt_list *ent;
|
||||
|
||||
for (i = 0; i < opt->arg.l.nr; i++) {
|
||||
ent = &opt->arg.l.p[i];
|
||||
if (val == ent->i) {
|
||||
if (ent->str[0] != '\0')
|
||||
ngbe_info("%s\n", ent->str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
ngbe_info("ngbe: Invalid %s specified (%d), %s\n",
|
||||
opt->name, val, opt->err);
|
||||
*value = (u32)opt->def;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_check_options - Range Checking for Command Line Parameters
|
||||
* @adapter: board private structure
|
||||
*
|
||||
* This routine checks all command line parameters for valid user
|
||||
* input. If an invalid value is given, or if no user specified
|
||||
* value exists, a default value is used. The final value is stored
|
||||
* in a variable in the adapter structure.
|
||||
**/
|
||||
void __devinit ngbe_check_options(struct ngbe_adapter *adapter)
|
||||
{
|
||||
u32 bd = adapter->bd_number;
|
||||
u32 *aflags = &adapter->flags;
|
||||
struct ngbe_ring_feature *feature = adapter->ring_feature;
|
||||
u32 vmdq;
|
||||
|
||||
if (bd >= NGBE_MAX_NIC) {
|
||||
ngbe_notice("Warning: no configuration for board #%d\n", bd);
|
||||
ngbe_notice("Using defaults for all values\n");
|
||||
#ifndef module_param_array
|
||||
bd = NGBE_MAX_NIC;
|
||||
#endif
|
||||
}
|
||||
|
||||
{ /* Interrupt Mode */
|
||||
u32 int_mode;
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Interrupt Mode",
|
||||
.err =
|
||||
"using default of "__MODULE_STRING(NGBE_DEFAULT_INT),
|
||||
.def = NGBE_DEFAULT_INT,
|
||||
.arg = { .r = { .min = NGBE_INT_LEGACY,
|
||||
.max = NGBE_INT_MSIX} }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_IntMode > bd || num_InterruptType > bd) {
|
||||
#endif
|
||||
int_mode = IntMode[bd];
|
||||
if (int_mode == OPTION_UNSET)
|
||||
int_mode = InterruptType[bd];
|
||||
ngbe_validate_option(&int_mode, &opt);
|
||||
switch (int_mode) {
|
||||
case NGBE_INT_MSIX:
|
||||
if (!(*aflags & NGBE_FLAG_MSIX_CAPABLE))
|
||||
ngbe_info(
|
||||
"Ignoring MSI-X setting; "
|
||||
"support unavailable\n");
|
||||
break;
|
||||
case NGBE_INT_MSI:
|
||||
if (!(*aflags & NGBE_FLAG_MSI_CAPABLE)) {
|
||||
ngbe_info(
|
||||
"Ignoring MSI setting; "
|
||||
"support unavailable\n");
|
||||
} else {
|
||||
*aflags &= ~NGBE_FLAG_MSIX_CAPABLE;
|
||||
}
|
||||
break;
|
||||
case NGBE_INT_LEGACY:
|
||||
default:
|
||||
*aflags &= ~NGBE_FLAG_MSIX_CAPABLE;
|
||||
*aflags &= ~NGBE_FLAG_MSI_CAPABLE;
|
||||
break;
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
/* default settings */
|
||||
if (opt.def == NGBE_INT_MSIX &&
|
||||
*aflags & NGBE_FLAG_MSIX_CAPABLE) {
|
||||
*aflags |= NGBE_FLAG_MSIX_CAPABLE;
|
||||
*aflags |= NGBE_FLAG_MSI_CAPABLE;
|
||||
} else if (opt.def == NGBE_INT_MSI &&
|
||||
*aflags & NGBE_FLAG_MSI_CAPABLE) {
|
||||
*aflags &= ~NGBE_FLAG_MSIX_CAPABLE;
|
||||
*aflags |= NGBE_FLAG_MSI_CAPABLE;
|
||||
} else {
|
||||
*aflags &= ~NGBE_FLAG_MSIX_CAPABLE;
|
||||
*aflags &= ~NGBE_FLAG_MSI_CAPABLE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{ /* Multiple Queue Support */
|
||||
static struct ngbe_option opt = {
|
||||
.type = enable_option,
|
||||
.name = "Multiple Queue Support",
|
||||
.err = "defaulting to Enabled",
|
||||
.def = OPTION_ENABLED
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_MQ > bd) {
|
||||
#endif
|
||||
u32 mq = MQ[bd];
|
||||
ngbe_validate_option(&mq, &opt);
|
||||
if (mq)
|
||||
*aflags |= NGBE_FLAG_MQ_CAPABLE;
|
||||
else
|
||||
*aflags &= ~NGBE_FLAG_MQ_CAPABLE;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
if (opt.def == OPTION_ENABLED)
|
||||
*aflags |= NGBE_FLAG_MQ_CAPABLE;
|
||||
else
|
||||
*aflags &= ~NGBE_FLAG_MQ_CAPABLE;
|
||||
}
|
||||
#endif
|
||||
/* Check Interoperability */
|
||||
if ((*aflags & NGBE_FLAG_MQ_CAPABLE) &&
|
||||
!(*aflags & NGBE_FLAG_MSIX_CAPABLE)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"Multiple queues are not supported while MSI-X "
|
||||
"is disabled. Disabling Multiple Queues.\n");
|
||||
*aflags &= ~NGBE_FLAG_MQ_CAPABLE;
|
||||
}
|
||||
}
|
||||
|
||||
{ /* Receive-Side Scaling (RSS) */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Receive-Side Scaling (RSS)",
|
||||
.err = "using default.",
|
||||
.def = 0,
|
||||
.arg = { .r = { .min = 0,
|
||||
.max = 1} }
|
||||
};
|
||||
u32 rss = RSS[bd];
|
||||
/* adjust Max allowed RSS queues based on MAC type */
|
||||
opt.arg.r.max = min_t(int, ngbe_max_rss_indices(adapter),
|
||||
num_online_cpus());
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_RSS > bd) {
|
||||
#endif
|
||||
ngbe_validate_option(&rss, &opt);
|
||||
/* base it off num_online_cpus() with hardware limit */
|
||||
if (!rss)
|
||||
rss = min_t(int, opt.arg.r.max,
|
||||
num_online_cpus());
|
||||
|
||||
feature[RING_F_RSS].limit = (u16)rss;
|
||||
#ifdef module_param_array
|
||||
} else if (opt.def == 0) {
|
||||
rss = min_t(int, ngbe_max_rss_indices(adapter),
|
||||
num_online_cpus());
|
||||
feature[RING_F_RSS].limit = rss;
|
||||
}
|
||||
#endif
|
||||
/* Check Interoperability */
|
||||
if (rss > 1) {
|
||||
if (!(*aflags & NGBE_FLAG_MQ_CAPABLE)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"Multiqueue is disabled. "
|
||||
"Limiting RSS.\n");
|
||||
feature[RING_F_RSS].limit = 1;
|
||||
}
|
||||
}
|
||||
adapter->flags2 |= NGBE_FLAG2_RSS_ENABLED;
|
||||
}
|
||||
{ /* Virtual Machine Device Queues (VMDQ) */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Virtual Machine Device Queues (VMDQ)",
|
||||
.err = "defaulting to Disabled",
|
||||
.def = OPTION_DISABLED,
|
||||
.arg = { .r = { .min = OPTION_DISABLED,
|
||||
.max = NGBE_MAX_VMDQ_INDICES
|
||||
} }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_VMDQ > bd) {
|
||||
#endif
|
||||
vmdq = VMDQ[bd];
|
||||
|
||||
ngbe_validate_option(&vmdq, &opt);
|
||||
|
||||
/* zero or one both mean disabled from our driver's
|
||||
* perspective */
|
||||
if (vmdq > 1) {
|
||||
*aflags |= NGBE_FLAG_VMDQ_ENABLED;
|
||||
} else
|
||||
*aflags &= ~NGBE_FLAG_VMDQ_ENABLED;
|
||||
|
||||
feature[RING_F_VMDQ].limit = (u16)vmdq;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
if (opt.def == OPTION_DISABLED)
|
||||
*aflags &= ~NGBE_FLAG_VMDQ_ENABLED;
|
||||
else
|
||||
*aflags |= NGBE_FLAG_VMDQ_ENABLED;
|
||||
|
||||
feature[RING_F_VMDQ].limit = opt.def;
|
||||
}
|
||||
#endif
|
||||
/* Check Interoperability */
|
||||
if (*aflags & NGBE_FLAG_VMDQ_ENABLED) {
|
||||
if (!(*aflags & NGBE_FLAG_MQ_CAPABLE)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"VMDQ is not supported while multiple "
|
||||
"queues are disabled. "
|
||||
"Disabling VMDQ.\n");
|
||||
*aflags &= ~NGBE_FLAG_VMDQ_ENABLED;
|
||||
feature[RING_F_VMDQ].limit = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
{ /* Single Root I/O Virtualization (SR-IOV) */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "I/O Virtualization (IOV)",
|
||||
.err = "defaulting to Disabled",
|
||||
.def = OPTION_DISABLED,
|
||||
.arg = { .r = { .min = OPTION_DISABLED,
|
||||
.max = MAX_SRIOV_VFS} }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_max_vfs > bd) {
|
||||
#endif
|
||||
u32 vfs = max_vfs[bd];
|
||||
if (ngbe_validate_option(&vfs, &opt)) {
|
||||
vfs = 0;
|
||||
DPRINTK(PROBE, INFO,
|
||||
"max_vfs out of range "
|
||||
"Disabling SR-IOV.\n");
|
||||
}
|
||||
|
||||
adapter->num_vfs = vfs;
|
||||
|
||||
if (vfs)
|
||||
*aflags |= NGBE_FLAG_SRIOV_ENABLED;
|
||||
else
|
||||
*aflags &= ~NGBE_FLAG_SRIOV_ENABLED;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
if (opt.def == OPTION_DISABLED) {
|
||||
adapter->num_vfs = 0;
|
||||
*aflags &= ~NGBE_FLAG_SRIOV_ENABLED;
|
||||
} else {
|
||||
adapter->num_vfs = opt.def;
|
||||
*aflags |= NGBE_FLAG_SRIOV_ENABLED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check Interoperability */
|
||||
if (*aflags & NGBE_FLAG_SRIOV_ENABLED) {
|
||||
if (!(*aflags & NGBE_FLAG_SRIOV_CAPABLE)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"IOV is not supported on this "
|
||||
"hardware. Disabling IOV.\n");
|
||||
*aflags &= ~NGBE_FLAG_SRIOV_ENABLED;
|
||||
adapter->num_vfs = 0;
|
||||
} else if (!(*aflags & NGBE_FLAG_MQ_CAPABLE)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"IOV is not supported while multiple "
|
||||
"queues are disabled. "
|
||||
"Disabling IOV.\n");
|
||||
*aflags &= ~NGBE_FLAG_SRIOV_ENABLED;
|
||||
adapter->num_vfs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
{ /* VEPA Bridge Mode enable for SR-IOV mode */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "VEPA Bridge Mode Enable",
|
||||
.err = "defaulting to disabled",
|
||||
.def = OPTION_DISABLED,
|
||||
.arg = { .r = { .min = OPTION_DISABLED,
|
||||
.max = OPTION_ENABLED} }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_VEPA > bd) {
|
||||
#endif
|
||||
u32 vepa = VEPA[bd];
|
||||
ngbe_validate_option(&vepa, &opt);
|
||||
if (vepa)
|
||||
adapter->flags |=
|
||||
NGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
if (opt.def == OPTION_ENABLED)
|
||||
adapter->flags |=
|
||||
NGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
{ /* Interrupt Throttling Rate */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Interrupt Throttling Rate (ints/sec)",
|
||||
.err = "using default of "__MODULE_STRING(DEFAULT_ITR),
|
||||
.def = DEFAULT_ITR,
|
||||
.arg = { .r = { .min = MIN_ITR,
|
||||
.max = MAX_ITR } }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_InterruptThrottleRate > bd) {
|
||||
#endif
|
||||
u32 itr = InterruptThrottleRate[bd];
|
||||
switch (itr) {
|
||||
case 0:
|
||||
DPRINTK(PROBE, INFO, "%s turned off\n",
|
||||
opt.name);
|
||||
adapter->rx_itr_setting = 0;
|
||||
break;
|
||||
case 1:
|
||||
DPRINTK(PROBE, INFO, "dynamic interrupt "
|
||||
"throttling enabled\n");
|
||||
adapter->rx_itr_setting = 1;
|
||||
break;
|
||||
default:
|
||||
ngbe_validate_option(&itr, &opt);
|
||||
/* the first bit is used as control */
|
||||
adapter->rx_itr_setting = (u16)((1000000/itr) << 2);
|
||||
break;
|
||||
}
|
||||
adapter->tx_itr_setting = adapter->rx_itr_setting;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->rx_itr_setting = opt.def;
|
||||
adapter->tx_itr_setting = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifndef NGBE_NO_LLI
|
||||
{ /* Low Latency Interrupt TCP Port*/
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Low Latency Interrupt TCP Port",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(DEFAULT_LLIPORT),
|
||||
.def = DEFAULT_LLIPORT,
|
||||
.arg = { .r = { .min = MIN_LLIPORT,
|
||||
.max = MAX_LLIPORT } }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_LLIPort > bd) {
|
||||
#endif
|
||||
adapter->lli_port = LLIPort[bd];
|
||||
if (adapter->lli_port) {
|
||||
ngbe_validate_option(&adapter->lli_port, &opt);
|
||||
} else {
|
||||
DPRINTK(PROBE, INFO, "%s turned off\n",
|
||||
opt.name);
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->lli_port = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{ /* Low Latency Interrupt on Packet Size */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Low Latency Interrupt on Packet Size",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(DEFAULT_LLISIZE),
|
||||
.def = DEFAULT_LLISIZE,
|
||||
.arg = { .r = { .min = MIN_LLISIZE,
|
||||
.max = MAX_LLISIZE } }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_LLISize > bd) {
|
||||
#endif
|
||||
adapter->lli_size = LLISize[bd];
|
||||
if (adapter->lli_size) {
|
||||
ngbe_validate_option(&adapter->lli_size, &opt);
|
||||
} else {
|
||||
DPRINTK(PROBE, INFO, "%s turned off\n",
|
||||
opt.name);
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->lli_size = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{ /* Low Latency Interrupt EtherType*/
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Low Latency Interrupt on Ethernet Protocol "
|
||||
"Type",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(DEFAULT_LLIETYPE),
|
||||
.def = DEFAULT_LLIETYPE,
|
||||
.arg = { .r = { .min = MIN_LLIETYPE,
|
||||
.max = MAX_LLIETYPE } }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_LLIEType > bd) {
|
||||
#endif
|
||||
adapter->lli_etype = LLIEType[bd];
|
||||
if (adapter->lli_etype) {
|
||||
ngbe_validate_option(&adapter->lli_etype,
|
||||
&opt);
|
||||
} else {
|
||||
DPRINTK(PROBE, INFO, "%s turned off\n",
|
||||
opt.name);
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->lli_etype = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{ /* LLI VLAN Priority */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Low Latency Interrupt on VLAN priority "
|
||||
"threshold",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(DEFAULT_LLIVLANP),
|
||||
.def = DEFAULT_LLIVLANP,
|
||||
.arg = { .r = { .min = MIN_LLIVLANP,
|
||||
.max = MAX_LLIVLANP } }
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_LLIVLANP > bd) {
|
||||
#endif
|
||||
adapter->lli_vlan_pri = LLIVLANP[bd];
|
||||
if (adapter->lli_vlan_pri) {
|
||||
ngbe_validate_option(&adapter->lli_vlan_pri,
|
||||
&opt);
|
||||
} else {
|
||||
DPRINTK(PROBE, INFO, "%s turned off\n",
|
||||
opt.name);
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->lli_vlan_pri = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* NGBE_NO_LLI */
|
||||
#ifdef HAVE_TX_MQ
|
||||
{ /* Flow Director ATR Tx sample packet rate */
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Software ATR Tx packet sample rate",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(NGBE_DEFAULT_ATR_SAMPLE_RATE),
|
||||
.def = NGBE_DEFAULT_ATR_SAMPLE_RATE,
|
||||
.arg = {.r = {.min = NGBE_ATR_SAMPLE_RATE_OFF,
|
||||
.max = NGBE_MAX_ATR_SAMPLE_RATE} }
|
||||
};
|
||||
static const char atr_string[] =
|
||||
"ATR Tx Packet sample rate set to";
|
||||
|
||||
if (num_AtrSampleRate > bd) {
|
||||
adapter->atr_sample_rate = AtrSampleRate[bd];
|
||||
|
||||
if (adapter->atr_sample_rate) {
|
||||
ngbe_validate_option(&adapter->atr_sample_rate,
|
||||
&opt);
|
||||
DPRINTK(PROBE, INFO, "%s %d\n", atr_string,
|
||||
adapter->atr_sample_rate);
|
||||
}
|
||||
} else {
|
||||
adapter->atr_sample_rate = opt.def;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_TX_MQ */
|
||||
{ /* LRO - Set Large Receive Offload */
|
||||
struct ngbe_option opt = {
|
||||
.type = enable_option,
|
||||
.name = "LRO - Large Receive Offload",
|
||||
.err = "defaulting to Disabled",
|
||||
/* lro switch to ON when run on SW and FT platform */
|
||||
/* emerald temp setting */
|
||||
#if defined(TXGBE_SUPPORT_DEEPIN_SW) || \
|
||||
defined(TXGBE_SUPPORT_KYLIN_SW) || \
|
||||
defined(TXGBE_SUPPORT_KYLIN_FT)
|
||||
.def = OPTION_ENABLED
|
||||
#else
|
||||
.def = OPTION_DISABLED
|
||||
#endif
|
||||
};
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
#ifdef NGBE_NO_LRO
|
||||
opt.def = OPTION_DISABLED;
|
||||
|
||||
#endif
|
||||
#ifdef module_param_array
|
||||
if (num_LRO > bd) {
|
||||
#endif
|
||||
u32 lro = LRO[bd];
|
||||
ngbe_validate_option(&lro, &opt);
|
||||
if (lro)
|
||||
netdev->features |= NETIF_F_LRO;
|
||||
else
|
||||
netdev->features &= ~NETIF_F_LRO;
|
||||
#ifdef module_param_array
|
||||
} else if (opt.def == OPTION_ENABLED) {
|
||||
netdev->features |= NETIF_F_LRO;
|
||||
} else {
|
||||
netdev->features &= ~NETIF_F_LRO;
|
||||
}
|
||||
#endif
|
||||
#ifdef NGBE_NO_LRO
|
||||
if ((netdev->features & NETIF_F_LRO)) {
|
||||
DPRINTK(PROBE, INFO,
|
||||
"RSC is not supported on this "
|
||||
"hardware. Disabling RSC.\n");
|
||||
netdev->features &= ~NETIF_F_LRO;
|
||||
}
|
||||
#endif /* NGBE_NO_LRO */
|
||||
}
|
||||
{ /* DMA Coalescing */
|
||||
struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "dmac_watchdog",
|
||||
.err = "defaulting to 0 (disabled)",
|
||||
.def = 0,
|
||||
.arg = { .r = { .min = 41, .max = 10000 } },
|
||||
};
|
||||
const char *cmsg = "DMA coalescing not supported on this "
|
||||
"hardware";
|
||||
|
||||
opt.err = cmsg;
|
||||
opt.msg = cmsg;
|
||||
opt.arg.r.min = 0;
|
||||
opt.arg.r.max = 0;
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_dmac_watchdog > bd) {
|
||||
#endif
|
||||
u32 dmac_wd = dmac_watchdog[bd];
|
||||
|
||||
ngbe_validate_option(&dmac_wd, &opt);
|
||||
adapter->hw.mac.dmac_config.watchdog_timer = (u16)dmac_wd;
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
adapter->hw.mac.dmac_config.watchdog_timer = opt.def;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{ /* Rx buffer mode */
|
||||
u32 rx_buf_mode;
|
||||
static struct ngbe_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Rx buffer mode",
|
||||
.err = "using default of "
|
||||
__MODULE_STRING(NGBE_DEFAULT_RXBUFMODE),
|
||||
.def = NGBE_DEFAULT_RXBUFMODE,
|
||||
.arg = {.r = {.min = NGBE_RXBUFMODE_NO_HEADER_SPLIT,
|
||||
.max = NGBE_RXBUFMODE_HEADER_SPLIT} }
|
||||
|
||||
};
|
||||
|
||||
#ifdef module_param_array
|
||||
if (num_RxBufferMode > bd) {
|
||||
#endif
|
||||
rx_buf_mode = RxBufferMode[bd];
|
||||
ngbe_validate_option(&rx_buf_mode, &opt);
|
||||
switch (rx_buf_mode) {
|
||||
case NGBE_RXBUFMODE_NO_HEADER_SPLIT:
|
||||
*aflags &= ~NGBE_FLAG_RX_HS_ENABLED;
|
||||
break;
|
||||
case NGBE_RXBUFMODE_HEADER_SPLIT:
|
||||
*aflags |= NGBE_FLAG_RX_HS_ENABLED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef module_param_array
|
||||
} else {
|
||||
*aflags &= ~NGBE_FLAG_RX_HS_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include "ngbe_pcierr.h"
|
||||
#include "ngbe.h"
|
||||
#define NGBE_ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \
|
||||
PCI_ERR_ROOT_CMD_NONFATAL_EN| \
|
||||
PCI_ERR_ROOT_CMD_FATAL_EN)
|
||||
|
||||
#ifndef PCI_ERS_RESULT_NO_AER_DRIVER
|
||||
/* No AER capabilities registered for the driver */
|
||||
#define PCI_ERS_RESULT_NO_AER_DRIVER ((__force pci_ers_result_t) 6)
|
||||
#endif
|
||||
|
||||
#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
|
||||
/* redefinition because centos 6 can't use pci_walk_bus in pci.h*/
|
||||
|
||||
struct rw_semaphore pci_bus_sem;
|
||||
|
||||
/** pci_walk_bus - walk devices on/under bus, calling callback.
|
||||
* @top bus whose devices should be walked
|
||||
* @cb callback to be called for each device found
|
||||
* @userdata arbitrary pointer to be passed to callback.
|
||||
*
|
||||
* Walk the given bus, including any bridged devices
|
||||
* on buses under this bus. Call the provided callback
|
||||
* on each device found.
|
||||
*
|
||||
* We check the return of @cb each time. If it returns anything
|
||||
* other than 0, we break out.
|
||||
*
|
||||
*/
|
||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus;
|
||||
struct list_head *next;
|
||||
int retval;
|
||||
|
||||
bus = top;
|
||||
down_read(&pci_bus_sem);
|
||||
next = top->devices.next;
|
||||
for (;;) {
|
||||
if (next == &bus->devices) {
|
||||
/* end of this bus, go up or finish */
|
||||
if (bus == top)
|
||||
break;
|
||||
next = bus->self->bus_list.next;
|
||||
bus = bus->self->bus;
|
||||
continue;
|
||||
}
|
||||
dev = list_entry(next, struct pci_dev, bus_list);
|
||||
if (dev->subordinate) {
|
||||
/* this is a pci-pci bridge, do its devices next */
|
||||
next = dev->subordinate->devices.next;
|
||||
bus = dev->subordinate;
|
||||
} else
|
||||
next = dev->bus_list.next;
|
||||
|
||||
retval = cb(dev, userdata);
|
||||
if (retval)
|
||||
break;
|
||||
}
|
||||
up_read(&pci_bus_sem);
|
||||
}
|
||||
#endif
|
||||
|
||||
static pci_ers_result_t merge_result(enum pci_ers_result orig,
|
||||
enum pci_ers_result new)
|
||||
{
|
||||
if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
|
||||
return PCI_ERS_RESULT_NO_AER_DRIVER;
|
||||
if (new == PCI_ERS_RESULT_NONE)
|
||||
return orig;
|
||||
switch (orig) {
|
||||
case PCI_ERS_RESULT_CAN_RECOVER:
|
||||
case PCI_ERS_RESULT_RECOVERED:
|
||||
orig = new;
|
||||
break;
|
||||
case PCI_ERS_RESULT_DISCONNECT:
|
||||
if (new == PCI_ERS_RESULT_NEED_RESET)
|
||||
orig = PCI_ERS_RESULT_NEED_RESET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return orig;
|
||||
}
|
||||
|
||||
static int ngbe_report_error_detected(struct pci_dev *dev,
|
||||
pci_channel_state_t state,
|
||||
enum pci_ers_result *result)
|
||||
{
|
||||
pci_ers_result_t vote;
|
||||
const struct pci_error_handlers *err_handler;
|
||||
|
||||
device_lock(&dev->dev);
|
||||
if (
|
||||
!dev->driver ||
|
||||
!dev->driver->err_handler ||
|
||||
!dev->driver->err_handler->error_detected) {
|
||||
/*
|
||||
* If any device in the subtree does not have an error_detected
|
||||
* callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
|
||||
* error callbacks of "any" device in the subtree, and will
|
||||
* exit in the disconnected error state.
|
||||
*/
|
||||
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
|
||||
vote = PCI_ERS_RESULT_NO_AER_DRIVER;
|
||||
else
|
||||
vote = PCI_ERS_RESULT_NONE;
|
||||
} else {
|
||||
err_handler = dev->driver->err_handler;
|
||||
vote = err_handler->error_detected(dev, state);
|
||||
}
|
||||
|
||||
*result = merge_result(*result, vote);
|
||||
device_unlock(&dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngbe_report_frozen_detected(struct pci_dev *dev, void *data)
|
||||
{
|
||||
return ngbe_report_error_detected(dev, pci_channel_io_frozen, data);
|
||||
}
|
||||
|
||||
static int ngbe_report_mmio_enabled(struct pci_dev *dev, void *data)
|
||||
{
|
||||
pci_ers_result_t vote, *result = data;
|
||||
const struct pci_error_handlers *err_handler;
|
||||
|
||||
device_lock(&dev->dev);
|
||||
if (!dev->driver ||
|
||||
!dev->driver->err_handler ||
|
||||
!dev->driver->err_handler->mmio_enabled)
|
||||
goto out;
|
||||
|
||||
err_handler = dev->driver->err_handler;
|
||||
vote = err_handler->mmio_enabled(dev);
|
||||
*result = merge_result(*result, vote);
|
||||
out:
|
||||
device_unlock(&dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngbe_report_slot_reset(struct pci_dev *dev, void *data)
|
||||
{
|
||||
pci_ers_result_t vote, *result = data;
|
||||
const struct pci_error_handlers *err_handler;
|
||||
|
||||
device_lock(&dev->dev);
|
||||
if (!dev->driver ||
|
||||
!dev->driver->err_handler ||
|
||||
!dev->driver->err_handler->slot_reset)
|
||||
goto out;
|
||||
|
||||
err_handler = dev->driver->err_handler;
|
||||
vote = err_handler->slot_reset(dev);
|
||||
*result = merge_result(*result, vote);
|
||||
out:
|
||||
device_unlock(&dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngbe_report_resume(struct pci_dev *dev, void *data)
|
||||
{
|
||||
const struct pci_error_handlers *err_handler;
|
||||
|
||||
device_lock(&dev->dev);
|
||||
dev->error_state = pci_channel_io_normal;
|
||||
if (
|
||||
!dev->driver ||
|
||||
!dev->driver->err_handler ||
|
||||
!dev->driver->err_handler->resume)
|
||||
goto out;
|
||||
|
||||
err_handler = dev->driver->err_handler;
|
||||
err_handler->resume(dev);
|
||||
out:
|
||||
device_unlock(&dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngbe_pcie_do_recovery(struct pci_dev *dev)
|
||||
{
|
||||
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
|
||||
struct pci_bus *bus;
|
||||
u32 reg32;
|
||||
int pos;
|
||||
int delay = 1;
|
||||
u32 id;
|
||||
u16 ctrl;
|
||||
/*
|
||||
* Error recovery runs on all subordinates of the first downstream port.
|
||||
* If the downstream port detected the error, it is cleared at the end.
|
||||
*/
|
||||
if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
|
||||
dev = dev->bus->self;
|
||||
bus = dev->subordinate;
|
||||
|
||||
pci_walk_bus(bus, ngbe_report_frozen_detected, &status);
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~NGBE_ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
|
||||
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
|
||||
|
||||
/*
|
||||
* * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms. Double
|
||||
* * this to 2ms to ensure that we meet the minimum requirement.
|
||||
* */
|
||||
|
||||
msleep(2);
|
||||
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
|
||||
|
||||
/*
|
||||
* * Trhfa for conventional PCI is 2^25 clock cycles.
|
||||
* * Assuming a minimum 33MHz clock this results in a 1s
|
||||
* * delay before we can consider subordinate devices to
|
||||
* * be re-initialized. PCIe has some ways to shorten this,
|
||||
* * but we don't make use of them yet.
|
||||
* */
|
||||
ssleep(1);
|
||||
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
while (id == ~0) {
|
||||
if (delay > 60000) {
|
||||
pci_warn(dev, "not ready %dms after %s; giving up\n",
|
||||
delay - 1, "bus_reset");
|
||||
return;
|
||||
}
|
||||
|
||||
if (delay > 1000)
|
||||
pci_info(dev, "not ready %dms after %s; waiting\n",
|
||||
delay - 1, "bus_reset");
|
||||
|
||||
msleep(delay);
|
||||
delay *= 2;
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
}
|
||||
|
||||
if (delay > 1000)
|
||||
pci_info(dev, "ready %dms after %s\n", delay - 1,
|
||||
"bus_reset");
|
||||
|
||||
pci_info(dev, "Root Port link has been reset\n");
|
||||
|
||||
if (pos) {
|
||||
/* Clear Root Error Status */
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32);
|
||||
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= NGBE_ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
if (status == PCI_ERS_RESULT_CAN_RECOVER) {
|
||||
status = PCI_ERS_RESULT_RECOVERED;
|
||||
pci_dbg(dev, "broadcast mmio_enabled message\n");
|
||||
pci_walk_bus(bus, ngbe_report_mmio_enabled, &status);
|
||||
}
|
||||
|
||||
if (status == PCI_ERS_RESULT_NEED_RESET) {
|
||||
/*
|
||||
* TODO: Should call platform-specific
|
||||
* functions to reset slot before calling
|
||||
* drivers' slot_reset callbacks?
|
||||
*/
|
||||
status = PCI_ERS_RESULT_RECOVERED;
|
||||
pci_dbg(dev, "broadcast slot_reset message\n");
|
||||
pci_walk_bus(bus, ngbe_report_slot_reset, &status);
|
||||
}
|
||||
|
||||
if (status != PCI_ERS_RESULT_RECOVERED)
|
||||
goto failed;
|
||||
|
||||
pci_dbg(dev, "broadcast resume message\n");
|
||||
pci_walk_bus(bus, ngbe_report_resume, &status);
|
||||
|
||||
failed:
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _NGBE_PCIERR_H_
|
||||
#define _NGBE_PCIERR_H_
|
||||
|
||||
void ngbe_pcie_do_recovery(struct pci_dev *dev);
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGBE_PHY_H_
|
||||
#define _NGBE_PHY_H_
|
||||
|
||||
#include "ngbe_type.h"
|
||||
#include "ngbe.h"
|
||||
|
||||
/* EEPROM byte offsets */
|
||||
#define NGBE_SFF_IDENTIFIER 0x0
|
||||
#define NGBE_SFF_IDENTIFIER_SFP 0x3
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE0 0x25
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE1 0x26
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE2 0x27
|
||||
#define NGBE_SFF_1GBE_COMP_CODES 0x6
|
||||
#define NGBE_SFF_10GBE_COMP_CODES 0x3
|
||||
#define NGBE_SFF_CABLE_TECHNOLOGY 0x8
|
||||
#define NGBE_SFF_CABLE_SPEC_COMP 0x3C
|
||||
#define NGBE_SFF_SFF_8472_SWAP 0x5C
|
||||
#define NGBE_SFF_SFF_8472_COMP 0x5E
|
||||
#define NGBE_SFF_SFF_8472_OSCB 0x6E
|
||||
#define NGBE_SFF_SFF_8472_ESCB 0x76
|
||||
#define NGBE_SFF_IDENTIFIER_QSFP_PLUS 0xD
|
||||
#define NGBE_SFF_QSFP_VENDOR_OUI_BYTE0 0xA5
|
||||
#define NGBE_SFF_QSFP_VENDOR_OUI_BYTE1 0xA6
|
||||
#define NGBE_SFF_QSFP_VENDOR_OUI_BYTE2 0xA7
|
||||
#define NGBE_SFF_QSFP_CONNECTOR 0x82
|
||||
#define NGBE_SFF_QSFP_10GBE_COMP 0x83
|
||||
#define NGBE_SFF_QSFP_1GBE_COMP 0x86
|
||||
#define NGBE_SFF_QSFP_CABLE_LENGTH 0x92
|
||||
#define NGBE_SFF_QSFP_DEVICE_TECH 0x93
|
||||
|
||||
/* Bitmasks */
|
||||
#define NGBE_SFF_DA_PASSIVE_CABLE 0x4
|
||||
#define NGBE_SFF_DA_ACTIVE_CABLE 0x8
|
||||
#define NGBE_SFF_DA_SPEC_ACTIVE_LIMITING 0x4
|
||||
#define NGBE_SFF_1GBASESX_CAPABLE 0x1
|
||||
#define NGBE_SFF_1GBASELX_CAPABLE 0x2
|
||||
#define NGBE_SFF_1GBASET_CAPABLE 0x8
|
||||
#define NGBE_SFF_10GBASESR_CAPABLE 0x10
|
||||
#define NGBE_SFF_10GBASELR_CAPABLE 0x20
|
||||
#define NGBE_SFF_SOFT_RS_SELECT_MASK 0x8
|
||||
#define NGBE_SFF_SOFT_RS_SELECT_10G 0x8
|
||||
#define NGBE_SFF_SOFT_RS_SELECT_1G 0x0
|
||||
#define NGBE_SFF_ADDRESSING_MODE 0x4
|
||||
#define NGBE_SFF_QSFP_DA_ACTIVE_CABLE 0x1
|
||||
#define NGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8
|
||||
#define NGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE 0x23
|
||||
#define NGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL 0x0
|
||||
#define NGBE_I2C_EEPROM_READ_MASK 0x100
|
||||
#define NGBE_I2C_EEPROM_STATUS_MASK 0x3
|
||||
#define NGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
|
||||
#define NGBE_I2C_EEPROM_STATUS_PASS 0x1
|
||||
#define NGBE_I2C_EEPROM_STATUS_FAIL 0x2
|
||||
#define NGBE_I2C_EEPROM_STATUS_IN_PROGRESS 0x3
|
||||
|
||||
#define NGBE_CS4227 0xBE /* CS4227 address */
|
||||
#define NGBE_CS4227_GLOBAL_ID_LSB 0
|
||||
#define NGBE_CS4227_SCRATCH 2
|
||||
#define NGBE_CS4227_GLOBAL_ID_VALUE 0x03E5
|
||||
#define NGBE_CS4227_SCRATCH_VALUE 0x5aa5
|
||||
#define NGBE_CS4227_RETRIES 5
|
||||
#define NGBE_CS4227_LINE_SPARE22_MSB 0x12AD /* Reg to program speed */
|
||||
#define NGBE_CS4227_LINE_SPARE24_LSB 0x12B0 /* Reg to program EDC */
|
||||
#define NGBE_CS4227_HOST_SPARE22_MSB 0x1AAD /* Reg to program speed */
|
||||
#define NGBE_CS4227_HOST_SPARE24_LSB 0x1AB0 /* Reg to program EDC */
|
||||
#define NGBE_CS4227_EDC_MODE_CX1 0x0002
|
||||
#define NGBE_CS4227_EDC_MODE_SR 0x0004
|
||||
#define NGBE_CS4227_RESET_HOLD 500 /* microseconds */
|
||||
#define NGBE_CS4227_RESET_DELAY 500 /* milliseconds */
|
||||
#define NGBE_CS4227_CHECK_DELAY 30 /* milliseconds */
|
||||
#define NGBE_PE 0xE0 /* Port expander address */
|
||||
#define NGBE_PE_OUTPUT 1 /* Output register offset */
|
||||
#define NGBE_PE_CONFIG 3 /* Config register offset */
|
||||
#define NGBE_PE_BIT1 (1 << 1)
|
||||
|
||||
/* Flow control defines */
|
||||
#define NGBE_TAF_SYM_PAUSE (0x1)
|
||||
#define NGBE_TAF_ASM_PAUSE (0x2)
|
||||
|
||||
/* Bit-shift macros */
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE0_SHIFT 24
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE1_SHIFT 16
|
||||
#define NGBE_SFF_VENDOR_OUI_BYTE2_SHIFT 8
|
||||
|
||||
/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */
|
||||
#define NGBE_SFF_VENDOR_OUI_TYCO 0x00407600
|
||||
#define NGBE_SFF_VENDOR_OUI_FTL 0x00906500
|
||||
#define NGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00
|
||||
#define NGBE_SFF_VENDOR_OUI_INTEL 0x001B2100
|
||||
|
||||
/* I2C SDA and SCL timing parameters for standard mode */
|
||||
#define NGBE_I2C_T_HD_STA 4
|
||||
#define NGBE_I2C_T_LOW 5
|
||||
#define NGBE_I2C_T_HIGH 4
|
||||
#define NGBE_I2C_T_SU_STA 5
|
||||
#define NGBE_I2C_T_HD_DATA 5
|
||||
#define NGBE_I2C_T_SU_DATA 1
|
||||
#define NGBE_I2C_T_RISE 1
|
||||
#define NGBE_I2C_T_FALL 1
|
||||
#define NGBE_I2C_T_SU_STO 4
|
||||
#define NGBE_I2C_T_BUF 5
|
||||
|
||||
#ifndef NGBE_SFP_DETECT_RETRIES
|
||||
#define NGBE_SFP_DETECT_RETRIES 10
|
||||
#endif /* NGBE_SFP_DETECT_RETRIES */
|
||||
|
||||
/* SFP+ SFF-8472 Compliance */
|
||||
#define NGBE_SFF_SFF_8472_UNSUP 0x00
|
||||
|
||||
bool ngbe_check_reset_blocked(struct ngbe_hw *hw);
|
||||
enum ngbe_phy_type ngbe_get_phy_type_from_id(struct ngbe_hw *hw);
|
||||
void ngbe_init_phy_ops_common(struct ngbe_hw *hw);
|
||||
int ngbe_phy_read_reg_mdi( struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 *phy_data);
|
||||
int ngbe_phy_write_reg_mdi( struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 phy_data);
|
||||
|
||||
int ngbe_phy_read_reg_sds_mii_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 *phy_data);
|
||||
int ngbe_phy_write_reg_sds_mii_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 phy_data);
|
||||
|
||||
int ngbe_phy_read_reg_ext_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 *phy_data);
|
||||
int ngbe_phy_write_reg_ext_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 phy_data);
|
||||
|
||||
int ngbe_phy_read_reg_sds_ext_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 *phy_data);
|
||||
int ngbe_phy_write_reg_sds_ext_yt8521s(struct ngbe_hw *hw,
|
||||
u32 reg_addr,
|
||||
u32 device_type,
|
||||
u16 phy_data);
|
||||
|
||||
int ngbe_phy_init(struct ngbe_hw *hw);
|
||||
int ngbe_phy_identify(struct ngbe_hw *hw);
|
||||
int ngbe_phy_reset(struct ngbe_hw *hw);
|
||||
u32 ngbe_phy_setup_link(struct ngbe_hw *hw,
|
||||
u32 speed,
|
||||
bool need_restart_AN);
|
||||
u32 ngbe_phy_led_ctrl(struct ngbe_hw *hw);
|
||||
int ngbe_phy_reset_m88e1512(struct ngbe_hw *hw);
|
||||
u32 ngbe_phy_setup_link_m88e1512( struct ngbe_hw *hw,
|
||||
u32 speed,
|
||||
bool autoneg_wait_to_complete);
|
||||
int ngbe_phy_check_overtemp(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_mv_suspend(struct ngbe_hw *hw);
|
||||
int ngbe_yt_suspend(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_phy_check_event(struct ngbe_hw *hw);
|
||||
int ngbe_phy_check_event_m88e1512(struct ngbe_hw *hw);
|
||||
int ngbe_phy_set_pause_advertisement_m88e1512(struct ngbe_hw *hw,
|
||||
u16 pause_bit);
|
||||
int ngbe_phy_get_advertised_pause_m88e1512(struct ngbe_hw *hw, u8 *pause_bit);
|
||||
int ngbe_phy_get_lp_advertised_pause_m88e1512(struct ngbe_hw *hw, u8 *pause_bit);
|
||||
int ngbe_phy_check_event_yt8521s(struct ngbe_hw *hw);
|
||||
int ngbe_phy_get_advertised_pause_yt8521s(struct ngbe_hw *hw, u8 *pause_bit);
|
||||
int ngbe_phy_get_lp_advertised_pause_yt8521s(struct ngbe_hw *hw, u8 *pause_bit);
|
||||
int ngbe_phy_reset_yt8521s(struct ngbe_hw *hw);
|
||||
u32 ngbe_phy_setup_link_yt8521s( struct ngbe_hw *hw,
|
||||
u32 speed,
|
||||
bool autoneg_wait_to_complete);
|
||||
int ngbe_phy_set_pause_advertisement_yt8521s(struct ngbe_hw *hw,
|
||||
u16 pause_bit);
|
||||
int ngbe_gphy_wait_mdio_access_on(struct ngbe_hw *hw);
|
||||
int ngbe_gphy_efuse_calibration(struct ngbe_hw *hw);
|
||||
|
||||
int ngbe_gphy_dis_eee(struct ngbe_hw *hw);
|
||||
|
||||
|
||||
#endif /* _NGBE_PHY_H_ */
|
|
@ -0,0 +1,924 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ngbe.h"
|
||||
#include "ngbe_hw.h"
|
||||
#include "ngbe_type.h"
|
||||
|
||||
#ifdef NGBE_PROCFS
|
||||
#ifndef NGBE_SYSFS
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
static struct proc_dir_entry *ngbe_top_dir;
|
||||
|
||||
static struct net_device_stats *procfs_get_stats(struct net_device *netdev)
|
||||
{
|
||||
#ifndef HAVE_NETDEV_STATS_IN_NETDEV
|
||||
struct ngbe_adapter *adapter;
|
||||
#endif
|
||||
if (netdev == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_NETDEV_STATS_IN_NETDEV
|
||||
/* only return the current stats */
|
||||
return &netdev->stats;
|
||||
#else
|
||||
adapter = netdev_priv(netdev);
|
||||
|
||||
/* only return the current stats */
|
||||
return &adapter->net_stats;
|
||||
#endif /* HAVE_NETDEV_STATS_IN_NETDEV */
|
||||
}
|
||||
|
||||
static int ngbe_fwbanner(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%s\n", adapter->eeprom_id);
|
||||
}
|
||||
|
||||
static int ngbe_porttype(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
return snprintf(page, count, "%d\n",
|
||||
test_bit(__NGBE_DOWN, &adapter->state));
|
||||
}
|
||||
|
||||
static int ngbe_portspeed(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
int speed = 0;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case NGBE_LINK_SPEED_100_FULL:
|
||||
speed = 1;
|
||||
break;
|
||||
case NGBE_LINK_SPEED_1GB_FULL:
|
||||
speed = 10;
|
||||
break;
|
||||
case NGBE_LINK_SPEED_10GB_FULL:
|
||||
speed = 100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return snprintf(page, count, "%d\n", speed);
|
||||
}
|
||||
|
||||
static int ngbe_wqlflag(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", adapter->wol);
|
||||
}
|
||||
|
||||
static int ngbe_xflowctl(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct ngbe_hw *hw;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", hw->fc.current_mode);
|
||||
}
|
||||
|
||||
static int ngbe_rxdrops(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->rx_dropped);
|
||||
}
|
||||
|
||||
static int ngbe_rxerrors(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n", net_stats->rx_errors);
|
||||
}
|
||||
|
||||
static int ngbe_rxupacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", rd32(hw, NGBE_TPR));
|
||||
}
|
||||
|
||||
static int ngbe_rxmpacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
int i, mprc = 0;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
for (i = 0; i < 8; i++)
|
||||
mprc += rd32(hw, NGBE_PX_MPRC(i));
|
||||
return snprintf(page, count, "%d\n", mprc);
|
||||
}
|
||||
|
||||
static int ngbe_rxbpacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
rd32(hw, NGBE_RX_BC_FRAMES_GOOD_LOW));
|
||||
}
|
||||
|
||||
static int ngbe_txupacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
rd32(hw, NGBE_TX_FRAME_CNT_GOOD_BAD_LOW));
|
||||
}
|
||||
|
||||
static int ngbe_txmpacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
rd32(hw, NGBE_TX_MC_FRAMES_GOOD_LOW));
|
||||
}
|
||||
|
||||
static int ngbe_txbpacks(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
rd32(hw, NGBE_TX_BC_FRAMES_GOOD_LOW));
|
||||
}
|
||||
|
||||
static int ngbe_txerrors(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->tx_errors);
|
||||
}
|
||||
|
||||
static int ngbe_txdrops(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->tx_dropped);
|
||||
}
|
||||
|
||||
static int ngbe_rxframes(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->rx_packets);
|
||||
}
|
||||
|
||||
static int ngbe_rxbytes(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->rx_bytes);
|
||||
}
|
||||
|
||||
static int ngbe_txframes(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->tx_packets);
|
||||
}
|
||||
|
||||
static int ngbe_txbytes(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device_stats *net_stats;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
net_stats = procfs_get_stats(adapter->netdev);
|
||||
if (net_stats == NULL)
|
||||
return snprintf(page, count, "error: no net stats\n");
|
||||
|
||||
return snprintf(page, count, "%lu\n",
|
||||
net_stats->tx_bytes);
|
||||
}
|
||||
|
||||
static int ngbe_linkstat(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
int bitmask = 0;
|
||||
u32 link_speed;
|
||||
bool link_up = false;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
if (!test_bit(__NGBE_DOWN, &adapter->state))
|
||||
bitmask |= 1;
|
||||
|
||||
/* always assume link is up, if no check link function */
|
||||
link_up = true;
|
||||
if (link_up)
|
||||
bitmask |= 2;
|
||||
|
||||
if (adapter->old_lsc != adapter->lsc_int) {
|
||||
bitmask |= 4;
|
||||
adapter->old_lsc = adapter->lsc_int;
|
||||
}
|
||||
|
||||
return snprintf(page, count, "0x%X\n", bitmask);
|
||||
}
|
||||
|
||||
static int ngbe_funcid(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct ngbe_hw *hw;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "0x%X\n", hw->bus.func);
|
||||
}
|
||||
|
||||
static int ngbe_funcvers(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void __always_unused *data)
|
||||
{
|
||||
return snprintf(page, count, "%s\n", ngbe_driver_version);
|
||||
}
|
||||
|
||||
static int ngbe_macburn(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "0x%02X%02X%02X%02X%02X%02X\n",
|
||||
(unsigned int)hw->mac.perm_addr[0],
|
||||
(unsigned int)hw->mac.perm_addr[1],
|
||||
(unsigned int)hw->mac.perm_addr[2],
|
||||
(unsigned int)hw->mac.perm_addr[3],
|
||||
(unsigned int)hw->mac.perm_addr[4],
|
||||
(unsigned int)hw->mac.perm_addr[5]);
|
||||
}
|
||||
|
||||
static int ngbe_macadmn(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_hw *hw;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
return snprintf(page, count, "0x%02X%02X%02X%02X%02X%02X\n",
|
||||
(unsigned int)hw->mac.addr[0],
|
||||
(unsigned int)hw->mac.addr[1],
|
||||
(unsigned int)hw->mac.addr[2],
|
||||
(unsigned int)hw->mac.addr[3],
|
||||
(unsigned int)hw->mac.addr[4],
|
||||
(unsigned int)hw->mac.addr[5]);
|
||||
}
|
||||
|
||||
static int ngbe_maclla1(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct ngbe_hw *hw;
|
||||
int rc;
|
||||
u16 eeprom_buff[6];
|
||||
u16 first_word = 0x37;
|
||||
const u16 word_count = ARRAY_SIZE(eeprom_buff);
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
hw = &adapter->hw;
|
||||
if (hw == NULL)
|
||||
return snprintf(page, count, "error: no hw data\n");
|
||||
|
||||
rc = hw->eeprom.ops.read_buffer(hw, first_word, 1, &first_word);
|
||||
if (rc != 0)
|
||||
return snprintf(page, count,
|
||||
"error: reading pointer to the EEPROM\n");
|
||||
|
||||
if (first_word != 0x0000 && first_word != 0xFFFF) {
|
||||
rc = hw->eeprom.ops.read_buffer(hw, first_word, word_count,
|
||||
eeprom_buff);
|
||||
if (rc != 0)
|
||||
return snprintf(page, count, "error: reading buffer\n");
|
||||
} else {
|
||||
memset(eeprom_buff, 0, sizeof(eeprom_buff));
|
||||
}
|
||||
|
||||
switch (hw->bus.func) {
|
||||
case 0:
|
||||
return snprintf(page, count, "0x%04X%04X%04X\n",
|
||||
eeprom_buff[0],
|
||||
eeprom_buff[1],
|
||||
eeprom_buff[2]);
|
||||
case 1:
|
||||
return snprintf(page, count, "0x%04X%04X%04X\n",
|
||||
eeprom_buff[3],
|
||||
eeprom_buff[4],
|
||||
eeprom_buff[5]);
|
||||
default:
|
||||
return snprintf(page, count, "unexpected port %d\n", hw->bus.func);
|
||||
}
|
||||
}
|
||||
|
||||
static int ngbe_mtusize(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device *netdev;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
netdev = adapter->netdev;
|
||||
if (netdev == NULL)
|
||||
return snprintf(page, count, "error: no net device\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", netdev->mtu);
|
||||
}
|
||||
|
||||
static int ngbe_featflag(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
int bitmask = 0;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device *netdev;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
netdev = adapter->netdev;
|
||||
if (netdev == NULL)
|
||||
return snprintf(page, count, "error: no net device\n");
|
||||
if (adapter->netdev->features & NETIF_F_RXCSUM)
|
||||
bitmask |= 1;
|
||||
return snprintf(page, count, "%d\n", bitmask);
|
||||
}
|
||||
|
||||
static int ngbe_lsominct(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void __always_unused *data)
|
||||
{
|
||||
return snprintf(page, count, "%d\n", 1);
|
||||
}
|
||||
|
||||
static int ngbe_prommode(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
struct net_device *netdev;
|
||||
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
netdev = adapter->netdev;
|
||||
if (netdev == NULL)
|
||||
return snprintf(page, count, "error: no net device\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
netdev->flags & IFF_PROMISC);
|
||||
}
|
||||
|
||||
static int ngbe_txdscqsz(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", adapter->tx_ring[0]->count);
|
||||
}
|
||||
|
||||
static int ngbe_rxdscqsz(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", adapter->rx_ring[0]->count);
|
||||
}
|
||||
|
||||
static int ngbe_rxqavg(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
int index;
|
||||
int diff = 0;
|
||||
u16 ntc;
|
||||
u16 ntu;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
for (index = 0; index < adapter->num_rx_queues; index++) {
|
||||
ntc = adapter->rx_ring[index]->next_to_clean;
|
||||
ntu = adapter->rx_ring[index]->next_to_use;
|
||||
|
||||
if (ntc >= ntu)
|
||||
diff += (ntc - ntu);
|
||||
else
|
||||
diff += (adapter->rx_ring[index]->count - ntu + ntc);
|
||||
}
|
||||
if (adapter->num_rx_queues <= 0)
|
||||
return snprintf(page, count,
|
||||
"can't calculate, number of queues %d\n",
|
||||
adapter->num_rx_queues);
|
||||
return snprintf(page, count, "%d\n", diff/adapter->num_rx_queues);
|
||||
}
|
||||
|
||||
static int ngbe_txqavg(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
int index;
|
||||
int diff = 0;
|
||||
u16 ntc;
|
||||
u16 ntu;
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
for (index = 0; index < adapter->num_tx_queues; index++) {
|
||||
ntc = adapter->tx_ring[index]->next_to_clean;
|
||||
ntu = adapter->tx_ring[index]->next_to_use;
|
||||
|
||||
if (ntc >= ntu)
|
||||
diff += (ntc - ntu);
|
||||
else
|
||||
diff += (adapter->tx_ring[index]->count - ntu + ntc);
|
||||
}
|
||||
if (adapter->num_tx_queues <= 0)
|
||||
return snprintf(page, count,
|
||||
"can't calculate, number of queues %d\n",
|
||||
adapter->num_tx_queues);
|
||||
return snprintf(page, count, "%d\n",
|
||||
diff/adapter->num_tx_queues);
|
||||
}
|
||||
|
||||
static int ngbe_iovotype(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void __always_unused *data)
|
||||
{
|
||||
return snprintf(page, count, "2\n");
|
||||
}
|
||||
|
||||
static int ngbe_funcnbr(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", adapter->num_vfs);
|
||||
}
|
||||
|
||||
static int ngbe_pciebnbr(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_adapter *adapter = (struct ngbe_adapter *)data;
|
||||
if (adapter == NULL)
|
||||
return snprintf(page, count, "error: no adapter\n");
|
||||
|
||||
return snprintf(page, count, "%d\n", adapter->pdev->bus->number);
|
||||
}
|
||||
|
||||
static int ngbe_therm_dealarmthresh(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_therm_proc_data *therm_data =
|
||||
(struct ngbe_therm_proc_data *)data;
|
||||
|
||||
if (therm_data == NULL)
|
||||
return snprintf(page, count, "error: no therm_data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
therm_data->sensor_data->dalarm_thresh);
|
||||
}
|
||||
|
||||
|
||||
static int ngbe_therm_alarmthresh(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
struct ngbe_therm_proc_data *therm_data =
|
||||
(struct ngbe_therm_proc_data *)data;
|
||||
|
||||
if (therm_data == NULL)
|
||||
return snprintf(page, count, "error: no therm_data\n");
|
||||
|
||||
return snprintf(page, count, "%d\n",
|
||||
therm_data->sensor_data->alarm_thresh);
|
||||
}
|
||||
|
||||
static int ngbe_therm_temp(char *page, char __always_unused **start,
|
||||
off_t __always_unused off, int count,
|
||||
int __always_unused *eof, void *data)
|
||||
{
|
||||
int status;
|
||||
struct ngbe_therm_proc_data *therm_data =
|
||||
(struct ngbe_therm_proc_data *)data;
|
||||
|
||||
if (therm_data == NULL)
|
||||
return snprintf(page, count, "error: no therm_data\n");
|
||||
|
||||
status = ngbe_get_thermal_sensor_data(therm_data->hw);
|
||||
if (status != 0)
|
||||
snprintf(page, count, "error: status %d returned\n", status);
|
||||
|
||||
return snprintf(page, count, "%d\n", therm_data->sensor_data->temp);
|
||||
}
|
||||
|
||||
|
||||
struct ngbe_proc_type {
|
||||
char name[32];
|
||||
int (*read)(char*, char**, off_t, int, int*, void*);
|
||||
};
|
||||
|
||||
struct ngbe_proc_type ngbe_proc_entries[] = {
|
||||
{"fwbanner", &ngbe_fwbanner},
|
||||
{"porttype", &ngbe_porttype},
|
||||
{"portspeed", &ngbe_portspeed},
|
||||
{"wqlflag", &ngbe_wqlflag},
|
||||
{"xflowctl", &ngbe_xflowctl},
|
||||
{"rxdrops", &ngbe_rxdrops},
|
||||
{"rxerrors", &ngbe_rxerrors},
|
||||
{"rxupacks", &ngbe_rxupacks},
|
||||
{"rxmpacks", &ngbe_rxmpacks},
|
||||
{"rxbpacks", &ngbe_rxbpacks},
|
||||
{"txdrops", &ngbe_txdrops},
|
||||
{"txerrors", &ngbe_txerrors},
|
||||
{"txupacks", &ngbe_txupacks},
|
||||
{"txmpacks", &ngbe_txmpacks},
|
||||
{"txbpacks", &ngbe_txbpacks},
|
||||
{"rxframes", &ngbe_rxframes},
|
||||
{"rxbytes", &ngbe_rxbytes},
|
||||
{"txframes", &ngbe_txframes},
|
||||
{"txbytes", &ngbe_txbytes},
|
||||
{"linkstat", &ngbe_linkstat},
|
||||
{"funcid", &ngbe_funcid},
|
||||
{"funcvers", &ngbe_funcvers},
|
||||
{"macburn", &ngbe_macburn},
|
||||
{"macadmn", &ngbe_macadmn},
|
||||
{"maclla1", &ngbe_maclla1},
|
||||
{"mtusize", &ngbe_mtusize},
|
||||
{"featflag", &ngbe_featflag},
|
||||
{"lsominct", &ngbe_lsominct},
|
||||
{"prommode", &ngbe_prommode},
|
||||
{"txdscqsz", &ngbe_txdscqsz},
|
||||
{"rxdscqsz", &ngbe_rxdscqsz},
|
||||
{"txqavg", &ngbe_txqavg},
|
||||
{"rxqavg", &ngbe_rxqavg},
|
||||
{"iovotype", &ngbe_iovotype},
|
||||
{"funcnbr", &ngbe_funcnbr},
|
||||
{"pciebnbr", &ngbe_pciebnbr},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
struct ngbe_proc_type ngbe_internal_entries[] = {
|
||||
{"temp", &ngbe_therm_temp},
|
||||
{"alarmthresh", &ngbe_therm_alarmthresh},
|
||||
{"dealarmthresh", &ngbe_therm_dealarmthresh},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
void ngbe_del_proc_entries(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int index;
|
||||
int i;
|
||||
char buf[16]; /* much larger than the sensor number will ever be */
|
||||
|
||||
if (ngbe_top_dir == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < NGBE_MAX_SENSORS; i++) {
|
||||
if (adapter->therm_dir[i] == NULL)
|
||||
continue;
|
||||
|
||||
for (index = 0; ; index++) {
|
||||
if (ngbe_internal_entries[index].read == NULL)
|
||||
break;
|
||||
|
||||
remove_proc_entry(ngbe_internal_entries[index].name,
|
||||
adapter->therm_dir[i]);
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "sensor_%d", i);
|
||||
remove_proc_entry(buf, adapter->info_dir);
|
||||
}
|
||||
|
||||
if (adapter->info_dir != NULL) {
|
||||
for (index = 0; ; index++) {
|
||||
if (ngbe_proc_entries[index].read == NULL)
|
||||
break;
|
||||
remove_proc_entry(ngbe_proc_entries[index].name,
|
||||
adapter->info_dir);
|
||||
}
|
||||
remove_proc_entry("info", adapter->eth_dir);
|
||||
}
|
||||
|
||||
if (adapter->eth_dir != NULL)
|
||||
remove_proc_entry(pci_name(adapter->pdev), ngbe_top_dir);
|
||||
}
|
||||
|
||||
/* called from ngbe_main.c */
|
||||
void ngbe_procfs_exit(struct ngbe_adapter *adapter)
|
||||
{
|
||||
ngbe_del_proc_entries(adapter);
|
||||
}
|
||||
|
||||
int ngbe_procfs_topdir_init(void)
|
||||
{
|
||||
ngbe_top_dir = proc_mkdir("driver/ngbe", NULL);
|
||||
if (ngbe_top_dir == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngbe_procfs_topdir_exit(void)
|
||||
{
|
||||
remove_proc_entry("driver/ngbe", NULL);
|
||||
}
|
||||
|
||||
/* called from ngbe_main.c */
|
||||
int ngbe_procfs_init(struct ngbe_adapter *adapter)
|
||||
{
|
||||
int rc = 0;
|
||||
int index;
|
||||
int i;
|
||||
char buf[16]; /* much larger than the sensor number will ever be */
|
||||
|
||||
adapter->eth_dir = NULL;
|
||||
adapter->info_dir = NULL;
|
||||
adapter->therm_dir = NULL;
|
||||
|
||||
if (ngbe_top_dir == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
adapter->eth_dir = proc_mkdir(pci_name(adapter->pdev), ngbe_top_dir);
|
||||
if (adapter->eth_dir == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
adapter->info_dir = proc_mkdir("info", adapter->eth_dir);
|
||||
if (adapter->info_dir == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
for (index = 0; ; index++) {
|
||||
if (ngbe_proc_entries[index].read == NULL)
|
||||
break;
|
||||
if (!(create_proc_read_entry(ngbe_proc_entries[index].name,
|
||||
0444,
|
||||
adapter->info_dir,
|
||||
ngbe_proc_entries[index].read,
|
||||
adapter))) {
|
||||
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (!adapter->hw->ops.init_thermal_sensor_thresh(hw))
|
||||
goto exit;
|
||||
|
||||
|
||||
snprintf(buf, sizeof(buf), "sensor");
|
||||
adapter->therm_dir = proc_mkdir(buf, adapter->info_dir);
|
||||
if (adapter->therm_dir == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
for (index = 0; ; index++) {
|
||||
if (ngbe_internal_entries[index].read == NULL)
|
||||
break;
|
||||
/*
|
||||
* therm_data struct contains pointer the read func
|
||||
* will be needing
|
||||
*/
|
||||
adapter->therm_data.hw = &adapter->hw;
|
||||
adapter->therm_data.sensor_data =
|
||||
&adapter->hw.mac.thermal_sensor_data.sensor;
|
||||
|
||||
if (!(create_proc_read_entry(
|
||||
ngbe_internal_entries[index].name,
|
||||
0444,
|
||||
adapter->therm_dir,
|
||||
ngbe_internal_entries[index].read,
|
||||
&adapter->therm_data))) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
fail:
|
||||
ngbe_del_proc_entries(adapter);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* !NGBE_SYSFS */
|
||||
#endif /* NGBE_PROCFS */
|
|
@ -0,0 +1,887 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
|
||||
#include "ngbe.h"
|
||||
#include <linux/ptp_classify.h>
|
||||
|
||||
/*
|
||||
* SYSTIME is defined by a fixed point system which allows the user to
|
||||
* define the scale counter increment value at every level change of
|
||||
* the oscillator driving SYSTIME value. The time unit is determined by
|
||||
* the clock frequency of the oscillator and TIMINCA register.
|
||||
* The cyclecounter and timecounter structures are used to to convert
|
||||
* the scale counter into nanoseconds. SYSTIME registers need to be converted
|
||||
* to ns values by use of only a right shift.
|
||||
* The following math determines the largest incvalue that will fit into
|
||||
* the available bits in the TIMINCA register:
|
||||
* Period * [ 2 ^ ( MaxWidth - PeriodWidth ) ]
|
||||
* PeriodWidth: Number of bits to store the clock period
|
||||
* MaxWidth: The maximum width value of the TIMINCA register
|
||||
* Period: The clock period for the oscillator, which changes based on the link
|
||||
* speed:
|
||||
* At 10Gb link or no link, the period is 6.4 ns.
|
||||
* At 1Gb link, the period is multiplied by 10. (64ns)
|
||||
* At 100Mb link, the period is multiplied by 100. (640ns)
|
||||
* round(): discard the fractional portion of the calculation
|
||||
*
|
||||
* The calculated value allows us to right shift the SYSTIME register
|
||||
* value in order to quickly convert it into a nanosecond clock,
|
||||
* while allowing for the maximum possible adjustment value.
|
||||
*
|
||||
* LinkSpeed ClockFreq ClockPeriod TIMINCA:IV
|
||||
* 10000Mbps 156.25MHz 6.4*10^-9 0xCCCCCC(0xFFFFF/ns)
|
||||
* 1000 Mbps 62.5 MHz 16 *10^-9 0x800000(0x7FFFF/ns)
|
||||
* 100 Mbps 6.25 MHz 160*10^-9 0xA00000(0xFFFF/ns)
|
||||
* 10 Mbps 0.625 MHz 1600*10^-9 0xC7F380(0xFFF/ns)
|
||||
* FPGA 31.25 MHz 32 *10^-9 0x800000(0x3FFFF/ns)
|
||||
*
|
||||
* These diagrams are only for the 10Gb link period
|
||||
*
|
||||
* +--------------+ +--------------+
|
||||
* | 32 | | 8 | 3 | 20 |
|
||||
* *--------------+ +--------------+
|
||||
* \________ 43 bits ______/ fract
|
||||
*
|
||||
* The 43 bit SYSTIME overflows every
|
||||
* 2^43 * 10^-9 / 3600 = 2.4 hours
|
||||
*/
|
||||
#define NGBE_INCVAL_10GB 0xCCCCCC
|
||||
#define NGBE_INCVAL_1GB 0x2000000/*in Emerald all speed is same*/
|
||||
#define NGBE_INCVAL_100 0xA00000
|
||||
#define NGBE_INCVAL_10 0xC7F380
|
||||
#define NGBE_INCVAL_FPGA 0x800000
|
||||
|
||||
#define NGBE_INCVAL_SHIFT_10GB 20
|
||||
#define NGBE_INCVAL_SHIFT_1GB 22/*in Emerald all speed is same*/
|
||||
#define NGBE_INCVAL_SHIFT_100 15
|
||||
#define NGBE_INCVAL_SHIFT_10 12
|
||||
#define NGBE_INCVAL_SHIFT_FPGA 17
|
||||
|
||||
#define NGBE_OVERFLOW_PERIOD (HZ * 30)
|
||||
#define NGBE_PTP_TX_TIMEOUT (HZ)
|
||||
|
||||
/**
|
||||
* ngbe_ptp_read - read raw cycle counter (to be used by time counter)
|
||||
* @hw_cc: the cyclecounter structure
|
||||
*
|
||||
* this function reads the cyclecounter registers and is called by the
|
||||
* cyclecounter structure used to construct a ns counter from the
|
||||
* arbitrary fixed point registers
|
||||
*/
|
||||
static u64 ngbe_ptp_read(const struct cyclecounter *hw_cc)
|
||||
{
|
||||
struct ngbe_adapter *adapter =
|
||||
container_of(hw_cc, struct ngbe_adapter, hw_cc);
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
u64 stamp = 0;
|
||||
|
||||
stamp |= (u64)rd32(hw, NGBE_TSEC_1588_SYSTIML);
|
||||
stamp |= (u64)rd32(hw, NGBE_TSEC_1588_SYSTIMH) << 32;
|
||||
|
||||
return stamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_convert_to_hwtstamp - convert register value to hw timestamp
|
||||
* @adapter: private adapter structure
|
||||
* @hwtstamp: stack timestamp structure
|
||||
* @systim: unsigned 64bit system time value
|
||||
*
|
||||
* We need to convert the adapter's RX/TXSTMP registers into a hwtstamp value
|
||||
* which can be used by the stack's ptp functions.
|
||||
*
|
||||
* The lock is used to protect consistency of the cyclecounter and the SYSTIME
|
||||
* registers. However, it does not need to protect against the Rx or Tx
|
||||
* timestamp registers, as there can't be a new timestamp until the old one is
|
||||
* unlatched by reading.
|
||||
*
|
||||
* In addition to the timestamp in hardware, some controllers need a software
|
||||
* overflow cyclecounter, and this function takes this into account as well.
|
||||
**/
|
||||
static void ngbe_ptp_convert_to_hwtstamp(struct ngbe_adapter *adapter,
|
||||
struct skb_shared_hwtstamps *hwtstamp,
|
||||
u64 timestamp)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
|
||||
memset(hwtstamp, 0, sizeof(*hwtstamp));
|
||||
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
ns = timecounter_cyc2time(&adapter->hw_tc, timestamp);
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
hwtstamp->hwtstamp = ns_to_ktime(ns);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ngbe_ptp_adjfreq
|
||||
* @ptp: the ptp clock structure
|
||||
* @ppb: parts per billion adjustment from base
|
||||
*
|
||||
* adjust the frequency of the ptp cycle counter by the
|
||||
* indicated ppb from the base frequency.
|
||||
*/
|
||||
#ifndef HAVE_NOT_PTT_ADJFREQ
|
||||
static int ngbe_ptp_adjfreq(struct ptp_clock_info *ptp, int ppb)
|
||||
{
|
||||
struct ngbe_adapter *adapter =
|
||||
container_of(ptp, struct ngbe_adapter, ptp_caps);
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
u64 freq, incval;
|
||||
u32 diff;
|
||||
int neg_adj = 0;
|
||||
|
||||
if (ppb < 0) {
|
||||
neg_adj = 1;
|
||||
ppb = -ppb;
|
||||
}
|
||||
|
||||
smp_mb();
|
||||
incval = READ_ONCE(adapter->base_incval);
|
||||
|
||||
freq = incval;
|
||||
freq *= ppb;
|
||||
diff = div_u64(freq, 1000000000ULL);
|
||||
|
||||
incval = neg_adj ? (incval - diff) : (incval + diff);
|
||||
/* temp setting*/
|
||||
|
||||
if (incval > NGBE_TSEC_1588_INC_IV(~0))
|
||||
e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
|
||||
wr32(hw, NGBE_TSEC_1588_INC, NGBE_TSEC_1588_INC_IV(incval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ngbe_ptp_adjtime
|
||||
* @ptp: the ptp clock structure
|
||||
* @delta: offset to adjust the cycle counter by ns
|
||||
*
|
||||
* adjust the timer by resetting the timecounter structure.
|
||||
*/
|
||||
static int ngbe_ptp_adjtime(struct ptp_clock_info *ptp,
|
||||
s64 delta)
|
||||
{
|
||||
struct ngbe_adapter *adapter =
|
||||
container_of(ptp, struct ngbe_adapter, ptp_caps);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
timecounter_adjtime(&adapter->hw_tc, delta);
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_gettime64
|
||||
* @ptp: the ptp clock structure
|
||||
* @ts: timespec64 structure to hold the current time value
|
||||
*
|
||||
* read the timecounter and return the correct value on ns,
|
||||
* after converting it into a struct timespec64.
|
||||
*/
|
||||
static int ngbe_ptp_gettime64(struct ptp_clock_info *ptp,
|
||||
struct timespec64 *ts)
|
||||
{
|
||||
struct ngbe_adapter *adapter =
|
||||
container_of(ptp, struct ngbe_adapter, ptp_caps);
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
ns = timecounter_read(&adapter->hw_tc);
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_settime64
|
||||
* @ptp: the ptp clock structure
|
||||
* @ts: the timespec64 containing the new time for the cycle counter
|
||||
*
|
||||
* reset the timecounter to use a new base value instead of the kernel
|
||||
* wall timer value.
|
||||
*/
|
||||
static int ngbe_ptp_settime64(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
struct ngbe_adapter *adapter =
|
||||
container_of(ptp, struct ngbe_adapter, ptp_caps);
|
||||
u64 ns;
|
||||
unsigned long flags;
|
||||
|
||||
ns = timespec64_to_ns(ts);
|
||||
|
||||
/* reset the timecounter */
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
timecounter_init(&adapter->hw_tc, &adapter->hw_cc, ns);
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_PTP_CLOCK_INFO_GETTIME64
|
||||
static int ngbe_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
|
||||
{
|
||||
struct timespec64 ts64;
|
||||
int err;
|
||||
|
||||
err = ngbe_ptp_gettime64(ptp, &ts64);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*ts = timespec64_to_timespec(ts64);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngbe_ptp_settime(struct ptp_clock_info *ptp,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct timespec64 ts64;
|
||||
|
||||
ts64 = timespec_to_timespec64(*ts);
|
||||
return ngbe_ptp_settime64(ptp, &ts64);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ngbe_ptp_feature_enable
|
||||
* @ptp: the ptp clock structure
|
||||
* @rq: the requested feature to change
|
||||
* @on: whether to enable or disable the feature
|
||||
*
|
||||
* enable (or disable) ancillary features of the phc subsystem.
|
||||
* our driver only supports the PPS feature on the X540
|
||||
*/
|
||||
static int ngbe_ptp_feature_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_check_pps_event
|
||||
* @adapter: the private adapter structure
|
||||
* @eicr: the interrupt cause register value
|
||||
*
|
||||
* This function is called by the interrupt routine when checking for
|
||||
* interrupts. It will check and handle a pps event.
|
||||
*/
|
||||
void ngbe_ptp_check_pps_event(struct ngbe_adapter *adapter)
|
||||
{
|
||||
/* this check is necessary in case the interrupt was enabled via some
|
||||
* alternative means (ex. debug_fs). Better to check here than
|
||||
* everywhere that calls this function.
|
||||
*/
|
||||
if (!adapter->ptp_clock)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
|
||||
* @adapter: private adapter struct
|
||||
*
|
||||
* this watchdog task periodically reads the timecounter
|
||||
* in order to prevent missing when the system time registers wrap
|
||||
* around. This needs to be run approximately twice a minute for the fastest
|
||||
* overflowing hardware. We run it for all hardware since it shouldn't have a
|
||||
* large impact.
|
||||
*/
|
||||
void ngbe_ptp_overflow_check(struct ngbe_adapter *adapter)
|
||||
{
|
||||
bool timeout = time_is_before_jiffies(adapter->last_overflow_check +
|
||||
NGBE_OVERFLOW_PERIOD);
|
||||
struct timespec64 ts;
|
||||
|
||||
if (timeout) {
|
||||
ngbe_ptp_gettime64(&adapter->ptp_caps, &ts);
|
||||
adapter->last_overflow_check = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_rx_hang - detect error case when Rx timestamp registers latched
|
||||
* @adapter: private network adapter structure
|
||||
*
|
||||
* this watchdog task is scheduled to detect error case where hardware has
|
||||
* dropped an Rx packet that was timestamped when the ring is full. The
|
||||
* particular error is rare but leaves the device in a state unable to timestamp
|
||||
* any future packets.
|
||||
*/
|
||||
void ngbe_ptp_rx_hang(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
struct ngbe_ring *rx_ring;
|
||||
u32 tsyncrxctl = rd32(hw, NGBE_PSR_1588_CTL);
|
||||
unsigned long rx_event;
|
||||
int n;
|
||||
|
||||
/* if we don't have a valid timestamp in the registers, just update the
|
||||
* timeout counter and exit
|
||||
*/
|
||||
if (!(tsyncrxctl & NGBE_PSR_1588_CTL_VALID)) {
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
/* determine the most recent watchdog or rx_timestamp event */
|
||||
rx_event = adapter->last_rx_ptp_check;
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
if (time_after(rx_ring->last_rx_timestamp, rx_event))
|
||||
rx_event = rx_ring->last_rx_timestamp;
|
||||
}
|
||||
|
||||
/* only need to read the high RXSTMP register to clear the lock */
|
||||
if (time_is_before_jiffies(rx_event + 5 * HZ)) {
|
||||
rd32(hw, NGBE_PSR_1588_STMPH);
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
|
||||
adapter->rx_hwtstamp_cleared++;
|
||||
e_warn(drv, "clearing RX Timestamp hang");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state
|
||||
* @adapter: the private adapter structure
|
||||
*
|
||||
* This function should be called whenever the state related to a Tx timestamp
|
||||
* needs to be cleared. This helps ensure that all related bits are reset for
|
||||
* the next Tx timestamp event.
|
||||
*/
|
||||
static void ngbe_ptp_clear_tx_timestamp(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
|
||||
rd32(hw, NGBE_TSEC_1588_STMPH);
|
||||
if (adapter->ptp_tx_skb) {
|
||||
dev_kfree_skb_any(adapter->ptp_tx_skb);
|
||||
adapter->ptp_tx_skb = NULL;
|
||||
}
|
||||
clear_bit_unlock(__NGBE_PTP_TX_IN_PROGRESS, &adapter->state);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
|
||||
* @adapter: the private adapter struct
|
||||
*
|
||||
* if the timestamp is valid, we convert it into the timecounter ns
|
||||
* value, then store that result into the shhwtstamps structure which
|
||||
* is passed up the network stack
|
||||
*/
|
||||
static void ngbe_ptp_tx_hwtstamp(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
u64 regval = 0;
|
||||
|
||||
regval |= (u64)rd32(hw, NGBE_TSEC_1588_STMPL);
|
||||
regval |= (u64)rd32(hw, NGBE_TSEC_1588_STMPH) << 32;
|
||||
|
||||
ngbe_ptp_convert_to_hwtstamp(adapter, &shhwtstamps, regval);
|
||||
skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
|
||||
|
||||
ngbe_ptp_clear_tx_timestamp(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_tx_hwtstamp_work
|
||||
* @work: pointer to the work struct
|
||||
*
|
||||
* This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
|
||||
* timestamp has been taken for the current skb. It is necesary, because the
|
||||
* descriptor's "done" bit does not correlate with the timestamp event.
|
||||
*/
|
||||
static void ngbe_ptp_tx_hwtstamp_work(struct work_struct *work)
|
||||
{
|
||||
struct ngbe_adapter *adapter = container_of(work, struct ngbe_adapter,
|
||||
ptp_tx_work);
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
|
||||
NGBE_PTP_TX_TIMEOUT);
|
||||
u32 tsynctxctl;
|
||||
|
||||
/* we have to have a valid skb to poll for a timestamp */
|
||||
if (!adapter->ptp_tx_skb) {
|
||||
ngbe_ptp_clear_tx_timestamp(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
/* stop polling once we have a valid timestamp */
|
||||
tsynctxctl = rd32(hw, NGBE_TSEC_1588_CTL);
|
||||
if (tsynctxctl & NGBE_TSEC_1588_CTL_VALID) {
|
||||
ngbe_ptp_tx_hwtstamp(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check timeout last in case timestamp event just occurred */
|
||||
if (timeout) {
|
||||
ngbe_ptp_clear_tx_timestamp(adapter);
|
||||
adapter->tx_hwtstamp_timeouts++;
|
||||
e_warn(drv, "clearing Tx Timestamp hang");
|
||||
} else {
|
||||
/* reschedule to keep checking until we timeout */
|
||||
schedule_work(&adapter->ptp_tx_work);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_rx_rgtstamp - utility function which checks for RX time stamp
|
||||
* @q_vector: structure containing interrupt and ring information
|
||||
* @skb: particular skb to send timestamp with
|
||||
*
|
||||
* if the timestamp is valid, we convert it into the timecounter ns
|
||||
* value, then store that result into the shhwtstamps structure which
|
||||
* is passed up the network stack
|
||||
*/
|
||||
void ngbe_ptp_rx_hwtstamp(struct ngbe_adapter *adapter, struct sk_buff *skb)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
u64 regval = 0;
|
||||
u32 tsyncrxctl;
|
||||
|
||||
/*
|
||||
* Read the tsyncrxctl register afterwards in order to prevent taking an
|
||||
* I/O hit on every packet.
|
||||
*/
|
||||
tsyncrxctl = rd32(hw, NGBE_PSR_1588_CTL);
|
||||
if (!(tsyncrxctl & NGBE_PSR_1588_CTL_VALID))
|
||||
return;
|
||||
|
||||
regval |= (u64)rd32(hw, NGBE_PSR_1588_STMPL);
|
||||
regval |= (u64)rd32(hw, NGBE_PSR_1588_STMPH) << 32;
|
||||
|
||||
ngbe_ptp_convert_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_get_ts_config - get current hardware timestamping configuration
|
||||
* @adapter: pointer to adapter structure
|
||||
* @ifreq: ioctl data
|
||||
*
|
||||
* This function returns the current timestamping settings. Rather than
|
||||
* attempt to deconstruct registers to fill in the values, simply keep a copy
|
||||
* of the old settings around, and return a copy when requested.
|
||||
*/
|
||||
int ngbe_ptp_get_ts_config(struct ngbe_adapter *adapter, struct ifreq *ifr)
|
||||
{
|
||||
struct hwtstamp_config *config = &adapter->tstamp_config;
|
||||
|
||||
return copy_to_user(ifr->ifr_data, config,
|
||||
sizeof(*config)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_set_timestamp_mode - setup the hardware for the requested mode
|
||||
* @adapter: the private ngbe adapter structure
|
||||
* @config: the hwtstamp configuration requested
|
||||
*
|
||||
* Outgoing time stamping can be enabled and disabled. Play nice and
|
||||
* disable it when requested, although it shouldn't cause any overhead
|
||||
* when no packet needs it. At most one packet in the queue may be
|
||||
* marked for time stamping, otherwise it would be impossible to tell
|
||||
* for sure to which packet the hardware time stamp belongs.
|
||||
*
|
||||
* Incoming time stamping has to be configured via the hardware
|
||||
* filters. Not all combinations are supported, in particular event
|
||||
* type has to be specified. Matching the kind of event packet is
|
||||
* not supported, with the exception of "all V2 events regardless of
|
||||
* level 2 or 4".
|
||||
*
|
||||
* Since hardware always timestamps Path delay packets when timestamping V2
|
||||
* packets, regardless of the type specified in the register, only use V2
|
||||
* Event mode. This more accurately tells the user what the hardware is going
|
||||
* to do anyways.
|
||||
*
|
||||
* Note: this may modify the hwtstamp configuration towards a more general
|
||||
* mode, if required to support the specifically requested mode.
|
||||
*/
|
||||
static int ngbe_ptp_set_timestamp_mode(struct ngbe_adapter *adapter,
|
||||
struct hwtstamp_config *config)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
u32 tsync_tx_ctl = NGBE_TSEC_1588_CTL_ENABLED;
|
||||
u32 tsync_rx_ctl = NGBE_PSR_1588_CTL_ENABLED;
|
||||
u32 tsync_rx_mtrl = PTP_EV_PORT << 16;
|
||||
bool is_l2 = false;
|
||||
u32 regval;
|
||||
|
||||
/* reserved for future extensions */
|
||||
if (config->flags)
|
||||
return -EINVAL;
|
||||
|
||||
switch (config->tx_type) {
|
||||
case HWTSTAMP_TX_OFF:
|
||||
tsync_tx_ctl = 0;
|
||||
case HWTSTAMP_TX_ON:
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
switch (config->rx_filter) {
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
tsync_rx_ctl = 0;
|
||||
tsync_rx_mtrl = 0;
|
||||
adapter->flags &= ~(NGBE_FLAG_RX_HWTSTAMP_ENABLED |
|
||||
NGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
|
||||
tsync_rx_ctl |= NGBE_PSR_1588_CTL_TYPE_L4_V1;
|
||||
tsync_rx_mtrl |= NGBE_PSR_1588_MSGTYPE_V1_SYNC_MSG;
|
||||
adapter->flags |= (NGBE_FLAG_RX_HWTSTAMP_ENABLED |
|
||||
NGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
|
||||
tsync_rx_ctl |= NGBE_PSR_1588_CTL_TYPE_L4_V1;
|
||||
tsync_rx_mtrl |= NGBE_PSR_1588_MSGTYPE_V1_DELAY_REQ_MSG;
|
||||
adapter->flags |= (NGBE_FLAG_RX_HWTSTAMP_ENABLED |
|
||||
NGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
|
||||
tsync_rx_ctl |= NGBE_PSR_1588_CTL_TYPE_EVENT_V2;
|
||||
is_l2 = true;
|
||||
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
adapter->flags |= (NGBE_FLAG_RX_HWTSTAMP_ENABLED |
|
||||
NGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_ALL:
|
||||
default:
|
||||
/* register RXMTRL must be set in order to do V1 packets,
|
||||
* therefore it is not possible to time stamp both V1 Sync and
|
||||
* Delay_Req messages unless hardware supports timestamping all
|
||||
* packets => return error
|
||||
*/
|
||||
adapter->flags &= ~(NGBE_FLAG_RX_HWTSTAMP_ENABLED |
|
||||
NGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
|
||||
config->rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* define ethertype filter for timestamping L2 packets */
|
||||
if (is_l2)
|
||||
wr32(hw,
|
||||
NGBE_PSR_ETYPE_SWC(NGBE_PSR_ETYPE_SWC_FILTER_1588),
|
||||
(NGBE_PSR_ETYPE_SWC_FILTER_EN | /* enable filter */
|
||||
NGBE_PSR_ETYPE_SWC_1588 | /* enable timestamping */
|
||||
ETH_P_1588)); /* 1588 eth protocol type */
|
||||
else
|
||||
wr32(hw,
|
||||
NGBE_PSR_ETYPE_SWC(NGBE_PSR_ETYPE_SWC_FILTER_1588),
|
||||
0);
|
||||
|
||||
/* enable/disable TX */
|
||||
regval = rd32(hw, NGBE_TSEC_1588_CTL);
|
||||
regval &= ~NGBE_TSEC_1588_CTL_ENABLED;
|
||||
regval |= tsync_tx_ctl;
|
||||
wr32(hw, NGBE_TSEC_1588_CTL, regval);
|
||||
|
||||
/* enable/disable RX */
|
||||
regval = rd32(hw, NGBE_PSR_1588_CTL);
|
||||
regval &= ~(NGBE_PSR_1588_CTL_ENABLED | NGBE_PSR_1588_CTL_TYPE_MASK);
|
||||
regval |= tsync_rx_ctl;
|
||||
wr32(hw, NGBE_PSR_1588_CTL, regval);
|
||||
|
||||
/* define which PTP packets are time stamped */
|
||||
wr32(hw, NGBE_PSR_1588_MSGTYPE, tsync_rx_mtrl);
|
||||
|
||||
NGBE_WRITE_FLUSH(hw);
|
||||
|
||||
/* clear TX/RX timestamp state, just to be sure */
|
||||
ngbe_ptp_clear_tx_timestamp(adapter);
|
||||
rd32(hw, NGBE_PSR_1588_STMPH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_set_ts_config - user entry point for timestamp mode
|
||||
* @adapter: pointer to adapter struct
|
||||
* @ifreq: ioctl data
|
||||
*
|
||||
* Set hardware to requested mode. If unsupported, return an error with no
|
||||
* changes. Otherwise, store the mode for future reference.
|
||||
*/
|
||||
int ngbe_ptp_set_ts_config(struct ngbe_adapter *adapter, struct ifreq *ifr)
|
||||
{
|
||||
struct hwtstamp_config config;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
||||
return -EFAULT;
|
||||
|
||||
err = ngbe_ptp_set_timestamp_mode(adapter, &config);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* save these settings for future reference */
|
||||
memcpy(&adapter->tstamp_config, &config,
|
||||
sizeof(adapter->tstamp_config));
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
|
||||
static void ngbe_ptp_link_speed_adjust(struct ngbe_adapter *adapter,
|
||||
u32 *shift, u32 *incval)
|
||||
{
|
||||
/**
|
||||
* Scale the NIC cycle counter by a large factor so that
|
||||
* relatively small corrections to the frequency can be added
|
||||
* or subtracted. The drawbacks of a large factor include
|
||||
* (a) the clock register overflows more quickly, (b) the cycle
|
||||
* counter structure must be able to convert the systime value
|
||||
* to nanoseconds using only a multiplier and a right-shift,
|
||||
* and (c) the value must fit within the timinca register space
|
||||
* => math based on internal DMA clock rate and available bits
|
||||
*
|
||||
* Note that when there is no link, internal DMA clock is same as when
|
||||
* link speed is 10Gb. Set the registers correctly even when link is
|
||||
* down to preserve the clock setting
|
||||
*/
|
||||
|
||||
*shift = NGBE_INCVAL_SHIFT_1GB;
|
||||
*incval = NGBE_INCVAL_1GB;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_start_cyclecounter - create the cycle counter from hw
|
||||
* @adapter: pointer to the adapter structure
|
||||
*
|
||||
* This function should be called to set the proper values for the TIMINCA
|
||||
* register and tell the cyclecounter structure what the tick rate of SYSTIME
|
||||
* is. It does not directly modify SYSTIME registers or the timecounter
|
||||
* structure. It should be called whenever a new TIMINCA value is necessary,
|
||||
* such as during initialization or when the link speed changes.
|
||||
*/
|
||||
void ngbe_ptp_start_cyclecounter(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
unsigned long flags;
|
||||
struct cyclecounter cc;
|
||||
u32 incval = 0;
|
||||
|
||||
/* For some of the boards below this mask is technically incorrect.
|
||||
* The timestamp mask overflows at approximately 61bits. However the
|
||||
* particular hardware does not overflow on an even bitmask value.
|
||||
* Instead, it overflows due to conversion of upper 32bits billions of
|
||||
* cycles. Timecounters are not really intended for this purpose so
|
||||
* they do not properly function if the overflow point isn't 2^N-1.
|
||||
* However, the actual SYSTIME values in question take ~138 years to
|
||||
* overflow. In practice this means they won't actually overflow. A
|
||||
* proper fix to this problem would require modification of the
|
||||
* timecounter delta calculations.
|
||||
*/
|
||||
cc.mask = CLOCKSOURCE_MASK(64);
|
||||
cc.mult = 1;
|
||||
cc.shift = 0;
|
||||
|
||||
cc.read = ngbe_ptp_read;
|
||||
ngbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval);
|
||||
wr32(hw, NGBE_TSEC_1588_INC, NGBE_TSEC_1588_INC_IV(incval));
|
||||
|
||||
/* update the base incval used to calculate frequency adjustment */
|
||||
WRITE_ONCE(adapter->base_incval, incval);
|
||||
smp_mb();
|
||||
|
||||
/* need lock to prevent incorrect read while modifying cyclecounter */
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
memcpy(&adapter->hw_cc, &cc, sizeof(adapter->hw_cc));
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_reset
|
||||
* @adapter: the ngbe private board structure
|
||||
*
|
||||
* When the MAC resets, all of the hardware configuration for timesync is
|
||||
* reset. This function should be called to re-enable the device for PTP,
|
||||
* using the last known settings. However, we do lose the current clock time,
|
||||
* so we fallback to resetting it based on the kernel's realtime clock.
|
||||
*
|
||||
* This function will maintain the hwtstamp_config settings, and it retriggers
|
||||
* the SDP output if it's enabled.
|
||||
*/
|
||||
void ngbe_ptp_reset(struct ngbe_adapter *adapter)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* reset the hardware timestamping mode */
|
||||
ngbe_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
|
||||
ngbe_ptp_start_cyclecounter(adapter);
|
||||
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
|
||||
ktime_to_ns(ktime_get_real()));
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
adapter->last_overflow_check = jiffies;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_create_clock
|
||||
* @adapter: the ngbe private adapter structure
|
||||
*
|
||||
* This function performs setup of the user entry point function table and
|
||||
* initalizes the PTP clock device used by userspace to access the clock-like
|
||||
* features of the PTP core. It will be called by ngbe_ptp_init, and may
|
||||
* re-use a previously initialized clock (such as during a suspend/resume
|
||||
* cycle).
|
||||
*/
|
||||
|
||||
static long ngbe_ptp_create_clock(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
long err;
|
||||
|
||||
/* do nothing if we already have a clock device */
|
||||
if (!IS_ERR_OR_NULL(adapter->ptp_clock))
|
||||
return 0;
|
||||
|
||||
snprintf(adapter->ptp_caps.name, sizeof(adapter->ptp_caps.name),
|
||||
"%s", netdev->name);
|
||||
adapter->ptp_caps.owner = THIS_MODULE;
|
||||
adapter->ptp_caps.max_adj = 500000000; /* 10^-9s */
|
||||
adapter->ptp_caps.n_alarm = 0;
|
||||
adapter->ptp_caps.n_ext_ts = 0;
|
||||
adapter->ptp_caps.n_per_out = 0;
|
||||
adapter->ptp_caps.pps = 0;
|
||||
#ifndef HAVE_NOT_PTT_ADJFREQ
|
||||
adapter->ptp_caps.adjfreq = ngbe_ptp_adjfreq;
|
||||
#endif
|
||||
adapter->ptp_caps.adjtime = ngbe_ptp_adjtime;
|
||||
#ifdef HAVE_PTP_CLOCK_INFO_GETTIME64
|
||||
adapter->ptp_caps.gettime64 = ngbe_ptp_gettime64;
|
||||
adapter->ptp_caps.settime64 = ngbe_ptp_settime64;
|
||||
#else
|
||||
adapter->ptp_caps.gettime = ngbe_ptp_gettime;
|
||||
adapter->ptp_caps.settime = ngbe_ptp_settime;
|
||||
#endif
|
||||
adapter->ptp_caps.enable = ngbe_ptp_feature_enable;
|
||||
|
||||
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
|
||||
pci_dev_to_dev(adapter->pdev));
|
||||
if (IS_ERR(adapter->ptp_clock)) {
|
||||
err = PTR_ERR(adapter->ptp_clock);
|
||||
adapter->ptp_clock = NULL;
|
||||
e_dev_err("ptp_clock_register failed\n");
|
||||
return err;
|
||||
} else
|
||||
e_dev_info("registered PHC device on %s\n", netdev->name);
|
||||
|
||||
/* Set the default timestamp mode to disabled here. We do this in
|
||||
* create_clock instead of initialization, because we don't want to
|
||||
* override the previous settings during a suspend/resume cycle.
|
||||
*/
|
||||
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_init
|
||||
* @adapter: the ngbe private adapter structure
|
||||
*
|
||||
* This function performs the required steps for enabling ptp
|
||||
* support. If ptp support has already been loaded it simply calls the
|
||||
* cyclecounter init routine and exits.
|
||||
*/
|
||||
void ngbe_ptp_init(struct ngbe_adapter *adapter)
|
||||
{
|
||||
/* initialize the spin lock first, since the user might call the clock
|
||||
* functions any time after we've initialized the ptp clock device.
|
||||
*/
|
||||
spin_lock_init(&adapter->tmreg_lock);
|
||||
|
||||
/* obtain a ptp clock device, or re-use an existing device */
|
||||
if (ngbe_ptp_create_clock(adapter))
|
||||
return;
|
||||
|
||||
/* we have a clock, so we can intialize work for timestamps now */
|
||||
INIT_WORK(&adapter->ptp_tx_work, ngbe_ptp_tx_hwtstamp_work);
|
||||
|
||||
/* reset the ptp related hardware bits */
|
||||
ngbe_ptp_reset(adapter);
|
||||
|
||||
/* enter the NGBE_PTP_RUNNING state */
|
||||
set_bit(__NGBE_PTP_RUNNING, &adapter->state);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_suspend - stop ptp work items
|
||||
* @adapter: pointer to adapter struct
|
||||
*
|
||||
* This function suspends ptp activity, and prevents more work from being
|
||||
* generated, but does not destroy the clock device.
|
||||
*/
|
||||
void ngbe_ptp_suspend(struct ngbe_adapter *adapter)
|
||||
{
|
||||
/* leave the NGBE_PTP_RUNNING STATE */
|
||||
if (!test_and_clear_bit(__NGBE_PTP_RUNNING, &adapter->state))
|
||||
return;
|
||||
|
||||
adapter->flags2 &= ~NGBE_FLAG2_PTP_PPS_ENABLED;
|
||||
|
||||
cancel_work_sync(&adapter->ptp_tx_work);
|
||||
ngbe_ptp_clear_tx_timestamp(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_ptp_stop - destroy the ptp_clock device
|
||||
* @adapter: pointer to adapter struct
|
||||
*
|
||||
* Completely destroy the ptp_clock device, and disable all PTP related
|
||||
* features. Intended to be run when the device is being closed.
|
||||
*/
|
||||
void ngbe_ptp_stop(struct ngbe_adapter *adapter)
|
||||
{
|
||||
/* first, suspend ptp activity */
|
||||
ngbe_ptp_suspend(adapter);
|
||||
|
||||
/* now destroy the ptp clock device */
|
||||
if (adapter->ptp_clock) {
|
||||
ptp_clock_unregister(adapter->ptp_clock);
|
||||
adapter->ptp_clock = NULL;
|
||||
e_dev_info("removed PHC on %s\n",
|
||||
adapter->netdev->name);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGBE_SRIOV_H_
|
||||
#define _NGBE_SRIOV_H_
|
||||
|
||||
/* ngbe driver limit the max number of VFs could be enabled to
|
||||
* 7 (NGBE_MAX_VF_FUNCTIONS - 1)
|
||||
*/
|
||||
#define NGBE_MAX_VFS_DRV_LIMIT (NGBE_MAX_VF_FUNCTIONS - 1)
|
||||
|
||||
void ngbe_restore_vf_multicasts(struct ngbe_adapter *adapter);
|
||||
int ngbe_set_vf_vlan(struct ngbe_adapter *adapter, int add, int vid, u16 vf);
|
||||
void ngbe_set_vmolr(struct ngbe_hw *hw, u16 vf, bool aupe);
|
||||
void ngbe_msg_task(struct ngbe_adapter *adapter);
|
||||
int ngbe_set_vf_mac(struct ngbe_adapter *adapter,
|
||||
u16 vf, unsigned char *mac_addr);
|
||||
void ngbe_disable_tx_rx(struct ngbe_adapter *adapter);
|
||||
void ngbe_ping_all_vfs(struct ngbe_adapter *adapter);
|
||||
void ngbe_ping_all_vfs_with_link_status(struct ngbe_adapter *adapter, bool link_up);
|
||||
|
||||
#ifdef IFLA_VF_MAX
|
||||
int ngbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
|
||||
#ifdef IFLA_VF_VLAN_INFO_MAX
|
||||
int ngbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
|
||||
u8 qos, __be16 vlan_proto);
|
||||
#else
|
||||
int ngbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
|
||||
u8 qos);
|
||||
#endif
|
||||
#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
|
||||
int ngbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int min_tx_rate,
|
||||
int max_tx_rate);
|
||||
#else
|
||||
int ngbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
|
||||
#endif /* HAVE_NDO_SET_VF_MIN_MAX_TX_RATE */
|
||||
#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
|
||||
int ngbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
|
||||
#endif
|
||||
#ifdef HAVE_NDO_SET_VF_TRUST
|
||||
int ngbe_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting);
|
||||
#endif
|
||||
int ngbe_ndo_get_vf_config(struct net_device *netdev,
|
||||
int vf, struct ifla_vf_info *ivi);
|
||||
#endif /* IFLA_VF_MAX */
|
||||
int ngbe_disable_sriov(struct ngbe_adapter *adapter);
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
int ngbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
|
||||
void ngbe_enable_sriov(struct ngbe_adapter *adapter);
|
||||
#endif
|
||||
int ngbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
|
||||
|
||||
#define NGBE_VF_STATUS_LINKUP 0x1
|
||||
|
||||
/*
|
||||
* These are defined in ngbe_type.h on behalf of the VF driver
|
||||
* but we need them here unwrapped for the PF driver.
|
||||
*/
|
||||
//#define NGBE_DEV_ID_SP_VF 0x1000
|
||||
#endif /* _NGBE_SRIOV_H_ */
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* WangXun Gigabit PCI Express Linux driver
|
||||
* Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ngbe.h"
|
||||
#include "ngbe_hw.h"
|
||||
#include "ngbe_type.h"
|
||||
|
||||
#ifdef NGBE_SYSFS
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/time.h>
|
||||
#ifdef NGBE_HWMON
|
||||
#include <linux/hwmon.h>
|
||||
#endif
|
||||
|
||||
#ifdef NGBE_HWMON
|
||||
/* hwmon callback functions */
|
||||
static ssize_t ngbe_hwmon_show_temp(struct device __always_unused *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *ngbe_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
struct ngbe_hw *hw = ngbe_attr->hw;
|
||||
unsigned int value;
|
||||
|
||||
/* reset the temp field */
|
||||
hw->mac.ops.get_thermal_sensor_data(hw);
|
||||
|
||||
value = ngbe_attr->sensor->temp;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
static ssize_t ngbe_hwmon_show_alarmthresh(struct device __always_unused *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *ngbe_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
unsigned int value = ngbe_attr->sensor->alarm_thresh;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
static ssize_t ngbe_hwmon_show_dalarmthresh(struct device __always_unused *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *ngbe_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
unsigned int value = ngbe_attr->sensor->dalarm_thresh;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
|
||||
* @adapter: pointer to the adapter structure
|
||||
* @type: type of sensor data to display
|
||||
*
|
||||
* For each file we want in hwmon's sysfs interface we need a device_attribute
|
||||
* This is included in our hwmon_attr struct that contains the references to
|
||||
* the data structures we need to get the data to display.
|
||||
*/
|
||||
static int ngbe_add_hwmon_attr(struct ngbe_adapter *adapter, int type)
|
||||
{
|
||||
int rc;
|
||||
unsigned int n_attr;
|
||||
struct hwmon_attr *ngbe_attr;
|
||||
|
||||
n_attr = adapter->ngbe_hwmon_buff.n_hwmon;
|
||||
ngbe_attr = &adapter->ngbe_hwmon_buff.hwmon_list[n_attr];
|
||||
|
||||
switch (type) {
|
||||
case NGBE_HWMON_TYPE_TEMP:
|
||||
ngbe_attr->dev_attr.show = ngbe_hwmon_show_temp;
|
||||
snprintf(ngbe_attr->name, sizeof(ngbe_attr->name),
|
||||
"temp%u_input", 0);
|
||||
break;
|
||||
case NGBE_HWMON_TYPE_ALARMTHRESH:
|
||||
ngbe_attr->dev_attr.show = ngbe_hwmon_show_alarmthresh;
|
||||
snprintf(ngbe_attr->name, sizeof(ngbe_attr->name),
|
||||
"temp%u_alarmthresh", 0);
|
||||
break;
|
||||
case NGBE_HWMON_TYPE_DALARMTHRESH:
|
||||
ngbe_attr->dev_attr.show = ngbe_hwmon_show_dalarmthresh;
|
||||
snprintf(ngbe_attr->name, sizeof(ngbe_attr->name),
|
||||
"temp%u_dalarmthresh", 0);
|
||||
break;
|
||||
default:
|
||||
rc = -EPERM;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* These always the same regardless of type */
|
||||
ngbe_attr->sensor =
|
||||
&adapter->hw.mac.thermal_sensor_data.sensor;
|
||||
ngbe_attr->hw = &adapter->hw;
|
||||
ngbe_attr->dev_attr.store = NULL;
|
||||
ngbe_attr->dev_attr.attr.mode = S_IRUGO;
|
||||
ngbe_attr->dev_attr.attr.name = ngbe_attr->name;
|
||||
|
||||
rc = device_create_file(pci_dev_to_dev(adapter->pdev),
|
||||
&ngbe_attr->dev_attr);
|
||||
|
||||
if (rc == 0)
|
||||
++adapter->ngbe_hwmon_buff.n_hwmon;
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* NGBE_HWMON */
|
||||
|
||||
static void ngbe_sysfs_del_adapter(
|
||||
struct ngbe_adapter __maybe_unused *adapter)
|
||||
{
|
||||
#ifdef NGBE_HWMON
|
||||
int i;
|
||||
|
||||
if (adapter == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < adapter->ngbe_hwmon_buff.n_hwmon; i++) {
|
||||
device_remove_file(pci_dev_to_dev(adapter->pdev),
|
||||
&adapter->ngbe_hwmon_buff.hwmon_list[i].dev_attr);
|
||||
}
|
||||
|
||||
kfree(adapter->ngbe_hwmon_buff.hwmon_list);
|
||||
|
||||
if (adapter->ngbe_hwmon_buff.device)
|
||||
hwmon_device_unregister(adapter->ngbe_hwmon_buff.device);
|
||||
#endif /* NGBE_HWMON */
|
||||
}
|
||||
|
||||
/* called from ngbe_main.c */
|
||||
void ngbe_sysfs_exit(struct ngbe_adapter *adapter)
|
||||
{
|
||||
ngbe_sysfs_del_adapter(adapter);
|
||||
}
|
||||
|
||||
/* called from ngbe_main.c */
|
||||
int ngbe_sysfs_init(struct ngbe_adapter *adapter)
|
||||
{
|
||||
struct ngbe_hw *hw = &adapter->hw;
|
||||
int rc = 0;
|
||||
#ifdef NGBE_HWMON
|
||||
struct hwmon_buff *ngbe_hwmon = &adapter->ngbe_hwmon_buff;
|
||||
int n_attrs;
|
||||
|
||||
#endif /* NGBE_HWMON */
|
||||
if (adapter == NULL)
|
||||
goto err;
|
||||
|
||||
#ifdef NGBE_HWMON
|
||||
|
||||
/* Don't create thermal hwmon interface if no sensors present */
|
||||
if (hw->mac.ops.init_thermal_sensor_thresh(hw))
|
||||
goto no_thermal;
|
||||
|
||||
/*
|
||||
* Allocation space for max attributs
|
||||
* max num sensors * values (temp, alamthresh, dalarmthresh)
|
||||
*/
|
||||
n_attrs = 3;
|
||||
ngbe_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
|
||||
GFP_KERNEL);
|
||||
if (!ngbe_hwmon->hwmon_list) {
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ngbe_hwmon->device =
|
||||
hwmon_device_register(pci_dev_to_dev(adapter->pdev));
|
||||
if (IS_ERR(ngbe_hwmon->device)) {
|
||||
rc = PTR_ERR(ngbe_hwmon->device);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
/* Bail if any hwmon attr struct fails to initialize */
|
||||
rc = ngbe_add_hwmon_attr(adapter, NGBE_HWMON_TYPE_TEMP);
|
||||
rc |= ngbe_add_hwmon_attr(adapter, NGBE_HWMON_TYPE_ALARMTHRESH);
|
||||
rc |= ngbe_add_hwmon_attr(adapter, NGBE_HWMON_TYPE_DALARMTHRESH);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
no_thermal:
|
||||
#endif /* NGBE_HWMON */
|
||||
goto exit;
|
||||
|
||||
err:
|
||||
ngbe_sysfs_del_adapter(adapter);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
#endif /* NGBE_SYSFS */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue