From patchwork Fri Jun 30 16:51:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ferruh Yigit X-Patchwork-Id: 26125 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 542827CD5; Fri, 30 Jun 2017 18:52:38 +0200 (CEST) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 22B35235 for ; Fri, 30 Jun 2017 18:52:04 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 30 Jun 2017 09:52:03 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,287,1496127600"; d="scan'208";a="103233280" Received: from silpixa00372839.ir.intel.com (HELO silpixa00372839.ger.corp.intel.com) ([10.237.222.154]) by orsmga004.jf.intel.com with ESMTP; 30 Jun 2017 09:52:02 -0700 From: Ferruh Yigit To: dev@dpdk.org Cc: Ferruh Yigit , Stephen Hemminger , Bruce Richardson , Anatoly Burakov Date: Fri, 30 Jun 2017 17:51:33 +0100 Message-Id: <20170630165140.59594-14-ferruh.yigit@intel.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170630165140.59594-1-ferruh.yigit@intel.com> References: <20170621110651.75299-1-ferruh.yigit@intel.com> <20170630165140.59594-1-ferruh.yigit@intel.com> Subject: [dpdk-dev] [PATCH v9 13/20] unci: add ethtool support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add ethtool support to the virtual interface. Ethtool functions also use netlink exec to get data from userspace. Signed-off-by: Ferruh Yigit --- lib/librte_eal/linuxapp/unci/Makefile | 1 + lib/librte_eal/linuxapp/unci/unci_dev.h | 2 + lib/librte_eal/linuxapp/unci/unci_ethtool.c | 293 ++++++++++++++++++++++++++++ lib/librte_eal/linuxapp/unci/unci_net.c | 2 + 4 files changed, 298 insertions(+) create mode 100644 lib/librte_eal/linuxapp/unci/unci_ethtool.c diff --git a/lib/librte_eal/linuxapp/unci/Makefile b/lib/librte_eal/linuxapp/unci/Makefile index c2a81be7d..25d20d94d 100644 --- a/lib/librte_eal/linuxapp/unci/Makefile +++ b/lib/librte_eal/linuxapp/unci/Makefile @@ -49,5 +49,6 @@ MODULE_CFLAGS += -Wall -Werror # SRCS-$(CONFIG_RTE_UNCI_KMOD) := unci_net.c SRCS-$(CONFIG_RTE_UNCI_KMOD) += unci_nl.c +SRCS-$(CONFIG_RTE_UNCI_KMOD) += unci_ethtool.c include $(RTE_SDK)/mk/rte.module.mk diff --git a/lib/librte_eal/linuxapp/unci/unci_dev.h b/lib/librte_eal/linuxapp/unci/unci_dev.h index 75a4098bd..01a759de6 100644 --- a/lib/librte_eal/linuxapp/unci/unci_dev.h +++ b/lib/librte_eal/linuxapp/unci/unci_dev.h @@ -45,4 +45,6 @@ void unci_nl_release(void); int unci_nl_exec(u32 cmd, struct net_device *dev, void *in_data, size_t in_len, void *out_data, size_t out_len); +void unci_set_ethtool_ops(struct net_device *netdev); + #endif /* _UNCI_DEV_H_ */ diff --git a/lib/librte_eal/linuxapp/unci/unci_ethtool.c b/lib/librte_eal/linuxapp/unci/unci_ethtool.c new file mode 100644 index 000000000..13106fab3 --- /dev/null +++ b/lib/librte_eal/linuxapp/unci/unci_ethtool.c @@ -0,0 +1,293 @@ +/*- + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that 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; + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + */ + +#include "unci_dev.h" + +#define ETHTOOL_GEEPROM_LEN 99 +#define ETHTOOL_GREGS_LEN 98 +#define ETHTOOL_GSSET_COUNT 97 + +static int unci_check_if_running(struct net_device *dev) +{ + return 0; +} + +static void unci_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + int ret; + + ret = unci_nl_exec(info->cmd, dev, NULL, 0, + info, sizeof(struct ethtool_drvinfo)); + if (ret < 0) + memset(info, 0, sizeof(struct ethtool_drvinfo)); +} + +static int unci_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + return unci_nl_exec(ecmd->cmd, dev, NULL, 0, + ecmd, sizeof(struct ethtool_cmd)); +} + +static int unci_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + return unci_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd), + NULL, 0); +} + +static void unci_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + int ret; + + ret = unci_nl_exec(wol->cmd, dev, NULL, 0, + wol, sizeof(struct ethtool_wolinfo)); + if (ret < 0) + memset(wol, 0, sizeof(struct ethtool_wolinfo)); +} + +static int unci_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + return unci_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo), + NULL, 0); +} + +static int unci_nway_reset(struct net_device *dev) +{ + return unci_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0); +} + +static u32 unci_get_link(struct net_device *dev) +{ + u32 data; + int ret; + + ret = unci_nl_exec(ETHTOOL_GLINK, dev, NULL, 0, &data, sizeof(u32)); + if (ret < 0) + return 0; + + return data; +} + +static int unci_get_eeprom_len(struct net_device *dev) +{ + int data; + int ret; + + ret = unci_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0, + &data, sizeof(int)); + if (ret < 0) + return 0; + + return data; +} + +static int unci_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct ethtool_eeprom eeprom_tmp; + int ret = 0; + int remaining; + u32 offset = 0; + + eeprom_tmp = *eeprom; + + remaining = eeprom_tmp.len; + while (remaining > 0 && ret == 0) { + eeprom_tmp.len = min(remaining, UNCI_NL_MSG_LEN); + + ret = unci_nl_exec(eeprom_tmp.cmd, dev, + &eeprom_tmp, sizeof(struct ethtool_eeprom), + data + offset, eeprom_tmp.len); + eeprom_tmp.offset += eeprom_tmp.len; + offset += eeprom_tmp.len; + remaining -= eeprom_tmp.len; + } + + return ret; +} + +static int unci_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct ethtool_eeprom *eeprom_tmp; + int ret = 0; + u32 remaining; + u32 offset = 0; + u32 payload; + + if (sizeof(struct ethtool_eeprom) > UNCI_NL_MSG_LEN) + return -1; + + eeprom_tmp = kmalloc(UNCI_NL_MSG_LEN, GFP_KERNEL); + payload = UNCI_NL_MSG_LEN - sizeof(struct ethtool_eeprom); + + *eeprom_tmp = *eeprom; + remaining = eeprom->len; + + while (remaining > 0 && ret == 0) { + eeprom_tmp->len = min(remaining, payload); + + memcpy(eeprom_tmp->data, data + offset, payload); + + ret = unci_nl_exec(eeprom->cmd, dev, eeprom, + UNCI_NL_MSG_LEN, NULL, 0); + + eeprom_tmp->offset += eeprom_tmp->len; + offset += eeprom_tmp->len; + remaining -= eeprom_tmp->len; + } + + kfree(eeprom_tmp); + + return ret; +} + +static void unci_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + unci_nl_exec(ring->cmd, dev, NULL, 0, + ring, sizeof(struct ethtool_ringparam)); +} + +static int unci_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + return unci_nl_exec(ring->cmd, dev, ring, + sizeof(struct ethtool_ringparam), NULL, 0); +} + +static void unci_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + unci_nl_exec(pause->cmd, dev, NULL, 0, + pause, sizeof(struct ethtool_pauseparam)); +} + +static int unci_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + return unci_nl_exec(pause->cmd, dev, pause, + sizeof(struct ethtool_pauseparam), NULL, 0); +} + +static u32 unci_get_msglevel(struct net_device *dev) +{ + u32 data; + int ret; + + ret = unci_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(u32)); + if (ret < 0) + return 0; + + return data; +} + +static void unci_set_msglevel(struct net_device *dev, u32 data) +{ + unci_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(u32), NULL, 0); +} + +static int unci_get_regs_len(struct net_device *dev) +{ + int data; + int ret; + + ret = unci_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int)); + if (ret < 0) + return 0; + + return data; +} + +static void unci_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct ethtool_regs regs_tmp; + u32 len = regs->len; + + regs_tmp = *regs; + + if (len > UNCI_NL_MSG_LEN) { + len = UNCI_NL_MSG_LEN; + regs_tmp.len = len; + } + + unci_nl_exec(regs->cmd, dev, ®s_tmp, sizeof(struct ethtool_regs), + p, len); +} + +static void unci_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + unci_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0); +} + +static int unci_get_sset_count(struct net_device *dev, int sset) +{ + int data; + int ret; + + ret = unci_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int), + &data, sizeof(int)); + if (ret < 0) + return 0; + + return data; +} + +static void unci_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + unci_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats), + data, stats->n_stats); +} + +static const struct ethtool_ops unci_ethtool_ops = { + .begin = unci_check_if_running, + .get_drvinfo = unci_get_drvinfo, + .get_settings = unci_get_settings, + .set_settings = unci_set_settings, + .get_regs_len = unci_get_regs_len, + .get_regs = unci_get_regs, + .get_wol = unci_get_wol, + .set_wol = unci_set_wol, + .nway_reset = unci_nway_reset, + .get_link = unci_get_link, + .get_eeprom_len = unci_get_eeprom_len, + .get_eeprom = unci_get_eeprom, + .set_eeprom = unci_set_eeprom, + .get_ringparam = unci_get_ringparam, + .set_ringparam = unci_set_ringparam, + .get_pauseparam = unci_get_pauseparam, + .set_pauseparam = unci_set_pauseparam, + .get_msglevel = unci_get_msglevel, + .set_msglevel = unci_set_msglevel, + .get_strings = unci_get_strings, + .get_sset_count = unci_get_sset_count, + .get_ethtool_stats = unci_get_ethtool_stats, +}; + +void unci_set_ethtool_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &unci_ethtool_ops; +} diff --git a/lib/librte_eal/linuxapp/unci/unci_net.c b/lib/librte_eal/linuxapp/unci/unci_net.c index 2ce337a48..e83136382 100644 --- a/lib/librte_eal/linuxapp/unci/unci_net.c +++ b/lib/librte_eal/linuxapp/unci/unci_net.c @@ -168,6 +168,8 @@ static void unci_net_setup(struct net_device *dev) unci = netdev_priv(dev); init_completion(&unci->msg_received); + + unci_set_ethtool_ops(dev); } static int unci_net_newlink(struct net *net, struct net_device *dev,