[PATCH net-next 05/12] net: dsa: qca8k: Move request sequence number handling into core

From: Luke Howard

Date: Fri Jul 03 2026 - 03:32:54 EST


From: Andrew Lunn <andrew@xxxxxxx>

Each request/reply frame is likely to have a sequence number so that
request and the reply can be matched together. Move this sequence
number into the inband structure. The driver must provide a helper to
insert the sequence number into the skb, and the core will perform the
increment.

To allow different devices to have different size sequence numbers, a
mask is provided. This can be used for example to reduce the u32
sequence number down to a u8.

Signed-off-by: Andrew Lunn <andrew@xxxxxxx>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 29 +++++++++--------------------
drivers/net/dsa/qca/qca8k.h | 1 -
include/net/dsa.h | 6 +++++-
net/dsa/dsa.c | 16 +++++++++++++++-
4 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 3b3fe96016176..fc5070402188e 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -186,7 +186,8 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
len *= sizeof(u16);

/* Make sure the seq match the requested packet. If not, drop. */
- if (get_unaligned_le32(&mgmt_ethhdr->seq) != mgmt_eth_data->seq)
+ if (get_unaligned_le32(&mgmt_ethhdr->seq) !=
+ dsa_inband_seqno(&mgmt_eth_data->inband))
return;

if (cmd == MDIO_READ) {
@@ -332,12 +333,10 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)

skb->dev = priv->mgmt_conduit;

- /* Increment seq_num and set it in the mdio pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

ret = dsa_inband_request(&mgmt_eth_data->inband, skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

*val = mgmt_eth_data->data[0];
@@ -380,12 +379,10 @@ static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)

skb->dev = priv->mgmt_conduit;

- /* Increment seq_num and set it in the mdio pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

ret = dsa_inband_request(&mgmt_eth_data->inband, skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

ack = mgmt_eth_data->ack;
@@ -586,12 +583,10 @@ qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
if (!skb)
return -ENOMEM;

- /* Increment seq_num and set it in the copy pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

ret = dsa_inband_request(&mgmt_eth_data->inband, skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

ack = mgmt_eth_data->ack;
@@ -684,12 +679,10 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
clear_skb->dev = mgmt_conduit;
write_skb->dev = mgmt_conduit;

- /* Increment seq_num and set it in the write pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

ret = dsa_inband_request(&mgmt_eth_data->inband, write_skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

ack = mgmt_eth_data->ack;
@@ -716,12 +709,10 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
}

if (read) {
- /* Increment seq_num and set it in the read pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

ret = dsa_inband_request(&mgmt_eth_data->inband, read_skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

ack = mgmt_eth_data->ack;
@@ -739,13 +730,11 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
kfree_skb(read_skb);
}
exit:
- /* Increment seq_num and set it in the clear pkt */
- mgmt_eth_data->seq++;
- qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;

/* This is expected to fail sometimes, so don't check return value. */
dsa_inband_request(&mgmt_eth_data->inband, clear_skb,
+ qca8k_mdio_header_fill_seq_num,
QCA8K_ETHERNET_TIMEOUT);

mutex_unlock(&mgmt_eth_data->mutex);
@@ -2080,7 +2069,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
return -ENOMEM;

mutex_init(&priv->mgmt_eth_data.mutex);
- dsa_inband_init(&priv->mgmt_eth_data.inband);
+ dsa_inband_init(&priv->mgmt_eth_data.inband, U32_MAX);

mutex_init(&priv->mib_eth_data.mutex);
init_completion(&priv->mib_eth_data.rw_done);
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 938f2c9ff0cac..1054ba1c7e590 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -395,7 +395,6 @@ struct qca8k_mgmt_eth_data {
struct dsa_inband inband;
struct mutex mutex; /* Enforce one mdio read/write at time */
bool ack;
- u32 seq;
u32 data[4];
};

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6b5aeb99ec3bb..cdf2487397c2b 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1353,13 +1353,17 @@ int dsa_port_simple_hsr_leave(struct dsa_switch *ds, int port,
*/
struct dsa_inband {
struct completion completion;
+ u32 seqno;
+ u32 seqno_mask;
};

-void dsa_inband_init(struct dsa_inband *inband);
+void dsa_inband_init(struct dsa_inband *inband, u32 seqno_mask);
void dsa_inband_complete(struct dsa_inband *inband);
int dsa_inband_request(struct dsa_inband *inband, struct sk_buff *skb,
+ void (*insert_seqno)(struct sk_buff *skb, u32 seqno),
int timeout_ms);
int dsa_inband_wait_for_completion(struct dsa_inband *inband, int timeout_ms);
+u32 dsa_inband_seqno(struct dsa_inband *inband);

/* Keep inline for faster access in hot path */
static inline bool netdev_uses_dsa(const struct net_device *dev)
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index f6ae11b06b4ab..98a75ee08f011 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -1834,9 +1834,11 @@ int dsa_port_simple_hsr_leave(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL_GPL(dsa_port_simple_hsr_leave);

-void dsa_inband_init(struct dsa_inband *inband)
+void dsa_inband_init(struct dsa_inband *inband, u32 seqno_mask)
{
init_completion(&inband->completion);
+ inband->seqno_mask = seqno_mask;
+ inband->seqno = 0;
}
EXPORT_SYMBOL_GPL(dsa_inband_init);

@@ -1875,11 +1877,17 @@ EXPORT_SYMBOL_GPL(dsa_inband_wait_for_completion);
* be reinitialised before the skb is queued, to avoid races.
*/
int dsa_inband_request(struct dsa_inband *inband, struct sk_buff *skb,
+ void (*insert_seqno)(struct sk_buff *skb, u32 seqno),
int timeout_ms)
{
unsigned long jiffies = msecs_to_jiffies(timeout_ms);
int ret;

+ if (insert_seqno) {
+ WRITE_ONCE(inband->seqno, inband->seqno + 1);
+ insert_seqno(skb, inband->seqno & inband->seqno_mask);
+ }
+
reinit_completion(&inband->completion);

dev_queue_xmit(skb);
@@ -1891,6 +1899,12 @@ int dsa_inband_request(struct dsa_inband *inband, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(dsa_inband_request);

+u32 dsa_inband_seqno(struct dsa_inband *inband)
+{
+ return READ_ONCE(inband->seqno) & inband->seqno_mask;
+}
+EXPORT_SYMBOL_GPL(dsa_inband_seqno);
+
static const struct dsa_stubs __dsa_stubs = {
.conduit_hwtstamp_validate = __dsa_conduit_hwtstamp_validate,
};

--
2.43.0