1223 lines
32 KiB
C
1223 lines
32 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/kobject.h>
|
|
#include <linux/device.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/hwmon.h>
|
|
#include <linux/ctype.h>
|
|
|
|
#include "rnpgbe.h"
|
|
#include "rnpgbe_common.h"
|
|
#include "rnpgbe_type.h"
|
|
#include "rnpgbe_mbx.h"
|
|
#include "rnpgbe_mbx_fw.h"
|
|
|
|
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 maintain_reply {
|
|
int magic;
|
|
#define MAINTAIN_REPLY_MAGIC 0xB6B7B8B9
|
|
int cmd;
|
|
int arg0;
|
|
int data_bytes;
|
|
int rev;
|
|
int 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;
|
|
}
|
|
|
|
#ifdef RNP_HWMON
|
|
static ssize_t rnpgbe_hwmon_show_location(struct device __always_unused *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct hwmon_attr *rnpgbe_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
|
|
return snprintf(buf, PAGE_SIZE, "loc%u\n",
|
|
rnpgbe_attr->sensor->location);
|
|
}
|
|
|
|
static ssize_t rnpgbe_hwmon_show_name(struct device __always_unused *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return snprintf(buf, PAGE_SIZE, "rnp\n");
|
|
}
|
|
|
|
static ssize_t rnpgbe_hwmon_show_temp(struct device __always_unused *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct hwmon_attr *rnpgbe_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value;
|
|
|
|
/* reset the temp field */
|
|
rnpgbe_attr->hw->ops.get_thermal_sensor_data(rnpgbe_attr->hw);
|
|
|
|
value = rnpgbe_attr->sensor->temp;
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
static ssize_t
|
|
rnpgbe_hwmon_show_cautionthresh(struct device __always_unused *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct hwmon_attr *rnpgbe_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value = rnpgbe_attr->sensor->caution_thresh;
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
static ssize_t rnpgbe_hwmon_show_maxopthresh(struct device __always_unused *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct hwmon_attr *rnpgbe_attr =
|
|
container_of(attr, struct hwmon_attr, dev_attr);
|
|
unsigned int value = rnpgbe_attr->sensor->max_op_thresh;
|
|
|
|
/* display millidegree */
|
|
value *= 1000;
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
|
}
|
|
|
|
/**
|
|
* rnpgbe_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 rnpgbe_add_hwmon_attr(struct rnpgbe_adapter *adapter,
|
|
unsigned int offset, int type)
|
|
{
|
|
unsigned int n_attr;
|
|
struct hwmon_attr *rnpgbe_attr;
|
|
|
|
n_attr = adapter->rnpgbe_hwmon_buff->n_hwmon;
|
|
rnpgbe_attr = &adapter->rnpgbe_hwmon_buff->hwmon_list[n_attr];
|
|
|
|
switch (type) {
|
|
case RNP_HWMON_TYPE_LOC:
|
|
rnpgbe_attr->dev_attr.show = rnpgbe_hwmon_show_location;
|
|
snprintf(rnpgbe_attr->name, sizeof(rnpgbe_attr->name),
|
|
"temp%u_label", offset + 1);
|
|
break;
|
|
case RNP_HWMON_TYPE_NAME:
|
|
rnpgbe_attr->dev_attr.show = rnpgbe_hwmon_show_name;
|
|
snprintf(rnpgbe_attr->name, sizeof(rnpgbe_attr->name), "name");
|
|
break;
|
|
case RNP_HWMON_TYPE_TEMP:
|
|
rnpgbe_attr->dev_attr.show = rnpgbe_hwmon_show_temp;
|
|
snprintf(rnpgbe_attr->name, sizeof(rnpgbe_attr->name),
|
|
"temp%u_input", offset + 1);
|
|
break;
|
|
case RNP_HWMON_TYPE_CAUTION:
|
|
rnpgbe_attr->dev_attr.show = rnpgbe_hwmon_show_cautionthresh;
|
|
snprintf(rnpgbe_attr->name, sizeof(rnpgbe_attr->name),
|
|
"temp%u_max", offset + 1);
|
|
break;
|
|
case RNP_HWMON_TYPE_MAX:
|
|
rnpgbe_attr->dev_attr.show = rnpgbe_hwmon_show_maxopthresh;
|
|
snprintf(rnpgbe_attr->name, sizeof(rnpgbe_attr->name),
|
|
"temp%u_crit", offset + 1);
|
|
break;
|
|
default:
|
|
return -EPERM;
|
|
}
|
|
|
|
/* These always the same regardless of type */
|
|
rnpgbe_attr->sensor = &adapter->hw.thermal_sensor_data.sensor[offset];
|
|
rnpgbe_attr->hw = &adapter->hw;
|
|
rnpgbe_attr->dev_attr.store = NULL;
|
|
rnpgbe_attr->dev_attr.attr.mode = 0444;
|
|
rnpgbe_attr->dev_attr.attr.name = rnpgbe_attr->name;
|
|
|
|
sysfs_attr_init(&rnpgbe_attr->dev_attr.attr);
|
|
|
|
adapter->rnpgbe_hwmon_buff->attrs[n_attr] = &rnpgbe_attr->dev_attr.attr;
|
|
|
|
++adapter->rnpgbe_hwmon_buff->n_hwmon;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RNP_HWMON */
|
|
|
|
#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 rnpgbe_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 void n500_exchange_share_ram(struct rnpgbe_hw *hw, u32 *buf, int flag, int len)
|
|
{
|
|
int i;
|
|
struct rnpgbe_mbx_info *mbx = &hw->mbx;
|
|
u32 addr = mbx->cpu_vf_share_ram;
|
|
|
|
if (len > mbx->share_size)
|
|
return;
|
|
if (flag) {
|
|
for (i = 0; i < len; i = i + 4)
|
|
rnpgbe_wr_reg(hw->hw_addr + addr + i,
|
|
*(buf + i / 4));
|
|
} else {
|
|
for (i = 0; i < len; i = i + 4)
|
|
*(buf + i / 4) = rnpgbe_rd_reg(hw->hw_addr + addr + i);
|
|
}
|
|
}
|
|
|
|
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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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);
|
|
|
|
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;
|
|
int offset;
|
|
struct rnpgbe_mbx_info *mbx = &hw->mbx;
|
|
|
|
if (req->cmd) {
|
|
int data_len;
|
|
int ram_size = mbx->share_size;
|
|
|
|
offset = 0;
|
|
while (offset < req->req_data_bytes) {
|
|
data_len = (req->req_data_bytes - offset) >
|
|
ram_size ? ram_size :
|
|
(req->req_data_bytes - offset);
|
|
/* copy to ram */
|
|
n500_exchange_share_ram(hw,
|
|
(u32 *)(dma_buf + offset + sizeof(*req)),
|
|
1, data_len);
|
|
err = rnpgbe_maintain_req(hw,
|
|
req->cmd, req->arg0, offset, 0, 0);
|
|
if (err != 0)
|
|
goto err_quit;
|
|
|
|
offset += data_len;
|
|
}
|
|
} else {
|
|
int data_len;
|
|
int ram_size = mbx->share_size;
|
|
struct maintain_reply reply;
|
|
/* it is a read */
|
|
adapter->maintain_buf =
|
|
kmalloc(adapter->maintain_buf_len, GFP_KERNEL);
|
|
if (!adapter->maintain_buf) {
|
|
err = -ENOMEM;
|
|
|
|
goto err_quit;
|
|
}
|
|
reply.magic = MAINTAIN_REPLY_MAGIC;
|
|
reply.cmd = req->cmd;
|
|
reply.arg0 = req->arg0;
|
|
reply.data_bytes = req->reply_bytes;
|
|
memcpy(adapter->maintain_buf, &reply,
|
|
sizeof(struct maintain_reply));
|
|
/* copy req first */
|
|
offset = 0;
|
|
while (offset < reply_bytes) {
|
|
data_len = (reply_bytes - offset) > ram_size ?
|
|
ram_size :
|
|
(reply_bytes - offset);
|
|
err = rnpgbe_maintain_req(hw,
|
|
req->cmd, req->arg0, 0, offset, 0);
|
|
if (err != 0)
|
|
goto err_quit;
|
|
n500_exchange_share_ram(hw,
|
|
(u32 *)(adapter->maintain_buf + offset +
|
|
sizeof(*req)), 0, data_len);
|
|
offset += data_len;
|
|
}
|
|
}
|
|
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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
|
|
u32 rx_desc_num = adapter->sysfs_rx_desc_num;
|
|
struct rnpgbe_ring *ring = adapter->rx_ring[rx_ring_num];
|
|
int ret = 0;
|
|
union rnpgbe_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 rnpgbe_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 rnpgbe_ring *ring = adapter->rx_ring[rx_ring_num];
|
|
|
|
if (kstrtou32(buf, 0, &rx_desc_num) != 0)
|
|
return -EINVAL;
|
|
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 rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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 rnpgbe_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_drop_info_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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 rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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 rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
|
|
struct rnpgbe_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;
|
|
|
|
eth->ops.set_vfta(eth, adapter->stags_vid, true);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t gephy_test_info_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
int ret = 0;
|
|
|
|
if (adapter->gephy_test_mode)
|
|
ret += sprintf(buf + ret, "gephy_test on: %d\n",
|
|
adapter->gephy_test_mode);
|
|
else
|
|
ret += sprintf(buf + ret, "gephy_test off\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t gephy_test_info_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
int ret = count;
|
|
u32 test_mode;
|
|
|
|
#define MAX_MODE (5)
|
|
if (kstrtou32(buf, 0, &test_mode) != 0)
|
|
return -EINVAL;
|
|
if (test_mode < 5)
|
|
adapter->gephy_test_mode = test_mode;
|
|
else
|
|
ret = -EINVAL;
|
|
|
|
rnpgbe_mbx_gephy_test_set(hw, test_mode);
|
|
|
|
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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
|
|
u32 tx_desc_num = adapter->sysfs_tx_desc_num;
|
|
struct rnpgbe_ring *ring = adapter->tx_ring[tx_ring_num];
|
|
int ret = 0;
|
|
struct rnpgbe_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);
|
|
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 rnpgbe_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 rnpgbe_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 rx_ring_info_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
u32 rx_ring_num = adapter->sysfs_rx_ring_num;
|
|
struct rnpgbe_ring *ring = adapter->rx_ring[rx_ring_num];
|
|
int ret = 0;
|
|
union rnpgbe_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 rnpgbe_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 mii_reg_info_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
int ret = count;
|
|
|
|
u32 reg_num;
|
|
|
|
if (kstrtou32(buf, 0, ®_num) != 0)
|
|
return -EINVAL;
|
|
adapter->sysfs_mii_reg = reg_num;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mii_control_info_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
int ret = count;
|
|
|
|
u32 reg_num;
|
|
|
|
if (kstrtou32(buf, 0, ®_num) != 0)
|
|
return -EINVAL;
|
|
adapter->sysfs_mii_control = reg_num;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mii_value_info_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
int ret = count;
|
|
|
|
u32 reg_value;
|
|
|
|
if (kstrtou32(buf, 0, ®_value) != 0)
|
|
return -EINVAL;
|
|
adapter->sysfs_mii_value = reg_value;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int rnpgbe_mdio_read(struct net_device *netdev, int prtad, int devad,
|
|
u32 addr, u32 *phy_value)
|
|
{
|
|
int rc = -EIO;
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
u16 value;
|
|
|
|
rc = hw->ops.phy_read_reg(hw, addr, 0, &value);
|
|
*phy_value = value;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int rnpgbe_mdio_write(struct net_device *netdev, int prtad, int devad,
|
|
u16 addr, u16 value)
|
|
{
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
|
|
return hw->ops.phy_write_reg(hw, addr, 0, value);
|
|
}
|
|
|
|
static ssize_t mii_info_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
u32 reg_num = adapter->sysfs_mii_reg;
|
|
u32 reg_value = adapter->sysfs_mii_value;
|
|
int ret = 0;
|
|
u32 value;
|
|
|
|
if (adapter->sysfs_mii_control) {
|
|
rnpgbe_mdio_write(netdev, 0, 0, reg_num, reg_value);
|
|
ret += sprintf(buf + ret, "write reg %x : %x\n", reg_num,
|
|
reg_value);
|
|
|
|
} else {
|
|
rnpgbe_mdio_read(netdev, 0, 0, reg_num, &value);
|
|
ret += sprintf(buf + ret, "read reg %x : %x\n", reg_num, value);
|
|
}
|
|
|
|
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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
u32 tx_ring_num = adapter->sysfs_tx_ring_num;
|
|
struct rnpgbe_ring *ring = adapter->tx_ring[tx_ring_num];
|
|
int ret = 0;
|
|
struct rnpgbe_tx_buffer *tx_buffer;
|
|
struct rnpgbe_tx_desc *eop_desc;
|
|
|
|
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 rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_ring *ring;
|
|
struct rnpgbe_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->rnpgbe_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->rnpgbe_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);
|
|
rnpgbe_for_each_ring(ring, q_vector->tx) {
|
|
ret += sprintf(buf + ret, "tx ring %d\n",
|
|
ring->rnpgbe_queue_idx);
|
|
}
|
|
rnpgbe_for_each_ring(ring, q_vector->rx) {
|
|
ret += sprintf(buf + ret, "rx ring %d\n",
|
|
ring->rnpgbe_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 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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
u8 vfnum = hw->max_vfs - 1;
|
|
|
|
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) {
|
|
wr32(hw, RNP_DMA_PORT_VEB_VID_TBL(0, vfnum), vid);
|
|
} else {
|
|
wr32(hw, RNP_DMA_PORT_VEB_VID_TBL(adapter->port, vfnum),
|
|
vid);
|
|
}
|
|
err = 0;
|
|
}
|
|
|
|
return err ? err : count;
|
|
}
|
|
|
|
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 rnpgbe_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 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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_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 = rnpgbe_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 rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
|
|
if (rnpgbe_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 temperature_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct net_device *netdev = to_net_device(dev);
|
|
struct rnpgbe_adapter *adapter = netdev_priv(netdev);
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
int ret = 0, temp = 0, voltage = 0;
|
|
|
|
temp = rnpgbe_mbx_get_temp(hw, &voltage);
|
|
|
|
ret += sprintf(buf, "temp:%d oC\n", temp);
|
|
|
|
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 rnpgbe_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 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_RO(mii_info);
|
|
static DEVICE_ATTR_WO(mii_reg_info);
|
|
static DEVICE_ATTR_WO(mii_control_info);
|
|
static DEVICE_ATTR_WO(mii_value_info);
|
|
static DEVICE_ATTR_RW(rx_ring_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_RO(rx_skip_info);
|
|
static DEVICE_ATTR_RW(tx_stags_info);
|
|
static DEVICE_ATTR_RW(gephy_test_info);
|
|
|
|
static struct attribute *dev_attrs[] = {
|
|
&dev_attr_tx_stags_info.attr,
|
|
&dev_attr_gephy_test_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_mii_info.attr,
|
|
&dev_attr_mii_control_info.attr,
|
|
&dev_attr_mii_reg_info.attr,
|
|
&dev_attr_mii_value_info.attr,
|
|
&dev_attr_rx_ring_info.attr,
|
|
&dev_attr_tx_desc_info.attr,
|
|
&dev_attr_rx_desc_info.attr,
|
|
&dev_attr_port_idx.attr,
|
|
&dev_attr_temperature.attr,
|
|
&dev_attr_pci.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
|
|
rnpgbe_sysfs_del_adapter(struct rnpgbe_adapter __maybe_unused *adapter)
|
|
{
|
|
}
|
|
|
|
/* called from rnpgbe_main.c */
|
|
void rnpgbe_sysfs_exit(struct rnpgbe_adapter *adapter)
|
|
{
|
|
rnpgbe_sysfs_del_adapter(adapter);
|
|
sysfs_remove_group(&adapter->netdev->dev.kobj, &dev_attr_grp);
|
|
|
|
kfree(adapter->maintain_buf);
|
|
adapter->maintain_buf = NULL;
|
|
adapter->maintain_buf_len = 0;
|
|
}
|
|
|
|
/* called from rnpgbe_main.c */
|
|
int rnpgbe_sysfs_init(struct rnpgbe_adapter *adapter)
|
|
{
|
|
int rc = 0;
|
|
int flag;
|
|
#ifdef RNP_HWMON
|
|
struct hwmon_buff *rnpgbe_hwmon;
|
|
struct device *hwmon_dev;
|
|
unsigned int i;
|
|
#endif /* RNP_HWMON */
|
|
|
|
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;
|
|
}
|
|
#ifdef RNP_HWMON
|
|
/* 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;
|
|
|
|
rnpgbe_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*rnpgbe_hwmon),
|
|
GFP_KERNEL);
|
|
|
|
if (!rnpgbe_hwmon) {
|
|
rc = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
|
|
adapter->rnpgbe_hwmon_buff = rnpgbe_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 = rnpgbe_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_CAUTION);
|
|
if (rc)
|
|
goto err;
|
|
rc = rnpgbe_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_LOC);
|
|
if (rc)
|
|
goto err;
|
|
rc = rnpgbe_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_TEMP);
|
|
if (rc)
|
|
goto err;
|
|
rc = rnpgbe_add_hwmon_attr(adapter, i, RNP_HWMON_TYPE_MAX);
|
|
if (rc)
|
|
goto err;
|
|
}
|
|
|
|
rnpgbe_hwmon->groups[0] = &rnpgbe_hwmon->group;
|
|
rnpgbe_hwmon->group.attrs = rnpgbe_hwmon->attrs;
|
|
|
|
hwmon_dev = devm_hwmon_device_register_with_groups(
|
|
&adapter->pdev->dev, "rnp", rnpgbe_hwmon, rnpgbe_hwmon->groups);
|
|
|
|
if (IS_ERR(hwmon_dev)) {
|
|
rc = PTR_ERR(hwmon_dev);
|
|
goto exit;
|
|
}
|
|
|
|
no_thermal:
|
|
#endif /* RNP_HWMON */
|
|
goto exit;
|
|
|
|
err:
|
|
rnpgbe_sysfs_exit(adapter);
|
|
exit:
|
|
return rc;
|
|
}
|