From 3fa01bcd71c1c7680ac4e48623ef7f6515d008ee Mon Sep 17 00:00:00 2001 From: Narayan Reddy Date: Wed, 3 Apr 2019 22:00:27 +0530 Subject: [PATCH] nvethernet: MAC loopback support When MAC HW loopback is enabled, MAC receives back all the packets that is being sent by it. Packets which were sent are looped inside the MAC itself. Bug 200512681 Change-Id: Ifb29dcdbfbf2c1b3baab438bf5b98c0fb362e6d8 Signed-off-by: Narayan Reddy Reviewed-on: https://git-master.nvidia.com/r/2088984 Reviewed-by: mobile promotions Tested-by: mobile promotions --- .../net/ethernet/nvidia/nvethernet/Makefile | 1 + .../ethernet/nvidia/nvethernet/ether_linux.c | 16 +- .../ethernet/nvidia/nvethernet/ether_linux.h | 5 + .../net/ethernet/nvidia/nvethernet/sysfs.c | 150 ++++++++++++++++++ 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/nvidia/nvethernet/sysfs.c 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); +}