From: Jakub Raczynski <j.raczynski@samsung.com>
To: netdev@vger.kernel.org
Cc: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, mcoquelin.stm32@gmail.com,
alexandre.torgue@foss.st.com, linux-kernel@vger.kernel.org,
k.domagalski@samsung.com, k.tegowski@samsung.com,
cs0617.lee@samsung.com, Jakub Raczynski <j.raczynski@samsung.com>
Subject: [PATCH net-next v2 1/3] net/stmmac/dwxgmac: Modify DMA functions for future hardware
Date: Mon, 1 Jun 2026 18:25:35 +0200 [thread overview]
Message-ID: <20260601162537.553512-2-j.raczynski@samsung.com> (raw)
In-Reply-To: <20260601162537.553512-1-j.raczynski@samsung.com>
Datasheet for newer hardware of XGMAC (3.20a and 3.40a) list support for
up to 16 DMA/MTL queues. Currently maximum amount of queues in 8 set by
STMMAC_CH_MAX, MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES macros.
But before we set these to higher value there are changes to be made.
While newer hardware supports up to 16 MTL/DMA queues, there is support only
for 8 TC's (traffic control) entries. Current source assumes these are equal,
which might not be true. While in some cases it would be just incorrect value,
there are possible wrong memory accesses.
Fix this by saving number of TC supported by hardware in mac_device_info and
verify it in related functions. Also use TC count rather than MTL_MAX values
where it applies.
Co-developed-by: Chang-Sub Lee <cs0617.lee@samsung.com>
Signed-off-by: Chang-Sub Lee <cs0617.lee@samsung.com>
Signed-off-by: Jakub Raczynski <j.raczynski@samsung.com>
---
drivers/net/ethernet/stmicro/stmmac/common.h | 1 +
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 46 ++++++++++++++++++-
.../ethernet/stmicro/stmmac/dwxgmac2_dma.c | 15 +++++-
drivers/net/ethernet/stmicro/stmmac/hwif.c | 3 ++
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
5 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 927ea6230073..359a76d3658c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -620,6 +620,7 @@ struct mac_device_info {
const struct stmmac_mmc_ops *mmc;
const struct stmmac_est_ops *est;
const struct stmmac_vlan_ops *vlan;
+ struct stmmac_priv *priv_data;
struct dw_xpcs *xpcs;
struct phylink_pcs *phylink_pcs;
struct mii_regs mii; /* MII register Addresses */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index f02b434bbd50..dbedf31bb2ab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -97,11 +97,19 @@ static void dwxgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode,
static void dwxgmac2_rx_queue_prio(struct mac_device_info *hw, u32 prio,
u32 queue)
{
+ const unsigned int numtc = hw->priv_data->dma_cap.numtc;
+ struct net_device *ndev = hw->priv_data->dev;
void __iomem *ioaddr = hw->pcsr;
u32 clear_mask = 0;
u32 ctrl2, ctrl3;
int i;
+ if (queue >= numtc) {
+ netdev_err(ndev, "%s: invalid TC queue %d, supported %d\n",
+ __func__, queue, numtc);
+ return;
+ }
+
ctrl2 = readl(ioaddr + XGMAC_RXQ_CTRL2);
ctrl3 = readl(ioaddr + XGMAC_RXQ_CTRL3);
@@ -138,9 +146,17 @@ static void dwxgmac2_rx_queue_prio(struct mac_device_info *hw, u32 prio,
static void dwxgmac2_tx_queue_prio(struct mac_device_info *hw, u32 prio,
u32 queue)
{
+ const unsigned int numtc = hw->priv_data->dma_cap.numtc;
+ struct net_device *ndev = hw->priv_data->dev;
void __iomem *ioaddr = hw->pcsr;
u32 value, reg;
+ if (queue >= numtc) {
+ netdev_err(ndev, "%s: invalid TC queue %d, supported %d\n",
+ __func__, queue, numtc);
+ return;
+ }
+
reg = (queue < 4) ? XGMAC_TC_PRTY_MAP0 : XGMAC_TC_PRTY_MAP1;
if (queue >= 4)
queue -= 4;
@@ -207,6 +223,7 @@ static void dwxgmac2_prog_mtl_rx_algorithms(struct mac_device_info *hw,
static void dwxgmac2_prog_mtl_tx_algorithms(struct mac_device_info *hw,
u32 tx_alg)
{
+ const unsigned int numtc = hw->priv_data->dma_cap.numtc;
void __iomem *ioaddr = hw->pcsr;
bool ets = true;
u32 value;
@@ -233,7 +250,7 @@ static void dwxgmac2_prog_mtl_tx_algorithms(struct mac_device_info *hw,
writel(value, ioaddr + XGMAC_MTL_OPMODE);
/* Set ETS if desired */
- for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
+ for (i = 0; i < numtc; i++) {
value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i));
value &= ~XGMAC_TSA;
if (ets)
@@ -246,8 +263,15 @@ static void dwxgmac2_set_mtl_tx_queue_weight(struct stmmac_priv *priv,
struct mac_device_info *hw,
u32 weight, u32 queue)
{
+ const unsigned int numtc = priv->dma_cap.numtc;
void __iomem *ioaddr = hw->pcsr;
+ if (queue >= numtc) {
+ netdev_err(priv->dev, "%s: invalid TC queue %d, supported %d\n",
+ __func__, queue, numtc);
+ return;
+ }
+
writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
}
@@ -273,9 +297,16 @@ static void dwxgmac2_config_cbs(struct stmmac_priv *priv,
u32 send_slope, u32 idle_slope,
u32 high_credit, u32 low_credit, u32 queue)
{
+ const unsigned int numtc = priv->dma_cap.numtc;
void __iomem *ioaddr = hw->pcsr;
u32 value;
+ if (queue >= numtc) {
+ netdev_err(priv->dev, "%s: invalid TC queue %d, supported %d\n",
+ __func__, queue, numtc);
+ return;
+ }
+
writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(queue));
writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(queue));
@@ -357,6 +388,8 @@ static void dwxgmac2_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
unsigned int fc, unsigned int pause_time,
u8 tx_cnt)
{
+ const unsigned int numtc = hw->priv_data->dma_cap.numtc;
+ struct net_device *ndev = hw->priv_data->dev;
void __iomem *ioaddr = hw->pcsr;
u8 i;
@@ -366,6 +399,17 @@ static void dwxgmac2_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
for (i = 0; i < tx_cnt; i++) {
u32 value = XGMAC_TFE;
+ if (i >= numtc) {
+ netdev_err(ndev,
+ "%s: invalid TC queue %d, supported %d\n",
+ __func__, i, numtc);
+ /* This will skip all other wrong channels,
+ * but triggering this is preceded by warnings
+ * from other functions, so limit the spam.
+ */
+ break;
+ }
+
if (duplex)
value |= FIELD_PREP(XGMAC_PT, pause_time);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 03437f1cf3df..f70eaa181dad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -204,8 +204,19 @@ static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
value = u32_replace_bits(value, ttc, XGMAC_TTC);
}
- /* Use static TC to Queue mapping */
- value |= FIELD_PREP(XGMAC_Q2TCMAP, channel);
+ /* Newer XGMAC hardware does support up to 16 MTL/DMA queues but
+ * only 8 traffic class queues. Redirect these, but this is error in
+ * configuration.
+ */
+ if (channel >= priv->dma_cap.numtc) {
+ netdev_err(priv->dev,
+ "%s: Wrong channel set for TX mode redirecting to TC 0\n",
+ __func__);
+ value |= FIELD_PREP(XGMAC_Q2TCMAP, 0);
+ } else {
+ /* Use static TC to Queue mapping */
+ value |= FIELD_PREP(XGMAC_Q2TCMAP, channel);
+ }
if (qmode != MTL_QUEUE_AVB)
txqen = 0x2;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 511b0fd5e834..52842366ae0c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -368,6 +368,9 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
return -EINVAL;
}
+ /* Assign priv struct internally for easier processing */
+ mac->priv_data = priv;
+
/* Only use generic HW helpers if needed */
mac->desc = mac->desc ? : entry->desc;
mac->dma = mac->dma ? : entry->dma;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3591755ea30b..5917bf47c7de 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4140,7 +4140,7 @@ static int __stmmac_open(struct net_device *dev,
u8 chan;
int ret;
- for (int i = 0; i < MTL_MAX_TX_QUEUES; i++)
+ for (int i = 0; i < priv->plat->tx_queues_to_use; i++)
if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN)
dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
--
2.34.1
next prev parent reply other threads:[~2026-06-01 16:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20260601162617eucas1p2efc386a4d9f9e7e98e8acb83f9c550d6@eucas1p2.samsung.com>
2026-06-01 16:25 ` [PATCH net-next v2 0/3] xgmac: Support for 16 MTL/DMA queues Jakub Raczynski
2026-06-01 16:25 ` Jakub Raczynski [this message]
2026-06-03 11:46 ` [PATCH net-next v2 1/3] net/stmmac/dwxgmac: Modify DMA functions for future hardware Jakub Raczynski
2026-06-03 12:45 ` Larysa Zaremba
2026-06-06 2:02 ` Jakub Kicinski
2026-06-01 16:25 ` [PATCH net-next v2 2/3] net/stmmac/dwxgmac: Extend MTL/DMA support to 16 queues Jakub Raczynski
2026-06-03 14:23 ` Larysa Zaremba
2026-06-01 16:25 ` [PATCH net-next v2 3/3] include/stmmac: Increase max DMA/MTL channel count from 8 to 16 Jakub Raczynski
2026-06-04 13:16 ` Paolo Abeni
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260601162537.553512-2-j.raczynski@samsung.com \
--to=j.raczynski@samsung.com \
--cc=alexandre.torgue@foss.st.com \
--cc=andrew+netdev@lunn.ch \
--cc=cs0617.lee@samsung.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=k.domagalski@samsung.com \
--cc=k.tegowski@samsung.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mcoquelin.stm32@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox