From nobody Fri Sep 25 16:01:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E3B1C56C62C; Thu, 10 Sep 2026 18:09:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063773; cv=none; b=oYJoLJ83DnU0mdtwq8fa/C+uqFjNjH+rH3DGrwwfMIVfKGBVvzHcztB5fvQvUk89gd1haDhc+9k9DXJUWsfVD8IyzsWT46RIGpD9flGju+F9L8Tn+GMdcPHVBgSO85ejd9lvkLH7z9yl7ATbhlMnWbKTlmj3qXZEfMjF/Fe6iNQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063773; c=relaxed/simple; bh=Tfuw52YtaaBXZqgBSMLMoP4m9l9L0XwnDIp4xCS3rxM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NQQsSlkAH8C4kBRo8yzhQjQMeTMk4WMSjMQjxWbRvsat5X5oDEIEYnm1xVnztnh70qXYOEBeeXH5Cf+TT38vNCpzL0pCvJ1TUS26Li14JqBjgZ1+74UQoHnPw3LpG2JWDAd6n624n/ZXtnpW39hR22BsKyH01cGW/Ds2rVG6U9o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=npZH4chh; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="npZH4chh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B265C1F00893; Thu, 10 Sep 2026 18:09:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789063765; bh=XlwruAm6gWUToleBgBzypJygbCkpGPiNpwcXKoUZ3j0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=npZH4chhZ5WsZjoyg1RU6vzfevAlijWicz+nxbcZJbvD0WQBaYEUbkw46gkTCCuGd LyYPZ1y/44a1r/xnN9kawBZpjE+vO3Fynhr9RN0kPjhbWNzES5EPOPr+NfGI9+yx3/ VC6pbTK2mqEpVsH5VyeNoNWeSNXTN2m/KCoR4TlUYBnlsFqGn1jVcqxLfusp1jy4PR 5pTQJ/J3VPlQUcEWwS9fPwx20qmsfniRrzaCbUu6o7HsjDX9ERhNeM2wLJOVZ1jTu9 0MSpvi0ORCs2CJNDfsvBSqIs+le2NF6iTGWRNH9VTnEm1EUtu1QQJ1ptf7FEaWTnsP 3gf2hchnx0FRw== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Shuah Khan , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Daniel Borkmann Cc: "Mike Marciniszyn (Meta)" , Mohsin Bashir , Stanislav Fomichev , Bobby Eshleman , Dimitri Daskalakis , Weiming Shi , Maxime Chevallier , Jacob Keller , Breno Leitao , Tao Cui , Pavel Begunkov , David Wei , =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Subject: [PATCH net-next v2 1/5] net: Add netdev_config helpers Date: Thu, 10 Sep 2026 20:09:01 +0200 Message-ID: <20260910180908.1506533-2-bjorn@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260910180908.1506533-1-bjorn@kernel.org> References: <20260910180908.1506533-1-bjorn@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Jakub Kicinski netdev_config manipulation will become slightly more complicated soon and will be used by both ethtool and the queue API. Encapsulate the logic in helper functions. Signed-off-by: Jakub Kicinski Signed-off-by: Bj=C3=B6rn T=C3=B6pel Reviewed-by: Breno Leitao --- net/core/dev.c | 7 ++----- net/core/dev.h | 5 +++++ net/core/netdev_config.c | 37 +++++++++++++++++++++++++++++++++++++ net/ethtool/netlink.c | 15 +++++++-------- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 290e0f099e6b..4a7c5a5e48e5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -12195,10 +12195,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_pri= v, const char *name, if (!dev->ethtool) goto free_all; =20 - dev->cfg =3D kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT); - if (!dev->cfg) + if (netdev_alloc_config(dev)) goto free_all; - dev->cfg_pending =3D dev->cfg; =20 dev->num_napi_configs =3D maxqs; napi_config_sz =3D array_size(maxqs, sizeof(*dev->napi_config)); @@ -12270,8 +12268,7 @@ void free_netdev(struct net_device *dev) return; } =20 - WARN_ON(dev->cfg !=3D dev->cfg_pending); - kfree(dev->cfg); + netdev_free_config(dev); kfree(dev->ethtool); netif_free_tx_queues(dev); netif_free_rx_queues(dev); diff --git a/net/core/dev.h b/net/core/dev.h index b757faead4d1..4b52ff779cba 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -102,6 +102,11 @@ extern struct rw_semaphore dev_addr_sem; extern struct list_head net_todo_list; void netdev_run_todo(void); =20 +int netdev_alloc_config(struct net_device *dev); +void __netdev_free_config(struct netdev_config *cfg); +void netdev_free_config(struct net_device *dev); +int netdev_reconfig_start(struct net_device *dev); + int netdev_queue_config_validate(struct net_device *dev, int rxq_idx, struct netdev_queue_config *qcfg, struct netlink_ext_ack *extack); diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c index f14af365d5cd..b101341e3251 100644 --- a/net/core/netdev_config.c +++ b/net/core/netdev_config.c @@ -6,6 +6,43 @@ =20 #include "dev.h" =20 +int netdev_alloc_config(struct net_device *dev) +{ + struct netdev_config *cfg; + + cfg =3D kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT); + if (!cfg) + return -ENOMEM; + + dev->cfg =3D cfg; + dev->cfg_pending =3D cfg; + return 0; +} + +void __netdev_free_config(struct netdev_config *cfg) +{ + kfree(cfg); +} + +void netdev_free_config(struct net_device *dev) +{ + WARN_ON(dev->cfg !=3D dev->cfg_pending); + __netdev_free_config(dev->cfg); +} + +int netdev_reconfig_start(struct net_device *dev) +{ + struct netdev_config *cfg; + + WARN_ON(dev->cfg !=3D dev->cfg_pending); + cfg =3D kmemdup(dev->cfg, sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT); + if (!cfg) + return -ENOMEM; + + dev->cfg_pending =3D cfg; + return 0; +} + static int netdev_nop_validate_qcfg(struct net_device *dev, struct netdev_queue_config *qcfg, struct netlink_ext_ack *extack) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 1af395b54330..383e911f50f7 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -11,6 +11,8 @@ #include "module_fw.h" #include "netlink.h" =20 +#include "../core/dev.h" + static struct genl_family ethtool_genl_family; =20 static bool ethnl_ok __read_mostly; @@ -934,12 +936,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb,= struct genl_info *info) if (need_rtnl) rtnl_lock(); netdev_lock_ops(dev); - dev->cfg_pending =3D kmemdup(dev->cfg, sizeof(*dev->cfg), - GFP_KERNEL_ACCOUNT); - if (!dev->cfg_pending) { - ret =3D -ENOMEM; - goto out_tie_cfg; - } + ret =3D netdev_reconfig_start(dev); + if (ret) + goto out_unlock; =20 ret =3D ethnl_ops_begin(dev); if (ret < 0) @@ -958,9 +957,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, = struct genl_info *info) out_ops: ethnl_ops_complete(dev); out_free_cfg: - kfree(dev->cfg_pending); -out_tie_cfg: + __netdev_free_config(dev->cfg_pending); dev->cfg_pending =3D dev->cfg; +out_unlock: netdev_unlock_ops(dev); if (need_rtnl) rtnl_unlock(); --=20 2.55.0 From nobody Fri Sep 25 16:01:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44F50576EC1; Thu, 10 Sep 2026 18:09:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063778; cv=none; b=RKv+7lcl4Ix8iHa/UgAa6KDXfHLHin9NCM95OrrRTmcXrYQ1WdFOn64oSGIMhLDXmIWaMzFoJG6Algx7rTWIT9sikB/0MFz/2epehuaDB+GMRU7zQK2HTNQIi7VAcfU+ly9P5csPMa1d4VJeurvF4OxVj52pu5uCZWsKYRy4KJg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063778; c=relaxed/simple; bh=AGgu+ENKrVSJPA71RPTaLquFuD/X0E+DiCFuD79O070=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XsD0JxXQbxj2NcMpubRZf2GVO0ruZ4aT847Gq7hepBnRbN2jCyKX8xw8w7u5Zx8dkr7j9ebnh7l0zlr9zsRh9Wlz75c/ba8bnpDq1raJY3zQqJLQIxisVHCwWUHJryAQ0XfV6TZmA/+3Q2/V7l1rpv/BAThoo1kqBOVPCAzI20w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bXYgbIIq; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bXYgbIIq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 535441F000FF; Thu, 10 Sep 2026 18:09:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789063771; bh=twSaqNEMy/6zpzMysTkC1f1SYwon9nWhNFj4Yb50QhA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=bXYgbIIqQHgPk8mmAEow8Vq4mE8ZerFjluVqgwnL3Zd/hOeXZ9hYyCdR/7WR4rSQn h3cu12Vs0TayuB8EOD+lFzYGU544Ch+SySjebMNDRCYtdGnO3dnX9qXyyTmCw7R4Kg kgcjdt4dN3OByzEazn928xl9ceJdwF98n0WlxeQxSNhE+clgz6nymP3HhPz12NwgRe rZ/7ZZTDMJo2Q8BemTu3RnUmtpSQ7jRoilr5LH6ukD9p/tt35iXQQuJovsTW5qP33k QUA0rPgZbnvYUbilxyxMfUf0jrX1srkGuvFS0xRjseLj5RUqVaRVeNYSrnmR/dWDuZ is5i2fy+OE0tA== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Shuah Khan , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Daniel Borkmann Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , "Mike Marciniszyn (Meta)" , Mohsin Bashir , Stanislav Fomichev , Bobby Eshleman , Dimitri Daskalakis , Weiming Shi , Maxime Chevallier , Jacob Keller , Breno Leitao , Tao Cui , Pavel Begunkov , David Wei Subject: [PATCH net-next v2 2/5] fbnic: Track BDQ device-page geometry per ring Date: Thu, 10 Sep 2026 20:09:02 +0200 Message-ID: <20260910180908.1506533-3-bjorn@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260910180908.1506533-1-bjorn@kernel.org> References: <20260910180908.1506533-1-bjorn@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable fbnic derives the BDQ buffer layout from PAGE_SIZE. That decides at build time how a posted page is split into 4 KiB device pages, and uses the same completion decoding for HPQ and PPQ. That is wrong once the queues use different posted-page sizes; completions must be decoded with the geometry of the queue that produced them. Keep PAGE_SIZE as the posted-page size for both queues in this change, so the descriptor format and runtime behavior stay unchanged. Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 34 ++------ .../net/ethernet/meta/fbnic/fbnic_debugfs.c | 5 +- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 83 ++++++++++++------- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 6 ++ 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethe= rnet/meta/fbnic/fbnic_csr.h index 64b958df7774..2b9f8644b132 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -109,34 +109,19 @@ enum { =20 /* Rx Buffer Descriptor Format * - * The layout of this can vary depending on the page size of the system. + * Buffer descriptors describe 4 KiB device pages. A posted page larger th= an + * 4 KiB is represented by consecutive device-page descriptors. * - * If the page size is 4K then the layout will simply consist of ID for - * the 16 most significant bits, and the lower 46 are essentially the page - * address with the lowest 12 bits being reserved 0 due to the fact that - * a page will be aligned. - * - * If the page size is larger than 4K then the lower n bits of the ID and - * page address will be reserved for the fragment ID. This fragment will - * be 4K in size and will be used to index both the DMA address and the ID - * by the same amount. + * The address field stores the 4 KiB-aligned DMA address. The ID field st= ores + * the software page ID, with the low n bits used as the device-page ID wh= en a + * posted page spans multiple device pages. The driver increments both the + * address and ID by one device page for each descriptor belonging to a po= sted + * page. */ #define FBNIC_BD_DESC_ADDR_MASK DESC_GENMASK(45, 12) #define FBNIC_BD_DESC_ID_MASK DESC_GENMASK(63, 48) -#define FBNIC_BD_FRAG_SIZE \ +#define FBNIC_BD_PAGE_SIZE \ (FBNIC_BD_DESC_ADDR_MASK & ~(FBNIC_BD_DESC_ADDR_MASK - 1)) -#define FBNIC_BD_FRAG_COUNT \ - (PAGE_SIZE / FBNIC_BD_FRAG_SIZE) -#define FBNIC_BD_FRAG_ADDR_MASK \ - (FBNIC_BD_DESC_ADDR_MASK & \ - ~(FBNIC_BD_DESC_ADDR_MASK * FBNIC_BD_FRAG_COUNT)) -#define FBNIC_BD_FRAG_ID_MASK \ - (FBNIC_BD_DESC_ID_MASK & \ - ~(FBNIC_BD_DESC_ID_MASK * FBNIC_BD_FRAG_COUNT)) -#define FBNIC_BD_PAGE_ADDR_MASK \ - (FBNIC_BD_DESC_ADDR_MASK & ~FBNIC_BD_FRAG_ADDR_MASK) -#define FBNIC_BD_PAGE_ID_MASK \ - (FBNIC_BD_DESC_ID_MASK & ~FBNIC_BD_FRAG_ID_MASK) =20 /* Rx Completion Queue Descriptors */ #define FBNIC_RCD_TYPE_MASK DESC_GENMASK(62, 61) @@ -151,9 +136,6 @@ enum { =20 /* Address/Length Completion Descriptors */ #define FBNIC_RCD_AL_BUFF_ID_MASK DESC_GENMASK(15, 0) -#define FBNIC_RCD_AL_BUFF_FRAG_MASK (FBNIC_BD_FRAG_COUNT - 1) -#define FBNIC_RCD_AL_BUFF_PAGE_MASK \ - (FBNIC_RCD_AL_BUFF_ID_MASK & ~FBNIC_RCD_AL_BUFF_FRAG_MASK) #define FBNIC_RCD_AL_BUFF_LEN_MASK DESC_GENMASK(28, 16) #define FBNIC_RCD_AL_BUFF_OFF_MASK DESC_GENMASK(43, 32) #define FBNIC_RCD_AL_PAGE_FIN DESC_BIT(60) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/= ethernet/meta/fbnic/fbnic_debugfs.c index 3c4563c8f403..7f23a0f97e63 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c @@ -181,8 +181,8 @@ static int fbnic_dbg_tcq_desc_seq_show(struct seq_file = *s, void *v) static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v) { struct fbnic_ring *ring =3D s->private; + unsigned int i, desc_count; char hdr[80]; - int i; =20 /* Generate header on first entry */ fbnic_dbg_ring_show(s); @@ -197,7 +197,8 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file = *s, void *v) return 0; } =20 - for (i =3D 0; i < (ring->size_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) { + desc_count =3D (ring->size_mask + 1) * fbnic_bd_page_count(ring); + for (i =3D 0; i < desc_count; i++) { u64 bd =3D le64_to_cpu(ring->desc[i]); =20 seq_printf(s, "%04x %#04llx %#014llx\n", i, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/eth= ernet/meta/fbnic/fbnic_txrx.c index 401f8b8ae1ca..28b962307c08 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -871,19 +871,31 @@ static void fbnic_clean_bdq(struct fbnic_ring *ring, = unsigned int hw_head, ring->head =3D head; } =20 +static u16 fbnic_rcd_bd_idx(const struct fbnic_ring *bdq, u64 rcd) +{ + return FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd) >> bdq->bd_page_shift; +} + +static unsigned int fbnic_rcd_bd_page_offset(const struct fbnic_ring *bdq, + u64 rcd) +{ + u16 id =3D FIELD_GET(FBNIC_RCD_AL_BUFF_ID_MASK, rcd); + u16 page_id =3D id & (fbnic_bd_page_count(bdq) - 1); + + return page_id * FBNIC_BD_PAGE_SIZE; +} + static void fbnic_bd_prep(struct fbnic_ring *bdq, u16 id, netmem_ref netme= m) { - __le64 *bdq_desc =3D &bdq->desc[id * FBNIC_BD_FRAG_COUNT]; + __le64 *bdq_desc =3D &bdq->desc[id * fbnic_bd_page_count(bdq)]; dma_addr_t dma =3D page_pool_get_dma_addr_netmem(netmem); - u64 bd, i =3D FBNIC_BD_FRAG_COUNT; + u64 bd, i =3D fbnic_bd_page_count(bdq); =20 - bd =3D (FBNIC_BD_PAGE_ADDR_MASK & dma) | - FIELD_PREP(FBNIC_BD_PAGE_ID_MASK, id); + bd =3D (FBNIC_BD_DESC_ADDR_MASK & dma) | + FIELD_PREP(FBNIC_BD_DESC_ID_MASK, (u64)id << bdq->bd_page_shift); =20 - /* In the case that a page size is larger than 4K we will map a - * single page to multiple fragments. The fragments will be - * FBNIC_BD_FRAG_COUNT in size and the lower n bits will be use - * to indicate the individual fragment IDs. + /* Posted pages larger than 4 KiB use consecutive device-page IDs in + * the low bits of the software page ID. */ do { *bdq_desc =3D cpu_to_le64(bd); @@ -928,7 +940,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq) /* Force DMA writes to flush before writing to tail */ dma_wmb(); =20 - writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell); + writel(i * fbnic_bd_page_count(bdq), bdq->doorbell); } } =20 @@ -959,26 +971,27 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vecto= r *nv, u64 rcd, struct fbnic_pkt_buff *pkt, struct fbnic_q_triad *qt) { - unsigned int hdr_pg_idx =3D FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd); unsigned int hdr_pg_off =3D FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd); - struct page *page =3D fbnic_page_pool_get_head(qt, hdr_pg_idx); unsigned int len =3D FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd); + unsigned int hdr_pg_idx =3D fbnic_rcd_bd_idx(&qt->sub0, rcd); unsigned int frame_sz, hdr_pg_start, hdr_pg_end, headroom; unsigned char *hdr_start; + struct page *page; =20 /* data_hard_start should always be NULL when this is called */ WARN_ON_ONCE(pkt->buff.data_hard_start); =20 + page =3D fbnic_page_pool_get_head(qt, hdr_pg_idx); + /* Short-cut the end calculation if we know page is fully consumed */ hdr_pg_end =3D FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ? - FBNIC_BD_FRAG_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len); + FBNIC_BD_PAGE_SIZE : fbnic_hdr_pg_end(hdr_pg_off, len); hdr_pg_start =3D fbnic_hdr_pg_start(hdr_pg_off); =20 headroom =3D hdr_pg_off - hdr_pg_start + FBNIC_RX_PAD; frame_sz =3D hdr_pg_end - hdr_pg_start; xdp_init_buff(&pkt->buff, frame_sz, &qt->xdp_rxq); - hdr_pg_start +=3D (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) * - FBNIC_BD_FRAG_SIZE; + hdr_pg_start +=3D fbnic_rcd_bd_page_offset(&qt->sub0, rcd); =20 /* Sync DMA buffer */ dma_sync_single_range_for_cpu(nv->dev, page_pool_get_dma_addr(page), @@ -999,18 +1012,19 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vect= or *nv, u64 rcd, struct fbnic_pkt_buff *pkt, struct fbnic_q_triad *qt) { - unsigned int pg_idx =3D FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd); unsigned int pg_off =3D FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd); unsigned int len =3D FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd); - netmem_ref netmem =3D fbnic_page_pool_get_data(qt, pg_idx); + unsigned int pg_idx =3D fbnic_rcd_bd_idx(&qt->sub1, rcd); unsigned int truesize; + netmem_ref netmem; bool added; =20 - truesize =3D FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ? - FBNIC_BD_FRAG_SIZE - pg_off : ALIGN(len, 128); + netmem =3D fbnic_page_pool_get_data(qt, pg_idx); =20 - pg_off +=3D (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) * - FBNIC_BD_FRAG_SIZE; + truesize =3D FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ? + FBNIC_BD_PAGE_SIZE - pg_off : ALIGN(len, 128); + + pg_off +=3D fbnic_rcd_bd_page_offset(&qt->sub1, rcd); =20 /* Sync DMA buffer */ page_pool_dma_sync_netmem_for_cpu(qt->sub1.page_pool, netmem, @@ -1257,12 +1271,12 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector= *nv, =20 switch (FIELD_GET(FBNIC_RCD_TYPE_MASK, rcd)) { case FBNIC_RCD_TYPE_HDR_AL: - head0 =3D FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd); + head0 =3D fbnic_rcd_bd_idx(&qt->sub0, rcd); fbnic_pkt_prepare(nv, rcd, pkt, qt); =20 break; case FBNIC_RCD_TYPE_PAY_AL: - head1 =3D FIELD_GET(FBNIC_RCD_AL_BUFF_PAGE_MASK, rcd); + head1 =3D fbnic_rcd_bd_idx(&qt->sub1, rcd); fbnic_add_rx_frag(nv, rcd, pkt, qt); =20 break; @@ -1603,6 +1617,16 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, str= uct fbnic_q_triad *qt, return PTR_ERR(pp); } =20 +static u8 fbnic_bdq_page_shift(u32 page_size) +{ + return ilog2(page_size / FBNIC_BD_PAGE_SIZE); +} + +static void fbnic_bdq_set_page_size(struct fbnic_ring *bdq, u32 page_size) +{ + bdq->bd_page_shift =3D fbnic_bdq_page_shift(page_size); +} + static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell, int q_idx, u8 flags) { @@ -1610,6 +1634,7 @@ static void fbnic_ring_init(struct fbnic_ring *ring, = u32 __iomem *doorbell, ring->doorbell =3D doorbell; ring->q_idx =3D q_idx; ring->flags =3D flags; + fbnic_bdq_set_page_size(ring, PAGE_SIZE); ring->deferred_head =3D -1; } =20 @@ -1894,12 +1919,12 @@ static int fbnic_alloc_rx_ring_desc(struct fbnic_ne= t *fbn, =20 switch (rxr->doorbell - fbnic_ring_csr_base(rxr)) { case FBNIC_QUEUE_BDQ_HPQ_TAIL: - rxq_size =3D fbn->hpq_size / FBNIC_BD_FRAG_COUNT; - desc_size *=3D FBNIC_BD_FRAG_COUNT; + rxq_size =3D fbn->hpq_size / fbnic_bd_page_count(rxr); + desc_size *=3D fbnic_bd_page_count(rxr); break; case FBNIC_QUEUE_BDQ_PPQ_TAIL: - rxq_size =3D fbn->ppq_size / FBNIC_BD_FRAG_COUNT; - desc_size *=3D FBNIC_BD_FRAG_COUNT; + rxq_size =3D fbn->ppq_size / fbnic_bd_page_count(rxr); + desc_size *=3D fbnic_bd_page_count(rxr); break; case FBNIC_QUEUE_RCQ_HEAD: rxq_size =3D fbn->rcq_size; @@ -2565,7 +2590,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, = struct fbnic_ring *ppq) hpq->tail =3D 0; hpq->head =3D 0; =20 - log_size =3D fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT); + log_size =3D fls(hpq->size_mask) + hpq->bd_page_shift; =20 /* Store descriptor ring address and size */ fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma)); @@ -2577,7 +2602,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, = struct fbnic_ring *ppq) if (!ppq->size_mask) goto write_ctl; =20 - log_size =3D fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT); + log_size =3D fls(ppq->size_mask) + ppq->bd_page_shift; =20 /* Add enabling of PPQ to BDQ control */ bdq_ctl |=3D FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE; @@ -2846,8 +2871,10 @@ static int fbnic_queue_mem_alloc(struct net_device *= dev, =20 fbnic_ring_init(&qt->sub0, real->sub0.doorbell, real->sub0.q_idx, real->sub0.flags); + qt->sub0.bd_page_shift =3D real->sub0.bd_page_shift; fbnic_ring_init(&qt->sub1, real->sub1.doorbell, real->sub1.q_idx, real->sub1.flags); + qt->sub1.bd_page_shift =3D real->sub1.bd_page_shift; fbnic_ring_init(&qt->cmpl, real->cmpl.doorbell, real->cmpl.q_idx, real->cmpl.flags); =20 diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/eth= ernet/meta/fbnic/fbnic_txrx.h index e03c9d2c38dc..626729b1a8b6 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -121,6 +121,7 @@ struct fbnic_ring { u16 size_mask; /* Size of ring in descriptors - 1 */ u8 q_idx; /* Logical netdev ring index */ u8 flags; /* Ring flags (FBNIC_RING_F_*) */ + u8 bd_page_shift; /* BDQ: ilog2(page_size / 4096) */ =20 u32 head, tail; /* Head/Tail of ring */ =20 @@ -162,6 +163,11 @@ struct fbnic_napi_vector { =20 extern const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_ops; =20 +static inline u16 fbnic_bd_page_count(const struct fbnic_ring *bdq) +{ + return 1U << bdq->bd_page_shift; +} + netdev_tx_t fbnic_xmit_frame(struct sk_buff *skb, struct net_device *dev); netdev_features_t fbnic_features_check(struct sk_buff *skb, struct net_device *dev, --=20 2.55.0 From nobody Fri Sep 25 16:01:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE2C7576ED2; Thu, 10 Sep 2026 18:09:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063780; cv=none; b=fxbxlgb6vk2OZbodc41hXxXFRDwITDuP5D/aVSnxVNw6xWoGfUbJhkUOdMj0/CPgc7SB32B/NDP7R8/1bbGLrCTbYW9VkGAnW7cp1tMXbR/z3TfeSc5Cyb9VoHwdKVpsr3bTgKmOuQpFILd+rtTLDVNm1bg3NqhXhV8nPOyst9M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063780; c=relaxed/simple; bh=itED+FPnTuuYMTVf0aT7/l0YAOO4jYS5kDe0sd3IKjQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Q7/JSK56Olqs7LoDH+thiADF99yyjqRvpvRO0s3RRQutGrekYu1HIEEqD+04C03wD7Yw8VjwUzopjtuiXaB+g874uEVzvEXfSa8QmIq/3fszf0GtXV1ZkbBNKMcIkICISFPv7YNvVblZNZyTks93rW9rp4HyJ6NnNkytia5IrPs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AM6yX1G2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AM6yX1G2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E7D221F00898; Thu, 10 Sep 2026 18:09:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789063777; bh=TyuxKJFpKoXV0EnfwakjYX5wWgMU/Zoar3sFBUrB1Y4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=AM6yX1G2G0zYJ48YmVr9iylxaYJfmHA6PYsPOZAN1QrC0dznBav3O8029BZzwCkpU A8oqjPAMJdJwsmxTZj22dJmSTI2rpj8Z1p/gFqVsxuF1E9ggAgfWsnoWTI6MjaDCRf dpbd1hTsFhgqeWROiFlQljIsrN3IVa09jfG0Oo0W3BchGLPZD0/oiOVPgN800kwf10 4wv+OIXxY12To+BDCTY0SQG4MhQaxQne/xIT3P4KX/7hBGWnBuUDrr35dq/YtCtqEg X8Qummpf/T1HoyNrTb+HE5rKh/pdeINhoCQxG1aDUT+9W9xAjPUUHAQUPgyILl/6rV x6tDqEk0UL6gg== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Shuah Khan , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Daniel Borkmann Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , "Mike Marciniszyn (Meta)" , Mohsin Bashir , Stanislav Fomichev , Bobby Eshleman , Dimitri Daskalakis , Weiming Shi , Maxime Chevallier , Jacob Keller , Breno Leitao , Tao Cui , Pavel Begunkov , David Wei Subject: [PATCH net-next v2 3/5] net: Revalidate queue config for ringparam changes Date: Thu, 10 Sep 2026 20:09:03 +0200 Message-ID: <20260910180908.1506533-4-bjorn@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260910180908.1506533-1-bjorn@kernel.org> References: <20260910180908.1506533-1-bjorn@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Memory-provider queue configuration is validated when the provider is bound. A later ethtool ring change may invalidate it because drivers can size queue memory from both ring depth and RX page size. For example, fbnic uses multiple PPQ entries for each RX page larger than PAGE_SIZE, which reduces the usable software ring depth. Keep accepted ring depths in netdev_config and stage proposed values in cfg_pending. Validate every RX queue before calling the driver. Each check validates the device defaults, then the queue's memory-provider override when present. Commit the values only after the driver accepts them. The callback receives a rendered configuration rather than a queue ID. Validation should depend on the configuration, not queue identity. Checking defaults also covers the case where every queue has a memory-provider override. Use the same transaction for ioctl and netlink. Drivers without ndo_validate_qcfg skip the new validation. Link: https://lore.kernel.org/all/20250421222827.283737-14-kuba@kernel.org/ Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- include/net/netdev_queues.h | 48 +++++++++++++++++++++++++++++++++---- net/core/dev.h | 2 ++ net/core/netdev_config.c | 38 ++++++++++++++++++++++++++--- net/ethtool/common.c | 9 +++++++ net/ethtool/common.h | 2 ++ net/ethtool/ioctl.c | 24 +++++++++++++++++-- net/ethtool/rings.c | 13 +++++++++- 7 files changed, 126 insertions(+), 10 deletions(-) diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h index 70c9fe9e83cc..31121900aac8 100644 --- a/include/net/netdev_queues.h +++ b/include/net/netdev_queues.h @@ -4,18 +4,59 @@ =20 #include =20 +/** + * struct netdev_ring_config - accepted RX/TX ring depth configuration + * @rx_pending: Size of the regular RX ring. + * @rx_mini_pending: Size of the RX mini ring. + * @rx_jumbo_pending: Size of the RX jumbo ring. + * @tx_pending: Size of the TX ring. + * + * This stores only persistent configuration values. Capability fields, + * such as max ring sizes, are reported by drivers but are not part of the + * accepted configuration. + * + * Note: these values are only used for queue-configuration validation + * today. Some drivers update their ring sizes without reflecting the chan= ge + * in @cfg. Before using the stored values for anything else, those cases + * need to be audited, and the core likely needs a driver notification API + * similar to ethtool_rxfh_context_lost(). + */ +struct netdev_ring_config { + u32 rx_pending; + u32 rx_mini_pending; + u32 rx_jumbo_pending; + u32 tx_pending; +}; + /** * struct netdev_config - queue-related configuration for a netdev * @hds_thresh: HDS Threshold value. * @hds_config: HDS value from userspace. + * @rings: Accepted RX/TX ring depths. + * + * Direct values, such as @hds_thresh and @rings, hold the current + * accepted configuration. Drivers which use them for queue rendering + * must initialize them with their defaults. */ struct netdev_config { u32 hds_thresh; u8 hds_config; + + struct netdev_ring_config rings; }; =20 +/** + * struct netdev_queue_config - rendered configuration for an RX queue + * @rx_page_size: Size of one RX page-pool allocation. + * @rx_ring_size: Effective size of the regular RX ring. + * @rx_mini_ring_size: Effective size of the RX mini ring. + * @rx_jumbo_ring_size: Effective size of the RX jumbo ring. + */ struct netdev_queue_config { u32 rx_page_size; + u32 rx_ring_size; + u32 rx_mini_ring_size; + u32 rx_jumbo_ring_size; }; =20 /* See the netdev.yaml spec for definition of each statistic */ @@ -145,10 +186,9 @@ enum { * * @ndo_validate_qcfg: (Optional) Check if queue config is supported. * Called when configuration affecting a queue may be - * changing, either due to NIC-wide config, or config - * scoped to the queue at a specified index. - * When NIC-wide config is changed the callback will - * be invoked for all queues. + * changing. When NIC-wide config is changed the + * callback will be invoked for the defaults and all + * queue overrides. * * @ndo_queue_create: Create a new RX queue on a virtual device that will * be paired with a physical device's queue via leasing. diff --git a/net/core/dev.h b/net/core/dev.h index 4b52ff779cba..567e7b82ef24 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -110,6 +110,8 @@ int netdev_reconfig_start(struct net_device *dev); int netdev_queue_config_validate(struct net_device *dev, int rxq_idx, struct netdev_queue_config *qcfg, struct netlink_ext_ack *extack); +int netdev_queue_config_revalidate(struct net_device *dev, + struct netlink_ext_ack *extack); =20 bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx); bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx); diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c index b101341e3251..1975de42a60d 100644 --- a/net/core/netdev_config.c +++ b/net/core/netdev_config.c @@ -50,6 +50,15 @@ static int netdev_nop_validate_qcfg(struct net_device *d= ev, return 0; } =20 +static void netdev_qcfg_apply_dev(struct netdev_queue_config *qcfg, + const struct netdev_config *cfg) +{ + /* Device config overrides callback-provided fallbacks. */ + qcfg->rx_ring_size =3D cfg->rings.rx_pending; + qcfg->rx_mini_ring_size =3D cfg->rings.rx_mini_pending; + qcfg->rx_jumbo_ring_size =3D cfg->rings.rx_jumbo_pending; +} + static int __netdev_queue_config(struct net_device *dev, int rxq_idx, struct netdev_queue_config *qcfg, struct netlink_ext_ack *extack, @@ -70,6 +79,7 @@ static int __netdev_queue_config(struct net_device *dev, = int rxq_idx, /* Get defaults from the driver, in case user config not set */ if (dev->queue_mgmt_ops->ndo_default_qcfg) dev->queue_mgmt_ops->ndo_default_qcfg(dev, qcfg); + netdev_qcfg_apply_dev(qcfg, dev->cfg_pending); err =3D validate_cb(dev, qcfg, extack); if (err) return err; @@ -91,9 +101,11 @@ static int __netdev_queue_config(struct net_device *dev= , int rxq_idx, * @rxq_idx: index of the queue of interest * @qcfg: queue configuration struct (output) * - * Render the configuration for a given queue. This helper should be used - * by drivers which support queue configuration to retrieve config for - * a particular queue. + * Render the configuration for a given queue. During a configuration + * transaction this includes the proposed device-wide values in + * @dev->cfg_pending; otherwise @dev->cfg_pending points to the accepted + * configuration. This helper should be used by drivers which support queue + * configuration to retrieve config for a particular queue. * * @qcfg is an output parameter and is always fully initialized by this * function. Some values may not be set by the user, drivers may either @@ -113,3 +125,23 @@ int netdev_queue_config_validate(struct net_device *de= v, int rxq_idx, { return __netdev_queue_config(dev, rxq_idx, qcfg, extack, true); } + +int netdev_queue_config_revalidate(struct net_device *dev, + struct netlink_ext_ack *extack) +{ + const struct netdev_queue_mgmt_ops *qops =3D dev->queue_mgmt_ops; + struct netdev_queue_config qcfg; + unsigned int i; + int err; + + if (!qops || !qops->ndo_validate_qcfg) + return 0; + + for (i =3D 0; i < dev->real_num_rx_queues; i++) { + err =3D netdev_queue_config_validate(dev, i, &qcfg, extack); + if (err) + return err; + } + + return 0; +} diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 23db40618fed..05ed22fd1f90 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -956,6 +956,15 @@ void ethtool_ringparam_get_cfg(struct net_device *dev, kparam->hds_thresh =3D dev->cfg->hds_thresh; } =20 +void ethtool_ringparam_set_cfg(struct netdev_config *cfg, + const struct ethtool_ringparam *param) +{ + cfg->rings.rx_pending =3D param->rx_pending; + cfg->rings.rx_mini_pending =3D param->rx_mini_pending; + cfg->rings.rx_jumbo_pending =3D param->rx_jumbo_pending; + cfg->rings.tx_pending =3D param->tx_pending; +} + static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info) { memset(info, 0, sizeof(*info)); diff --git a/net/ethtool/common.h b/net/ethtool/common.h index 4e5356e26f40..a27944d4cbf8 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -53,6 +53,8 @@ void ethtool_ringparam_get_cfg(struct net_device *dev, struct ethtool_ringparam *param, struct kernel_ethtool_ringparam *kparam, struct netlink_ext_ack *extack); +void ethtool_ringparam_set_cfg(struct netdev_config *cfg, + const struct ethtool_ringparam *param); =20 int ethtool_get_rx_ring_count(struct net_device *dev); =20 diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 4b0bc503f930..1320289025b2 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -35,6 +35,7 @@ #include =20 #include "common.h" +#include "../core/dev.h" =20 /* State held across locks and calls for commands which have devlink fallb= ack */ struct ethtool_devlink_compat { @@ -2239,10 +2240,29 @@ static int ethtool_set_ringparam(struct net_device = *dev, void __user *useraddr) ringparam.tx_pending > max.tx_max_pending) return -EINVAL; =20 + ret =3D netdev_reconfig_start(dev); + if (ret) + return ret; + + ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam); + + ret =3D netdev_queue_config_revalidate(dev, NULL); + if (ret) + goto out_free_cfg; + ret =3D dev->ethtool_ops->set_ringparam(dev, &ringparam, &kernel_ringparam, NULL); - if (!ret) - ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF); + if (ret) + goto out_free_cfg; + + /* The driver may adjust the accepted ring depths. */ + ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam); + swap(dev->cfg, dev->cfg_pending); + ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF); + +out_free_cfg: + __netdev_free_config(dev->cfg_pending); + dev->cfg_pending =3D dev->cfg; return ret; } =20 diff --git a/net/ethtool/rings.c b/net/ethtool/rings.c index 9054c89c5d7b..c04312fc0d06 100644 --- a/net/ethtool/rings.c +++ b/net/ethtool/rings.c @@ -4,6 +4,7 @@ =20 #include "common.h" #include "netlink.h" +#include "../core/dev.h" =20 struct rings_req_info { struct ethnl_req_info base; @@ -299,10 +300,20 @@ ethnl_set_rings(struct ethnl_req_info *req_info, stru= ct genl_info *info) =20 dev->cfg_pending->hds_config =3D kernel_ringparam.tcp_data_split; dev->cfg_pending->hds_thresh =3D kernel_ringparam.hds_thresh; + ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam); + + ret =3D netdev_queue_config_revalidate(dev, info->extack); + if (ret) + return ret; =20 ret =3D dev->ethtool_ops->set_ringparam(dev, &ringparam, &kernel_ringparam, info->extack); - return ret < 0 ? ret : 1; + if (ret < 0) + return ret; + + /* The driver may adjust the accepted ring depths. */ + ethtool_ringparam_set_cfg(dev->cfg_pending, &ringparam); + return 1; } =20 const struct ethnl_request_ops ethnl_rings_request_ops =3D { --=20 2.55.0 From nobody Fri Sep 25 16:01:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB670576EB3; Thu, 10 Sep 2026 18:09:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063791; cv=none; b=TkObBrEqLGem/Q8IGBMRBB/IG0or0WnQ3mv8dxl2x4GLTULnxtJiwoLlYGmyKQUR2qFh3zAqsPsAfVcBekII1YMxwW9RQpSYpdUEKWhP1RORMSfd7zUIyvyMij+lyhV/uXKcgCaJAe8ubEtkHOQvnJ0rG0JLcjb6/Yjjke8IPf0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063791; c=relaxed/simple; bh=sZa9nUo7GWRdbbbuX7Xm0T+s+CXjr+TdOMHiDkK0v1I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WP8icwjJIxWZtW34ujAvK/X8efuaK41hcd/LNQEQv+fYUS4iwzBOqgZzdcQKzOIqcZRhJSVrPe8tsABGZa+4Hi2EPWjrRwyklpjE4rPnHzS8k/4cVfi/cxzYiVtCIOC7p2fOOZmTsutK68QoEI/c4uMPCFlC82obfKx4T9MTyiE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BDWZrxWm; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BDWZrxWm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 875481F00893; Thu, 10 Sep 2026 18:09:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789063782; bh=EEf/YWzFHZGKhM2Jy30+UZPxNnpabVz+Ru9kLig3LpA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BDWZrxWmaGPU2Ss2z8cNmu1Ymbj0DLHxuFbSH3PNuw5A7T3aAVgq2nBP6XIqHT4vg hbWGYXmwsfTUmdv4e9eFxzGPDeXadN0sP/d3K9JWPDY/v6edfwEigQxFllBlf2SRau MvkHRsXUGUdcpn9YXdK5Q1FM6GXfLU09sA4fB+ExgN7HpfMRuULqQLqe4cEH5Weu/F R2Wc+N6AWrQgZ6T1YQXG2AMvl8+OpRxnyMo0GEYamVPQSq6T+w1wF4dNsbn4xhKf3E Y2csL0jJX4EDbELVzNcvKmd3VyiDS9qf+oPoogMxtg0ywZzUCpWnOxD9/ZIKKN9d5T q1UcjmIx4/Zgg== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Shuah Khan , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Daniel Borkmann Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , "Mike Marciniszyn (Meta)" , Mohsin Bashir , Stanislav Fomichev , Bobby Eshleman , Dimitri Daskalakis , Weiming Shi , Maxime Chevallier , Jacob Keller , Breno Leitao , Tao Cui , Pavel Begunkov , David Wei Subject: [PATCH net-next v2 4/5] fbnic: Support larger memory-provider RX pages Date: Thu, 10 Sep 2026 20:09:04 +0200 Message-ID: <20260910180908.1506533-5-bjorn@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260910180908.1506533-1-bjorn@kernel.org> References: <20260910180908.1506533-1-bjorn@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Memory providers can set the receive page size for a queue through QCFG_RX_PAGE_SIZE. fbnic creates PAGE_SIZE PPQ page-pool allocations, so larger rx_buf_len values are not reflected in the PPQ BDQ geometry. Use the rendered rx_page_size for PPQ allocations and completion decoding. The NIC still consumes 4 KiB device pages; a larger PPQ page is represented by consecutive device-page descriptors, and completion IDs decode to offsets within the same netmem allocation. Validate rx_page_size against fbnic's fragment-reference budget, device-page geometry, and rendered PPQ depth. The page size must be a power-of-two of at least one device page, its worst-case payload fragment count must fit the page-pool reference bias, and the PPQ must retain usable software depth after expansion. Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 8 +- .../net/ethernet/meta/fbnic/fbnic_netdev.c | 5 ++ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 88 +++++++++++++++++-- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 6 ++ 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/= ethernet/meta/fbnic/fbnic_ethtool.c index 0e47088ec44b..2def4c26207d 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -334,10 +334,10 @@ fbnic_set_ringparam(struct net_device *netdev, struct= ethtool_ringparam *ring, struct fbnic_net *clone; int err; =20 - ring->rx_pending =3D roundup_pow_of_two(ring->rx_pending); - ring->rx_mini_pending =3D roundup_pow_of_two(ring->rx_mini_pending); - ring->rx_jumbo_pending =3D roundup_pow_of_two(ring->rx_jumbo_pending); - ring->tx_pending =3D roundup_pow_of_two(ring->tx_pending); + ring->rx_pending =3D fbnic_ring_size_pow2(ring->rx_pending); + ring->rx_mini_pending =3D fbnic_ring_size_pow2(ring->rx_mini_pending); + ring->rx_jumbo_pending =3D fbnic_ring_size_pow2(ring->rx_jumbo_pending); + ring->tx_pending =3D fbnic_ring_size_pow2(ring->tx_pending); =20 /* These are absolute minimums allowing the device and driver to operate * but not necessarily guarantee reasonable performance. Settings below diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/e= thernet/meta/fbnic/fbnic_netdev.c index 10bf99be3f24..8bc5e6e5c59e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -773,6 +773,11 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev= *fbd) fbn->ppq_size =3D FBNIC_PPQ_SIZE_DEFAULT; fbn->rcq_size =3D FBNIC_RCQ_SIZE_DEFAULT; =20 + netdev->cfg->rings.rx_pending =3D fbn->rcq_size; + netdev->cfg->rings.rx_mini_pending =3D fbn->hpq_size; + netdev->cfg->rings.rx_jumbo_pending =3D fbn->ppq_size; + netdev->cfg->rings.tx_pending =3D fbn->txq_size; + fbn->tx_usecs =3D FBNIC_TX_USECS_DEFAULT; fbn->rx_usecs =3D FBNIC_RX_USECS_DEFAULT; fbn->rx_max_frames =3D FBNIC_RX_FRAMES_DEFAULT; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/eth= ernet/meta/fbnic/fbnic_txrx.c index 28b962307c08..5e22905a6373 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -1022,7 +1022,8 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vecto= r *nv, u64 rcd, netmem =3D fbnic_page_pool_get_data(qt, pg_idx); =20 truesize =3D FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ? - FBNIC_BD_PAGE_SIZE - pg_off : ALIGN(len, 128); + FBNIC_BD_PAGE_SIZE - pg_off : + ALIGN(len, FBNIC_RX_PAYLD_ALIGN); =20 pg_off +=3D fbnic_rcd_bd_page_offset(&qt->sub1, rcd); =20 @@ -1030,6 +1031,9 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vecto= r *nv, u64 rcd, page_pool_dma_sync_netmem_for_cpu(qt->sub1.page_pool, netmem, pg_off, truesize); =20 + /* Consecutive device-page completions from one PPQ page are adjacent + * ranges in the same netmem. + */ added =3D xdp_buff_add_frag(&pkt->buff, netmem, pg_off, len, truesize); if (unlikely(!added)) { pkt->add_frag_failed =3D true; @@ -1564,7 +1568,7 @@ void fbnic_free_napi_vectors(struct fbnic_net *fbn) =20 static int fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt, - unsigned int rxq_idx) + unsigned int rxq_idx, u32 rx_page_size) { struct page_pool_params pp_params =3D { .order =3D 0, @@ -1599,6 +1603,8 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, stru= ct fbnic_q_triad *qt, =20 qt->sub0.page_pool =3D pp; if (netif_rxq_has_unreadable_mp(fbn->netdev, rxq_idx)) { + pp_params.order =3D get_order(rx_page_size); + pp_params.max_len =3D rx_page_size; pp_params.flags |=3D PP_FLAG_ALLOW_UNREADABLE_NETMEM; pp_params.dma_dir =3D DMA_FROM_DEVICE; =20 @@ -2028,15 +2034,18 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic= _net *fbn, =20 static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn, struct fbnic_napi_vector *nv, - struct fbnic_q_triad *qt) + struct fbnic_q_triad *qt, + u32 rx_page_size) { struct device *dev =3D fbn->netdev->dev.parent; int err; =20 - err =3D fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx); + err =3D fbnic_alloc_qt_page_pools(fbn, qt, qt->cmpl.q_idx, rx_page_size); if (err) return err; =20 + fbnic_bdq_set_page_size(&qt->sub1, rx_page_size); + err =3D xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->sub0.q_idx, nv->napi.napi_id); if (err) @@ -2097,7 +2106,11 @@ static int fbnic_alloc_nv_resources(struct fbnic_net= *fbn, =20 /* Allocate Rx Resources */ for (j =3D 0; j < nv->rxt_count; j++, i++) { - err =3D fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i]); + struct netdev_queue_config qcfg; + + netdev_queue_config(fbn->netdev, nv->qt[i].cmpl.q_idx, &qcfg); + err =3D fbnic_alloc_rx_qt_resources(fbn, nv, &nv->qt[i], + qcfg.rx_page_size); if (err) goto free_qt_resources; } @@ -2864,21 +2877,75 @@ static int fbnic_queue_mem_alloc(struct net_device = *dev, struct fbnic_napi_vector *nv; =20 if (!netif_running(dev)) - return fbnic_alloc_qt_page_pools(fbn, qt, idx); + return fbnic_alloc_qt_page_pools(fbn, qt, idx, + qcfg->rx_page_size); =20 real =3D container_of(fbn->rx[idx], struct fbnic_q_triad, cmpl); nv =3D fbn->napi[idx % fbn->num_napi]; =20 fbnic_ring_init(&qt->sub0, real->sub0.doorbell, real->sub0.q_idx, real->sub0.flags); - qt->sub0.bd_page_shift =3D real->sub0.bd_page_shift; fbnic_ring_init(&qt->sub1, real->sub1.doorbell, real->sub1.q_idx, real->sub1.flags); - qt->sub1.bd_page_shift =3D real->sub1.bd_page_shift; fbnic_ring_init(&qt->cmpl, real->cmpl.doorbell, real->cmpl.q_idx, real->cmpl.flags); =20 - return fbnic_alloc_rx_qt_resources(fbn, nv, qt); + return fbnic_alloc_rx_qt_resources(fbn, nv, qt, qcfg->rx_page_size); +} + +static void fbnic_default_qcfg(struct net_device *dev, + struct netdev_queue_config *qcfg) +{ + qcfg->rx_page_size =3D PAGE_SIZE; +} + +static int fbnic_validate_qcfg(struct net_device *dev, + struct netdev_queue_config *qcfg, + struct netlink_ext_ack *extack) +{ + u32 ppq_size =3D fbnic_ring_size_pow2(qcfg->rx_jumbo_ring_size); + u32 bd_page_count, ppq_entries, frag_count; + u32 rx_page_size =3D qcfg->rx_page_size; + + if (!is_power_of_2(rx_page_size)) { + NL_SET_ERR_MSG_MOD(extack, + "rx_page_size must be a power of 2"); + return -EINVAL; + } + + if (rx_page_size < FBNIC_BD_PAGE_SIZE) { + NL_SET_ERR_MSG_MOD(extack, + "rx_page_size must be at least 4K"); + return -EINVAL; + } + + /* Payload fragments occupy multiples of FBNIC_RX_PAYLD_ALIGN bytes. + * Keep at least one reference in the bias until fbnic_clean_bdq() + * observes a completion from a subsequent allocation. + */ + frag_count =3D rx_page_size / FBNIC_RX_PAYLD_ALIGN; + if (frag_count >=3D FBNIC_PAGECNT_BIAS_MAX) { + NL_SET_ERR_MSG_MOD(extack, + "rx_page_size can produce too many fragments"); + return -EINVAL; + } + + bd_page_count =3D rx_page_size / FBNIC_BD_PAGE_SIZE; + ppq_entries =3D ppq_size / bd_page_count; + /* The PPQ is sized in 4 KiB device pages. One software entry tracks + * each page-pool allocation. In addition to the unused entry for + * empty/full accounting, cleanup retains the current allocation + * until a completion identifies a subsequent allocation. A two-entry + * ring can only post one allocation and cannot make progress. + * Require at least four entries, since ring sizes are powers of two. + */ + if (ppq_entries < 4) { + NL_SET_ERR_MSG_MOD(extack, + "rx-jumbo ring size too small for rx_page_size"); + return -EINVAL; + } + + return 0; } =20 static void fbnic_queue_mem_free(struct net_device *dev, void *qmem) @@ -2980,4 +3047,7 @@ const struct netdev_queue_mgmt_ops fbnic_queue_mgmt_o= ps =3D { .ndo_queue_mem_free =3D fbnic_queue_mem_free, .ndo_queue_start =3D fbnic_queue_start, .ndo_queue_stop =3D fbnic_queue_stop, + .ndo_default_qcfg =3D fbnic_default_qcfg, + .ndo_validate_qcfg =3D fbnic_validate_qcfg, + .supported_params =3D QCFG_RX_PAGE_SIZE, }; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/eth= ernet/meta/fbnic/fbnic_txrx.h index 626729b1a8b6..12b3a684f461 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -49,12 +49,18 @@ struct fbnic_net; #define FBNIC_RX_USECS_DEFAULT 30 #define FBNIC_RX_FRAMES_DEFAULT 0 =20 +static inline u32 fbnic_ring_size_pow2(u32 size) +{ + return size ? roundup_pow_of_two(size) : 0; +} + #define FBNIC_RX_TROOM \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) #define FBNIC_RX_HROOM_PAD 128 #define FBNIC_RX_HROOM \ (ALIGN(FBNIC_RX_TROOM + FBNIC_RX_HROOM_PAD, 128) - FBNIC_RX_TROOM) #define FBNIC_RX_PAD 0 +#define FBNIC_RX_PAYLD_ALIGN 128 #define FBNIC_RX_PAYLD_OFFSET 0 #define FBNIC_RX_PAYLD_PG_CL 0 =20 --=20 2.55.0 From nobody Fri Sep 25 16:01:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6C30857982A; Thu, 10 Sep 2026 18:09:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063791; cv=none; b=ByO6xQSYLo3yCJVt3hWIdVYIdmE+uYBfdPNsBHjbnUMnBaagIkB4VadGG5Ao7rpSYuxJ967tGh5TQvYceWEBMlgtiQJp8AsnBM4nc15omhJVmhjeD44ykGbjuNSXOzEI0C+2UPNA2zuMZsNBTNhlcBUzDR3UzCxuZjGtK9+RgnE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789063791; c=relaxed/simple; bh=W8EE3u46dp8cHeR4vyIuI1eHp+oIhfLynDuPDtL+npk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ql2d9/8BrO8T9Vqlcfm+OvjdLkUJvPRD/JmUooz/Oq/tWNR74RniI2PVQrmcrb/2W+cFxw2b0esKSZxMUnz0zGDKDQu+Pb8bFZGjxVQ6W3glGsDSRXIwyujZHDIzTBX0BQcB5znEdDBDuuSX9kMldb6/V7L2oRKDQtY6LoQbh/4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aCWIsRaa; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aCWIsRaa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 26D151F000FF; Thu, 10 Sep 2026 18:09:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789063788; bh=2kx4i/5vuO1bwBYb/SFslZeM845NWdOIhPQSfY8uSPU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=aCWIsRaazdlT9pc/pa+zVL11V8omSJdY/oDvLyLze5Vp7+yNgwMJ7iaH+l6FKsGC1 aES/9Ulo8PnuqKYa6F6eN0pKNX92YtnvxoADcNDQuq7Ltmq+0ezPcXWv8GSccMzxqA jIZtga21NM7cjvOJri0ls/NuWKQnKMpCIgiJ3IHvHWiMS8KDgLCv7LT17zpaSA//qY R9S70NnqN1WZub8M7sbvnT+G+fNslkhjLB2RLpnXzTXynGvo+igT9GB2EMew3W5DEP A+vbeBCL81oyli6V1IzKWm5MpQZPQLF8bSzHlc4ilM9JoqprXorzrb9WiidFxU/+Ww 6EMdW8UhZoNkw== From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Shuah Khan , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Daniel Borkmann Cc: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , "Mike Marciniszyn (Meta)" , Mohsin Bashir , Stanislav Fomichev , Bobby Eshleman , Dimitri Daskalakis , Weiming Shi , Maxime Chevallier , Jacob Keller , Breno Leitao , Tao Cui , Pavel Begunkov , David Wei Subject: [PATCH net-next v2 5/5] selftests: drv-net: Test large zcrx buffers Date: Thu, 10 Sep 2026 20:09:05 +0200 Message-ID: <20260910180908.1506533-6-bjorn@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260910180908.1506533-1-bjorn@kernel.org> References: <20260910180908.1506533-1-bjorn@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable A zcrx RX buffer larger than PAGE_SIZE does not prove that the driver uses space beyond the first MTU-sized part of the buffer. The test assumes that a driver which accepts a large rx_buf_len uses space beyond the first MTU-sized region during sustained receive traffic. Drivers which do not support large buffers are expected to reject the requested size; the feature probe then skips them. A driver which accepts the size but only uses the first MTU-sized region fails. Request a power-of-two RX buffer larger than twice the device MTU and require one zero-copy receive CQE to end past the first MTU-sized region. Signed-off-by: Bj=C3=B6rn T=C3=B6pel --- .../selftests/drivers/net/hw/iou-zcrx.c | 33 ++++++++++++++++--- .../selftests/drivers/net/hw/iou-zcrx.py | 6 +++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/test= ing/selftests/drivers/net/hw/iou-zcrx.c index f6a8fc5fac24..c0d9065b2103 100644 --- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c +++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c @@ -84,6 +84,9 @@ static int cfg_oneshot_recvs; static int cfg_send_size =3D SEND_SIZE; static struct sockaddr_in6 cfg_addr; static unsigned int cfg_rx_buf_len; +static unsigned int cfg_min_data_end; +static bool cfg_check_data_end; +static bool seen_data_end; static bool cfg_dry_run; =20 static char *payload; @@ -298,6 +301,15 @@ static void process_recvzc(struct io_uring *ring, stru= ct io_uring_cqe *cqe) mask =3D (1ULL << IORING_ZCRX_AREA_SHIFT) - 1; data =3D (char *)area_ptr + (rcqe->off & mask); =20 + if (cfg_check_data_end) { + unsigned int rx_buf_len =3D cfg_rx_buf_len ?: page_size; + unsigned int data_end_off; + + data_end_off =3D (rcqe->off & mask) % rx_buf_len + n; + if (data_end_off > cfg_min_data_end) + seen_data_end =3D true; + } + for (i =3D 0; i < n; i++) { if (*(data + i) !=3D payload[(received + i)]) error(1, 0, "payload mismatch at %d", i); @@ -373,7 +385,10 @@ static void run_server(void) server_loop(&ring); =20 if (!stop) - error(1, 0, "test failed\n"); + error(1, 0, "test failed after receiving %zu bytes", received); + if (cfg_check_data_end && !seen_data_end) + error(1, 0, "no payload CQE ending past offset %u", + cfg_min_data_end); } =20 static void run_client(void) @@ -406,8 +421,11 @@ static void run_client(void) =20 static void usage(const char *filepath) { - error(1, 0, "Usage: %s (-4|-6) (-s|-c) -h -p " - "-l -i -q", filepath); + error(1, 0, + "Usage: %s (-4|-6) (-s|-c) -h -p\n" + "\t-l -i -q\n" + "\t[-x] [-E] [-d]\n", + filepath); } =20 static void parse_opts(int argc, char **argv) @@ -425,7 +443,7 @@ static void parse_opts(int argc, char **argv) usage(argv[0]); cfg_payload_len =3D max_payload_len; =20 - while ((c =3D getopt(argc, argv, "sch:p:l:i:q:o:z:x:d")) !=3D -1) { + while ((c =3D getopt(argc, argv, "sch:p:l:i:q:o:z:x:E:d")) !=3D -1) { switch (c) { case 's': if (cfg_client) @@ -463,6 +481,10 @@ static void parse_opts(int argc, char **argv) case 'x': cfg_rx_buf_len =3D page_size * strtoul(optarg, NULL, 0); break; + case 'E': + cfg_check_data_end =3D true; + cfg_min_data_end =3D strtoul(optarg, NULL, 0); + break; case 'd': cfg_dry_run =3D true; break; @@ -484,6 +506,9 @@ static void parse_opts(int argc, char **argv) =20 if (cfg_payload_len > max_payload_len) error(1, 0, "-l: payload exceeds max (%d)", max_payload_len); + if (cfg_check_data_end && + cfg_min_data_end >=3D (cfg_rx_buf_len ?: page_size)) + error(1, 0, "-E: offset outside rx_buf_len"); } =20 int main(int argc, char **argv) diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py b/tools/tes= ting/selftests/drivers/net/hw/iou-zcrx.py index b7a225fe4bea..a9f62c6b950b 100755 --- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py +++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py @@ -175,9 +175,13 @@ def test_zcrx_large_chunks(cfg) -> None: =20 single(cfg) page_size =3D resource.getpagesize() + mtu =3D cfg.dev["mtu"] nr_pages =3D 2 + while nr_pages * page_size <=3D 2 * mtu: + nr_pages *=3D 2 rx_buf_len =3D nr_pages * page_size - rx_cmd =3D f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.= target} -x {nr_pages}" + rx_cmd =3D (f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} " + f"-q {cfg.target} -x {nr_pages} -E {mtu}") tx_cmd =3D f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l= 12840" =20 probe =3D cmd(rx_cmd + " -d", fail=3DFalse) --=20 2.55.0