// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 1999 - 2018 Intel Corporation. */
/* ethtool support for ixgbevf */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/if_vlan.h>
#include <linux/uaccess.h>
#include "ixgbevf.h"
#define IXGBE_ALL_RAR_ENTRIES 16
enum {NETDEV_STATS, IXGBEVF_STATS};
struct ixgbe_stats {
char stat_string[ETH_GSTRING_LEN];
int type;
int sizeof_stat;
int stat_offset;
};
#define IXGBEVF_STAT(_name, _stat) { \
.stat_string = _name, \
.type = IXGBEVF_STATS, \
.sizeof_stat = FIELD_SIZEOF(struct ixgbevf_adapter, _stat), \
.stat_offset = offsetof(struct ixgbevf_adapter, _stat) \
}
#define IXGBEVF_NETDEV_STAT(_net_stat) { \
.stat_string = #_net_stat, \
.type = NETDEV_STATS, \
.sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \
.stat_offset = offsetof(struct net_device_stats, _net_stat) \
}
static struct ixgbe_stats ixgbevf_gstrings_stats[] = {
IXGBEVF_NETDEV_STAT(rx_packets),
IXGBEVF_NETDEV_STAT(tx_packets),
IXGBEVF_NETDEV_STAT(rx_bytes),
IXGBEVF_NETDEV_STAT(tx_bytes),
IXGBEVF_STAT("tx_busy", tx_busy),
IXGBEVF_STAT("tx_restart_queue", restart_queue),
IXGBEVF_STAT("tx_timeout_count", tx_timeout_count),
IXGBEVF_NETDEV_STAT(multicast),
IXGBEVF_STAT("rx_csum_offload_errors", hw_csum_rx_error),
IXGBEVF_STAT("alloc_rx_page", alloc_rx_page),
IXGBEVF_STAT("alloc_rx_page_failed", alloc_rx_page_failed),
IXGBEVF_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
};
#define IXGBEVF_QUEUE_STATS_LEN ( \
(((struct ixgbevf_adapter *)netdev_priv(netdev))->num_tx_queues + \
((struct ixgbevf_adapter *)netdev_priv(netdev))->num_xdp_queues + \
((struct ixgbevf_adapter *)netdev_priv(netdev))->num_rx_queues) * \
(sizeof(struct ixgbevf_stats) / sizeof(u64)))
#define IXGBEVF_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbevf_gstrings_stats)
#define IXGBEVF_STATS_LEN (IXGBEVF_GLOBAL_STATS_LEN + IXGBEVF_QUEUE_STATS_LEN)
static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
"Register test (offline)",
"Link test (on/offline)"
};
#define IXGBEVF_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
static const char ixgbevf_priv_flags_strings[][ETH_GSTRING_LEN] = {
#define IXGBEVF_PRIV_FLAGS_LEGACY_RX BIT(0)
"legacy-rx",
};
#define IXGBEVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbevf_priv_flags_strings)
static int ixgbevf_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
u32 link_speed = 0;
bool link_up;
ethtool_link_ksettings_zero_link_mode(cmd, supported);
ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full);
cmd->base.autoneg = AUTONEG_DISABLE;
cmd->base.port = -1;
hw->mac.get_link_status = 1;
hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
if (link_up) {
__u32 speed = SPEED_10000;
switch (link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
speed = SPEED_10000;
break;
case IXGBE_LINK_SPEED_1GB_FULL:
speed = SPEED_1000;
break;
case IXGBE_LINK_SPEED_100_FULL:
speed = SPEED_100;
break;
}
cmd->base.speed = speed;
cmd->base.duplex = DUPLEX_FULL;
} else {
cmd->base.speed = SPEED_UNKNOWN;
cmd->base.duplex = DUPLEX_UNKNOWN;
}
return 0;
}
static u32 ixgbevf_get_msglevel(struct net_device *netdev)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
return adapter->msg_enable;
}
static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
adapter->msg_enable = data;
}
#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_)
static int ixgbevf_get_regs_len(struct net_device *netdev)
{
#define IXGBE_REGS_LEN 45
return IXGBE_REGS_LEN * sizeof(u32);
}
static void ixgbevf_get_regs(struct net_device *netdev,
struct ethtool_regs *regs,
void *p)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
u32 *regs_buff = p;
u32 regs_len = ixgbevf_get_regs_len(netdev);
u8 i;
memset(p, 0, regs_len);
/* generate a number suitable for ethtool's register version */
regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id;
/* General Registers */
regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL);
regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS);
regs_buff[