nvethernet: dump HW features through debugfs

cat /sys/kernel/debug/nvethernet-<interface>/hw_features to
dump the HW features

Bug 200563382

Change-Id: Ifd8eab0564123d1f588241fbadb739e6ef553114
Signed-off-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2338196
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Rakesh Goyal <rgoyal@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Rakesh Goyal <rgoyal@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Bhadram Varka
2020-04-09 16:11:10 +05:30
committed by Revanth Kumar Uppala
parent d7e0d58393
commit a921c9487b
3 changed files with 467 additions and 17 deletions

View File

@@ -4145,8 +4145,8 @@ static void init_filter_values(struct ether_priv_data *pdata)
pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_128; pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_128;
} else if (pdata->hw_feat.mac_addr32_sel == OSI_ENABLE) { } else if (pdata->hw_feat.mac_addr32_sel == OSI_ENABLE) {
pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_64; pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_64;
} else if (pdata->hw_feat.mac_addr16_sel == } else if (pdata->hw_feat.mac_addr_sel ==
EQOS_MAC_HFR0_ADDMACADRSEL_MASK) { (ETHER_ADDR_REG_CNT_32 - 1U)) {
pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_32; pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_32;
} else { } else {
pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_1; pdata->num_mac_addr_regs = ETHER_ADDR_REG_CNT_1;
@@ -4320,19 +4320,20 @@ static int ether_probe(struct platform_device *pdev)
ether_tx_usecs_hrtimer; ether_tx_usecs_hrtimer;
} }
ret = register_netdev(ndev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register netdev\n");
goto err_netdev;
}
/* Register sysfs entry */ /* Register sysfs entry */
ret = ether_sysfs_register(pdata->dev); ret = ether_sysfs_register(pdata);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to create nvethernet sysfs group\n"); "failed to create nvethernet sysfs group\n");
goto err_sysfs; goto err_sysfs;
} }
ret = register_netdev(ndev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register netdev\n");
goto err_netdev;
}
spin_lock_init(&pdata->rlock); spin_lock_init(&pdata->rlock);
init_filter_values(pdata); init_filter_values(pdata);
@@ -4351,9 +4352,9 @@ static int ether_probe(struct platform_device *pdev)
return 0; return 0;
err_netdev:
ether_sysfs_unregister(pdata->dev);
err_sysfs: err_sysfs:
unregister_netdev(ndev);
err_netdev:
err_napi: err_napi:
mdiobus_unregister(pdata->mii); mdiobus_unregister(pdata->mii);
err_dma_mask: err_dma_mask:
@@ -4388,7 +4389,7 @@ static int ether_remove(struct platform_device *pdev)
unregister_netdev(ndev); unregister_netdev(ndev);
/* remove nvethernet sysfs group under /sys/devices/<ether_device>/ */ /* remove nvethernet sysfs group under /sys/devices/<ether_device>/ */
ether_sysfs_unregister(pdata->dev); ether_sysfs_unregister(pdata);
if (pdata->mii != NULL) { if (pdata->mii != NULL) {
mdiobus_unregister(pdata->mii); mdiobus_unregister(pdata->mii);

View File

@@ -29,6 +29,7 @@
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/debugfs.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/reset.h> #include <linux/reset.h>
@@ -372,6 +373,12 @@ struct ether_priv_data {
#endif #endif
/** VM channel info data associated with VM IRQ */ /** VM channel info data associated with VM IRQ */
struct ether_vm_irq_data *vm_irq_data; struct ether_vm_irq_data *vm_irq_data;
#ifdef CONFIG_DEBUG_FS
/** Debug fs directory pointer */
struct dentry *dbgfs_dir;
/** HW features dump debug fs pointer */
struct dentry *dbgfs_hw_feat;
#endif
}; };
/** /**
@@ -385,21 +392,21 @@ void ether_set_ethtool_ops(struct net_device *ndev);
/** /**
* @brief Creates Ethernet sysfs group * @brief Creates Ethernet sysfs group
* *
* @param[in] dev: device instance * @param[in] pdata: Ethernet driver private data
* *
* @retval 0 - success, * @retval 0 - success,
* @retval "negative value" - failure. * @retval "negative value" - failure.
*/ */
int ether_sysfs_register(struct device *dev); int ether_sysfs_register(struct ether_priv_data *pdata);
/** /**
* @brief Removes Ethernet sysfs group * @brief Removes Ethernet sysfs group
* *
* @param[in] dev: device instance * @param[in] pdata: Ethernet driver private data
* *
* @note nvethernet sysfs group need to be registered during probe. * @note nvethernet sysfs group need to be registered during probe.
*/ */
void ether_sysfs_unregister(struct device *dev); void ether_sysfs_unregister(struct ether_priv_data *pdata);
/** /**
* @brief Function to register ptp clock driver * @brief Function to register ptp clock driver

View File

@@ -133,14 +133,456 @@ static struct attribute_group ether_attribute_group = {
.attrs = ether_sysfs_attrs, .attrs = ether_sysfs_attrs,
}; };
int ether_sysfs_register(struct device *dev) #ifdef CONFIG_DEBUG_FS
static char *timestamp_system_source(unsigned int source)
{ {
switch (source) {
case 1:
return "Internal";
case 2:
return "External";
case 3:
return "Internal and External";
case 0:
return "Reserved";
}
return "None";
}
static char *active_phy_selected_interface(unsigned int act_phy_sel)
{
switch (act_phy_sel) {
case 0:
return "GMII or MII";
case 1:
return "RGMII";
case 2:
return "SGMII";
case 3:
return "TBI";
case 4:
return "RMII";
case 5:
return "RTBI";
case 6:
return "SMII";
case 7:
return "RevMII";
}
return "None";
}
static char *mtl_fifo_size(unsigned int fifo_size)
{
switch (fifo_size) {
case 0:
return "128 Bytes";
case 1:
return "256 Bytes";
case 2:
return "512 Bytes";
case 3:
return "1KB";
case 4:
return "2KB";
case 5:
return "4KB";
case 6:
return "8KB";
case 7:
return "16KB";
case 8:
return "32KB";
case 9:
return "64KB";
case 10:
return "128KB";
case 11:
return "256KB";
default:
return "Reserved";
}
}
static char *address_width(unsigned int val)
{
switch (val) {
case 0:
return "32";
case 1:
return "40";
case 2:
return "48";
default:
return "Reserved";
}
}
static char *hash_table_size(unsigned int size)
{
switch (size) {
case 0:
return "No Hash Table";
case 1:
return "64";
case 2:
return "128";
case 3:
return "256";
default:
return "Invalid size";
}
}
static char *num_vlan_filters(unsigned int filters)
{
switch (filters) {
case 0:
return "Zero";
case 1:
return "4";
case 2:
return "8";
case 3:
return "16";
case 4:
return "24";
case 5:
return "32";
default:
return "Unknown";
}
}
static char *max_frp_bytes(unsigned int bytes)
{
switch (bytes) {
case 0:
return "64 Bytes";
case 1:
return "128 Bytes";
case 2:
return "256 Bytes";
case 3:
return "Reserved";
default:
return "Invalid";
}
}
static char *max_frp_instructions(unsigned int entries)
{
switch (entries) {
case 0:
return "64";
case 1:
return "128";
case 2:
return "256";
case 3:
return "Reserved";
default:
return "Invalid";
}
}
static char *auto_safety_package(unsigned int pkg)
{
switch (pkg) {
case 0:
return "No Safety features selected";
case 1:
return "Only 'ECC protection for external memory' feature is selected";
case 2:
return "All the Automotive Safety features are selected without the 'Parity Port Enable for external interface' feature";
case 3:
return "All the Automotive Safety features are selected with the 'Parity Port Enable for external interface' feature";
default:
return "Invalid";
}
}
static char *tts_fifo_depth(unsigned int depth)
{
switch (depth) {
case 1:
return "1";
case 2:
return "2";
case 3:
return "4";
case 4:
return "8";
case 5:
return "16";
default:
return "Reserved";
}
}
static char *gate_ctl_depth(unsigned int depth)
{
switch (depth) {
case 0:
return "No Depth Configured";
case 1:
return "64";
case 2:
return "128";
case 3:
return "256";
case 4:
return "512";
case 5:
return "1024";
default:
return "Reserved";
}
}
static char *gate_ctl_width(unsigned int width)
{
switch (width) {
case 0:
return "Width not configured";
case 1:
return "16";
case 2:
return "20";
case 3:
return "24";
default:
return "Invalid";
}
}
static int ether_hw_features_read(struct seq_file *seq, void *v)
{
struct net_device *ndev = seq->private;
struct ether_priv_data *pdata = netdev_priv(ndev);
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct osi_hw_features *hw_feat = &pdata->hw_feat;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return 0;
}
seq_printf(seq, "==============================\n");
seq_printf(seq, "\tHW features\n");
seq_printf(seq, "==============================\n");
seq_printf(seq, "\t10/100 Mbps: %s\n",
(hw_feat->mii_sel) ? "Y" : "N");
seq_printf(seq, "\tRGMII Mode: %s\n",
(hw_feat->rgmii_sel) ? "Y" : "N");
seq_printf(seq, "\tRMII Mode: %s\n",
(hw_feat->rmii_sel) ? "Y" : "N");
seq_printf(seq, "\t1000 Mpbs: %s\n",
(hw_feat->gmii_sel) ? "Y" : "N");
seq_printf(seq, "\tHalf duplex support: %s\n",
(hw_feat->hd_sel) ? "Y" : "N");
seq_printf(seq, "\tTBI/SGMII/RTBI PHY interface: %s\n",
(hw_feat->pcs_sel) ? "Y" : "N");
seq_printf(seq, "\tVLAN Hash Filtering: %s\n",
(hw_feat->vlan_hash_en) ? "Y" : "N");
seq_printf(seq, "\tMDIO interface: %s\n",
(hw_feat->sma_sel) ? "Y" : "N");
seq_printf(seq, "\tRemote Wake-Up Packet Detection: %s\n",
(hw_feat->rwk_sel) ? "Y" : "N");
seq_printf(seq, "\tMagic Packet Detection: %s\n",
(hw_feat->mgk_sel) ? "Y" : "N");
seq_printf(seq, "\tMAC Management Counters (MMC): %s\n",
(hw_feat->mmc_sel) ? "Y" : "N");
seq_printf(seq, "\tARP Offload: %s\n",
(hw_feat->arp_offld_en) ? "Y" : "N");
seq_printf(seq, "\tIEEE 1588 Timestamp Support: %s\n",
(hw_feat->ts_sel) ? "Y" : "N");
seq_printf(seq, "\tEnergy Efficient Ethernet (EEE) Support: %s\n",
(hw_feat->eee_sel) ? "Y" : "N");
seq_printf(seq, "\tTransmit TCP/IP Checksum Insertion Support: %s\n",
(hw_feat->tx_coe_sel) ? "Y" : "N");
seq_printf(seq, "\tReceive TCP/IP Checksum Support: %s\n",
(hw_feat->rx_coe_sel) ? "Y" : "N");
seq_printf(seq, "\t (1 - 31) MAC Address registers: %s\n",
(hw_feat->mac_addr_sel) ? "Y" : "N");
seq_printf(seq, "\t(32 - 63) MAC Address Registers: %s\n",
(hw_feat->mac_addr32_sel) ? "Y" : "N");
seq_printf(seq, "\t(64 - 127) MAC Address Registers: %s\n",
(hw_feat->mac_addr64_sel) ? "Y" : "N");
seq_printf(seq, "\tTimestamp System Time Source: %s\n",
timestamp_system_source(hw_feat->tsstssel));
seq_printf(seq, "\tSource Address or VLAN Insertion Enable: %s\n",
(hw_feat->sa_vlan_ins) ? "Y" : "N");
seq_printf(seq, "\tActive PHY selected Interface: %s\n",
active_phy_selected_interface(hw_feat->sa_vlan_ins));
seq_printf(seq, "\tVxLAN/NVGRE Support: %s\n",
(hw_feat->vxn) ? "Y" : "N");
seq_printf(seq, "\tDifferent Descriptor Cache Support: %s\n",
(hw_feat->ediffc) ? "Y" : "N");
seq_printf(seq, "\tEnhanced DMA Support: %s\n",
(hw_feat->edma) ? "Y" : "N");
seq_printf(seq, "\tMTL Receive FIFO Size: %s\n",
mtl_fifo_size(hw_feat->rx_fifo_size));
seq_printf(seq, "\tMTL Transmit FIFO Size: %s\n",
mtl_fifo_size(hw_feat->tx_fifo_size));
seq_printf(seq, "\tPFC Enable: %s\n",
(hw_feat->pfc_en) ? "Y" : "N");
seq_printf(seq, "\tOne-Step Timestamping Support: %s\n",
(hw_feat->ost_en) ? "Y" : "N");
seq_printf(seq, "\tPTP Offload Enable: %s\n",
(hw_feat->pto_en) ? "Y" : "N");
seq_printf(seq, "\tIEEE 1588 High Word Register Enable: %s\n",
(hw_feat->adv_ts_hword) ? "Y" : "N");
seq_printf(seq, "\tAXI Address width: %s\n",
address_width(hw_feat->addr_64));
seq_printf(seq, "\tDCB Feature Support: %s\n",
(hw_feat->dcb_en) ? "Y" : "N");
seq_printf(seq, "\tSplit Header Feature Support: %s\n",
(hw_feat->sph_en) ? "Y" : "N");
seq_printf(seq, "\tTCP Segmentation Offload Support: %s\n",
(hw_feat->tso_en) ? "Y" : "N");
seq_printf(seq, "\tDMA Debug Registers Enable: %s\n",
(hw_feat->dma_debug_gen) ? "Y" : "N");
seq_printf(seq, "\tAV Feature Enable: %s\n",
(hw_feat->av_sel) ? "Y" : "N");
seq_printf(seq, "\tRx Side Only AV Feature Enable: %s\n",
(hw_feat->rav_sel) ? "Y" : "N");
seq_printf(seq, "\tHash Table Size: %s\n",
hash_table_size(hw_feat->hash_tbl_sz));
seq_printf(seq, "\tTotal number of L3 or L4 Filters: %u\n",
hw_feat->l3l4_filter_num);
seq_printf(seq, "\tNumber of MTL Receive Queues: %u\n",
(hw_feat->rx_q_cnt + 1));
seq_printf(seq, "\tNumber of MTL Transmit Queues: %u\n",
(hw_feat->tx_q_cnt + 1));
seq_printf(seq, "\tNumber of Receive DMA channels: %u\n",
(hw_feat->rx_ch_cnt + 1));
seq_printf(seq, "\tNumber of Transmit DMA channels: %u\n",
(hw_feat->tx_ch_cnt + 1));
seq_printf(seq, "\tNumber of PPS outputs: %u\n",
hw_feat->pps_out_num);
seq_printf(seq, "\tNumber of Auxiliary Snapshot Inputs: %u\n",
hw_feat->aux_snap_num);
seq_printf(seq, "\tRSS Feature Enabled: %s\n",
(hw_feat->rss_en) ? "Y" : "N");
seq_printf(seq, "\tNumber of Traffic Classes: %u\n",
(hw_feat->num_tc + 1));
seq_printf(seq, "\tNumber of VLAN filters: %s\n",
num_vlan_filters(hw_feat->num_vlan_filters));
seq_printf(seq,
"\tQueue/Channel based VLAN tag insert on Tx Enable: %s\n",
(hw_feat->cbti_sel) ? "Y" : "N");
seq_printf(seq, "\tOne-Step for PTP over UDP/IP Feature Enable: %s\n",
(hw_feat->ost_over_udp) ? "Y" : "N");
seq_printf(seq, "\tDouble VLAN processing support: %s\n",
(hw_feat->double_vlan_en) ? "Y" : "N");
if (osi_core->mac_ver > OSI_EQOS_MAC_5_00) {
seq_printf(seq, "\tSupported Flexible Receive Parser: %s\n",
(hw_feat->frp_sel) ? "Y" : "N");
seq_printf(seq, "\tNumber of FRP Pipes: %u\n",
(hw_feat->num_frp_pipes + 1));
seq_printf(seq, "\tNumber of FRP Parsable Bytes: %s\n",
max_frp_bytes(hw_feat->max_frp_bytes));
seq_printf(seq, "\tNumber of FRP Instructions: %s\n",
max_frp_instructions(hw_feat->max_frp_entries));
seq_printf(seq, "\tAutomotive Safety Package: %s\n",
auto_safety_package(hw_feat->auto_safety_pkg));
seq_printf(seq, "\tTx Timestamp FIFO Depth: %s\n",
tts_fifo_depth(hw_feat->tts_fifo_depth));
seq_printf(seq, "\tEnhancements to Scheduling Traffic Support: %s\n",
(hw_feat->est_sel) ? "Y" : "N");
seq_printf(seq, "\tDepth of the Gate Control List: %s\n",
gate_ctl_depth(hw_feat->gcl_depth));
seq_printf(seq, "\tWidth of the Time Interval field in GCL: %s\n",
gate_ctl_width(hw_feat->gcl_width));
seq_printf(seq, "\tFrame Preemption Enable: %s\n",
(hw_feat->fpe_sel) ? "Y" : "N");
seq_printf(seq, "\tTime Based Scheduling Enable: %s\n",
(hw_feat->tbs_sel) ? "Y" : "N");
seq_printf(seq, "\tNumber of DMA channels enabled for TBS: %u\n",
(hw_feat->num_tbs_ch + 1));
}
return 0;
}
static int ether_hw_feat_open(struct inode *inode, struct file *file)
{
return single_open(file, ether_hw_features_read, inode->i_private);
}
static const struct file_operations ether_hw_features_fops = {
.owner = THIS_MODULE,
.open = ether_hw_feat_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int ether_create_debugfs(struct ether_priv_data *pdata)
{
char *buf;
int ret = 0;
buf = kasprintf(GFP_KERNEL, "nvethernet-%s", pdata->ndev->name);
if (!buf)
return -ENOMEM;
pdata->dbgfs_dir = debugfs_create_dir(buf, NULL);
if (!pdata->dbgfs_dir || IS_ERR(pdata->dbgfs_dir)) {
netdev_err(pdata->ndev,
"failed to create debugfs directory\n");
ret = -ENOMEM;
goto exit;
}
pdata->dbgfs_hw_feat = debugfs_create_file("hw_features", S_IRUGO,
pdata->dbgfs_dir, pdata->ndev,
&ether_hw_features_fops);
if (!pdata->dbgfs_hw_feat) {
netdev_err(pdata->ndev,
"failed to create HW features debugfs\n");
debugfs_remove_recursive(pdata->dbgfs_dir);
ret = -ENOMEM;
goto exit;
}
exit:
kfree(buf);
return ret;
}
static void ether_remove_debugfs(struct ether_priv_data *pdata)
{
debugfs_remove_recursive(pdata->dbgfs_dir);
}
#endif /* CONFIG_DEBUG_FS */
int ether_sysfs_register(struct ether_priv_data *pdata)
{
struct device *dev = pdata->dev;
int ret = 0;
#ifdef CONFIG_DEBUG_FS
ret = ether_create_debugfs(pdata);
if (ret < 0)
return ret;
#endif
/* Create nvethernet sysfs group under /sys/devices/<ether_device>/ */ /* Create nvethernet sysfs group under /sys/devices/<ether_device>/ */
return sysfs_create_group(&dev->kobj, &ether_attribute_group); return sysfs_create_group(&dev->kobj, &ether_attribute_group);
} }
void ether_sysfs_unregister(struct device *dev) void ether_sysfs_unregister(struct ether_priv_data *pdata)
{ {
struct device *dev = pdata->dev;
#ifdef CONFIG_DEBUG_FS
ether_remove_debugfs(pdata);
#endif
/* Remove nvethernet sysfs group under /sys/devices/<ether_device>/ */ /* Remove nvethernet sysfs group under /sys/devices/<ether_device>/ */
sysfs_remove_group(&dev->kobj, &ether_attribute_group); sysfs_remove_group(&dev->kobj, &ether_attribute_group);
} }