From c2f3c724bd8b5cce48866af597a53d3de78f1e48 Mon Sep 17 00:00:00 2001 From: Mohan Thadikamalla Date: Mon, 20 Apr 2020 15:27:33 +0530 Subject: [PATCH] nvethernet: Add FRP command IOCTL support Add new private IOCTL to perform Flexible Receive Parser table entry add, delete, and update operations using OSI API call. Bug 200565623 Change-Id: I00f2be1aaa6ee737de5154085be0521db0bb9593 Signed-off-by: Mohan Thadikamalla Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2331371 Reviewed-by: Rakesh Goyal Reviewed-by: Bhadram Varka --- .../net/ethernet/nvidia/nvethernet/Makefile | 1 + .../net/ethernet/nvidia/nvethernet/ethtool.c | 56 +++++++++++++++++++ .../net/ethernet/nvidia/nvethernet/ioctl.c | 45 +++++++++++++++ .../net/ethernet/nvidia/nvethernet/ioctl.h | 2 + .../net/ethernet/nvidia/nvethernet/sysfs.c | 44 +++++++++++++++ 5 files changed, 148 insertions(+) diff --git a/drivers/net/ethernet/nvidia/nvethernet/Makefile b/drivers/net/ethernet/nvidia/nvethernet/Makefile index 82c9608c..9b47ddae 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/Makefile +++ b/drivers/net/ethernet/nvidia/nvethernet/Makefile @@ -43,6 +43,7 @@ nvethernet-objs:= ether_linux.o \ $(OSI_DMA)/eqos_desc.o \ $(OSI_DMA)/mgbe_desc.o \ $(OSI_CORE)/mgbe_mmc.o \ + $(OSI_CORE)/frp.o \ $(OSI_CORE)/vlan_filter.o nvethernet-$(CONFIG_NVETHERNET_SELFTESTS) += selftests.o diff --git a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c index ce45fd63..e56b46cb 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c @@ -39,6 +39,35 @@ struct ether_stats { size_t stat_offset; }; +/** + * @brief Name of FRP statistics, with length of name not more than + * ETH_GSTRING_LEN + */ +#if KERNEL_VERSION(5, 5, 0) > LINUX_VERSION_CODE +#define ETHER_PKT_FRP_STAT(y) \ +{ (#y), FIELD_SIZEOF(struct osi_pkt_err_stats, y), \ + offsetof(struct osi_dma_priv_data, pkt_err_stats.y)} +#else +#define ETHER_PKT_FRP_STAT(y) \ +{ (#y), sizeof_field(struct osi_pkt_err_stats, y), \ + offsetof(struct osi_dma_priv_data, pkt_err_stats.y)} +#endif + +/** + * @brief FRP statistics + */ +static const struct ether_stats ether_frpstrings_stats[] = { + ETHER_PKT_FRP_STAT(frp_parsed), + ETHER_PKT_FRP_STAT(frp_dropped), + ETHER_PKT_FRP_STAT(frp_err), + ETHER_PKT_FRP_STAT(frp_incomplete), +}; + +/** + * @brief Ethernet FRP statistics array length + */ +#define ETHER_FRP_STAT_LEN OSI_ARRAY_SIZE(ether_frpstrings_stats) + /** * @brief Name of pkt_err statistics, with length of name not more than * ETH_GSTRING_LEN @@ -496,6 +525,15 @@ static void ether_get_ethtool_stats(struct net_device *dev, data[j++] = (ether_tstrings_stats[i].sizeof_stat == sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); } + + for (i = 0; ((i < ETHER_FRP_STAT_LEN) && + (pdata->hw_feat.frp_sel == OSI_ENABLE)); i++) { + char *p = (char *)osi_core + + ether_frpstrings_stats[i].stat_offset; + + data[j++] = (ether_frpstrings_stats[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + } } } @@ -546,6 +584,13 @@ static int ether_get_sset_count(struct net_device *dev, int sset) len += ETHER_EXTRA_TSN_STAT_LEN; } } + if (INT_MAX - ETHER_FRP_STAT_LEN < len) { + /* do nothing */ + } else { + if (pdata->hw_feat.frp_sel == OSI_ENABLE) { + len += ETHER_FRP_STAT_LEN; + } + } } else if (sset == ETH_SS_TEST) { len = ether_selftest_get_count(pdata); } else { @@ -619,6 +664,17 @@ static void ether_get_strings(struct net_device *dev, u32 stringset, u8 *data) } p += ETH_GSTRING_LEN; } + for (i = 0; ((i < ETHER_FRP_STAT_LEN) && + (pdata->hw_feat.frp_sel == OSI_ENABLE)); + i++) { + str = (u8 *) + ether_frpstrings_stats[i].stat_string; + if (memcpy(p, str, ETH_GSTRING_LEN) == + OSI_NULL) { + return; + } + p += ETH_GSTRING_LEN; + } } } else if (stringset == (u32)ETH_SS_TEST) { ether_selftest_get_strings(pdata, p); diff --git a/drivers/net/ethernet/nvidia/nvethernet/ioctl.c b/drivers/net/ethernet/nvidia/nvethernet/ioctl.c index 1a75be81..3cfbb36c 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ioctl.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ioctl.c @@ -256,6 +256,48 @@ static int ether_config_arp_offload(struct ether_priv_data *pdata, return ret; } +/** + * @brief This function is invoked by ioctl function when user issues an ioctl + * command to configure Flexible Receive Parser table entry add, delete, and + * update commands. + * + * @param[in] dev: Pointer to net device structure. + * @param[in] ifdata: pointer to IOCTL specific structure. + * + * @note MAC and PHY need to be initialized. + * + * @retval 0 on Success + * @retval "negative value" on Failure + */ +static int ether_config_frp_cmd(struct net_device *dev, + struct ether_ifr_data *ifdata) +{ + struct ether_priv_data *pdata = netdev_priv(dev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + struct osi_core_frp_cmd frp_cmd; + int ret = -EINVAL; + + if (pdata->hw_feat.frp_sel == OSI_DISABLE) { + dev_err(pdata->dev, "MAC doen't support FRP\n"); + return ret; + } + + if (!ifdata->ptr) { + dev_err(pdata->dev, "%s: Invalid data for priv ioctl %d\n", + __func__, ifdata->ifcmd); + return ret; + } + + if (copy_from_user(&frp_cmd, + (struct osi_core_frp_cmd *)ifdata->ptr, + sizeof(struct osi_core_frp_cmd)) != 0U) { + dev_err(pdata->dev, "%s copy from user failed\n", __func__); + return -EFAULT; + } + + return osi_configure_frp(osi_core, &frp_cmd); +} + /** * @brief This function is invoked by ioctl when user issues an ioctl command * to enable/disable L3/L4 filtering. @@ -910,6 +952,9 @@ int ether_handle_priv_ioctl(struct net_device *ndev, ret = -EOPNOTSUPP; } break; + case ETHER_CONFIG_FRP_CMD: + ret = ether_config_frp_cmd(ndev, &ifdata); + break; case EQOS_IPV4_FILTERING_CMD: ret = ether_config_ip4_filters(ndev, &ifdata); break; diff --git a/drivers/net/ethernet/nvidia/nvethernet/ioctl.h b/drivers/net/ethernet/nvidia/nvethernet/ioctl.h index a98ca3de..a469ffd9 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ioctl.h +++ b/drivers/net/ethernet/nvidia/nvethernet/ioctl.h @@ -58,6 +58,8 @@ #define ETHER_PTP_RXQUEUE 48 #define ETHER_CONFIG_EST 49 #define ETHER_CONFIG_FPE 50 +/* FRP Command */ +#define ETHER_CONFIG_FRP_CMD 51 /** @} */ /** diff --git a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c index 9d3b562d..9b261a7e 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c +++ b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c @@ -121,6 +121,49 @@ static DEVICE_ATTR(mac_loopback, (S_IRUGO | S_IWUSR), ether_mac_loopback_show, ether_mac_loopback_store); +/** + * @brief Shows the current setting of FRP Table + * + * Algorithm: Display the FRP table + * + * @param[in] dev: Device data. + * @param[in] attr: Device attribute + * @param[in] buf: Buffer to store the current MAC loopback setting + * + * @note MAC and PHY need to be initialized. + */ +static ssize_t ether_mac_frp_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); + struct osi_core_priv_data *osi_core = pdata->osi_core; + struct osi_core_frp_entry *entry = NULL; + struct osi_core_frp_data *data = NULL; + int i = 0, j = 0; + + /* Write FRP table entries */ + for (i = 0, j = 0; ((i < osi_core->frp_cnt) && (j < PAGE_SIZE)); i++) { + entry = &osi_core->frp_table[i]; + data = &entry->data; + j += scnprintf((buf + j), (PAGE_SIZE - j), + "[%d] ID:%d MD:0x%x ME:0x%x AF:%d RF:%d IM:%d NIC:%d FO:%d OKI:%d DCH:x%x\n", + i, entry->frp_id, data->match_data, + data->match_en, data->accept_frame, + data->reject_frame, data->inverse_match, + data->next_ins_ctrl, data->frame_offset, + data->ok_index, data->dma_chsel); + } + + return j; +} + +/** + * @brief Sysfs attribute for FRP table show + * + */ +static DEVICE_ATTR(frp, 0644, ether_mac_frp_show, NULL); + /** * @brief Shows the current setting of PTP mode * @@ -275,6 +318,7 @@ static struct attribute *ether_sysfs_attrs[] = { &dev_attr_mac_loopback.attr, &dev_attr_ptp_mode.attr, &dev_attr_ptp_sync.attr, + &dev_attr_frp.attr, NULL };