1843 lines
51 KiB
C
1843 lines
51 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/device.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/hwmon.h>
|
|
#include <linux/ctype.h>
|
|
#include "rnpm.h"
|
|
#include "rnpm_common.h"
|
|
#include "rnpm_type.h"
|
|
|
|
#include "rnpm_mbx.h"
|
|
#include "rnpm_mbx_fw.h"
|
|
|
|
struct maintain_req {
|
|
int magic;
|
|
#define MAINTAIN_MAGIC 0xa6a7a8a9
|
|
|
|
int cmd;
|
|
int arg0;
|
|
int req_data_bytes;
|
|
int reply_bytes;
|
|
} __packed;
|
|
|
|
struct ucfg_mac_sn {
|
|
unsigned char macaddr[64];
|
|
unsigned char sn[32];
|
|
int magic;
|
|
#define MAC_SN_MAGIC 0x87654321
|
|
char rev[52];
|
|
unsigned char pn[32];
|
|
} __packed __aligned(4);
|
|
|
|
u32 bar4_reg_val;
|
|
u32 bar4_reg_addr;
|
|
u32 pcs_phy_num;
|
|
int pcs_cnt;
|
|
|
|
#define to_net_device(n) container_of(n, struct net_device, dev)
|
|
|
|
#define PHY_EXT_REG_FLAG 0x80000000
|
|
static u32 is_phy_ext_reg;
|
|
static u32 phy_reg;
|
|
#ifndef NO_BIT_ATTRS
|
|
static ssize_t maintain_read(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
// struct rnpm_hw *hw = &adapter->hw;
|
|
int rbytes = count;
|
|
|
|
if (adapter->maintain_buf == NULL)
|
|
return 0;
|
|
|
|
if (off + count > adapter->maintain_buf_len)
|
|
rbytes = adapter->maintain_buf_len - off;
|
|
memcpy(buf, adapter->maintain_buf + off, rbytes);
|
|
|
|
// end-of-buf
|
|
if ((off + rbytes) >= adapter->maintain_buf_len) {
|
|
kfree(adapter->maintain_buf);
|
|
adapter->maintain_buf = NULL;
|
|
adapter->maintain_buf_len = 0;
|
|
}
|
|
|
|
return rbytes;
|
|
}
|
|
|
|
static ssize_t maintain_write(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
// int ret;
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
struct maintain_req *req;
|
|
void *dma_buf = NULL;
|
|
dma_addr_t dma_phy;
|
|
int bytes;
|
|
|
|
if (off == 0) {
|
|
if (count < sizeof(*req))
|
|
return -EINVAL;
|
|
req = (struct maintain_req *)buf;
|
|
if (req->magic != MAINTAIN_MAGIC)
|
|
return -EINVAL;
|
|
bytes = max_t(int, req->req_data_bytes, req->reply_bytes);
|
|
bytes += sizeof(*req);
|
|
|
|
// free no readed buf
|
|
kfree(adapter->maintain_buf);
|
|
adapter->maintain_buf = NULL;
|
|
adapter->maintain_buf_len = 0;
|
|
|
|
dma_buf = dma_alloc_coherent(&hw->pdev->dev, bytes, &dma_phy,
|
|
GFP_ATOMIC);
|
|
if (!dma_buf)
|
|
return -ENOMEM;
|
|
|
|
adapter->maintain_dma_buf = dma_buf;
|
|
adapter->maintain_dma_phy = dma_phy;
|
|
adapter->maintain_dma_size = bytes;
|
|
adapter->maintain_in_bytes = req->req_data_bytes + sizeof(*req);
|
|
|
|
memcpy(dma_buf + off, buf, count);
|
|
|
|
if (count < adapter->maintain_in_bytes)
|
|
return count;
|
|
}
|
|
|
|
dma_buf = adapter->maintain_dma_buf;
|
|
dma_phy = adapter->maintain_dma_phy;
|
|
req = (struct maintain_req *)dma_buf;
|
|
|
|
memcpy(dma_buf + off, buf, count);
|
|
|
|
// all data got, send req
|
|
if ((off + count) >= adapter->maintain_in_bytes) {
|
|
int reply_bytes = req->reply_bytes;
|
|
// send req
|
|
err = rnpm_maintain_req(hw, req->cmd, req->arg0,
|
|
req->req_data_bytes, req->reply_bytes,
|
|
dma_phy);
|
|
if (err != 0)
|
|
goto err_quit;
|
|
// req can't be acces, a
|
|
// copy data for read
|
|
if (reply_bytes > 0) {
|
|
adapter->maintain_buf_len = reply_bytes;
|
|
adapter->maintain_buf =
|
|
kmalloc(adapter->maintain_buf_len, GFP_KERNEL);
|
|
if (!adapter->maintain_buf) {
|
|
netdev_err(netdev,
|
|
"No Memory for maintain buf:%d\n",
|
|
adapter->maintain_buf_len);
|
|
err = -ENOMEM;
|
|
|
|
goto err_quit;
|
|
}
|
|
memcpy(adapter->maintain_buf, dma_buf, reply_bytes);
|
|
// buf_dump("rx", adapter->maintain_buf, reply_bytes);
|
|
}
|
|
|
|
if (dma_buf) {
|
|
//pci_free_consistent(
|
|
dma_free_coherent(&hw->pdev->dev,
|
|
adapter->maintain_dma_size, dma_buf,
|
|
dma_phy);
|
|
}
|
|
adapter->maintain_dma_buf = NULL;
|
|
}
|
|
|
|
return count;
|
|
err_quit:
|
|
if (dma_buf) {
|
|
//pci_free_consistent(
|
|
dma_free_coherent(&hw->pdev->dev, adapter->maintain_dma_size,
|
|
dma_buf, dma_phy);
|
|
adapter->maintain_dma_buf = NULL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/* some centos kernel maybe error use BIN_ATTR_RW */
|
|
//static BIN_ATTR_RW(maintain, 1 * 1024 * 1024);
|
|
static BIN_ATTR(maintain, 0644, maintain_read, maintain_write, 1 * 1024 * 1024);
|
|
#endif
|
|
|
|
static ssize_t active_vid_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
u16 current_vid = 0;
|
|
u16 vid = 0;
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
u8 vfnum = RNPM_MAX_VF_CNT - 1; //use last-vf's table entry. the las
|
|
|
|
if ((adapter->flags & RNPM_FLAG_SRIOV_ENABLED)) {
|
|
current_vid = rd32(hw, RNPM_DMA_PORT_VEB_VID_TBL(adapter->port,
|
|
vfnum));
|
|
}
|
|
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID) {
|
|
ret += sprintf(buf + ret, "%u%s ", vid,
|
|
(current_vid == vid ? "*" : ""));
|
|
}
|
|
ret += sprintf(buf + ret, "\n");
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t active_vid_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
u16 vid;
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw __maybe_unused *hw = &adapter->hw;
|
|
u8 __maybe_unused vfnum =
|
|
RNPM_MAX_VF_CNT - 1; // use last-vf's table entry. the las
|
|
int __maybe_unused port = 0;
|
|
|
|
if (!(adapter->flags & RNPM_FLAG_SRIOV_ENABLED))
|
|
return -EIO;
|
|
|
|
if (kstrtou16(buf, 0, &vid) != 0)
|
|
return -EINVAL;
|
|
if ((vid < 4096) && test_bit(vid, adapter->active_vlans)) {
|
|
if (rd32(hw, RNPM_DMA_VERSION) >= 0x20201231) {
|
|
for (port = 0; port < 4; port++)
|
|
wr32(hw, RNPM_DMA_PORT_VEB_VID_TBL(port, vfnum),
|
|
vid);
|
|
} else {
|
|
wr32(hw,
|
|
RNPM_DMA_PORT_VEB_VID_TBL(adapter->port, vfnum),
|
|
vid);
|
|
}
|
|
err = 0;
|
|
}
|
|
return err ? err : count;
|
|
}
|
|
static DEVICE_ATTR_RW(active_vid);
|
|
|
|
static ssize_t pf_reset_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_pf_adapter *pf_adapter = adapter->pf_adapter;
|
|
|
|
set_bit(RNPM_PF_RESET, &pf_adapter->flags);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR_WO(pf_reset);
|
|
|
|
static inline int pn_sn_dlen(char *v, int v_len)
|
|
{
|
|
int i, len = 0;
|
|
|
|
for (i = 0; i < v_len; i++) {
|
|
if (isascii(v[i]))
|
|
len++;
|
|
break;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int rnpm_mbx_get_pn_sn(struct rnpm_hw *hw, char pn[33], char sn[33])
|
|
{
|
|
struct maintain_req *req;
|
|
void *dma_buf = NULL;
|
|
dma_addr_t dma_phy;
|
|
struct ucfg_mac_sn *cfg;
|
|
|
|
int err = 0, bytes = sizeof(*req) + sizeof(struct ucfg_mac_sn);
|
|
|
|
memset(pn, 0, 33);
|
|
memset(sn, 0, 33);
|
|
|
|
dma_buf =
|
|
dma_alloc_coherent(&hw->pdev->dev, bytes, &dma_phy, GFP_KERNEL);
|
|
if (!dma_buf)
|
|
return -ENOMEM;
|
|
|
|
req = (struct maintain_req *)dma_buf;
|
|
memset(dma_buf, 0, bytes);
|
|
cfg = (struct ucfg_mac_sn *)(req + 1);
|
|
req->magic = MAINTAIN_MAGIC;
|
|
req->cmd = 0; // READ
|
|
req->arg0 = 3; // PARTITION 3
|
|
req->req_data_bytes = 0;
|
|
req->reply_bytes = bytes - sizeof(*req);
|
|
|
|
err = rnpm_maintain_req(hw, req->cmd, req->arg0, req->req_data_bytes,
|
|
req->reply_bytes, dma_phy);
|
|
if (err != 0)
|
|
goto err_quit;
|
|
if (cfg->magic == MAC_SN_MAGIC) {
|
|
int sz = pn_sn_dlen(cfg->pn, 32);
|
|
|
|
if (sz) {
|
|
memcpy(pn, cfg->pn, sz);
|
|
pn[sz] = 0;
|
|
}
|
|
sz = pn_sn_dlen(cfg->sn, 32);
|
|
if (sz) {
|
|
memcpy(sn, cfg->sn, sz);
|
|
sn[sz] = 0;
|
|
}
|
|
}
|
|
|
|
err_quit:
|
|
if (dma_buf) {
|
|
// pci_free_consistent(
|
|
dma_free_coherent(&hw->pdev->dev, bytes, dma_buf, dma_phy);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t own_vpd_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
char pn[33] = { 0 }, sn[33] = { 0 };
|
|
char *prod_name;
|
|
|
|
rnpm_mbx_get_pn_sn(hw, pn, sn);
|
|
|
|
if ((adapter->pdev->device & 0xff) == 0x20) {
|
|
prod_name =
|
|
"Ethernet Controller N10 Series for 10GbE (Quad-port)";
|
|
} else if ((adapter->pdev->device & 0xff) == 0x21) {
|
|
prod_name =
|
|
"Ethernet Controller N400 Series for 1GbE (Quad-port)";
|
|
} else if ((adapter->pdev->device & 0xff) == 0x60) {
|
|
prod_name =
|
|
"Ethernet Controller N10 Series for 10GbE (Oct-port)";
|
|
} else {
|
|
prod_name = "Ethernet Controller N10 Series for 10GbE";
|
|
}
|
|
|
|
ret += sprintf(buf + ret, "Product Name: %s\n", prod_name);
|
|
|
|
ret += sprintf(buf + ret, "[PN] Part number: %s\n", pn);
|
|
ret += sprintf(buf + ret, "[SN] Serial number: %s\n", sn);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(own_vpd);
|
|
|
|
//==========
|
|
|
|
/* show logical and physical ring num correspondence */
|
|
static ssize_t ring_num_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_ring *ring;
|
|
int ret = 0, i;
|
|
|
|
ret += sprintf(
|
|
buf + ret,
|
|
"show %s logical <-> physical ring num (Decimal) correspondence:\n",
|
|
netdev->name);
|
|
for (i = 0; i < netdev->real_num_tx_queues; i++) {
|
|
ring = adapter->tx_ring[i];
|
|
ret += sprintf(buf + ret, "%03d %03d\n", i,
|
|
ring->rnpm_queue_idx);
|
|
}
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(ring_num);
|
|
|
|
static ssize_t port_idx_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
// struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(buf, "%d\n", adapter->portid_of_card);
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(port_idx);
|
|
|
|
static ssize_t nr_lane_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
// struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(buf, "%d\n", adapter->lane);
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(nr_lane);
|
|
|
|
static ssize_t debug_linkstat_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(buf, "%d %d dumy:0x%x up-flag:%d carry:%d\n",
|
|
adapter->link_up, adapter->hw.link, rd32(hw, 0xc),
|
|
adapter->flags & RNPM_FLAG_NEED_LINK_UPDATE,
|
|
netif_carrier_ok(netdev));
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(debug_linkstat);
|
|
|
|
static ssize_t debug_aptstat_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(
|
|
buf,
|
|
"stat:%d %d dumy:0x%x up-flag:%d carry:%d\n"
|
|
"apt:flags:0x%x flags2:0x%x state:0x%lx timercnt:%u service cnt:%u\n"
|
|
"pf_apt:flags:0x%lx state:0x%lx timercnt:%u\n",
|
|
adapter->link_up, adapter->hw.link, rd32(hw, 0xc),
|
|
adapter->flags & RNPM_FLAG_NEED_LINK_UPDATE,
|
|
netif_carrier_ok(netdev), adapter->flags, adapter->flags2,
|
|
adapter->state, adapter->timer_count, adapter->service_count,
|
|
adapter->pf_adapter->flags, adapter->pf_adapter->state,
|
|
adapter->pf_adapter->timer_count);
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(debug_aptstat);
|
|
|
|
static ssize_t sfp_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0) {
|
|
ret += sprintf(buf, " IO Error\n");
|
|
} else {
|
|
ret += sprintf(
|
|
buf, "mod-abs:%d\ntx-fault:%d\ntx-dis:%d\nrx-los:%d\n",
|
|
adapter->sfp.mod_abs, adapter->sfp.fault,
|
|
adapter->sfp.tx_dis, adapter->sfp.los);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(sfp);
|
|
|
|
static ssize_t pci_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int gen = 3, lanes = 8;
|
|
|
|
if (count > 30)
|
|
return -EINVAL;
|
|
|
|
if (sscanf(buf, "gen%dx%d", &gen, &lanes) != 2) {
|
|
e_dev_info("Error: invalid input. example: gen3x8\n");
|
|
return -EINVAL;
|
|
}
|
|
if (gen > 3 || lanes > 8)
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_PCI_LANE, gen, lanes, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t pci_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "gen%dx%d\n", hw->pci_gen, hw->pci_lanes);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(pci);
|
|
|
|
static ssize_t prbs_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
long prbs = 0;
|
|
|
|
if (kstrtol(buf, 10, &prbs))
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_PRBS, prbs, 0, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
static DEVICE_ATTR_WO(prbs);
|
|
|
|
static ssize_t sfp_tx_disable_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
long enable = 0;
|
|
|
|
if (kstrtol(buf, 10, &enable))
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_SFP_TX_DISABLE, !!enable, 0, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t sfp_tx_disable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "%d\n", adapter->sfp.tx_dis);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(sfp_tx_disable);
|
|
|
|
static ssize_t link_traing_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
long enable = 0;
|
|
|
|
if (kstrtol(buf, 10, &enable))
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_LINK_TRAING, !!enable, 0, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t link_traing_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "%d\n", adapter->link_traing);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(link_traing);
|
|
|
|
static ssize_t fec_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
long enable = 0;
|
|
|
|
if (kstrtol(buf, 10, &enable))
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_FEC, !!enable, 0, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t fec_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "%d\n", adapter->fec);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(fec);
|
|
|
|
static ssize_t autoneg_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
long enable = 0;
|
|
|
|
if (kstrtol(buf, 10, &enable))
|
|
return -EINVAL;
|
|
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_AN, !!enable, 0, 0, 0);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t autoneg_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "%d\n", adapter->an);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(autoneg);
|
|
|
|
static ssize_t si_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err = -EINVAL;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int si_main = -1, si_pre = -1, si_post = -1, si_txboost = -1;
|
|
int cnt;
|
|
|
|
if (count > 100) {
|
|
e_dev_info("Error: Input size >100: too large\n");
|
|
return -EINVAL;
|
|
}
|
|
cnt = sscanf(buf, "%u %u %u %u", &si_main, &si_pre, &si_post,
|
|
&si_txboost);
|
|
if (cnt != 4) {
|
|
e_dev_info(
|
|
"Error: Invalid Input: <main> <pre> <post> <tx_boost>\n");
|
|
return -EINVAL;
|
|
}
|
|
if (si_main > 63 || si_pre > 63 || si_post > 63) {
|
|
e_dev_info("Error: Invalid value. should in 0~63\n");
|
|
return -EINVAL;
|
|
}
|
|
if (si_txboost > 16) {
|
|
e_dev_info("Error: Invalid txboost. should in 0~15\n");
|
|
return -EINVAL;
|
|
}
|
|
err = rnpm_set_lane_fun(hw, LANE_FUN_SI, si_main, si_pre, si_post,
|
|
si_txboost);
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
static ssize_t si_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
if (rnpm_mbx_get_lane_stat(hw) != 0)
|
|
ret += sprintf(buf, " IO Error\n");
|
|
else
|
|
ret += sprintf(buf, "main:%u pre:%u post:%u tx_boost:%u\n",
|
|
adapter->si.main, adapter->si.pre,
|
|
adapter->si.post, adapter->si.tx_boost);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(si);
|
|
|
|
static ssize_t temperature_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int ret = 0, temp = 0, voltage = 0;
|
|
|
|
temp = rnpm_mbx_get_temp(hw, &voltage);
|
|
|
|
ret += sprintf(buf, "temp:%d oC volatage:%d mV\n", temp, voltage);
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(temperature);
|
|
|
|
static ssize_t tx_counter_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
u32 val = 0;
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(buf + ret, "tx counters\n");
|
|
ret += sprintf(buf + ret, "ring0-tx:\n");
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_LEN(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"len:", RNPM_DMA_REG_TX_DESC_BUF_LEN(0), val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_HEAD(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"head:", RNPM_DMA_REG_TX_DESC_BUF_HEAD(0), val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_TAIL(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tail:", RNPM_DMA_REG_TX_DESC_BUF_TAIL(0), val);
|
|
|
|
ret += sprintf(buf + ret, "ring1-tx:\n");
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_LEN(1));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"len:", RNPM_DMA_REG_TX_DESC_BUF_LEN(1), val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_HEAD(1));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"head:", RNPM_DMA_REG_TX_DESC_BUF_HEAD(1), val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_TX_DESC_BUF_TAIL(1));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tail:", RNPM_DMA_REG_TX_DESC_BUF_TAIL(1), val);
|
|
|
|
ret += sprintf(buf + ret, "to_1to4_p1:\n");
|
|
|
|
val = rd32(hw, RNPM_ETH_1TO4_INST0_IN_PKTS);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"emac_in:", RNPM_ETH_1TO4_INST0_IN_PKTS, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_IN_0_TX_PKT_NUM(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"emac_send:", RNPM_ETH_IN_0_TX_PKT_NUM(0), val);
|
|
|
|
ret += sprintf(buf + ret, "to_1to4_p2:\n");
|
|
|
|
val = rd32(hw, RNPM_ETH_IN_1_TX_PKT_NUM(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"sop_pkt:", RNPM_ETH_IN_1_TX_PKT_NUM(0), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_IN_2_TX_PKT_NUM(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"eop_pkt:", RNPM_ETH_IN_2_TX_PKT_NUM(0), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_IN_3_TX_PKT_NUM(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"send_terr:", RNPM_ETH_IN_3_TX_PKT_NUM(0), val);
|
|
|
|
ret += sprintf(buf + ret, "to_tx_trans(phy):\n");
|
|
|
|
val = rd32(hw, RNPM_ETH_EMAC_TX_TO_PHY_PKTS(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"in:", RNPM_ETH_EMAC_TX_TO_PHY_PKTS(0), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TXTRANS_PTP_PKT_NUM(0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"out:", RNPM_ETH_TXTRANS_PTP_PKT_NUM(0), val);
|
|
|
|
ret += sprintf(buf + ret, "mac:\n");
|
|
|
|
val = rd32(hw, 0x1081c);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", "tx:", 0x1081c,
|
|
val);
|
|
|
|
val = rd32(hw, 0x1087c);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"underflow_err:", 0x1087c, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT0_SOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port0_txtrans_sop:", RNPM_ETH_TX_DEBUG_PORT0_SOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT0_EOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port0_txtrans_eop:", RNPM_ETH_TX_DEBUG_PORT0_EOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT1_SOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port1_txtrans_sop:", RNPM_ETH_TX_DEBUG_PORT1_SOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT1_EOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port1_txtrans_eop:", RNPM_ETH_TX_DEBUG_PORT1_EOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT2_SOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port2_txtrans_sop:", RNPM_ETH_TX_DEBUG_PORT2_SOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT2_EOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port2_txtrans_eop:", RNPM_ETH_TX_DEBUG_PORT2_EOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT3_SOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port3_txtrans_sop:", RNPM_ETH_TX_DEBUG_PORT3_SOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PORT3_EOP);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"port3_txtrans_eop:", RNPM_ETH_TX_DEBUG_PORT3_EOP, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_EMPTY);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tx_empty:", RNPM_ETH_TX_DEBUG_EMPTY, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_PROG_FULL);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tx_prog_full:", RNPM_ETH_TX_DEBUG_PROG_FULL, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_TX_DEBUG_FULL);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tx_full:", RNPM_ETH_TX_DEBUG_FULL, val);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(tx_counter);
|
|
|
|
static ssize_t rx_counter_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
u32 val = 0, port = 0;
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
ret += sprintf(buf + ret, "rx counters\n");
|
|
for (port = 0; port < 4; port++) {
|
|
ret += sprintf(buf + ret, "emac_rx_trans (port:%d):\n", port);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_RX_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"pkts:", RNPM_RXTRANS_RX_PKTS(port), val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_DROP_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"drop:", RNPM_RXTRANS_DROP_PKTS(port), val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_WDT_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"wdt_err:", RNPM_RXTRANS_WDT_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_CODE_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"code_err:", RNPM_RXTRANS_CODE_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_CRC_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"crc_err:", RNPM_RXTRANS_CRC_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_SLEN_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"slen_err:", RNPM_RXTRANS_SLEN_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_GLEN_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"glen_err:", RNPM_RXTRANS_GLEN_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_IPH_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"iph_err:", RNPM_RXTRANS_IPH_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_CSUM_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"csum_err:", RNPM_RXTRANS_CSUM_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_LEN_ERR_PKTS(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"len_err:", RNPM_RXTRANS_LEN_ERR_PKTS(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_CUT_ERR_PKTS(port));
|
|
ret += sprintf(
|
|
buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"trans_cut_err:", RNPM_RXTRANS_CUT_ERR_PKTS(port), val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_EXCEPT_BYTES(port));
|
|
ret += sprintf(
|
|
buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"expt_byte_err:", RNPM_RXTRANS_EXCEPT_BYTES(port), val);
|
|
|
|
val = rd32(hw, RNPM_RXTRANS_G1600_BYTES_PKTS(port));
|
|
ret += sprintf(
|
|
buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
">1600Byte:", RNPM_RXTRANS_G1600_BYTES_PKTS(port), val);
|
|
}
|
|
|
|
ret += sprintf(buf + ret, "gather:\n");
|
|
val = rd32(hw, RNPM_ETH_TOTAL_GAT_RX_PKT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"total_in_pkts:", RNPM_ETH_TOTAL_GAT_RX_PKT_NUM, val);
|
|
|
|
port = 0;
|
|
val = rd32(hw, RNPM_ETH_RX_PKT_NUM(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"to_nxt_mdodule:", RNPM_ETH_RX_PKT_NUM(port), val);
|
|
|
|
for (port = 0; port < 4; port++) {
|
|
u8 pname[16] = { 0 };
|
|
|
|
val = rd32(hw, RNPM_ETH_RX_PKT_NUM(port));
|
|
sprintf(pname, "p%d-rx:", port);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", pname,
|
|
RNPM_ETH_RX_PKT_NUM(port), val);
|
|
}
|
|
|
|
for (port = 0; port < 4; port++) {
|
|
u8 pname[16] = { 0 };
|
|
|
|
val = rd32(hw, RNPM_ETH_RX_DROP_PKT_NUM(port));
|
|
sprintf(pname, "p%d-drop:", port);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", pname,
|
|
RNPM_ETH_RX_DROP_PKT_NUM(port), val);
|
|
}
|
|
|
|
ret += sprintf(buf + ret, "ip-parse:\n");
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_EGRESS_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"pkg_egree:", RNPM_ETH_PKT_EGRESS_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_IP_HDR_LEN_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"L3_len_err:", RNPM_ETH_PKT_IP_HDR_LEN_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_IP_PKT_LEN_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"ip_hdr_err:", RNPM_ETH_PKT_IP_PKT_LEN_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_L3_HDR_CHK_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"l3-csum-err:", RNPM_ETH_PKT_L3_HDR_CHK_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_L4_HDR_CHK_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"l4-csum-err:", RNPM_ETH_PKT_L4_HDR_CHK_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_SCTP_CHK_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"sctp-err:", RNPM_ETH_PKT_SCTP_CHK_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_VLAN_ERR_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"vlan-err:", RNPM_ETH_PKT_VLAN_ERR_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_EXCEPT_SHORT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"except_short_num:", RNPM_ETH_PKT_EXCEPT_SHORT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_PKT_PTP_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"ptp:", RNPM_ETH_PKT_PTP_NUM, val);
|
|
|
|
ret += sprintf(buf + ret, "to-indecap:\n");
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_IN_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"*in engin*:", RNPM_ETH_DECAP_PKT_IN_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_OUT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"*out engin*:", RNPM_ETH_DECAP_PKT_OUT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_DMAC_OUT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"to-dma/host:", RNPM_ETH_DECAP_DMAC_OUT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_BMC_OUT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"to-bmc:", RNPM_ETH_DECAP_BMC_OUT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_SW_OUT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"to-switch:", RNPM_ETH_DECAP_SW_OUT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_MIRROR_OUT_NUM);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"bmc+host:", RNPM_ETH_DECAP_MIRROR_OUT_NUM, val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(0x0));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"err_drop:", RNPM_ETH_DECAP_PKT_DROP_NUM(0x0), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(1));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"plicy_drop:", RNPM_ETH_DECAP_PKT_DROP_NUM(1), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(2));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"dmac_drop:", RNPM_ETH_DECAP_PKT_DROP_NUM(2), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(3));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"bmc_drop:", RNPM_ETH_DECAP_PKT_DROP_NUM(3), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(4));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"sw_drop:", RNPM_ETH_DECAP_PKT_DROP_NUM(4), val);
|
|
|
|
val = rd32(hw, RNPM_ETH_DECAP_PKT_DROP_NUM(5));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"rm_vlane_num:", RNPM_ETH_DECAP_PKT_DROP_NUM(5), val);
|
|
|
|
ret += sprintf(buf + ret, "dma-2-host:\n");
|
|
|
|
val = rd32(hw, 0x264);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", "fifo equ:", 0x264,
|
|
val);
|
|
|
|
val = rd32(hw, 0x268);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", "fifo deq:", 0x268,
|
|
val);
|
|
|
|
val = rd32(hw, 0x114);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"unexpt_abtring:", 0x114, val);
|
|
|
|
val = rd32(hw, 0x288);
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n", "pci2host:", 0x288,
|
|
val);
|
|
|
|
for (port = 0; port < 4; port++) {
|
|
ret += sprintf(buf + ret, "rx-ring%d:\n", port);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_RX_DESC_BUF_HEAD(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"head:", RNPM_DMA_REG_RX_DESC_BUF_HEAD(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_RX_DESC_BUF_TAIL(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"tail:", RNPM_DMA_REG_RX_DESC_BUF_TAIL(port),
|
|
val);
|
|
|
|
val = rd32(hw, RNPM_DMA_REG_RX_DESC_BUF_LEN(port));
|
|
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
|
|
"len:", RNPM_DMA_REG_RX_DESC_BUF_LEN(port), val);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(rx_counter);
|
|
|
|
static ssize_t bar4_reg_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret += sprintf(buf + ret, "addr=0x%x, val=0x%x\n", bar4_reg_addr,
|
|
bar4_reg_val);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t bar4_reg_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int rc;
|
|
|
|
rc = kstrtou32(buf, 0, &bar4_reg_addr);
|
|
if (rc)
|
|
return -EINVAL;
|
|
bar4_reg_val = rd32(hw, bar4_reg_addr);
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_RW(bar4_reg);
|
|
|
|
static struct pci_dev *pcie_find_root_port_old(struct pci_dev *dev)
|
|
{
|
|
while (1) {
|
|
if (!pci_is_pcie(dev))
|
|
break;
|
|
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
|
return dev;
|
|
if (!dev->bus->self)
|
|
break;
|
|
dev = dev->bus->self;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static ssize_t root_slot_info_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
int ret = 0;
|
|
struct pci_dev *root_pdev = pcie_find_root_port_old(adapter->pdev);
|
|
|
|
if (root_pdev) {
|
|
ret += sprintf(buf + ret, "%02x:%02x.%x\n",
|
|
root_pdev->bus->number,
|
|
PCI_SLOT(root_pdev->devfn),
|
|
PCI_FUNC(root_pdev->devfn));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(root_slot_info);
|
|
|
|
static ssize_t phy_statistics_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
struct phy_statistics ps;
|
|
|
|
memset(&ps, 0, sizeof(ps));
|
|
|
|
if (rnpm_mbx_get_phy_statistics(hw, (u8 *)&ps) != 0)
|
|
return 0;
|
|
|
|
ret += sprintf(buf + ret, "RX crc good (64~1518) : %u\n",
|
|
ps.yt.pkg_ib_valid);
|
|
ret += sprintf(buf + ret, "RX crc good (>1518) : %u\n",
|
|
ps.yt.pkg_ib_os_good);
|
|
ret += sprintf(buf + ret, "RX crc good (<64) : %u\n",
|
|
ps.yt.pkg_ib_us_good);
|
|
ret += sprintf(buf + ret, "RX crc wrong (64~1518) : %u\n",
|
|
ps.yt.pkg_ib_err);
|
|
ret += sprintf(buf + ret, "RX crc wrong (>1518) : %u\n",
|
|
ps.yt.pkg_ib_os_bad);
|
|
ret += sprintf(buf + ret, "RX crc wrong (<64) : %u\n",
|
|
ps.yt.pkg_ib_frag);
|
|
ret += sprintf(buf + ret, "RX SFD missed (nosfd) : %u\n",
|
|
ps.yt.pkg_ib_nosfd);
|
|
ret += sprintf(buf + ret, "TX crc good (64~1518) : %u\n",
|
|
ps.yt.pkg_ob_valid);
|
|
ret += sprintf(buf + ret, "TX crc good (>1518) : %u\n",
|
|
ps.yt.pkg_ob_os_good);
|
|
ret += sprintf(buf + ret, "TX crc good (<64) : %u\n",
|
|
ps.yt.pkg_ob_us_good);
|
|
ret += sprintf(buf + ret, "TX crc wrong (64~1518) : %u\n",
|
|
ps.yt.pkg_ob_err);
|
|
ret += sprintf(buf + ret, "TX crc wrong (>1518) : %u\n",
|
|
ps.yt.pkg_ob_os_bad);
|
|
ret += sprintf(buf + ret, "TX crc wrong (<64) : %u\n",
|
|
ps.yt.pkg_ob_frag);
|
|
ret += sprintf(buf + ret, "TX SFD missed (nosfd) : %u\n",
|
|
ps.yt.pkg_ob_nosfd);
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RO(phy_statistics);
|
|
|
|
static ssize_t pcs_reg_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
// eg: echo "phy reg val" > pcs_reg
|
|
// sscanf
|
|
u32 pcs_phy_regs[] = {
|
|
0x00040000, 0x00041000, 0x00042000, 0x00043000,
|
|
0x00040000, 0x00041000, 0x00042000, 0x00043000,
|
|
};
|
|
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
u32 reg_hi = 0, reg_lo = 0, pcs_base_regs = 0;
|
|
|
|
if (count > 64) {
|
|
e_dev_info("Error: Input size >100: too large\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pcs_cnt = sscanf(buf, "%u %x %x", &pcs_phy_num, &bar4_reg_addr,
|
|
&bar4_reg_val);
|
|
|
|
if (pcs_cnt != 2 && pcs_cnt != 3) {
|
|
e_dev_info(
|
|
"Error: Invalid Input: read phy x reg 0xXXX or write phy x reg ");
|
|
e_dev_info("0xXXX val 0xXXX\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (pcs_phy_num > 8) {
|
|
e_dev_info("Error: Invalid value. should in 0~7\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (pcs_cnt) {
|
|
case 2:
|
|
reg_hi = bar4_reg_addr >> 8;
|
|
reg_lo = (bar4_reg_addr & 0xff) << 2;
|
|
pcs_base_regs = pcs_phy_regs[pcs_phy_num];
|
|
wr32(hw, pcs_base_regs + (0xff << 2), reg_hi);
|
|
bar4_reg_val = rd32(hw, pcs_base_regs + reg_lo);
|
|
break;
|
|
case 3:
|
|
reg_hi = bar4_reg_addr >> 8;
|
|
reg_lo = (bar4_reg_addr & 0xff) << 2;
|
|
pcs_base_regs = pcs_phy_regs[pcs_phy_num];
|
|
wr32(hw, pcs_base_regs + (0xff << 2), reg_hi);
|
|
wr32(hw, pcs_base_regs + reg_lo, bar4_reg_val);
|
|
break;
|
|
default:
|
|
e_dev_info("Error: Invalid value. pcs_cnt=%d\n", pcs_cnt);
|
|
break;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t pcs_reg_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
|
|
switch (pcs_cnt) {
|
|
case 2:
|
|
ret += sprintf(buf, "read phy %u reg 0x%x val 0x%x\n",
|
|
pcs_phy_num, bar4_reg_addr, bar4_reg_val);
|
|
break;
|
|
case 3:
|
|
ret += sprintf(buf, "write phy %u reg 0x%x val 0x%x\n",
|
|
pcs_phy_num, bar4_reg_addr, bar4_reg_val);
|
|
break;
|
|
default:
|
|
e_dev_info("Error: Invalid pcs_cnt value =%d\n", pcs_cnt);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR_RW(pcs_reg);
|
|
|
|
static ssize_t phy_reg_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int val = 0;
|
|
int err = -EINVAL;
|
|
|
|
if (hw) {
|
|
if (is_phy_ext_reg)
|
|
err = rnpm_mbx_phy_read(hw, phy_reg | PHY_EXT_REG_FLAG,
|
|
&val);
|
|
else
|
|
err = rnpm_mbx_phy_read(hw, phy_reg, &val);
|
|
}
|
|
|
|
if (err)
|
|
return 0;
|
|
else
|
|
return sprintf(buf, "phy %s 0x%04x : 0x%04x\n",
|
|
is_phy_ext_reg ? "ext reg" : "reg", phy_reg,
|
|
val & 0xffff);
|
|
}
|
|
|
|
static ssize_t phy_reg_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int i = 0, argc = 0, err = -EINVAL;
|
|
char argv[3][16];
|
|
unsigned long val[3] = { 0 };
|
|
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
memset(argv, 0, sizeof(argv));
|
|
argc = sscanf(buf, "%15s %15s %15s", argv[0], argv[1], argv[2]);
|
|
|
|
if (argc < 1)
|
|
return -EINVAL;
|
|
|
|
is_phy_ext_reg = 0;
|
|
|
|
if (strcmp(argv[0], "ext") == 0) {
|
|
is_phy_ext_reg = 1;
|
|
} else {
|
|
if (kstrtoul(argv[0], 0, &val[0]))
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (kstrtoul(argv[i], 0, &val[i]))
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (argc == 1) {
|
|
if (is_phy_ext_reg)
|
|
return -EINVAL;
|
|
/* set phy reg index */
|
|
phy_reg = val[0];
|
|
err = 0;
|
|
}
|
|
|
|
if (argc == 2) {
|
|
if (is_phy_ext_reg) {
|
|
/* set ext phy reg index */
|
|
phy_reg = val[1];
|
|
err = 0;
|
|
} else {
|
|
/* write phy reg */
|
|
phy_reg = val[0];
|
|
err = rnpm_mbx_phy_write(hw, phy_reg, val[1]);
|
|
}
|
|
}
|
|
|
|
if (argc == 3) {
|
|
if (is_phy_ext_reg) {
|
|
/* write ext phy reg */
|
|
phy_reg = val[1];
|
|
err = rnpm_mbx_phy_write(hw, phy_reg | PHY_EXT_REG_FLAG,
|
|
val[2]);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return err ? err : count;
|
|
}
|
|
static DEVICE_ATTR_RW(phy_reg);
|
|
|
|
static ssize_t pma_rx2tx_loopback_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int v, en_loopback, rc;
|
|
int nr_lane = adapter->lane % 4;
|
|
|
|
rc = kstrtou32(buf, 0, &en_loopback);
|
|
if (rc)
|
|
return -EINVAL;
|
|
e_dev_info("%s: nr_lane:%d lp:%d\n", __func__, nr_lane, en_loopback);
|
|
|
|
if (!hw->pcs.ops.write || !hw->pcs.ops.read)
|
|
return -EOPNOTSUPP;
|
|
|
|
// pma-rx2tx_loopback
|
|
v = hw->pcs.ops.read(hw, nr_lane, 0x18090);
|
|
if (en_loopback)
|
|
v |= 0xf << 4;
|
|
else
|
|
v &= ~(0xf << 4);
|
|
hw->pcs.ops.write(hw, nr_lane, 0x18090, v);
|
|
|
|
// mac tx-disable
|
|
v = rd32(hw, RNPM_MAC_TX_CFG(nr_lane));
|
|
if (en_loopback)
|
|
v &= ~(BIT(0)); // disable mac-tx
|
|
else
|
|
v |= (BIT(0)); // enable mac-tx
|
|
|
|
wr32(hw, RNPM_MAC_TX_CFG(nr_lane), v);
|
|
|
|
// mac rx-disable
|
|
v = rd32(hw, RNPM_MAC_RX_CFG(nr_lane));
|
|
if (en_loopback)
|
|
v &= ~(BIT(0)); // disable mac-rx
|
|
else
|
|
v |= (BIT(0)); // enable mac-rx
|
|
wr32(hw, RNPM_MAC_RX_CFG(nr_lane), v);
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_WO(pma_rx2tx_loopback);
|
|
|
|
static ssize_t pcs_rx2tx_loopback_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpm_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
int v, en_loopback, rc;
|
|
int nr_lane = adapter->lane % 4;
|
|
|
|
rc = kstrtou32(buf, 0, &en_loopback);
|
|
if (rc)
|
|
return -EINVAL;
|
|
e_dev_info("%s: nr_lane:%d lp:%d\n", __func__, nr_lane, en_loopback);
|
|
|
|
if (!hw->pcs.ops.write || !hw->pcs.ops.read)
|
|
return -EOPNOTSUPP;
|
|
|
|
// pma-rx2tx_loopback
|
|
v = hw->pcs.ops.read(hw, nr_lane, 0x38000);
|
|
if (en_loopback)
|
|
v |= BIT(14); // RX2TX_LB_EN
|
|
else
|
|
v &= ~BIT(14); // RX2TX_LB_EN
|
|
hw->pcs.ops.write(hw, nr_lane, 0x38000, v);
|
|
|
|
// mac tx-disable
|
|
v = rd32(hw, RNPM_MAC_TX_CFG(nr_lane));
|
|
if (en_loopback)
|
|
v &= ~(BIT(0)); // disable mac-tx
|
|
else
|
|
v |= (BIT(0)); // enable mac-tx
|
|
wr32(hw, RNPM_MAC_TX_CFG(nr_lane), v);
|
|
|
|
// mac rx-disable
|
|
v = rd32(hw, RNPM_MAC_RX_CFG(nr_lane));
|
|
if (en_loopback)
|
|
v &= ~(BIT(0)); // disable mac-rx
|
|
else
|
|
v |= (BIT(0)); // enable mac-rx
|
|
wr32(hw, RNPM_MAC_RX_CFG(nr_lane), v);
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_WO(pcs_rx2tx_loopback);
|
|
|
|
static int do_switch_loopback_set(struct rnpm_adapter *adapter, int en,
|
|
int sport_lane, int dst_switch_port)
|
|
{
|
|
int v;
|
|
struct rnpm_hw *hw = &adapter->hw;
|
|
|
|
e_dev_info("%s: %s %d -> %d en:%d\n", __func__,
|
|
netdev_name(adapter->netdev), sport_lane, dst_switch_port,
|
|
en);
|
|
|
|
if (en)
|
|
adapter->flags |= RNPM_FLAG_SWITCH_LOOPBACK_EN;
|
|
else
|
|
adapter->flags &= ~RNPM_FLAG_SWITCH_LOOPBACK_EN;
|
|
|
|
// redir pkgs to peer
|
|
wr32(hw, RNPM_ETH_INPORT_POLICY_REG(sport_lane),
|
|
BIT(29) | (dst_switch_port << 16));
|
|
|
|
// enable/disable policy
|
|
v = rd32(hw, RNPM_ETH_INPORT_POLICY_VAL);
|
|
if (en)
|
|
v |= BIT(sport_lane); // enable this-port-policy
|
|
else
|
|
v &= ~BIT(sport_lane);
|
|
wr32(hw, RNPM_ETH_INPORT_POLICY_VAL, v);
|
|
|
|
// mac promisc
|
|
v = rd32(hw, RNPM_MAC_PKT_FLT(sport_lane));
|
|
if (en)
|
|
v |= (RNPM_RX_ALL | RNPM_RX_ALL_MUL);
|
|
else
|
|
v &= ~(RNPM_RX_ALL | RNPM_RX_ALL_MUL);
|
|
wr32(hw, RNPM_MAC_PKT_FLT(sport_lane), v);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int to_switch_port(struct rnpm_adapter *adapter)
|
|
{
|
|
int switch_port = adapter->lane;
|
|
|
|
if (rnpm_is_pf1(adapter->pdev))
|
|
switch_port += 4;
|
|
|
|
if (adapter->hw.mode == MODE_NIC_MODE_2PORT) {
|
|
if (adapter->lane != 0)
|
|
switch_port += 1;
|
|
}
|
|
|
|
return switch_port;
|
|
}
|
|
|
|
static ssize_t _switch_loopback(struct rnpm_adapter *adapter,
|
|
const char *peer_eth, int en)
|
|
{
|
|
struct net_device *peer_netdev = NULL;
|
|
struct rnpm_adapter *peer_adapter = NULL;
|
|
int i;
|
|
char name[100];
|
|
|
|
strscpy(name, peer_eth, sizeof(name));
|
|
strim(name);
|
|
|
|
peer_netdev = dev_get_by_name(&init_net, name);
|
|
if (!peer_netdev) {
|
|
e_dev_info("canot' find [%s]\n", name);
|
|
return -EINVAL;
|
|
}
|
|
peer_adapter = netdev_priv(peer_netdev);
|
|
|
|
// check if in same slot
|
|
if (PCI_SLOT(peer_adapter->pdev->devfn) !=
|
|
PCI_SLOT(adapter->pdev->devfn)) {
|
|
e_dev_info("%s %s not in same slot\n",
|
|
netdev_name(adapter->netdev),
|
|
netdev_name(peer_adapter->netdev));
|
|
dev_put(peer_netdev);
|
|
return -EINVAL;
|
|
}
|
|
|
|
e_dev_info("%s: %s(%d,%d) <-> %s(%d,%d) en:%d\n", __func__,
|
|
netdev_name(adapter->netdev), adapter->lane, adapter->port,
|
|
netdev_name(peer_adapter->netdev), peer_adapter->lane,
|
|
peer_adapter->port, en);
|
|
|
|
/* clear pf0/pf1 input port policy eth reg */
|
|
for (i = 0; i < MAX_PORT_NUM; i++) {
|
|
wr32(&adapter->hw, RNPM_ETH_INPORT_POLICY_REG(i), 0);
|
|
wr32(&peer_adapter->hw, RNPM_ETH_INPORT_POLICY_REG(i), 0);
|
|
}
|
|
|
|
wr32(&adapter->hw, RNPM_ETH_INPORT_POLICY_VAL, 0);
|
|
wr32(&peer_adapter->hw, RNPM_ETH_INPORT_POLICY_VAL, 0);
|
|
|
|
do_switch_loopback_set(adapter, en, adapter->lane,
|
|
to_switch_port(peer_adapter));
|
|
|
|
do_switch_loopback_set(peer_adapter, en, peer_adapter->lane,
|
|
to_switch_port(adapter));
|
|
|
|
if (peer_netdev)
|
|
dev_put(peer_netdev);
|
|
|
|
return 0;
|
|
}
|
|
static ssize_t switch_loopback_on_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct rnpm_adapter *adapter = netdev_priv(to_net_device(dev));
|
|
|
|
return _switch_loopback(adapter, buf, 1) == 0 ? count : -EINVAL;
|
|
}
|
|
static DEVICE_ATTR_WO(switch_loopback_on);
|
|
|
|
static ssize_t switch_loopback_off_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct rnpm_adapter *adapter = netdev_priv(to_net_device(dev));
|
|
|
|
return _switch_loopback(adapter, buf, 0) == 0 ? count : -EINVAL;
|
|
}
|
|
static DEVICE_ATTR_WO(switch_loopback_off);
|
|
|
|
static struct attribute *dev_attrs[] = {
|
|
&dev_attr_root_slot_info.attr,
|
|
&dev_attr_active_vid.attr,
|
|
&dev_attr_pf_reset.attr,
|
|
&dev_attr_ring_num.attr,
|
|
&dev_attr_port_idx.attr,
|
|
&dev_attr_own_vpd.attr,
|
|
&dev_attr_nr_lane.attr,
|
|
&dev_attr_temperature.attr,
|
|
&dev_attr_si.attr,
|
|
&dev_attr_sfp.attr,
|
|
&dev_attr_autoneg.attr,
|
|
&dev_attr_sfp_tx_disable.attr,
|
|
&dev_attr_fec.attr,
|
|
&dev_attr_link_traing.attr,
|
|
&dev_attr_pci.attr,
|
|
&dev_attr_prbs.attr,
|
|
&dev_attr_debug_linkstat.attr,
|
|
&dev_attr_debug_aptstat.attr,
|
|
&dev_attr_tx_counter.attr,
|
|
&dev_attr_rx_counter.attr,
|
|
&dev_attr_bar4_reg.attr,
|
|
&dev_attr_phy_statistics.attr,
|
|
&dev_attr_pcs_reg.attr,
|
|
&dev_attr_phy_reg.attr,
|
|
&dev_attr_pma_rx2tx_loopback.attr,
|
|
&dev_attr_pcs_rx2tx_loopback.attr,
|
|
&dev_attr_switch_loopback_off.attr,
|
|
&dev_attr_switch_loopback_on.attr,
|
|
NULL,
|
|
};
|
|
|
|
#ifndef NO_BIT_ATTRS
|
|
static struct bin_attribute *dev_bin_attrs[] = {
|
|
&bin_attr_maintain,
|
|
NULL,
|
|
};
|
|
#endif
|
|
static struct attribute_group dev_attr_grp = {
|
|
.attrs = dev_attrs,
|
|
#ifndef NO_BIT_ATTRS
|
|
.bin_attrs = dev_bin_attrs,
|
|
#endif
|
|
};
|
|
|
|
/* hwmon callback functions */
|
|
static ssize_t rnpm_hwmon_show_location(struct device __always_unused *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct hwmon_attr *rnpm_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
|
|
return snprintf(buf, PAGE_SIZE, "loc%u\n", rnpm_attr->sensor->location);
|
|
}
|
|
|
|
static ssize_t rnpm_hwmon_show_name(struct device __always_unused *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "rnpm\n");
|
|
}
|
|
|
|
static ssize_t rnpm_hwmon_show_temp(struct device __always_unused *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct hwmon_attr *rnpm_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value;
|
|
|
|
/* reset the temp field */
|
|
rnpm_attr->hw->mac.ops.get_thermal_sensor_data(rnpm_attr->hw);
|
|
|
|
value = rnpm_attr->sensor->temp;
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
static ssize_t rnpm_hwmon_show_cautionthresh(struct device __always_unused *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct hwmon_attr *rnpm_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value = rnpm_attr->sensor->caution_thresh;
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
static ssize_t rnpm_hwmon_show_maxopthresh(struct device __always_unused *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct hwmon_attr *rnpm_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value = rnpm_attr->sensor->max_op_thresh;
|
|
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
/**
|
|
* rnpm_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
|
|
* @adapter: pointer to the adapter structure
|
|
* @offset: offset in the eeprom sensor data table
|
|
* @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 rnpm_add_hwmon_attr(struct rnpm_adapter *adapter,
|
|
unsigned int offset, int type)
|
|
{
|
|
unsigned int n_attr;
|
|
struct hwmon_attr *rnpm_attr;
|
|
|
|
n_attr = adapter->rnpm_hwmon_buff->n_hwmon;
|
|
rnpm_attr = &adapter->rnpm_hwmon_buff->hwmon_list[n_attr];
|
|
|
|
switch (type) {
|
|
case RNPM_HWMON_TYPE_LOC:
|
|
rnpm_attr->dev_attr.show = rnpm_hwmon_show_location;
|
|
snprintf(rnpm_attr->name, sizeof(rnpm_attr->name),
|
|
"temp%u_label", offset + 1);
|
|
|
|
break;
|
|
case RNPM_HWMON_TYPE_NAME:
|
|
rnpm_attr->dev_attr.show = rnpm_hwmon_show_name;
|
|
snprintf(rnpm_attr->name, sizeof(rnpm_attr->name), "name");
|
|
|
|
break;
|
|
case RNPM_HWMON_TYPE_TEMP:
|
|
rnpm_attr->dev_attr.show = rnpm_hwmon_show_temp;
|
|
snprintf(rnpm_attr->name, sizeof(rnpm_attr->name),
|
|
"temp%u_input", offset + 1);
|
|
|
|
break;
|
|
case RNPM_HWMON_TYPE_CAUTION:
|
|
rnpm_attr->dev_attr.show = rnpm_hwmon_show_cautionthresh;
|
|
snprintf(rnpm_attr->name, sizeof(rnpm_attr->name), "temp%u_max",
|
|
offset + 1);
|
|
|
|
break;
|
|
case RNPM_HWMON_TYPE_MAX:
|
|
rnpm_attr->dev_attr.show = rnpm_hwmon_show_maxopthresh;
|
|
snprintf(rnpm_attr->name, sizeof(rnpm_attr->name),
|
|
"temp%u_crit", offset + 1);
|
|
|
|
break;
|
|
default:
|
|
return -EPERM;
|
|
}
|
|
|
|
/* These always the same regardless of type */
|
|
rnpm_attr->sensor = &adapter->hw.mac.thermal_sensor_data.sensor[offset];
|
|
rnpm_attr->hw = &adapter->hw;
|
|
rnpm_attr->dev_attr.store = NULL;
|
|
rnpm_attr->dev_attr.attr.mode = 0444;
|
|
rnpm_attr->dev_attr.attr.name = rnpm_attr->name;
|
|
|
|
sysfs_attr_init(&rnpm_attr->dev_attr.attr);
|
|
|
|
adapter->rnpm_hwmon_buff->attrs[n_attr] = &rnpm_attr->dev_attr.attr;
|
|
|
|
++adapter->rnpm_hwmon_buff->n_hwmon;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* called from rnpm_main.c */
|
|
void rnpm_sysfs_exit(struct rnpm_adapter *adapter)
|
|
{
|
|
sysfs_remove_group(&adapter->netdev->dev.kobj, &dev_attr_grp);
|
|
}
|
|
|
|
/* called from rnpm_main.c */
|
|
int rnpm_sysfs_init(struct rnpm_adapter *adapter, int port)
|
|
{
|
|
int err, rc = 0;
|
|
struct hwmon_buff *rnpm_hwmon;
|
|
struct device *hwmon_dev;
|
|
unsigned int i;
|
|
|
|
err = sysfs_create_group(&adapter->netdev->dev.kobj, &dev_attr_grp);
|
|
if (err != 0) {
|
|
dev_err(&adapter->netdev->dev,
|
|
"sysfs_create_group failed:err:%d\n", err);
|
|
return err;
|
|
}
|
|
/* only port0 and pcie devfn all both 0 register temperature hwmon */
|
|
if (!!port || !!adapter->pdev->devfn)
|
|
goto exit;
|
|
|
|
/* If this method isn't defined we don't support thermals */
|
|
if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
|
|
goto no_thermal;
|
|
|
|
/* Don't create thermal hwmon interface if no sensors present */
|
|
if (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw))
|
|
goto no_thermal;
|
|
|
|
rnpm_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*rnpm_hwmon),
|
|
GFP_KERNEL);
|
|
|
|
if (!rnpm_hwmon) {
|
|
rc = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
|
|
adapter->rnpm_hwmon_buff = rnpm_hwmon;
|
|
/* Only support one sensor now */
|
|
for (i = 0; i < RNPM_MAX_SENSORS; i++) {
|
|
/* Only create hwmon sysfs entries for sensors that have
|
|
* meaningful data for.
|
|
*/
|
|
if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
|
|
continue;
|
|
|
|
/* Bail if any hwmon attr struct fails to initialize */
|
|
rc = rnpm_add_hwmon_attr(adapter, i, RNPM_HWMON_TYPE_CAUTION);
|
|
if (rc)
|
|
goto err;
|
|
rc = rnpm_add_hwmon_attr(adapter, i, RNPM_HWMON_TYPE_TEMP);
|
|
if (rc)
|
|
goto err;
|
|
rc = rnpm_add_hwmon_attr(adapter, i, RNPM_HWMON_TYPE_MAX);
|
|
if (rc)
|
|
goto err;
|
|
}
|
|
|
|
rnpm_hwmon->groups[0] = &rnpm_hwmon->group;
|
|
rnpm_hwmon->group.attrs = rnpm_hwmon->attrs;
|
|
|
|
hwmon_dev = devm_hwmon_device_register_with_groups(
|
|
&adapter->pdev->dev, "rnpm", rnpm_hwmon, rnpm_hwmon->groups);
|
|
|
|
if (IS_ERR(hwmon_dev)) {
|
|
rc = PTR_ERR(hwmon_dev);
|
|
goto exit;
|
|
}
|
|
no_thermal:
|
|
goto exit;
|
|
err:
|
|
exit:
|
|
return rc;
|
|
}
|