From patchwork Sat May 16 01:29:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinicius Costa Gomes X-Patchwork-Id: 219116 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CE42C433E1 for ; Sat, 16 May 2020 01:30:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 819A12076A for ; Sat, 16 May 2020 01:30:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727836AbgEPBaF (ORCPT ); Fri, 15 May 2020 21:30:05 -0400 Received: from mga18.intel.com ([134.134.136.126]:60904 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726261AbgEPBaE (ORCPT ); Fri, 15 May 2020 21:30:04 -0400 IronPort-SDR: SULQ8nwlsb6iaEVCIMwcHeoxpnMsOZSmwKctk0MTdUVioSNNOUUymGRdj2+RPVFNGM0FitgEW9 WgMtRXN+/QfQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 May 2020 18:30:02 -0700 IronPort-SDR: ubGvssz9qPtkmS1iGRCy0RUETkn5urebPSNU93/ZGaT2TN/5XwQP7LaHqQwbmxf5QVKgUjrM7O dK1DgPgRVOBQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,397,1583222400"; d="scan'208";a="307569152" Received: from wkbertra-mobl1.amr.corp.intel.com (HELO localhost.localdomain) ([10.251.131.129]) by FMSMGA003.fm.intel.com with ESMTP; 15 May 2020 18:30:01 -0700 From: Vinicius Costa Gomes To: intel-wired-lan@lists.osuosl.org Cc: Vinicius Costa Gomes , jeffrey.t.kirsher@intel.com, netdev@vger.kernel.org, vladimir.oltean@nxp.com, po.liu@nxp.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com Subject: [next-queue RFC 2/4] ethtool: Add support for configuring frame preemption via netlink Date: Fri, 15 May 2020 18:29:46 -0700 Message-Id: <20200516012948.3173993-3-vinicius.gomes@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200516012948.3173993-1-vinicius.gomes@intel.com> References: <20200516012948.3173993-1-vinicius.gomes@intel.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org ethtool is gaining support for using netlink as transport for its messages, being an alternative to ioctl() calls. Frame preemption, being new, makes a good target for being added to the list of features that are also supported via the netlink transport. Signed-off-by: Vinicius Costa Gomes --- include/uapi/linux/ethtool_netlink.h | 19 +++ net/ethtool/Makefile | 3 +- net/ethtool/netlink.c | 15 +++ net/ethtool/netlink.h | 2 + net/ethtool/preempt.c | 181 +++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 net/ethtool/preempt.c diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 2881af4..21afba1 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -40,6 +40,8 @@ enum { ETHTOOL_MSG_EEE_SET, ETHTOOL_MSG_TSINFO_GET, ETHTOOL_MSG_CABLE_TEST_ACT, + ETHTOOL_MSG_PREEMPT_GET, + ETHTOOL_MSG_PREEMPT_SET, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, @@ -76,6 +78,8 @@ enum { ETHTOOL_MSG_EEE_NTF, ETHTOOL_MSG_TSINFO_GET_REPLY, ETHTOOL_MSG_CABLE_TEST_NTF, + ETHTOOL_MSG_PREEMPT_GET_REPLY, + ETHTOOL_MSG_PREEMPT_NTF, /* add new constants above here */ __ETHTOOL_MSG_KERNEL_CNT, @@ -476,6 +480,21 @@ enum { ETHTOOL_A_CABLE_TEST_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_NTF_CNT - 1) }; +/* FRAME PREEMPTION */ +enum { + ETHTOOL_A_PREEMPT_UNSPEC, + ETHTOOL_A_PREEMPT_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_PREEMPT_SUPPORTED, /* u8 */ + ETHTOOL_A_PREEMPT_ACTIVE, /* u8 */ + ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE, /* u32 */ + ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED, /* u32 */ + ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE, /* u32 */ + + /* add new constants above here */ + __ETHTOOL_A_PREEMPT_CNT, + ETHTOOL_A_PREEMPT_MAX = (__ETHTOOL_A_PREEMPT_CNT - 1) +}; + /* generic netlink info */ #define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_VERSION 1 diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile index 0c2b94f..11661d1 100644 --- a/net/ethtool/Makefile +++ b/net/ethtool/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ linkstate.o debug.o wol.o features.o privflags.o rings.o \ - channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o + channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ + preempt.o diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 87bc02d..308653f 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -231,6 +231,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_PAUSE_GET] = ðnl_pause_request_ops, [ETHTOOL_MSG_EEE_GET] = ðnl_eee_request_ops, [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops, + [ETHTOOL_MSG_PREEMPT_GET] = ðnl_preempt_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -550,6 +551,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = { [ETHTOOL_MSG_COALESCE_NTF] = ðnl_coalesce_request_ops, [ETHTOOL_MSG_PAUSE_NTF] = ðnl_pause_request_ops, [ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops, + [ETHTOOL_MSG_PREEMPT_NTF] = ðnl_preempt_request_ops, }; /* default notification handler */ @@ -642,6 +644,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = { [ETHTOOL_MSG_COALESCE_NTF] = ethnl_default_notify, [ETHTOOL_MSG_PAUSE_NTF] = ethnl_default_notify, [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify, + [ETHTOOL_MSG_PREEMPT_NTF] = ethnl_default_notify, }; void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data) @@ -844,6 +847,18 @@ static const struct genl_ops ethtool_genl_ops[] = { .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_act_cable_test, }, + { + .cmd = ETHTOOL_MSG_PREEMPT_GET, + .doit = ethnl_default_doit, + .start = ethnl_default_start, + .dumpit = ethnl_default_dumpit, + .done = ethnl_default_done, + }, + { + .cmd = ETHTOOL_MSG_PREEMPT_SET, + .flags = GENL_UNS_ADMIN_PERM, + .doit = ethnl_set_preempt, + }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index b0eb5d9..d22dac6 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -347,6 +347,7 @@ extern const struct ethnl_request_ops ethnl_coalesce_request_ops; extern const struct ethnl_request_ops ethnl_pause_request_ops; extern const struct ethnl_request_ops ethnl_eee_request_ops; extern const struct ethnl_request_ops ethnl_tsinfo_request_ops; +extern const struct ethnl_request_ops ethnl_preempt_request_ops; int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); @@ -360,5 +361,6 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info); int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info); int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info); int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); +int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info); #endif /* _NET_ETHTOOL_NETLINK_H */ diff --git a/net/ethtool/preempt.c b/net/ethtool/preempt.c new file mode 100644 index 0000000..9c8df6f --- /dev/null +++ b/net/ethtool/preempt.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "netlink.h" +#include "common.h" + +struct preempt_req_info { + struct ethnl_req_info base; +}; + +struct preempt_reply_data { + struct ethnl_reply_data base; + struct ethtool_fp fp; +}; + +#define PREEMPT_REPDATA(__reply_base) \ + container_of(__reply_base, struct preempt_reply_data, base) + +static const struct nla_policy +preempt_get_policy[ETHTOOL_A_PREEMPT_MAX + 1] = { + [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED }, + [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_REJECT }, +}; + +static int preempt_prepare_data(const struct ethnl_req_info *req_base, + struct ethnl_reply_data *reply_base, + struct genl_info *info) +{ + struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base); + struct net_device *dev = reply_base->dev; + int ret; + + if (!dev->ethtool_ops->get_preempt) + return -EOPNOTSUPP; + + ret = ethnl_ops_begin(dev); + if (ret < 0) + return ret; + + ret = dev->ethtool_ops->get_preempt(dev, &data->fp); + ethnl_ops_complete(dev); + + return ret; +} + +static int preempt_reply_size(const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + int len = 0; + + len += nla_total_size(sizeof(u8)); /* _PREEMPT_SUPPORTED */ + len += nla_total_size(sizeof(u8)); /* _PREEMPT_ACTIVE */ + len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_SUPPORTED */ + len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_PREEMPTIBLE */ + len += nla_total_size(sizeof(u32)); /* _PREEMPT_MIN_FRAG_SIZE */ + + return len; +} + +static int preempt_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + const struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base); + const struct ethtool_fp *preempt = &data->fp; + + if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED, + preempt->supported_queues_mask)) + return -EMSGSIZE; + + if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE, + preempt->preemptible_queues_mask)) + return -EMSGSIZE; + + if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_ACTIVE, preempt->fp_enabled)) + return -EMSGSIZE; + + if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_SUPPORTED, + preempt->fp_supported)) + return -EMSGSIZE; + + if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE, + preempt->min_frag_size)) + return -EMSGSIZE; + + return 0; +} + +const struct ethnl_request_ops ethnl_preempt_request_ops = { + .request_cmd = ETHTOOL_MSG_PREEMPT_GET, + .reply_cmd = ETHTOOL_MSG_PREEMPT_GET_REPLY, + .hdr_attr = ETHTOOL_A_PREEMPT_HEADER, + .max_attr = ETHTOOL_A_PREEMPT_MAX, + .req_info_size = sizeof(struct preempt_req_info), + .reply_data_size = sizeof(struct preempt_reply_data), + .request_policy = preempt_get_policy, + + .prepare_data = preempt_prepare_data, + .reply_size = preempt_reply_size, + .fill_reply = preempt_fill_reply, +}; + +static const struct nla_policy +preempt_set_policy[ETHTOOL_A_PREEMPT_MAX + 1] = { + [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED }, + [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_U8 }, + [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_U32 }, + [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT }, + [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_U32 }, +}; + +int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1]; + struct ethtool_fp preempt = {}; + struct ethnl_req_info req_info = {}; + struct net_device *dev; + bool mod = false; + int ret; + + ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, + ETHTOOL_A_PREEMPT_MAX, preempt_set_policy, + info->extack); + if (ret < 0) + return ret; + + ret = ethnl_parse_header_dev_get(&req_info, + tb[ETHTOOL_A_PREEMPT_HEADER], + genl_info_net(info), info->extack, + true); + if (ret < 0) + return ret; + dev = req_info.dev; + ret = -EOPNOTSUPP; + if (!dev->ethtool_ops->get_preempt || + !dev->ethtool_ops->set_preempt) + goto out_dev; + + rtnl_lock(); + ret = ethnl_ops_begin(dev); + if (ret < 0) + goto out_rtnl; + + ret = dev->ethtool_ops->get_preempt(dev, &preempt); + if (ret < 0) { + if (info) + GENL_SET_ERR_MSG(info, "failed to retrieve frame preemption settings"); + goto out_ops; + } + + ethnl_update_u8(&preempt.fp_enabled, + tb[ETHTOOL_A_PREEMPT_ACTIVE], &mod); + ethnl_update_u32(&preempt.min_frag_size, + tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE], &mod); + ethnl_update_u32(&preempt.preemptible_queues_mask, + tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE], &mod); + + ret = 0; + if (!mod) + goto out_ops; + + ret = dev->ethtool_ops->set_preempt(dev, &preempt); + if (ret < 0) + GENL_SET_ERR_MSG(info, "frame preemption settings update failed"); + else + ethtool_notify(dev, ETHTOOL_MSG_PREEMPT_NTF, NULL); + +out_ops: + ethnl_ops_complete(dev); +out_rtnl: + rtnl_unlock(); +out_dev: + dev_put(dev); + return ret; +} From patchwork Sat May 16 01:29:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinicius Costa Gomes X-Patchwork-Id: 219115 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5503CC433DF for ; Sat, 16 May 2020 01:30:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 391DA20756 for ; Sat, 16 May 2020 01:30:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727847AbgEPBaG (ORCPT ); Fri, 15 May 2020 21:30:06 -0400 Received: from mga18.intel.com ([134.134.136.126]:60902 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727768AbgEPBaD (ORCPT ); Fri, 15 May 2020 21:30:03 -0400 IronPort-SDR: luYyEnzAq2NsBflOaYZCRr9Nskun4lo6Sa6B6dLxXcWmn5D9isimbkNuYNFEi6wU+ihQyf3diU uutnFzTf3RKQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 May 2020 18:30:02 -0700 IronPort-SDR: Dr1MVGAADYj10JA/nSbB+WQzcOH/8riix7vvHPIusm2lehVYcar6t22/z+UvVGkcoVAUkIf/Y0 TxmfxB0+eeXg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,397,1583222400"; d="scan'208";a="307569171" Received: from wkbertra-mobl1.amr.corp.intel.com (HELO localhost.localdomain) ([10.251.131.129]) by FMSMGA003.fm.intel.com with ESMTP; 15 May 2020 18:30:02 -0700 From: Vinicius Costa Gomes To: intel-wired-lan@lists.osuosl.org Cc: Vinicius Costa Gomes , jeffrey.t.kirsher@intel.com, netdev@vger.kernel.org, vladimir.oltean@nxp.com, po.liu@nxp.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com Subject: [next-queue RFC 3/4] igc: Add support for configuring frame preemption Date: Fri, 15 May 2020 18:29:47 -0700 Message-Id: <20200516012948.3173993-4-vinicius.gomes@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200516012948.3173993-1-vinicius.gomes@intel.com> References: <20200516012948.3173993-1-vinicius.gomes@intel.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org WIP Signed-off-by: Vinicius Costa Gomes --- drivers/net/ethernet/intel/igc/igc.h | 3 + drivers/net/ethernet/intel/igc/igc_defines.h | 6 ++ drivers/net/ethernet/intel/igc/igc_ethtool.c | 68 ++++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_tsn.c | 46 +++++++++++-- 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 5dbc5a1..963ac98 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -87,6 +87,7 @@ struct igc_ring { u8 queue_index; /* logical index of the ring*/ u8 reg_idx; /* physical index of the ring */ bool launchtime_enable; /* true if LaunchTime is enabled */ + bool preemptible; /* true if not express */ u32 start_time; u32 end_time; @@ -162,6 +163,8 @@ struct igc_adapter { ktime_t base_time; ktime_t cycle_time; + bool frame_preemption_active; + u32 min_frag_size; /* Frame preemption minimum fragment size */ /* OS defined structs */ struct pci_dev *pdev; diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 80b664e..fa823c3 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -364,6 +364,8 @@ #define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */ #define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */ +#define IGC_RXPBSIZE_TSN 0x00010090 /* 16KB for EXP + 16KB for BE + 2KB for BMC */ +#define IGC_RXPBSIZE_SIZE_MASK 0x0001FFFF #define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */ #define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */ @@ -422,10 +424,14 @@ /* Transmit Scheduling */ #define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001 #define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008 +#define IGC_TQAVCTRL_PREEMPT_ENA 0x00000002 +#define IGC_TQAVCTRL_MIN_FRAG_MASK 0x0000C000 +#define IGC_TQAVCTRL_MIN_FRAG_SHIFT 14 #define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001 #define IGC_TXQCTL_STRICT_CYCLE 0x00000002 #define IGC_TXQCTL_STRICT_END 0x00000004 +#define IGC_TXQCTL_PREEMPTABLE 0x00000008 /* Receive Checksum Control */ #define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 2214a5d..48d5d18 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -7,6 +7,7 @@ #include "igc.h" #include "igc_diag.h" +#include "igc_tsn.h" /* forward declaration */ struct igc_stats { @@ -1549,6 +1550,71 @@ static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags) return 0; } +static int igc_ethtool_get_preempt(struct net_device *netdev, + struct ethtool_fp *fpcmd) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + int i; + + fpcmd->fp_supported = 1; + fpcmd->fp_enabled = adapter->frame_preemption_active; + fpcmd->min_frag_size = adapter->min_frag_size; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *ring = adapter->tx_ring[i]; + + fpcmd->supported_queues_mask |= BIT(i); + + if (ring->preemptible) + fpcmd->preemptible_queues_mask |= BIT(i); + } + + return 0; +} + +static int igc_ethtool_set_preempt(struct net_device *netdev, + struct ethtool_fp *fpcmd) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + int i; + + /* The formula is (Section 8.12.4 of the datasheet): + * MIN_FRAG_SIZE = 4 + (1 + MIN_FRAG)*64 + * MIN_FRAG is represented by two bits, so we can only have + * min_frag_size between 68 and 260. + */ + if (fpcmd->min_frag_size < 68 || fpcmd->min_frag_size > 260) + return -EINVAL; + + fpcmd->fp_supported = 1; + + adapter->frame_preemption_active = fpcmd->fp_enabled; + adapter->min_frag_size = fpcmd->min_frag_size; + + /* We need to setup a dummy Qbv cycle for frame preemption to + * work, but we only need to set it up if none is set. This + * same check below exists for the same purpose. + */ + if (!adapter->base_time) + adapter->cycle_time = NSEC_PER_SEC; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *ring = adapter->tx_ring[i]; + bool preemptible = fpcmd->preemptible_queues_mask & BIT(i); + + fpcmd->fp_supported |= BIT(i); + ring->preemptible = preemptible; + + if (adapter->base_time) + continue; + + ring->start_time = 0; + ring->end_time = NSEC_PER_SEC; + } + + return igc_tsn_offload_apply(adapter); +} + static int igc_ethtool_begin(struct net_device *netdev) { struct igc_adapter *adapter = netdev_priv(netdev); @@ -1828,6 +1894,8 @@ static const struct ethtool_ops igc_ethtool_ops = { .get_ts_info = igc_ethtool_get_ts_info, .get_channels = igc_ethtool_get_channels, .set_channels = igc_ethtool_set_channels, + .get_preempt = igc_ethtool_get_preempt, + .set_preempt = igc_ethtool_set_preempt, .get_priv_flags = igc_ethtool_get_priv_flags, .set_priv_flags = igc_ethtool_set_priv_flags, .begin = igc_ethtool_begin, diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c index 174103c..1bebe1c 100644 --- a/drivers/net/ethernet/intel/igc/igc_tsn.c +++ b/drivers/net/ethernet/intel/igc/igc_tsn.c @@ -18,26 +18,45 @@ static bool is_any_launchtime(struct igc_adapter *adapter) return false; } +static u32 igc_min_frag_size_to_tqavctrl(u32 min_frag) +{ + u32 tqavctrl; + + tqavctrl = DIV_ROUND_UP((min_frag - 4), 64); + tqavctrl -= 1; + + tqavctrl <<= IGC_TQAVCTRL_MIN_FRAG_SHIFT; + + return tqavctrl; +} + /* Returns the TSN specific registers to their default values after * TSN offloading is disabled. */ static int igc_tsn_disable_offload(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; - u32 tqavctrl; + u32 tqavctrl, rxpbs; int i; if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED)) return 0; adapter->cycle_time = 0; + adapter->frame_preemption_active = false; + adapter->min_frag_size = 68; wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT); + rxpbs = rd32(IGC_RXPBS) & ~IGC_RXPBSIZE_SIZE_MASK; + rxpbs |= I225_RXPBSIZE_DEFAULT; + + wr32(IGC_RXPBS, rxpbs); + tqavctrl = rd32(IGC_TQAVCTRL); tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN | - IGC_TQAVCTRL_ENHANCED_QAV); + IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_PREEMPT_ENA); wr32(IGC_TQAVCTRL, tqavctrl); for (i = 0; i < adapter->num_tx_queues; i++) { @@ -46,6 +65,7 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter) ring->start_time = 0; ring->end_time = 0; ring->launchtime_enable = false; + ring->preemptible = false; wr32(IGC_TXQCTL(i), 0); wr32(IGC_STQT(i), 0); @@ -64,7 +84,7 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; u32 tqavctrl, baset_l, baset_h; - u32 sec, nsec, cycle; + u32 sec, nsec, cycle, rxpbs; ktime_t base_time, systim; int i; @@ -78,8 +98,20 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN); wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN); - tqavctrl = rd32(IGC_TQAVCTRL); + rxpbs = rd32(IGC_RXPBS) & ~IGC_RXPBSIZE_SIZE_MASK; + rxpbs |= IGC_RXPBSIZE_TSN; + + wr32(IGC_RXPBS, rxpbs); + + tqavctrl = rd32(IGC_TQAVCTRL) & + ~(IGC_TQAVCTRL_MIN_FRAG_MASK | IGC_TQAVCTRL_PREEMPT_ENA); tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; + + if (adapter->frame_preemption_active) + tqavctrl |= IGC_TQAVCTRL_PREEMPT_ENA; + + tqavctrl |= igc_min_frag_size_to_tqavctrl(adapter->min_frag_size); + wr32(IGC_TQAVCTRL, tqavctrl); wr32(IGC_QBVCYCLET_S, cycle); @@ -105,6 +137,9 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) if (ring->launchtime_enable) txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT; + if (ring->preemptible) + txqctl |= IGC_TXQCTL_PREEMPTABLE; + wr32(IGC_TXQCTL(i), txqctl); } @@ -132,7 +167,8 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) int igc_tsn_offload_apply(struct igc_adapter *adapter) { - bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter); + bool is_any_enabled = adapter->base_time || + is_any_launchtime(adapter) || adapter->frame_preemption_active; if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled) return 0;