2026-01-29 22:25:33 +08:00

2162 lines
58 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2023 Mucse Corporation. */
#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/hwmon.h>
#include <linux/ctype.h>
#include "rnp.h"
#include "rnp_common.h"
#include "rnp_type.h"
#include "rnp_mbx.h"
#include "rnp_mbx_fw.h"
#define PHY_EXT_REG_FLAG 0x80000000
struct maintain_req {
int magic;
#define MAINTAIN_MAGIC 0xa6a7a8a9
int cmd;
int arg0;
int req_data_bytes;
int reply_bytes;
char data[0];
} __attribute__((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];
} __attribute__((packed, aligned(4)));
static int print_desc(char *buf, void *data, int len)
{
u8 *ptr = (u8 *)data;
int ret = 0;
int i = 0;
for (i = 0; i < len; i++)
ret += sprintf(buf + ret, "%02x ", *(ptr + i));
return ret;
}
static ssize_t rnp_hwmon_show_location(struct device __always_unused *dev,
struct device_attribute *attr,
char *buf)
{
struct hwmon_attr *rnp_attr =
container_of(attr, struct hwmon_attr, dev_attr);
return snprintf(buf, PAGE_SIZE, "loc%u\n",
rnp_attr->sensor->location);
}
static ssize_t rnp_hwmon_show_name(struct device __always_unused *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "rnp\n");
}
static ssize_t rnp_hwmon_show_temp(struct device __always_unused *dev,
struct device_attribute *attr,
char *buf)
{
struct hwmon_attr *rnp_attr =
container_of(attr, struct hwmon_attr, dev_attr);
unsigned int value;
/* reset the temp field */
rnp_attr->hw->ops.get_thermal_sensor_data(rnp_attr->hw);
value = rnp_attr->sensor->temp;
/* display millidegree */
value *= 1000;
return snprintf(buf, PAGE_SIZE, "%u\n", value);
}
static ssize_t
rnp_hwmon_show_cautionthresh(struct device __always_unused *dev,
struct device_attribute *attr, char *buf)
{
struct hwmon_attr *rnp_attr =
container_of(attr, struct hwmon_attr, dev_attr);
unsigned int value = rnp_attr->sensor->caution_thresh;
/* display millidegree */
value *= 1000;
return snprintf(buf, PAGE_SIZE, "%u\n", value);
}
static ssize_t
rnp_hwmon_show_maxopthresh(struct device __always_unused *dev,
struct device_attribute *attr, char *buf)
{
struct hwmon_attr *rnp_attr =
container_of(attr, struct hwmon_attr, dev_attr);
unsigned int value = rnp_attr->sensor->max_op_thresh;
/* display millidegree */
value *= 1000;
return snprintf(buf, PAGE_SIZE, "%u\n", value);
}
/**
* rnp_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 rnp_add_hwmon_attr(struct rnp_adapter *adapter,
unsigned int offset, int type)
{
unsigned int n_attr;
struct hwmon_attr *rnp_attr;
n_attr = adapter->rnp_hwmon_buff->n_hwmon;
rnp_attr = &adapter->rnp_hwmon_buff->hwmon_list[n_attr];
switch (type) {
case RNP_HWMON_TYPE_LOC:
rnp_attr->dev_attr.show = rnp_hwmon_show_location;
snprintf(rnp_attr->name, sizeof(rnp_attr->name),
"temp%u_label", offset + 1);
break;
case RNP_HWMON_TYPE_NAME:
rnp_attr->dev_attr.show = rnp_hwmon_show_name;
snprintf(rnp_attr->name, sizeof(rnp_attr->name), "name");
break;
case RNP_HWMON_TYPE_TEMP:
rnp_attr->dev_attr.show = rnp_hwmon_show_temp;
snprintf(rnp_attr->name, sizeof(rnp_attr->name),
"temp%u_input", offset + 1);
break;
case RNP_HWMON_TYPE_CAUTION:
rnp_attr->dev_attr.show = rnp_hwmon_show_cautionthresh;
snprintf(rnp_attr->name, sizeof(rnp_attr->name),
"temp%u_max", offset + 1);
break;
case RNP_HWMON_TYPE_MAX:
rnp_attr->dev_attr.show = rnp_hwmon_show_maxopthresh;
snprintf(rnp_attr->name, sizeof(rnp_attr->name),
"temp%u_crit", offset + 1);
break;
default:
return -EPERM;
}
/* These always the same regardless of type */
rnp_attr->sensor = &adapter->hw.thermal_sensor_data.sensor[offset];
rnp_attr->hw = &adapter->hw;
rnp_attr->dev_attr.store = NULL;
rnp_attr->dev_attr.attr.mode = 0444;
rnp_attr->dev_attr.attr.name = rnp_attr->name;
sysfs_attr_init(&rnp_attr->dev_attr.attr);
adapter->rnp_hwmon_buff->attrs[n_attr] = &rnp_attr->dev_attr.attr;
++adapter->rnp_hwmon_buff->n_hwmon;
return 0;
}
#define to_net_device(n) container_of(n, struct net_device, dev)
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 rnp_adapter *adapter = netdev_priv(netdev);
int rbytes = count;
if (!adapter->maintain_buf)
return 0;
if (off + count > adapter->maintain_buf_len)
rbytes = adapter->maintain_buf_len - off;
memcpy(buf, adapter->maintain_buf + off, rbytes);
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 err = -EINVAL;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_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 = rnp_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) {
err = -ENOMEM;
goto err_quit;
}
memcpy(adapter->maintain_buf, dma_buf,
reply_bytes);
}
if (dma_buf) {
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) {
dma_free_coherent(&hw->pdev->dev,
adapter->maintain_dma_size, dma_buf,
dma_phy);
adapter->maintain_dma_buf = NULL;
}
return err;
}
static BIN_ATTR(maintain, 0644, maintain_read,
maintain_write, 1 * 1024 * 1024);
static ssize_t rx_desc_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
u32 rx_desc_num = adapter->sysfs_rx_desc_num;
struct rnp_ring *ring = adapter->rx_ring[rx_ring_num];
int ret = 0;
union rnp_rx_desc *desc;
desc = RNP_RX_DESC(ring, rx_desc_num);
ret += sprintf(buf + ret, "rx ring %d desc %d:\n", rx_ring_num,
rx_desc_num);
ret += print_desc(buf + ret, desc, sizeof(*desc));
ret += sprintf(buf + ret, "\n");
return ret;
}
static ssize_t rx_desc_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = count;
u32 rx_desc_num = adapter->sysfs_rx_desc_num;
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
struct rnp_ring *ring = adapter->rx_ring[rx_ring_num];
if (kstrtou32(buf, 0, &rx_desc_num) != 0)
return -EINVAL;
/* should check tx_ring_num is valid */
if (rx_desc_num < ring->count)
adapter->sysfs_rx_desc_num = rx_desc_num;
else
ret = -EINVAL;
return ret;
}
static ssize_t tcp_sync_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = 0;
if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC) {
ret += sprintf(buf + ret,
"tcp sync remap on queue %d prio %s\n",
adapter->tcp_sync_queue,
(adapter->priv_flags &
RNP_PRIV_FLAG_TCP_SYNC_PRIO) ?
"NO" :
"OFF");
} else {
ret += sprintf(buf + ret, "tcp sync remap off\n");
}
return ret;
}
static ssize_t tcp_sync_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int ret = count;
u32 tcp_sync_queue;
if (kstrtou32(buf, 0, &tcp_sync_queue) != 0)
return -EINVAL;
if (tcp_sync_queue < adapter->num_rx_queues) {
adapter->tcp_sync_queue = tcp_sync_queue;
adapter->priv_flags |= RNP_PRIV_FLAG_TCP_SYNC;
if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC_PRIO) {
hw->ops.set_tcp_sync_remapping(hw,
adapter->tcp_sync_queue,
true, true);
} else {
hw->ops.set_tcp_sync_remapping(hw,
adapter->tcp_sync_queue,
true, false);
}
} else {
adapter->priv_flags &= ~RNP_PRIV_FLAG_TCP_SYNC;
hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue,
false, false);
}
return ret;
}
static ssize_t rx_skip_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = 0;
if (adapter->priv_flags & RNP_PRIV_FLAG_RX_SKIP_EN)
ret += sprintf(buf + ret, "rx skip bytes: %d\n",
16 * (adapter->priv_skip_count + 1));
else
ret += sprintf(buf + ret, "rx skip off\n");
return ret;
}
static ssize_t rx_skip_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int ret = count;
u32 rx_skip_count;
if (kstrtou32(buf, 0, &rx_skip_count) != 0)
return -EINVAL;
if (rx_skip_count > 0 && rx_skip_count < 17) {
adapter->priv_skip_count = rx_skip_count - 1;
adapter->priv_flags |= RNP_PRIV_FLAG_RX_SKIP_EN;
hw->ops.set_rx_skip(hw, adapter->priv_skip_count, true);
} else {
adapter->priv_flags &= ~RNP_PRIV_FLAG_RX_SKIP_EN;
hw->ops.set_rx_skip(hw, adapter->priv_skip_count, false);
return -EINVAL;
}
return ret;
}
static ssize_t rx_drop_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = 0;
ret += sprintf(buf + ret, "rx_drop_status %llx\n",
adapter->rx_drop_status);
return ret;
}
static ssize_t rx_drop_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int ret = count;
u64 rx_drop_status;
if (kstrtou64(buf, 0, &rx_drop_status) != 0)
return -EINVAL;
adapter->rx_drop_status = rx_drop_status;
hw->ops.update_rx_drop(hw);
return ret;
}
static ssize_t outer_vlan_info_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = 0;
if (adapter->priv_flags & RNP_PRIV_FLAG_DOUBLE_VLAN)
ret += sprintf(buf + ret, "double vlan on\n");
else
ret += sprintf(buf + ret, "double vlan off\n");
switch (adapter->outer_vlan_type) {
case outer_vlan_type_88a8:
ret += sprintf(buf + ret, "outer vlan 0x88a8\n");
break;
case outer_vlan_type_9100:
ret += sprintf(buf + ret, "outer vlan 0x9100\n");
break;
case outer_vlan_type_9200:
ret += sprintf(buf + ret, "outer vlan 0x9200\n");
break;
default:
ret += sprintf(buf + ret, "outer vlan error\n");
break;
}
return ret;
}
static ssize_t outer_vlan_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int ret = count;
u32 outer_vlan_type;
if (kstrtou32(buf, 0, &outer_vlan_type) != 0)
return -EINVAL;
if (outer_vlan_type < outer_vlan_type_max)
adapter->outer_vlan_type = outer_vlan_type;
else
ret = -EINVAL;
if (hw->ops.set_outer_vlan_type)
hw->ops.set_outer_vlan_type(hw, outer_vlan_type);
return ret;
}
static ssize_t tx_stags_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = 0;
if (adapter->flags2 & RNP_FLAG2_VLAN_STAGS_ENABLED)
ret += sprintf(buf + ret, "tx stags on\n");
else
ret += sprintf(buf + ret, "tx stags off\n");
ret += sprintf(buf + ret, "vid 0x%x\n", adapter->stags_vid);
return ret;
}
static ssize_t tx_stags_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
struct rnp_eth_info *eth = &hw->eth;
int ret = count;
u16 tx_stags;
if (kstrtou16(buf, 0, &tx_stags) != 0)
return -EINVAL;
if (tx_stags < VLAN_N_VID)
adapter->stags_vid = tx_stags;
else
ret = -EINVAL;
/* should update vlan filter */
eth->ops.set_vfta(eth, adapter->stags_vid, true);
return ret;
}
static ssize_t tx_desc_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
u32 tx_desc_num = adapter->sysfs_tx_desc_num;
struct rnp_ring *ring = adapter->tx_ring[tx_ring_num];
int ret = 0;
struct rnp_tx_desc *desc;
desc = RNP_TX_DESC(ring, tx_desc_num);
ret += sprintf(buf + ret, "tx ring %d desc %d:\n", tx_ring_num,
tx_desc_num);
/* print next to watch desc */
ret += print_desc(buf + ret, desc, sizeof(*desc));
ret += sprintf(buf + ret, "\n");
return ret;
}
static ssize_t tx_desc_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = count;
u32 tx_desc_num = adapter->sysfs_tx_desc_num;
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
struct rnp_ring *ring = adapter->tx_ring[tx_ring_num];
if (kstrtou32(buf, 0, &tx_desc_num) != 0)
return -EINVAL;
if (tx_desc_num < ring->count)
adapter->sysfs_tx_desc_num = tx_desc_num;
else
ret = -EINVAL;
return ret;
}
static ssize_t para_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
struct rnp_eth_info *eth = &hw->eth;
struct rnp_mac_info *mac = &hw->mac;
ret += sprintf(buf + ret, "nsi_en:%d\n", hw->ncsi_en);
ret += sprintf(buf + ret,
"eth:\n\tmc_filter_type:%u, mcft_size:%u, vft_size:%u,\n",
eth->mc_filter_type, eth->mcft_size, eth->vft_size);
ret += sprintf(buf + ret, "num_rar_entries:%u,\n",
eth->num_rar_entries);
ret += sprintf(buf + ret,
"\trar_highwater:%u, rx_pb_size:%u, max_tx_queues:%u,\n",
eth->rar_highwater, eth->rx_pb_size,
eth->max_tx_queues);
ret += sprintf(buf + ret,
"max_rx_queues:%u,\n",
eth->max_rx_queues);
ret += sprintf(buf + ret,
"\treg_off:%u, orig_autoc:%u, cached_autoc:%u, orig_autoc2:%u\n",
eth->reg_off,
eth->orig_autoc, eth->cached_autoc, eth->orig_autoc2);
ret += sprintf(buf + ret,
"mac:\n\t");
ret += sprintf(buf + ret,
"mc_filter_type:%u mcft_size:%u vft_size:%u num_rar_entries:%u\n",
mac->mc_filter_type, mac->mcft_size, mac->vft_size,
mac->num_rar_entries);
ret += sprintf(buf + ret,
"\trar_highwater:%u rx_pb_size:%u max_tx_queues:%u max_rx_queues:%u\n",
mac->rar_highwater, mac->rx_pb_size, mac->max_tx_queues,
mac->max_rx_queues);
ret += sprintf(buf + ret,
"\treg_off:%u orig_autoc:%u cached_autoc:%u orig_autoc2:%u\n",
mac->reg_off,
mac->orig_autoc, mac->cached_autoc, mac->orig_autoc2);
ret += sprintf(buf + ret,
"orig_link_settings_stored:%u\n",
mac->orig_link_settings_stored);
ret += sprintf(buf + ret,
"\tautotry_restart:%u mac_flags:%u\n",
mac->autotry_restart,
mac->mac_flags);
return ret;
}
static ssize_t rx_ring_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
struct rnp_ring *ring = adapter->rx_ring[rx_ring_num];
int ret = 0;
union rnp_rx_desc *rx_desc;
ret += sprintf(buf + ret, "queue %d info:\n", rx_ring_num);
ret += sprintf(buf + ret, "next_to_use %d\n", ring->next_to_use);
ret += sprintf(buf + ret, "next_to_clean %d\n",
ring->next_to_clean);
rx_desc = RNP_RX_DESC(ring, ring->next_to_clean);
ret += sprintf(buf + ret, "next_to_clean desc: ");
ret += print_desc(buf + ret, rx_desc, sizeof(*rx_desc));
ret += sprintf(buf + ret, "\n");
return ret;
}
static ssize_t rx_ring_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = count;
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
if (kstrtou32(buf, 0, &rx_ring_num) != 0)
return -EINVAL;
if (rx_ring_num < adapter->num_rx_queues)
adapter->sysfs_rx_ring_num = rx_ring_num;
else
ret = -EINVAL;
return ret;
}
static ssize_t tx_ring_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
struct rnp_ring *ring = adapter->tx_ring[tx_ring_num];
int ret = 0;
struct rnp_tx_buffer *tx_buffer;
struct rnp_tx_desc *eop_desc;
/* print all tx_ring_num info */
ret += sprintf(buf + ret, "queue %d info:\n", tx_ring_num);
ret += sprintf(buf + ret, "next_to_use %d\n", ring->next_to_use);
ret += sprintf(buf + ret, "next_to_clean %d\n",
ring->next_to_clean);
tx_buffer = &ring->tx_buffer_info[ring->next_to_clean];
eop_desc = tx_buffer->next_to_watch;
/* if have watch desc */
if (eop_desc) {
ret += sprintf(buf + ret, "next_to_watch:\n");
ret += print_desc(buf + ret, eop_desc, sizeof(*eop_desc));
ret += sprintf(buf + ret, "\n");
} else {
ret += sprintf(buf + ret, "no next_to_watch data\n");
}
return ret;
}
static ssize_t tx_ring_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
int ret = count;
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
if (kstrtou32(buf, 0, &tx_ring_num) != 0)
return -EINVAL;
if (tx_ring_num < adapter->num_tx_queues)
adapter->sysfs_tx_ring_num = tx_ring_num;
else
ret = -EINVAL;
return ret;
}
static ssize_t queue_mapping_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
int i;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_ring *ring;
struct rnp_q_vector *q_vector;
ret += sprintf(buf + ret, "tx_queue count %d\n",
adapter->num_tx_queues);
ret += sprintf(buf + ret, "queue-mapping :\n");
for (i = 0; i < adapter->num_tx_queues; i++) {
ring = adapter->tx_ring[i];
ret += sprintf(buf + ret, "tx queue %d <---> ring %d\n", i,
ring->rnp_queue_idx);
}
ret += sprintf(buf + ret, "rx_queue count %d\n",
adapter->num_rx_queues);
ret += sprintf(buf + ret, "queue-mapping :\n");
for (i = 0; i < adapter->num_rx_queues; i++) {
ring = adapter->rx_ring[i];
ret += sprintf(buf + ret, "rx queue %d <---> ring %d\n", i,
ring->rnp_queue_idx);
}
ret += sprintf(buf + ret, "vector-queue mapping:\n");
for (i = 0; i < adapter->num_q_vectors; i++) {
q_vector = adapter->q_vector[i];
ret += sprintf(buf + ret, "---vector %d---\n", i);
rnp_for_each_ring(ring, q_vector->tx) {
ret += sprintf(buf + ret, "tx ring %d\n",
ring->rnp_queue_idx);
}
rnp_for_each_ring(ring, q_vector->rx) {
ret += sprintf(buf + ret, "rx ring %d\n",
ring->rnp_queue_idx);
}
}
return ret;
}
static ssize_t queue_mapping_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return count;
}
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
ret += sprintf(buf + ret, "tx counters\n");
ret += sprintf(buf + ret, "ring0-tx:\n");
val = rd32(hw, RNP_DMA_REG_TX_DESC_BUF_LEN);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"len:", RNP_DMA_REG_TX_DESC_BUF_LEN, val);
val = rd32(hw, RNP_DMA_REG_TX_DESC_BUF_HEAD);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"head:", RNP_DMA_REG_TX_DESC_BUF_HEAD, val);
val = rd32(hw, RNP_DMA_REG_TX_DESC_BUF_TAIL);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"tail:", RNP_DMA_REG_TX_DESC_BUF_TAIL, val);
ret += sprintf(buf + ret, "to_1to4_p1:\n");
val = rd32(hw, RNP_ETH_1TO4_INST0_IN_PKTS);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"emac_in:", RNP_ETH_1TO4_INST0_IN_PKTS, val);
val = rd32(hw, RNP_ETH_IN_0_TX_PKT_NUM(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"emac_send:", RNP_ETH_IN_0_TX_PKT_NUM(0), val);
ret += sprintf(buf + ret, "to_1to4_p2:\n");
val = rd32(hw, RNP_ETH_IN_1_TX_PKT_NUM(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"sop_pkt:", RNP_ETH_IN_1_TX_PKT_NUM(0), val);
val = rd32(hw, RNP_ETH_IN_2_TX_PKT_NUM(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"eop_pkt:", RNP_ETH_IN_2_TX_PKT_NUM(0), val);
val = rd32(hw, RNP_ETH_IN_3_TX_PKT_NUM(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"send_terr:", RNP_ETH_IN_3_TX_PKT_NUM(0), val);
ret += sprintf(buf + ret, "to_tx_trans(phy):\n");
val = rd32(hw, RNP_ETH_EMAC_TX_TO_PHY_PKTS(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"in:", RNP_ETH_EMAC_TX_TO_PHY_PKTS(0), val);
val = rd32(hw, RNP_ETH_TXTRANS_PTP_PKT_NUM(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"out:", RNP_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: %d\n", "tx:", 0x1081c,
val);
val = rd32(hw, 0x1087c);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"underflow_err:", 0x1087c, val);
val = rd32(hw, RNP_ETH_TX_DEBUG(0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"port0_txtrans_sop:", RNP_ETH_TX_DEBUG(0), val);
val = rd32(hw, RNP_ETH_TX_DEBUG(4));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"port0_txtrans_eop:", RNP_ETH_TX_DEBUG(4), val);
val = rd32(hw, RNP_ETH_TX_DEBUG(13));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"tx_empty:", RNP_ETH_TX_DEBUG(13), val);
val = rd32(hw, RNP_ETH_TX_DEBUG(14));
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
"tx_prog_full:", RNP_ETH_TX_DEBUG(14), val);
val = rd32(hw, RNP_ETH_TX_DEBUG(15));
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
"tx_full:", RNP_ETH_TX_DEBUG(15), 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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_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, RNP_RXTRANS_RX_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"pkts:", RNP_RXTRANS_RX_PKTS(port), val);
val = rd32(hw, RNP_RXTRANS_DROP_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"drop:", RNP_RXTRANS_DROP_PKTS(port), val);
val = rd32(hw, RNP_RXTRANS_WDT_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"wdt_err:", RNP_RXTRANS_WDT_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_CODE_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"code_err:", RNP_RXTRANS_CODE_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_CRC_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"crc_err:", RNP_RXTRANS_CRC_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_SLEN_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"slen_err:", RNP_RXTRANS_SLEN_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_GLEN_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"glen_err:", RNP_RXTRANS_GLEN_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_IPH_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"iph_err:", RNP_RXTRANS_IPH_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_CSUM_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"csum_err:", RNP_RXTRANS_CSUM_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_LEN_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"len_err:", RNP_RXTRANS_LEN_ERR_PKTS(port),
val);
val = rd32(hw, RNP_RXTRANS_CUT_ERR_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"trans_cut_err:",
RNP_RXTRANS_CUT_ERR_PKTS(port), val);
val = rd32(hw, RNP_RXTRANS_EXCEPT_BYTES(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"expt_byte_err:",
RNP_RXTRANS_EXCEPT_BYTES(port), val);
val = rd32(hw, RNP_RXTRANS_G1600_BYTES_PKTS(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
">1600Byte:",
RNP_RXTRANS_G1600_BYTES_PKTS(port), val);
}
ret += sprintf(buf + ret, "gather:\n");
val = rd32(hw, RNP_ETH_TOTAL_GAT_RX_PKT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"total_in_pkts:", RNP_ETH_TOTAL_GAT_RX_PKT_NUM,
val);
port = 0;
val = rd32(hw, RNP_ETH_RX_PKT_NUM(port));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"to_nxt_mdodule:", RNP_ETH_RX_PKT_NUM(port), val);
for (port = 0; port < 4; port++) {
u8 pname[16] = { 0 };
val = rd32(hw, RNP_ETH_RX_PKT_NUM(port));
sprintf(pname, "p%d-rx:", port);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n", pname,
RNP_ETH_RX_PKT_NUM(port), val);
}
for (port = 0; port < 4; port++) {
u8 pname[16] = { 0 };
val = rd32(hw, RNP_ETH_RX_DROP_PKT_NUM(port));
sprintf(pname, "p%d-drop:", port);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n", pname,
RNP_ETH_RX_DROP_PKT_NUM(port), val);
}
ret += sprintf(buf + ret, "ip-parse:\n");
val = rd32(hw, RNP_ETH_PKT_EGRESS_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"pkg_egree:", RNP_ETH_PKT_EGRESS_NUM, val);
val = rd32(hw, RNP_ETH_PKT_IP_HDR_LEN_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"L3_len_err:", RNP_ETH_PKT_IP_HDR_LEN_ERR_NUM, val);
val = rd32(hw, RNP_ETH_PKT_IP_PKT_LEN_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"ip_hdr_err:", RNP_ETH_PKT_IP_PKT_LEN_ERR_NUM, val);
val = rd32(hw, RNP_ETH_PKT_L3_HDR_CHK_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"l3-csum-err:", RNP_ETH_PKT_L3_HDR_CHK_ERR_NUM,
val);
val = rd32(hw, RNP_ETH_PKT_L4_HDR_CHK_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"l4-csum-err:", RNP_ETH_PKT_L4_HDR_CHK_ERR_NUM,
val);
val = rd32(hw, RNP_ETH_PKT_SCTP_CHK_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"sctp-err:", RNP_ETH_PKT_SCTP_CHK_ERR_NUM, val);
val = rd32(hw, RNP_ETH_PKT_VLAN_ERR_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"vlan-err:", RNP_ETH_PKT_VLAN_ERR_NUM, val);
val = rd32(hw, RNP_ETH_PKT_EXCEPT_SHORT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"except_short_num:", RNP_ETH_PKT_EXCEPT_SHORT_NUM,
val);
val = rd32(hw, RNP_ETH_PKT_PTP_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"ptp:", RNP_ETH_PKT_PTP_NUM, val);
ret += sprintf(buf + ret, "to-indecap:\n");
val = rd32(hw, RNP_ETH_DECAP_PKT_IN_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"*in engin*:", RNP_ETH_DECAP_PKT_IN_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_PKT_OUT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"*out engin*:", RNP_ETH_DECAP_PKT_OUT_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_DMAC_OUT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"to-dma/host:", RNP_ETH_DECAP_DMAC_OUT_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_BMC_OUT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"to-bmc:", RNP_ETH_DECAP_BMC_OUT_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_SW_OUT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"to-switch:", RNP_ETH_DECAP_SW_OUT_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_MIRROR_OUT_NUM);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"bmc+host:", RNP_ETH_DECAP_MIRROR_OUT_NUM, val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(0x0));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"err_drop:", RNP_ETH_DECAP_PKT_DROP_NUM(0x0), val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(1));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"plicy_drop:", RNP_ETH_DECAP_PKT_DROP_NUM(1), val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(2));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"dmac_drop:", RNP_ETH_DECAP_PKT_DROP_NUM(2), val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(3));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"bmc_drop:", RNP_ETH_DECAP_PKT_DROP_NUM(3), val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(4));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"sw_drop:", RNP_ETH_DECAP_PKT_DROP_NUM(4), val);
val = rd32(hw, RNP_ETH_DECAP_PKT_DROP_NUM(5));
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"rm_vlane_num:", RNP_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: %d\n",
"fifo equ:", 0x264, val);
val = rd32(hw, 0x268);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"fifo deq:", 0x268, val);
val = rd32(hw, 0x114);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"unexpt_abtring:", 0x114, val);
val = rd32(hw, 0x288);
ret += sprintf(buf + ret, "\t %16s 0x%08x: %d\n",
"pci2host:", 0x288, val);
for (port = 0; port < 4; port++) {
ret += sprintf(buf + ret, "rx-ring%d:\n", port);
val = rd32(hw, RNP_DMA_REG_RX_DESC_BUF_HEAD);
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
"head:", RNP_DMA_REG_RX_DESC_BUF_HEAD, val);
val = rd32(hw, RNP_DMA_REG_RX_DESC_BUF_TAIL);
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
"tail:", RNP_DMA_REG_RX_DESC_BUF_TAIL, val);
val = rd32(hw, RNP_DMA_REG_RX_DESC_BUF_LEN);
ret += sprintf(buf + ret, "\t %16s 0x%08x: 0x%x\n",
"len:", RNP_DMA_REG_RX_DESC_BUF_LEN, val);
}
return ret;
}
static DEVICE_ATTR_RO(rx_counter);
static ssize_t active_vid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u16 vid;
u16 current_vid = 0;
int ret = 0;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
u8 vfnum = hw->max_vfs - 1;
if ((adapter->flags & RNP_FLAG_SRIOV_ENABLED)) {
current_vid = rd32(hw,
RNP_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
u8 vfnum = hw->max_vfs - 1;
int port = 0;
if (!(adapter->flags & RNP_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, RNP_DMA_VERSION) >= 0x20201231) {
for (port = 0; port < 4; port++)
wr32(hw,
RNP_DMA_PORT_VEB_VID_TBL(port, vfnum),
vid);
} else {
wr32(hw, RNP_DMA_PORT_VEB_VID_TBL(adapter->port,
vfnum), vid);
}
err = 0;
}
return err ? err : count;
}
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++;
else
break;
}
return len;
}
static int rnp_mbx_get_pn_sn(struct rnp_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;
req->arg0 = 3;
req->req_data_bytes = 0;
req->reply_bytes = bytes - sizeof(*req);
err = rnp_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)
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
char pn[33] = { 0 }, sn[33] = { 0 };
rnp_mbx_get_pn_sn(hw, pn, sn);
ret += sprintf(buf + ret, "Product Name: %s\n",
"N10 Series for 10GbE or 40GbE (Dual-port)");
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);
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 rnp_adapter *adapter = netdev_priv(netdev);
ret += sprintf(buf, "%d\n", adapter->portid_of_card);
return ret;
}
static DEVICE_ATTR_RO(port_idx);
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_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 & RNP_FLAG_NEED_LINK_UPDATE,
netif_carrier_ok(netdev));
return ret;
}
static DEVICE_ATTR_RO(debug_linkstat);
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int gen = 3, lanes = 8;
if (count > 30)
return -EINVAL;
if (sscanf(buf, "gen%dx%d", &gen, &lanes) != 2)
return -EINVAL;
if (gen > 3 || lanes > 8)
return -EINVAL;
err = rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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 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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
long enable = 0;
if (kstrtol(buf, 10, &enable))
return -EINVAL;
err = rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
long enable = 0;
if (kstrtol(buf, 10, &enable))
return -EINVAL;
err = rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
long enable = 0;
if (kstrtol(buf, 10, &enable))
return -EINVAL;
err = rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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);
/* write pcs reg: echo "<lane> <pcs_reg> <val>" > pcs_reg */
/* read pcs reg: echo "<lane> <pcs_reg>" > pcs_reg */
static ssize_t pcs_reg_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
u32 reg_hi = 0, reg_lo = 0, pcs_base_regs = 0;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int input_arg_cnt;
u32 pcs_phy_regs[] = {
0x00040000, 0x00041000, 0x00042000, 0x00043000,
0x00040000, 0x00041000, 0x00042000, 0x00043000,
};
if (count > 64) {
e_err(drv, "Error: Input size >100: too large\n");
return -EINVAL;
}
input_arg_cnt = sscanf(buf, "%u %x %x",
&adapter->sysfs_pcs_lane_num,
&adapter->sysfs_bar4_reg_addr,
&adapter->sysfs_bar4_reg_val);
if (input_arg_cnt != 2 && input_arg_cnt != 3) {
e_err(drv, "Error: Invalid Input: read lane x reg 0xXXX or write phy x reg");
e_err(drv, "0xXXX val 0xXXX\n");
return -EINVAL;
}
if (adapter->sysfs_pcs_lane_num > 8) {
e_err(drv, "Error: Invalid value. should in 0~7\n");
return -EINVAL;
}
switch (input_arg_cnt) {
case 2:
reg_hi = adapter->sysfs_bar4_reg_addr >> 8;
reg_lo = (adapter->sysfs_bar4_reg_addr & 0xff) << 2;
pcs_base_regs = pcs_phy_regs[adapter->sysfs_pcs_lane_num];
wr32(hw, pcs_base_regs + (0xff << 2), reg_hi);
adapter->sysfs_bar4_reg_val =
rd32(hw, pcs_base_regs + reg_lo);
break;
case 3:
reg_hi = adapter->sysfs_bar4_reg_addr >> 8;
reg_lo = (adapter->sysfs_bar4_reg_addr & 0xff) << 2;
pcs_base_regs = pcs_phy_regs[adapter->sysfs_pcs_lane_num];
wr32(hw, pcs_base_regs + (0xff << 2), reg_hi);
wr32(hw, pcs_base_regs + reg_lo,
adapter->sysfs_bar4_reg_val);
break;
default:
e_err(drv, "Error: Invalid value. input_arg_cnt=%d\n",
input_arg_cnt);
break;
}
adapter->sysfs_input_arg_cnt = input_arg_cnt;
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 rnp_adapter *adapter = netdev_priv(netdev);
switch (adapter->sysfs_input_arg_cnt) {
case 2:
ret += sprintf(buf, "lane%u pcs: 0x%x => 0x%x\n",
adapter->sysfs_pcs_lane_num,
adapter->sysfs_bar4_reg_addr,
adapter->sysfs_bar4_reg_val);
break;
case 3:
ret += sprintf(buf, "lane%u pcs: 0x%x <= 0x%x\n",
adapter->sysfs_pcs_lane_num,
adapter->sysfs_bar4_reg_addr,
adapter->sysfs_bar4_reg_val);
break;
default:
e_err(drv, "Error: Invalid input_arg_cnt value =%d\n",
adapter->sysfs_input_arg_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int val = 0;
int err = -EINVAL;
int phy_reg = adapter->sysfs_phy_reg;
if (hw) {
if (adapter->sysfs_is_phy_ext_reg) {
err = rnp_mbx_phy_read(hw,
phy_reg |
PHY_EXT_REG_FLAG,
&val);
} else {
err = rnp_mbx_phy_read(hw, phy_reg, &val);
}
}
if (err) {
return 0;
} else {
return sprintf(buf, "phy %s 0x%04x : 0x%04x\n",
adapter->sysfs_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 };
int phy_reg = 0;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_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;
adapter->sysfs_is_phy_ext_reg = 0;
if (strcmp(argv[0], "ext") == 0) {
adapter->sysfs_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 (adapter->sysfs_is_phy_ext_reg)
return -EINVAL;
/* set phy reg index */
phy_reg = val[0];
err = 0;
}
if (argc == 2) {
if (adapter->sysfs_is_phy_ext_reg) {
/* set ext phy reg index */
phy_reg = val[1];
err = 0;
} else {
/* write phy reg */
phy_reg = val[0];
err = rnp_mbx_phy_write(hw, phy_reg, val[1]);
}
}
if (argc == 3) {
if (adapter->sysfs_is_phy_ext_reg) {
/* write ext phy reg */
phy_reg = val[1];
err = rnp_mbx_phy_write(hw,
phy_reg |
PHY_EXT_REG_FLAG,
val[2]);
} else {
return -EINVAL;
}
}
adapter->sysfs_phy_reg = phy_reg;
return err ? err : count;
}
static DEVICE_ATTR_RW(phy_reg);
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
long prbs = 0;
if (kstrtol(buf, 10, &prbs))
return -EINVAL;
err = rnp_set_lane_fun(hw, LANE_FUN_PRBS, prbs, 0, 0, 0);
return err ? err : count;
}
static DEVICE_ATTR_WO(prbs);
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
long enable = 0;
if (kstrtol(buf, 10, &enable))
return -EINVAL;
err = rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int si_main = -1, si_pre = -1, si_post = -1, si_txboost = -1;
int cnt;
if (rnp_mbx_get_lane_stat(hw) != 0) {
e_err(drv, "Error: rnp_mbx_get_lane_stat failed\n");
return -EIO;
}
if (count > 100) {
e_err(drv, "Error: Input size >100: too large\n");
return -EINVAL;
}
if (hw->supported_link &
(RNP_LINK_SPEED_40GB_FULL | RNP_LINK_SPEED_25GB_FULL)) {
u32 lane0_main, lane0_pre, lane0_post, lane0_boost;
u32 lane1_main, lane1_pre, lane1_post, lane1_boost;
u32 lane2_main, lane2_pre, lane2_post, lane2_boost;
u32 lane3_main, lane3_pre, lane3_post, lane3_boost;
cnt = sscanf(buf,
"%u %u %u %u,%u %u %u %u,%u %u %u %u,%u %u %u %u",
&lane0_main, &lane0_pre, &lane0_post, &lane0_boost,
&lane1_main, &lane1_pre, &lane1_post, &lane1_boost,
&lane2_main, &lane2_pre, &lane2_post, &lane2_boost,
&lane3_main, &lane3_pre, &lane3_post,
&lane3_boost);
if (cnt != 16) {
e_err(drv, "Error: Invalid Input.\n");
e_err(drv, " <lane0_si>,<lane1_si>,<lane2_si>,<lane3_si>\n");
e_err(drv, " laneX_si: <main> <pre> <post> <boost>\n\n");
e_err(drv, " ie: 21 0 11 11,22 0 12 12,23 0 13 13,24 0 14 14\n");
return -EINVAL;
}
si_main = ((lane0_main & 0xff) << 0) |
((lane1_main & 0xff) << 8) |
((lane2_main & 0xff) << 16) |
((lane3_main & 0xff) << 24);
si_pre = ((lane0_pre & 0xff) << 0) |
((lane1_pre & 0xff) << 8) |
((lane2_pre & 0xff) << 16) |
((lane3_pre & 0xff) << 24);
si_post = ((lane0_post & 0xff) << 0) |
((lane1_post & 0xff) << 8) |
((lane2_post & 0xff) << 16) |
((lane3_post & 0xff) << 24);
si_txboost = ((lane0_boost & 0xf) << 0) |
((lane1_boost & 0xf) << 4) |
((lane2_boost & 0xf) << 8) |
((lane3_boost & 0xf) << 12);
pr_info("%s: main:0x%x pre:0x%x post:0x%x boost:0x%x\n",
adapter->name, si_main, si_pre, si_post,
si_txboost);
} else {
cnt = sscanf(buf, "%u %u %u %u", &si_main, &si_pre,
&si_post, &si_txboost);
if (cnt != 4) {
e_err(drv, "Error: Invalid Input: <main> <pre> <post> <tx_boost>\n");
return -EINVAL;
}
if (si_main > 63 || si_pre > 63 || si_post > 63) {
e_err(drv, "Error: Invalid value. should in 0~63\n");
return -EINVAL;
}
if (si_txboost > 16) {
e_err(drv, "Error: Invalid txboost. should in 0~15\n");
return -EINVAL;
}
}
err = rnp_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, i;
struct net_device *netdev = to_net_device(dev);
struct rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
if (rnp_mbx_get_lane_stat(hw) != 0) {
ret += sprintf(buf, " IO Error\n");
} else {
if (hw->supported_link & (RNP_LINK_SPEED_40GB_FULL |
RNP_LINK_SPEED_25GB_FULL)) {
ret += sprintf(buf + ret,
"main:0x%08x pre:0x%08x post:0x%08x tx_boost:0x%04x\n\n",
adapter->si.main, adapter->si.pre,
adapter->si.post, adapter->si.tx_boost);
for (i = 0; i < 4; i++) {
ret += sprintf(buf + ret,
"lane%d main:%u pre:%u post:%u tx_boost:%u\n",
i,
(adapter->si.main >> (i * 8)) &
0xff,
(adapter->si.pre >> (i * 8)) &
0xff,
(adapter->si.post >> (i * 8)) &
0xff,
(adapter->si.tx_boost >> (i * 4)) &
0xf);
}
} else {
ret += sprintf(buf + ret,
"lane:%d main:%u pre:%u post:%u tx_boost:%u\n",
hw->nr_lane, adapter->si.main,
adapter->si.pre, adapter->si.post,
adapter->si.tx_boost & 0xf);
}
}
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 rnp_adapter *adapter = netdev_priv(netdev);
struct rnp_hw *hw = &adapter->hw;
int ret = 0, temp = 0, voltage = 0;
temp = rnp_mbx_get_temp(hw, &voltage);
ret += sprintf(buf, "temp:%d oC volatage:%d mV\n", temp, voltage);
return ret;
}
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 rnp_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 int do_switch_loopback_set(struct rnp_adapter *adapter, int en,
int sport_lane, int dport_lane)
{
int v;
struct rnp_hw *hw = &adapter->hw;
pr_info("%s: %s %d -> %d en:%d\n", __func__,
netdev_name(adapter->netdev), sport_lane, dport_lane, en);
if (en)
adapter->flags |= RNP_FLAG_SWITCH_LOOPBACK_EN;
else
adapter->flags &= ~RNP_FLAG_SWITCH_LOOPBACK_EN;
/* redir pkgs to peer */
wr32(hw, RNP_ETH_INPORT_POLICY_REG(sport_lane),
BIT(29) | (dport_lane << 16));
/* enable/disable policy */
v = rd32(hw, RNP_ETH_INPORT_POLICY_VAL);
/* enable this-port-policy */
if (en)
v |= BIT(sport_lane);
else
v &= ~BIT(sport_lane);
wr32(hw, RNP_ETH_INPORT_POLICY_VAL, v);
/* mac promisc */
v = mac_rd32(&hw->mac, RNP10_MAC_PKT_FLT);
if (en)
v |= (RNP_RX_ALL | RNP_RX_ALL_MUL);
else
v &= ~(RNP_RX_ALL | RNP_RX_ALL_MUL);
mac_wr32(&hw->mac, RNP10_MAC_PKT_FLT, v);
/* disable unicase-table */
eth_wr32(&hw->eth, RNP10_ETH_DMAC_MCSTCTRL, 0x0);
return 0;
}
static ssize_t _switch_loopback(struct rnp_adapter *adapter,
const char *peer_eth, int en)
{
struct net_device *peer_netdev = NULL;
struct rnp_adapter *peer_adapter = NULL;
char name[100];
strscpy(name, peer_eth, sizeof(name));
strim(name);
pr_info("%s: nr_lane:%d peer_lane:%s en:%d\n", __func__, 0,
peer_eth, en);
peer_netdev = dev_get_by_name(&init_net, name);
if (!peer_netdev) {
e_err(drv, "canot' find %s\n", name);
return -EINVAL;
}
peer_adapter = netdev_priv(peer_netdev);
if (PCI_SLOT(peer_adapter->pdev->devfn) !=
PCI_SLOT(adapter->pdev->devfn)) {
e_err(drv, "%s %s not in same slot\n",
netdev_name(adapter->netdev),
netdev_name(peer_adapter->netdev));
dev_put(peer_netdev);
return -EINVAL;
}
do_switch_loopback_set(adapter, en, 0,
rnp_is_pf1(&peer_adapter->hw) ? 4 : 0);
do_switch_loopback_set(peer_adapter, en, 0,
rnp_is_pf1(&adapter->hw) ? 4 : 0);
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 rnp_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 rnp_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 DEVICE_ATTR_RO(root_slot_info);
static DEVICE_ATTR_RO(temperature);
static DEVICE_ATTR_RW(active_vid);
static DEVICE_ATTR_RW(queue_mapping);
static DEVICE_ATTR_RW(tx_ring_info);
static DEVICE_ATTR_RW(rx_ring_info);
static DEVICE_ATTR_RO(para_info);
static DEVICE_ATTR_RW(tx_desc_info);
static DEVICE_ATTR_RW(rx_desc_info);
static DEVICE_ATTR_RW(rx_drop_info);
static DEVICE_ATTR_RW(outer_vlan_info);
static DEVICE_ATTR_RW(tcp_sync_info);
static DEVICE_ATTR_RW(rx_skip_info);
static DEVICE_ATTR_RW(tx_stags_info);
static struct attribute *dev_attrs[] = {
&dev_attr_tx_stags_info.attr,
&dev_attr_root_slot_info.attr,
&dev_attr_active_vid.attr,
&dev_attr_queue_mapping.attr,
&dev_attr_rx_drop_info.attr,
&dev_attr_outer_vlan_info.attr,
&dev_attr_tcp_sync_info.attr,
&dev_attr_rx_skip_info.attr,
&dev_attr_tx_ring_info.attr,
&dev_attr_rx_ring_info.attr,
&dev_attr_para_info.attr,
&dev_attr_tx_desc_info.attr,
&dev_attr_rx_desc_info.attr,
&dev_attr_tx_counter.attr,
&dev_attr_rx_counter.attr,
&dev_attr_own_vpd.attr,
&dev_attr_port_idx.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_pcs_reg.attr,
&dev_attr_phy_reg.attr,
&dev_attr_debug_linkstat.attr,
&dev_attr_switch_loopback_off.attr,
&dev_attr_switch_loopback_on.attr,
NULL,
};
static struct bin_attribute *dev_bin_attrs[] = {
&bin_attr_maintain,
NULL,
};
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
.bin_attrs = dev_bin_attrs,
};
static void
rnp_sysfs_del_adapter(struct rnp_adapter __maybe_unused *adapter)
{
}
/* called from rnp_main.c */
void rnp_sysfs_exit(struct rnp_adapter *adapter)
{
rnp_sysfs_del_adapter(adapter);
sysfs_remove_group(&adapter->netdev->dev.kobj, &dev_attr_grp);
}
/* called from rnp_main.c */
int rnp_sysfs_init(struct rnp_adapter *adapter)
{
int rc = 0;
int flag;
struct hwmon_buff *rnp_hwmon;
struct device *hwmon_dev;
unsigned int i;
flag = sysfs_create_group(&adapter->netdev->dev.kobj,
&dev_attr_grp);
if (flag != 0) {
dev_err(&adapter->netdev->dev,
"sysfs_create_group failed:flag:%d\n", flag);
return flag;
}
/* If this method isn't defined we don't support thermals */
if (!adapter->hw.ops.init_thermal_sensor_thresh)
goto no_thermal;
/* Don't create thermal hwmon interface if no sensors present */
if (adapter->hw.ops.init_thermal_sensor_thresh(&adapter->hw))
goto no_thermal;
rnp_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*rnp_hwmon),
GFP_KERNEL);
if (!rnp_hwmon) {
rc = -ENOMEM;
goto exit;
}
adapter->rnp_hwmon_buff = rnp_hwmon;
for (i = 0; i < RNP_MAX_SENSORS; i++) {
/* Only create hwmon sysfs entries for sensors that have
* meaningful data for.
*/
if (adapter->hw.thermal_sensor_data.sensor[i].location ==
0)
continue;
/* Bail if any hwmon attr struct fails to initialize */
rc = rnp_add_hwmon_attr(adapter, i,
RNP_HWMON_TYPE_CAUTION);
if (rc)
goto err;
rc = rnp_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_LOC);
if (rc)
goto err;
rc = rnp_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_TEMP);
if (rc)
goto err;
rc = rnp_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_MAX);
if (rc)
goto err;
}
rnp_hwmon->groups[0] = &rnp_hwmon->group;
rnp_hwmon->group.attrs = rnp_hwmon->attrs;
hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev,
"rnp",
rnp_hwmon,
rnp_hwmon->groups);
if (IS_ERR(hwmon_dev)) {
rc = PTR_ERR(hwmon_dev);
goto exit;
}
no_thermal:
goto exit;
err:
rnp_sysfs_exit(adapter);
exit:
return rc;
}