From nobody Tue Apr 7 11:17:14 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 257D038F651 for ; Fri, 13 Mar 2026 15:15:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773414960; cv=none; b=pQ0kABU40fBH+5GgavcZYjvNiN//1wyKl5HBSzdA/0RlBtmbrfKgtEb3NyNPd/uzpFHA6HM7HdLjwvfNd/ervhe+TZ8v3/xY56xQkqxIHZv2PiMgQ9UbhuaQ111YtmPDLXqsnepXY4Wl3SkxdMx1SRZGe5/A6iT+8/iWatQ7ITU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773414960; c=relaxed/simple; bh=Ng7XlfAeDOAMvcaVXtqNNzzvkne2lmdAwzTtJpBBUzU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dq7MV5fotn3UgItjj9sBVcyJENnL4cBELtUaS50hBINiewMzt9lIn3A6vyuMv1ZamOkh5+WCPrf2B1kOrafRn3mfhkMWvVCDaf2oAdKyypcPSmnpnpHx7aN9iH45n13c+rgjh8matWpiCFyGLB60ilaMoo7xDbjytST4tVAi0zk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=QnrnYBbT; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="QnrnYBbT" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id E9C2CC4270E; Fri, 13 Mar 2026 15:16:19 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id B5D2660027; Fri, 13 Mar 2026 15:15:57 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 4F06A10369F35; Fri, 13 Mar 2026 16:15:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1773414956; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=nrlCHCvVqMO3vaJQNZaTZnfQ1l/PaJiputp+qZzl5z0=; b=QnrnYBbTXOOq8lhsPlqwVYVb9blNjLPeni3LUztA7lHA9JilWeqwIE61sGJGK0Nz7H5FH+ dKAJ6gfLNyw6+CGiO9qo1DJLTX77HS33QjMa4GCYQEzDp3y6jzu44wCFzDhZz6GC6UDYPr WEpeza6NgXaOEKola5UAtcOg0TPIiASbjdbH/fXuv0QEYQrumOZjKcE/tuSV0oIPiEs6uy OJhlLFLEzAdGK62hQlkSKs1nZrbvvn/W1zgBJlRN6o/cfIFrsE1npPS680Tzi2yoZk5kGs ZxddpNSVLrebp8kby0wiK8YNPv3t97NCStrvvhEUAdkqV72L7fVFut95KmgECw== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 13 Mar 2026 16:15:52 +0100 Subject: [PATCH net-next v3 1/2] net: macb: implement ethtool_ops.get|set_channels() 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 Message-Id: <20260313-macb-set-channels-v3-1-c66b7781ddb8@bootlin.com> References: <20260313-macb-set-channels-v3-0-c66b7781ddb8@bootlin.com> In-Reply-To: <20260313-macb-set-channels-v3-0-c66b7781ddb8@bootlin.com> To: Nicolas Ferre , Claudiu Beznea , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , Gregory CLEMENT , =?utf-8?q?Beno=C3=AEt_Monin?= , Tawfik Bayouk , Thomas Petazzoni , Paolo Valerio , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev X-Last-TLS-Session-Version: TLSv1.3 bp->num_queues is the total number of queues and is constant from probe. Introduce bp->max_num_queues which takes the current role of bp->num_queues and allow `0 < bp->num_queues <=3D bp->max_num_queues`. MACB/GEM does not know about rx/tx specific queues; it only has combined queues. .set_channels() is reserved to devices with MACB_CAPS_QUEUE_DISABLE. The tieoff workaround would not work as packets would still be routed into queues with a tieoff descriptor. Implement .set_channels() operation by refusing if netif_running(). The reason to implement .set_channels() is memory savings, we cannot preallocate and swap at runtime. Nit: fix an alignment issue inside gem_ethtool_ops which does not deserve its own patch. Signed-off-by: Th=C3=A9o Lebrun --- drivers/net/ethernet/cadence/macb.h | 1 + drivers/net/ethernet/cadence/macb_main.c | 103 ++++++++++++++++++++++++++-= ---- 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cad= ence/macb.h index c69828b27dae..b08afe340996 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1309,6 +1309,7 @@ struct macb { unsigned int tx_ring_size; =20 unsigned int num_queues; + unsigned int max_num_queues; struct macb_queue queues[MACB_MAX_QUEUES]; =20 spinlock_t lock; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/etherne= t/cadence/macb_main.c index 5e27e0e87a55..562d16beffb4 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -468,9 +468,26 @@ static void macb_init_buffers(struct macb *bp) upper_32_bits(bp->queues[0].tx_ring_dma)); } =20 - for (q =3D 0, queue =3D bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma)); - queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); + for (q =3D 0, queue =3D bp->queues; q < bp->max_num_queues; ++q, ++queue)= { + if (q < bp->num_queues) { + queue_writel(queue, RBQP, + lower_32_bits(queue->rx_ring_dma)); + queue_writel(queue, TBQP, + lower_32_bits(queue->tx_ring_dma)); + } else { + /* + * macb_set_channels(), which is the only way of writing + * to bp->num_queues, is only allowed if + * MACB_CAPS_QUEUE_DISABLE. + */ + queue_writel(queue, RBQP, MACB_BIT(QUEUE_DISABLE)); + + /* Disable all interrupts */ + queue_writel(queue, IDR, -1); + queue_readl(queue, ISR); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, -1); + } } } =20 @@ -4114,8 +4131,8 @@ static int gem_set_rxnfc(struct net_device *netdev, s= truct ethtool_rxnfc *cmd) =20 switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS: - if ((cmd->fs.location >=3D bp->max_tuples) - || (cmd->fs.ring_cookie >=3D bp->num_queues)) { + if (cmd->fs.location >=3D bp->max_tuples || + cmd->fs.ring_cookie >=3D bp->max_num_queues) { ret =3D -EINVAL; break; } @@ -4133,6 +4150,54 @@ static int gem_set_rxnfc(struct net_device *netdev, = struct ethtool_rxnfc *cmd) return ret; } =20 +static void macb_get_channels(struct net_device *netdev, + struct ethtool_channels *ch) +{ + struct macb *bp =3D netdev_priv(netdev); + + ch->max_combined =3D bp->max_num_queues; + ch->combined_count =3D bp->num_queues; +} + +static int macb_set_channels(struct net_device *netdev, + struct ethtool_channels *ch) +{ + struct macb *bp =3D netdev_priv(netdev); + unsigned int old_count =3D bp->num_queues; + unsigned int count =3D ch->combined_count; + int ret; + + /* + * MACB_CAPS_QUEUE_DISABLE means that the field QUEUE_DISABLE/BIT0 in + * the per-queue RBQP register disables queue Rx. If we don't have that + * capability we can have multiple queues but we must always run with + * all enabled. + */ + if (!(bp->caps & MACB_CAPS_QUEUE_DISABLE)) + return -EOPNOTSUPP; + + /* + * An ideal .set_channels() implementation uses upfront allocated + * resources and swaps them in, bringing reliability under memory + * pressure. However, here we implement it for memory savings in + * setups with less than max number of queues active. + * + * Signal it by refusing .set_channels() once interface is opened. + */ + if (netif_running(bp->dev)) + return -EBUSY; + + if (count =3D=3D old_count) + return 0; + + ret =3D netif_set_real_num_queues(bp->dev, count, count); + if (ret) + return ret; + + bp->num_queues =3D count; + return 0; +} + static const struct ethtool_ops macb_ethtool_ops =3D { .get_regs_len =3D macb_get_regs_len, .get_regs =3D macb_get_regs, @@ -4148,6 +4213,8 @@ static const struct ethtool_ops macb_ethtool_ops =3D { .set_link_ksettings =3D macb_set_link_ksettings, .get_ringparam =3D macb_get_ringparam, .set_ringparam =3D macb_set_ringparam, + .get_channels =3D macb_get_channels, + .set_channels =3D macb_set_channels, }; =20 static int macb_get_eee(struct net_device *dev, struct ethtool_keee *eee) @@ -4182,12 +4249,14 @@ static const struct ethtool_ops gem_ethtool_ops =3D= { .set_link_ksettings =3D macb_set_link_ksettings, .get_ringparam =3D macb_get_ringparam, .set_ringparam =3D macb_set_ringparam, - .get_rxnfc =3D gem_get_rxnfc, - .set_rxnfc =3D gem_set_rxnfc, - .get_rx_ring_count =3D gem_get_rx_ring_count, - .nway_reset =3D phy_ethtool_nway_reset, + .get_rxnfc =3D gem_get_rxnfc, + .set_rxnfc =3D gem_set_rxnfc, + .get_rx_ring_count =3D gem_get_rx_ring_count, + .nway_reset =3D phy_ethtool_nway_reset, .get_eee =3D macb_get_eee, .set_eee =3D macb_set_eee, + .get_channels =3D macb_get_channels, + .set_channels =3D macb_set_channels, }; =20 static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -4328,9 +4397,9 @@ static int macb_taprio_setup_replace(struct net_devic= e *ndev, size_t i; int err; =20 - if (conf->num_entries > bp->num_queues) { + if (conf->num_entries > bp->max_num_queues) { netdev_err(ndev, "Too many TAPRIO entries: %zu > %d queues\n", - conf->num_entries, bp->num_queues); + conf->num_entries, bp->max_num_queues); return -EINVAL; } =20 @@ -4378,9 +4447,9 @@ static int macb_taprio_setup_replace(struct net_devic= e *ndev, =20 /* gate_mask must not select queues outside the valid queues */ queue_id =3D order_base_2(entry->gate_mask); - if (queue_id >=3D bp->num_queues) { + if (queue_id >=3D bp->max_num_queues) { netdev_err(ndev, "Entry %zu: gate_mask 0x%x exceeds queue range (max_qu= eues=3D%d)\n", - i, entry->gate_mask, bp->num_queues); + i, entry->gate_mask, bp->max_num_queues); err =3D -EINVAL; goto cleanup; } @@ -4440,7 +4509,7 @@ static int macb_taprio_setup_replace(struct net_devic= e *ndev, /* All validations passed - proceed with hardware configuration */ scoped_guard(spinlock_irqsave, &bp->lock) { /* Disable ENST queues if running before configuring */ - queue_mask =3D BIT_U32(bp->num_queues) - 1; + queue_mask =3D BIT_U32(bp->max_num_queues) - 1; gem_writel(bp, ENST_CONTROL, queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET); =20 @@ -4475,7 +4544,7 @@ static void macb_taprio_destroy(struct net_device *nd= ev) unsigned int q; =20 netdev_reset_tc(ndev); - queue_mask =3D BIT_U32(bp->num_queues) - 1; + queue_mask =3D BIT_U32(bp->max_num_queues) - 1; =20 scoped_guard(spinlock_irqsave, &bp->lock) { /* Single disable command for all queues */ @@ -4483,7 +4552,8 @@ static void macb_taprio_destroy(struct net_device *nd= ev) queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET); =20 /* Clear all queue ENST registers in batch */ - for (q =3D 0, queue =3D bp->queues; q < bp->num_queues; ++q, ++queue) { + for (q =3D 0, queue =3D bp->queues; q < bp->max_num_queues; + ++q, ++queue) { queue_writel(queue, ENST_START_TIME, 0); queue_writel(queue, ENST_ON_TIME, 0); queue_writel(queue, ENST_OFF_TIME, 0); @@ -5719,6 +5789,7 @@ static int macb_probe(struct platform_device *pdev) bp->macb_reg_writel =3D hw_writel; } bp->num_queues =3D num_queues; + bp->max_num_queues =3D num_queues; bp->dma_burst_length =3D macb_config->dma_burst_length; bp->pclk =3D pclk; bp->hclk =3D hclk; --=20 2.53.0 From nobody Tue Apr 7 11:17:14 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 B34A53A256A for ; Fri, 13 Mar 2026 15:16:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773414962; cv=none; b=goIlyzEeokaAEQq1ltqhRn9CB8uW+kLWdywwQbFMhxFx7o5Efa4HWG32mojTfp+02rE/YaZdgUt19DycovEadLEOUoPgK8BD+MvqfyweT+MLRs9jg2TyiD9W/k5MlykF6zrDKp77+5PtKzyPg5PrwXKttlCXgN3oGBvoO0M4i5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773414962; c=relaxed/simple; bh=Dnwpjt1MN+42sYIZEEdxWr6/yUFKCOPlbs5jDMePbh8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aa8T/zEiH6K1MTtuUgTQ37BP27H6Fo18IUPE70ePYADfKSYbdSauBEo9OlC7zxL9WQsTBwmEYu8KqpGxuNvFpJv4XNTqUassZ493AJeVfjndKsBBZ5OeZCesqBIbC3/7/nqmfc7Ld1Me2cMkrlgjAkNxput7Pfcwg8Ia85oFfyo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=XES5+2Fo; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="XES5+2Fo" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id D6283C4270F; Fri, 13 Mar 2026 15:16:21 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id A25E260027; Fri, 13 Mar 2026 15:15:59 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 17DB810369F38; Fri, 13 Mar 2026 16:15:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1773414958; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=o2zCtQjmgJKs4XT0DRE3bOj/jsd945/gCVvfVBYoz90=; b=XES5+2Fo8a4ifiOg9LpZgsSa4oJbpW++PIdGaRoLAfiuefMaUn3C9FMjDLbTQMUQJXhQ3/ hwIJXqyNN6tGqR3kKRBFbT6HePzGxG10bQlH8c0BFI2ObJp38HuqWBdtiTo4FQrHzxYK9d +1PiolV1L+W3YV8S8WP1I52tJnXIfhLm9hizU70+ROJFjCLPaxIJgfW4s2z5ksdGk1lCq6 UduefWscWOK6BCbwpT1YKs4Q8xsmyvtEW7EekWRVxRh1g8OWnf9HuujeBWMOyVQcve85RQ c4oD3VjM7GLv6/6YVRwuLGWqA7NeUbEgE6JJKaI0amebyxfUT9YD/sKKFNSeqA== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 13 Mar 2026 16:15:53 +0100 Subject: [PATCH net-next v3 2/2] net: macb: distribute evenly Tx SRAM segments 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 Message-Id: <20260313-macb-set-channels-v3-2-c66b7781ddb8@bootlin.com> References: <20260313-macb-set-channels-v3-0-c66b7781ddb8@bootlin.com> In-Reply-To: <20260313-macb-set-channels-v3-0-c66b7781ddb8@bootlin.com> To: Nicolas Ferre , Claudiu Beznea , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , Gregory CLEMENT , =?utf-8?q?Beno=C3=AEt_Monin?= , Tawfik Bayouk , Thomas Petazzoni , Paolo Valerio , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev X-Last-TLS-Session-Version: TLSv1.3 GEM has registers to configure the Tx SRAM segments distribution across queues. The reset value is apprioriate (even spread) but we need to care if/when number of active queues is modified (or if we inherited unevenly initialised hardware from bootloader). To distribute segments, we take as input the number of queues (bp->num_queues) and the number of segments (found inside DCFG6). Its output is a number of segments for each queue, formatted as powers-of-two (eg 2 for queue 0 means it has 2^2=3D4 segments). As the distribution logic is quite complex (at least its initial versions had bugs), it is kunit-tested in macb_kunit.c and the implementation lives in macb_utils.c. To test: =E2=9F=A9 env --unset=3DCROSS_COMPILE make ARCH=3Dum mrproper =E2=9F=A9 env --unset=3DCROSS_COMPILE ./tools/testing/kunit/kunit.py run \ --kconfig_add CONFIG_NET=3Dy \ --kconfig_add CONFIG_COMMON_CLK=3Dy macb Signed-off-by: Th=C3=A9o Lebrun --- drivers/net/ethernet/cadence/Kconfig | 12 +++++ drivers/net/ethernet/cadence/Makefile | 5 +- drivers/net/ethernet/cadence/macb.h | 8 ++++ drivers/net/ethernet/cadence/macb_kunit.c | 77 +++++++++++++++++++++++++++= ++++ drivers/net/ethernet/cadence/macb_main.c | 15 ++++++ drivers/net/ethernet/cadence/macb_utils.c | 56 ++++++++++++++++++++++ 6 files changed, 172 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/ca= dence/Kconfig index 5b2a461dfd28..a901f74fd4ab 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -51,4 +51,16 @@ config MACB_PCI To compile this driver as a module, choose M here: the module will be called macb_pci. =20 +config MACB_KUNIT_TEST + tristate "KUnit test for MACB" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Build KUnit tests for the MACB driver. + + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation. + + If unsure, say N. + endif # NET_VENDOR_CADENCE diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/c= adence/Makefile index 1f33cdca9a3c..a0740da68649 100644 --- a/drivers/net/ethernet/cadence/Makefile +++ b/drivers/net/ethernet/cadence/Makefile @@ -2,7 +2,7 @@ # # Makefile for the Atmel network device drivers. # -macb-y :=3D macb_main.o +macb-y :=3D macb_main.o macb_utils.o =20 ifeq ($(CONFIG_MACB_USE_HWSTAMP),y) macb-y +=3D macb_ptp.o @@ -10,3 +10,6 @@ endif =20 obj-$(CONFIG_MACB) +=3D macb.o obj-$(CONFIG_MACB_PCI) +=3D macb_pci.o + +obj-$(CONFIG_MACB_KUNIT_TEST) +=3D macb_test.o +macb_test-y :=3D macb_kunit.o macb_utils.o diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cad= ence/macb.h index b08afe340996..0464e774273a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -197,6 +197,9 @@ #define GEM_TXBDCTRL 0x04cc /* TX Buffer Descriptor control register */ #define GEM_RXBDCTRL 0x04d0 /* RX Buffer Descriptor control register */ =20 +#define GEM_TXQSEGALLOC_LOWER 0x05A0 /* Tx queue segment allocation (low) = */ +#define GEM_TXQSEGALLOC_UPPER 0x05A4 /* Tx queue segment allocation (high)= */ + /* Screener Type 2 match registers */ #define GEM_SCRT2 0x540 =20 @@ -549,6 +552,8 @@ #define GEM_PBUF_CUTTHRU_SIZE 1 #define GEM_DAW64_OFFSET 23 #define GEM_DAW64_SIZE 1 +#define GEM_SEGMENTS_BIT_SIZE_OFFSET 16 +#define GEM_SEGMENTS_BIT_SIZE_SIZE 3 =20 /* Bitfields in DCFG8. */ #define GEM_T1SCR_OFFSET 24 @@ -1494,4 +1499,7 @@ struct macb_queue_enst_config { u8 queue_id; }; =20 +u64 gem_sram_distribute_segments(unsigned int num_queues, + unsigned int num_segments); + #endif /* _MACB_H */ diff --git a/drivers/net/ethernet/cadence/macb_kunit.c b/drivers/net/ethern= et/cadence/macb_kunit.c new file mode 100644 index 000000000000..b91a10bda623 --- /dev/null +++ b/drivers/net/ethernet/cadence/macb_kunit.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include "macb.h" + +struct macb_sram_segments_case { + unsigned int num_queues, num_segments; +}; + +static void macb_sram_segments_test(struct kunit *test) +{ + const struct macb_sram_segments_case *p =3D test->param_value; + u64 val =3D gem_sram_distribute_segments(p->num_queues, p->num_segments); + unsigned int i, sum_segments =3D 0, max_assigned_segments; + unsigned int num_queues =3D min(p->num_queues, p->num_segments); + + for (i =3D 0; i < num_queues; i++) { + unsigned int q_segments =3D (val >> (i * 4)) & 0b11; + + q_segments =3D 1U << q_segments; + sum_segments +=3D q_segments; + KUNIT_ASSERT_GT_MSG(test, q_segments, 0, "queue %d, val %#llx", + i, val); + } + + for (i =3D num_queues; i < 16; i++) { + unsigned int pow =3D (val >> (i * 4)) & 0b11; + + KUNIT_ASSERT_EQ_MSG(test, pow, 0, "queue %d, val %#llx", + i, val); + } + + max_assigned_segments =3D min(p->num_segments, 8 * p->num_queues); + KUNIT_ASSERT_EQ_MSG(test, sum_segments, max_assigned_segments, + "val %#llx", val); +} + +struct macb_sram_segments_case macb_sram_segments_cases[] =3D { + /* num_segments can only be powers of two. */ + { .num_queues =3D 4, .num_segments =3D 2 }, + { .num_queues =3D 1, .num_segments =3D 16 }, + { .num_queues =3D 4, .num_segments =3D 16 }, + { .num_queues =3D 5, .num_segments =3D 16 }, + { .num_queues =3D 15, .num_segments =3D 16 }, + { .num_queues =3D 16, .num_segments =3D 16 }, +}; + +static void macb_sram_segments_case_desc(struct macb_sram_segments_case *t, + char *desc) +{ + u64 val =3D gem_sram_distribute_segments(t->num_queues, t->num_segments); + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "num_queues=3D%d num_segments=3D%d TXQSEGALLOC=3D%#llx", + t->num_queues, t->num_segments, val); +} + +KUNIT_ARRAY_PARAM(macb_sram_segments, + macb_sram_segments_cases, + macb_sram_segments_case_desc); + +static struct kunit_case macb_test_cases[] =3D { + KUNIT_CASE_PARAM(macb_sram_segments_test, + macb_sram_segments_gen_params), + {} +}; + +static struct kunit_suite macb_test_suite =3D { + .name =3D "macb", + .test_cases =3D macb_test_cases, +}; + +kunit_test_suite(macb_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver kunit tests"); +MODULE_AUTHOR("Th=C3=A9o Lebrun"); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/etherne= t/cadence/macb_main.c index 562d16beffb4..197970847082 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3046,6 +3046,21 @@ static void macb_init_hw(struct macb *bp) if (bp->caps & MACB_CAPS_JUMBO) bp->rx_frm_len_mask =3D MACB_RX_JFRMLEN_MASK; =20 + /* + * Distribute Tx SRAM segments evenly based on active number of queues. + */ + if (macb_is_gem(bp)) { + unsigned int num_segments; + u64 val; + + num_segments =3D 1U << GEM_BFEXT(SEGMENTS_BIT_SIZE, + gem_readl(bp, DCFG6)); + val =3D gem_sram_distribute_segments(bp->num_queues, + num_segments); + gem_writel(bp, TXQSEGALLOC_LOWER, val); + gem_writel(bp, TXQSEGALLOC_UPPER, val >> 32); + } + macb_configure_dma(bp); =20 /* Enable RX partial store and forward and set watermark */ diff --git a/drivers/net/ethernet/cadence/macb_utils.c b/drivers/net/ethern= et/cadence/macb_utils.c new file mode 100644 index 000000000000..77e0b5c1df86 --- /dev/null +++ b/drivers/net/ethernet/cadence/macb_utils.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include "macb.h" + +/* + * Distribute evenly available segments across queues. The computation is + * complex because (1) segments are counted in powers of two and (2) a que= ue + * can only use up to 8 segments. There are four types of cases: + * - Sharing all segments equally is doable. Take num_queues=3D4 and + * num_segments=3D16. Each queue will get 2^2=3D4 segments. + * - Sharing all segments is doable. Take num_queues=3D5 and num_segments= =3D16. + * Three queues will get 2^2=3D4 segments and two will get 2^1=3D2 segm= ents. + * - Sharing all segments is not doable because not enough queues are + * available. Take num_queues=3D1 and num_segments=3D16; queue 0 can on= ly have 8 + * segments. + * - Sharing all segments is not doable because not enough segments are + * available. Take num_queues=3D4 and num_segments=3D2. + * + * We start by computing the power each queue will have. For num_queues=3D= 5 and + * num_segments=3D16, each queue will have at least 2^1 segments. That lea= ves us + * with remaining_segments=3D6. If we increase the power for a queue, we g= et a + * delta of 2 (2^2-2^1). The first three queues will therefore be advantag= ed + * and each have 2^2 segments. The remaining 2 queues will only have 2^1 + * segments. + */ +u64 gem_sram_distribute_segments(unsigned int num_queues, + unsigned int num_segments) +{ + unsigned int pow, remaining_segments, i; + unsigned int num_advantaged_queues =3D 0; + u64 val =3D 0; + + /* pow=3D0 for all queues. ilog2(0) is dangerous. */ + if (num_queues >=3D num_segments) + return 0; + + pow =3D min(ilog2(num_segments / num_queues), 3); + remaining_segments =3D num_segments - num_queues * (1U << pow); + + /* + * We can only distribute remaining segments if (1) there are remaining + * segments and (2) we did not reach the max segments per queue (2^3). + */ + if (remaining_segments !=3D 0 && pow !=3D 3) { + unsigned int delta =3D (1U << (pow + 1)) - (1U << pow); + + num_advantaged_queues =3D remaining_segments / delta; + } + + for (i =3D 0; i < num_advantaged_queues; i++) + val |=3D ((pow + 1) & 0b11) << (i * 4); + for (i =3D num_advantaged_queues; i < num_queues; i++) + val |=3D (pow & 0b11) << (i * 4); + + return val; +} --=20 2.53.0