diff --git a/drivers/net/ethernet/nvidia/nvethernet/Makefile b/drivers/net/ethernet/nvidia/nvethernet/Makefile index 44e9cc71..d46c8a66 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/Makefile +++ b/drivers/net/ethernet/nvidia/nvethernet/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_NVETHERNET) += nvethernet.o nvethernet-objs:= ether_linux.o \ osd.o \ ethtool.o \ + sysfs.o \ $(OSI)/osi_core.o \ $(OSI)/osi_common.o \ $(OSI)/osi_dma.o \ diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index d118b7f8..3986b1f8 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -77,7 +77,8 @@ static void ether_adjust_link(struct net_device *dev) SPEED_100) ? 25000 * 1000 : 125000 * 1000); if (phydev->speed != SPEED_10) { if (osi_pad_calibrate(pdata->osi_core) < 0) - dev_err(pdata->dev, "failed to do pad caliberation\n"); + dev_err(pdata->dev, + "failed to do pad caliberation\n"); } } } @@ -2199,6 +2200,14 @@ static int ether_probe(struct platform_device *pdev) goto err_napi; } + /* Register sysfs entry */ + ret = ether_sysfs_register(pdata->dev); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to create nvethernet sysfs group\n"); + goto err_sysfs; + } + ret = register_netdev(ndev); if (ret < 0) { dev_err(&pdev->dev, "failed to register netdev\n"); @@ -2212,6 +2221,8 @@ static int ether_probe(struct platform_device *pdev) return 0; err_netdev: + ether_sysfs_unregister(pdata->dev); +err_sysfs: err_napi: mdiobus_unregister(pdata->mii); err_dma_mask: @@ -2241,6 +2252,9 @@ static int ether_remove(struct platform_device *pdev) unregister_netdev(ndev); + /* remove nvethernet sysfs group under /sys/devices// */ + ether_sysfs_unregister(pdata->dev); + if (pdata->mii != NULL) { mdiobus_unregister(pdata->mii); } diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h index 2f0166b4..91b4930d 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h @@ -133,7 +133,12 @@ struct ether_priv_data { int tx_irqs[ETHER_MAX_IRQS]; int rx_irqs[ETHER_MAX_IRQS]; unsigned long long dma_mask; + + /* for MAC loopback */ + unsigned int mac_loopback_mode; }; void ether_set_ethtool_ops(struct net_device *ndev); +int ether_sysfs_register(struct device *dev); +void ether_sysfs_unregister(struct device *dev); #endif /* ETHER_LINUX_H */ diff --git a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c new file mode 100644 index 00000000..6efd4ae1 --- /dev/null +++ b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ether_linux.h" + +/** + * ether_mac_loopback_show - Shows the current setting of MAC loopback + * @dev: Device data. + * @attr: Device attribute + * @buf: Buffer to store the current MAC loopback setting + * + * Algorithm: Display the current MAC loopback setting. + * + * Dependencies: MAC and PHY need to be initialized. + * + * Protection: None. + * + * Return: None. + */ +static ssize_t ether_mac_loopback_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + + return sprintf(buf, "%s\n", (pdata->mac_loopback_mode == 1) ? + "enabled" : "disabled"); +} + +/** + * ether_mac_loopback_store - Set the user setting of MAC loopback mode + * @dev: Device data. + * @attr: Device attribute + * @buf: Buffer which contains the user settings of MAC loopback + * @size: size of buffer + * + * Algorithm: This is used to set the user mode settings of MAC loopback. + * + * Dependencies: MAC and PHY need to be initialized. + * + * Protection: None. + * + * Return: size of buffer. + */ +static ssize_t ether_mac_loopback_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + int ret = -1; + + /* Interface is not up so LB mode can't be set */ + if (!netif_running(ndev)) { + dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n"); + return size; + } + + if (strncmp(buf, "enable", 6) == 0U) { + netif_carrier_on(ndev); + /* Enabling the MAC Loopback Mode */ + ret = osi_config_mac_loopback(pdata->osi_core, OSI_ENABLE); + if (ret < 0) { + dev_err(pdata->dev, "Enabling MAC Loopback failed\n"); + } else { + pdata->mac_loopback_mode = 1; + dev_info(pdata->dev, "Enabling MAC Loopback\n"); + } + } else if (strncmp(buf, "disable", 7) == 0U) { + netif_carrier_off(ndev); + /* Disabling the MAC Loopback Mode */ + ret = osi_config_mac_loopback(pdata->osi_core, OSI_DISABLE); + if (ret < 0) { + dev_err(pdata->dev, "Disabling MAC Loopback failed\n"); + } else { + pdata->mac_loopback_mode = 0; + dev_info(pdata->dev, "Disabling MAC Loopback\n"); + } + } else { + dev_err(pdata->dev, + "Invalid entry. Valid Entries are enable or disable\n"); + } + + return size; +} + +static DEVICE_ATTR(mac_loopback, (S_IRUGO | S_IWUSR), + ether_mac_loopback_show, + ether_mac_loopback_store); + +static struct attribute *ether_sysfs_attrs[] = { + &dev_attr_mac_loopback.attr, + NULL +}; + +static struct attribute_group ether_attribute_group = { + .name = "nvethernet", + .attrs = ether_sysfs_attrs, +}; + +/** + * ether_sysfs_register - Creates nvethernet sysfs group + * @dev: Net device data. + * + * Algorithm: Creates the sysfs group. + * + * Dependencies: MAC and PHY need to be initialized. + * + * Protection: None. + * + * Return: 0 - success, negative value - failure. + */ + +int ether_sysfs_register(struct device *dev) +{ + /* Create nvethernet sysfs group under /sys/devices// */ + return sysfs_create_group(&dev->kobj, ðer_attribute_group); +} + +/** + * ether_sysfs_unregister - Removes nvethernet sysfs group + * @dev: Net device data. + * + * Algorithm: Removes the sysfs group. + * + * Dependencies: nvethernet sysfs group need to be registered during probe. + * + * Protection: None. + * + * Return: None. + */ + +void ether_sysfs_unregister(struct device *dev) +{ + /* Remove nvethernet sysfs group under /sys/devices// */ + sysfs_remove_group(&dev->kobj, ðer_attribute_group); +}