* [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit
@ 2026-07-03 7:46 Luke Howard
2026-07-03 7:46 ` [PATCH net-next 01/17] net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP Luke Howard
` (17 more replies)
0 siblings, 18 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
This patch set shephards a series of commits made by Andrew Lunn
and others to support remotely managing Marvell switches over
Ethernet (as opposed to MDIO) using the Remote Management Unit
(RMU).
This is the second of four patch sets: the remaining two add
support for remote management when MDIO is unavailable.
Signed-off-by: Luke Howard <lukeh@padl.com>
---
Andrew Lunn (11):
net: dsa: tag_dsa: Add helper to add DSA header to RMU frame
net: dsa: mv88e6xxx: Add conduit state change handler
net: dsa: mv88e6xxx: Remove mv88e6xxx_rmu_setup()
net: dsa: mv88e6xxx: Add connect_tag_protocol handler
net: dsa: mv88e6xxx: Add sanity check of received RMU frame
net: dsa: mv88e6xxx: Get Product ID when enabling RMU
net: dsa: mv88e6xxx: Add RMU register read/write/wait for bit
net: dsa: mv88e6xxx: Move available stats into info structure
net: dsa: mv88e6xxx: Centralise common statistics check
net: dsa: mv88e6xxx: Get some MIB stats via the RMU
net: dsa: mv88e6xxx: Time RMU operations and disable if slow
Luke Howard (4):
net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP
net: dsa: mv88e6xxx: cancel PTP polling work on .shutdown
net: dsa: mv88e6xxx: size ATU snapshot buffer and region by num_macs
net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink
Mattias Forsblad (2):
net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation.
net: dsa: mv88e6xxx: Add RMU enable/disable for select switches.
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 92 ++++--
drivers/net/dsa/mv88e6xxx/chip.h | 35 +++
drivers/net/dsa/mv88e6xxx/devlink.c | 71 +++--
drivers/net/dsa/mv88e6xxx/global1.c | 64 ++++
drivers/net/dsa/mv88e6xxx/global1.h | 3 +
drivers/net/dsa/mv88e6xxx/global2.c | 1 +
drivers/net/dsa/mv88e6xxx/ptp.c | 14 +-
drivers/net/dsa/mv88e6xxx/ptp.h | 5 +
drivers/net/dsa/mv88e6xxx/rmu.c | 611 ++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 145 +++++++++
include/linux/dsa/mv88e6xxx.h | 11 +
net/dsa/tag_dsa.c | 67 +++-
13 files changed, 1073 insertions(+), 47 deletions(-)
---
base-commit: 165539241e210db8e962479c3c5072372576b618
change-id: 20260613-net-next-mv88e6xxx-rmu-2db17825ece0
Best regards,
--
Luke Howard <lukeh@padl.com>
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH net-next 01/17] net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation Luke Howard
` (16 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
If CONFIG_LOCKDEP is enabled, use lockdep_assert_held() rather than an
explicit check for the chip's register mutex.
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80b877c74513d..eada2f71cb7b3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -48,10 +48,14 @@
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
+#ifdef CONFIG_LOCKDEP
+ lockdep_assert_held(&chip->reg_lock);
+#else
if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
dev_err(chip->dev, "Switch registers lock not held!\n");
dump_stack();
}
+#endif
}
int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation.
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
2026-07-03 7:46 ` [PATCH net-next 01/17] net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:04 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame Luke Howard
` (15 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Mattias Forsblad <mattias.forsblad@gmail.com>
Support connecting Marvell dsa tagger to the switch driver frame2reg
function to decode received RMU frames.
(Note: during teardown or failed setup, tagger_data may be NULL when
a late FRAME2REG frame arrives.)
Signed-off-by: Luke Howard <lukeh@padl.com>
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
include/linux/dsa/mv88e6xxx.h | 8 ++++++++
net/dsa/tag_dsa.c | 43 ++++++++++++++++++++++++++++++++++++++-----
2 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/include/linux/dsa/mv88e6xxx.h b/include/linux/dsa/mv88e6xxx.h
index 8c3d45eca46bd..1e9460d6f7782 100644
--- a/include/linux/dsa/mv88e6xxx.h
+++ b/include/linux/dsa/mv88e6xxx.h
@@ -6,6 +6,14 @@
#define _NET_DSA_TAG_MV88E6XXX_H
#include <linux/if_vlan.h>
+#include <net/dsa.h>
+
+struct dsa_tagger_data {
+ /* DSA frame decoded to be from the RMU */
+ void (*rmu_frame2reg)(struct dsa_switch *ds,
+ struct sk_buff *skb,
+ u8 seqno);
+};
#define MV88E6XXX_VID_STANDALONE 0
#define MV88E6XXX_VID_BRIDGED (VLAN_N_VID - 1)
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index d5ffee35fbb53..5a95873e87340 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -201,14 +201,17 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
u8 extra)
{
+ struct dsa_tagger_data *tagger_data;
bool trap = false, trunk = false;
int source_device, source_port;
+ struct dsa_switch *ds;
enum dsa_code code;
enum dsa_cmd cmd;
u8 *dsa_header;
/* The ethertype field is part of the DSA header. */
dsa_header = dsa_etype_header_pos_rx(skb);
+ source_device = dsa_header[0] & 0x1f;
cmd = dsa_header[0] >> 6;
switch (cmd) {
@@ -220,12 +223,20 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
code = (dsa_header[1] & 0x6) | ((dsa_header[2] >> 4) & 1);
switch (code) {
- case DSA_CODE_FRAME2REG:
- /* Remote management is not implemented yet,
- * drop.
- */
+ case DSA_CODE_FRAME2REG: {
+ u8 seqno = dsa_header[3];
+
+ ds = dsa_conduit_find_switch(dev, source_device);
+ if (!ds) {
+ kfree_skb(skb);
+ return NULL;
+ }
+ tagger_data = ds->tagger_data;
+ if (likely(tagger_data && tagger_data->rmu_frame2reg))
+ tagger_data->rmu_frame2reg(ds, skb, seqno);
kfree_skb(skb);
return NULL;
+ }
case DSA_CODE_ARP_MIRROR:
case DSA_CODE_POLICY_MIRROR:
/* Mark mirrored packets to notify any upper
@@ -256,7 +267,6 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
return NULL;
}
- source_device = dsa_header[0] & 0x1f;
source_port = (dsa_header[1] >> 3) & 0x1f;
if (trunk) {
@@ -331,6 +341,25 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
return skb;
}
+static int dsa_tag_connect(struct dsa_switch *ds)
+{
+ struct dsa_tagger_data *tagger_data;
+
+ tagger_data = kzalloc_obj(*tagger_data, GFP_KERNEL);
+ if (!tagger_data)
+ return -ENOMEM;
+
+ ds->tagger_data = tagger_data;
+
+ return 0;
+}
+
+static void dsa_tag_disconnect(struct dsa_switch *ds)
+{
+ kfree(ds->tagger_data);
+ ds->tagger_data = NULL;
+}
+
#if IS_ENABLED(CONFIG_NET_DSA_TAG_DSA)
static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -353,6 +382,8 @@ static const struct dsa_device_ops dsa_netdev_ops = {
.proto = DSA_TAG_PROTO_DSA,
.xmit = dsa_xmit,
.rcv = dsa_rcv,
+ .connect = dsa_tag_connect,
+ .disconnect = dsa_tag_disconnect,
.needed_headroom = DSA_HLEN,
};
@@ -397,6 +428,8 @@ static const struct dsa_device_ops edsa_netdev_ops = {
.proto = DSA_TAG_PROTO_EDSA,
.xmit = edsa_xmit,
.rcv = edsa_rcv,
+ .connect = dsa_tag_connect,
+ .disconnect = dsa_tag_disconnect,
.needed_headroom = EDSA_HLEN,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
2026-07-03 7:46 ` [PATCH net-next 01/17] net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP Luke Howard
2026-07-03 7:46 ` [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:06 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches Luke Howard
` (14 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
A RMU frame sent to the switch needs a DSA header. Add a helper to the
tag driver to add such a header to an skbuff, and provide access to
the helper via the tagger data structure. This keeps most of the
details of the DSA header in the tag driver.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
include/linux/dsa/mv88e6xxx.h | 3 +++
net/dsa/tag_dsa.c | 24 ++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/linux/dsa/mv88e6xxx.h b/include/linux/dsa/mv88e6xxx.h
index 1e9460d6f7782..74a885b3bc4cb 100644
--- a/include/linux/dsa/mv88e6xxx.h
+++ b/include/linux/dsa/mv88e6xxx.h
@@ -13,6 +13,9 @@ struct dsa_tagger_data {
void (*rmu_frame2reg)(struct dsa_switch *ds,
struct sk_buff *skb,
u8 seqno);
+ /* Add DSA header to frame to be sent to switch */
+ void (*rmu_reg2frame)(struct dsa_switch *ds,
+ struct sk_buff *skb);
};
#define MV88E6XXX_VID_STANDALONE 0
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 5a95873e87340..a23c3279c49bd 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -341,6 +341,29 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
return skb;
}
+static void dsa_rmu_reg2frame(struct dsa_switch *ds,
+ struct sk_buff *skb)
+{
+ enum dsa_cmd cmd = DSA_CMD_FROM_CPU;
+ u8 tag_dev = ds->index;
+ u8 *dsa_header;
+
+ dsa_header = skb_push(skb, DSA_HLEN);
+ dsa_header[0] = (cmd << 6) | tag_dev;
+ dsa_header[1] = BIT(1) | 0x3e << 2;
+ dsa_header[2] = 6 << 5 | 0xf;
+ dsa_header[3] = 0; /* Sequence number is filled in later */
+
+ if (ds->dst->tag_ops->proto == DSA_TAG_PROTO_EDSA) {
+ u8 *edsa_header = skb_push(skb, 4);
+
+ edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
+ edsa_header[1] = ETH_P_EDSA & 0xff;
+ edsa_header[2] = 0x00;
+ edsa_header[3] = 0x00;
+ }
+}
+
static int dsa_tag_connect(struct dsa_switch *ds)
{
struct dsa_tagger_data *tagger_data;
@@ -349,6 +372,7 @@ static int dsa_tag_connect(struct dsa_switch *ds)
if (!tagger_data)
return -ENOMEM;
+ tagger_data->rmu_reg2frame = dsa_rmu_reg2frame;
ds->tagger_data = tagger_data;
return 0;
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches.
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (2 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:07 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler Luke Howard
` (13 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Mattias Forsblad <mattias.forsblad@gmail.com>
Add RMU enable and disable functionality for some Marvell SOHO
switches.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 15 +++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
drivers/net/dsa/mv88e6xxx/global1.c | 64 +++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 3 ++
4 files changed, 83 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index eada2f71cb7b3..dbfbdb982fc00 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4265,6 +4265,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.ppu_disable = mv88e6185_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
.rmu_disable = mv88e6085_g1_rmu_disable,
+ .rmu_enable = mv88e6085_g1_rmu_enable,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
@@ -4343,6 +4344,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6085_g1_rmu_disable,
+ .rmu_enable = mv88e6085_g1_rmu_enable,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.phylink_get_caps = mv88e6095_phylink_get_caps,
@@ -4477,6 +4479,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -4670,6 +4673,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_reset,
.rmu_disable = mv88e6352_g1_rmu_disable,
+ .rmu_enable = mv88e6352_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -4774,6 +4778,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_reset,
.rmu_disable = mv88e6352_g1_rmu_disable,
+ .rmu_enable = mv88e6352_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -4869,6 +4874,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -4928,6 +4934,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -4985,6 +4992,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5047,6 +5055,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_reset,
.rmu_disable = mv88e6352_g1_rmu_disable,
+ .rmu_enable = mv88e6352_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -5150,6 +5159,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5330,6 +5340,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -5488,6 +5499,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_reset,
.rmu_disable = mv88e6352_g1_rmu_disable,
+ .rmu_enable = mv88e6352_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -5551,6 +5563,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5615,6 +5628,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5682,6 +5696,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e966e7c4cc5de..12fdcb63252eb 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -701,6 +701,7 @@ struct mv88e6xxx_ops {
/* Remote Management Unit operations */
int (*rmu_disable)(struct mv88e6xxx_chip *chip);
+ int (*rmu_enable)(struct mv88e6xxx_chip *chip, int port);
/* Precision Time Protocol operations */
const struct mv88e6xxx_ptp_ops *ptp_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 9820cd5967574..ae0b6e5628184 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -536,18 +536,82 @@ int mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip *chip)
MV88E6085_G1_CTL2_RM_ENABLE, 0);
}
+int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
+{
+ int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
+
+ switch (port) {
+ case 9:
+ val = MV88E6085_G1_CTL2_RM_ENABLE;
+ break;
+ case 10:
+ val = MV88E6085_G1_CTL2_RM_ENABLE | MV88E6085_G1_CTL2_P10RM;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
+ MV88E6085_G1_CTL2_RM_ENABLE, val);
+}
+
int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
MV88E6352_G1_CTL2_RMU_MODE_DISABLED);
}
+int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
+{
+ int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
+
+ switch (port) {
+ case 4:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_4;
+ break;
+ case 5:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_5;
+ break;
+ case 6:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_6;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK, val);
+}
+
int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_RMU_MODE_MASK,
MV88E6390_G1_CTL2_RMU_MODE_DISABLED);
}
+int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
+{
+ int val = MV88E6390_G1_CTL2_RMU_MODE_DISABLED;
+
+ switch (port) {
+ case 0:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_0;
+ break;
+ case 1:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_1;
+ break;
+ case 9:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_9;
+ break;
+ case 10:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_10;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_RMU_MODE_MASK, val);
+}
+
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_HIST_MODE_MASK,
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 3dbb7a1b8fe11..4624d1bdfc243 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -316,8 +316,11 @@ int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_set_cascade_port(struct mv88e6xxx_chip *chip, int port);
int mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port);
int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index);
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (3 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:17 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 06/17] net: dsa: mv88e6xxx: Remove mv88e6xxx_rmu_setup() Luke Howard
` (12 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
When the conduit interface comes up, try to enable the RMU. Failing to
enable the remote management unit is not fatal, not all chips support
it, and some boards have chips which do support RMU, but with wrong
port is connected to the CPU.
When the conduit interface goes down, disable the RMU.
Keep track of the conduit interface, so that RMU frames can be sent to
it.
Co-developed: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 2 ++
drivers/net/dsa/mv88e6xxx/chip.h | 3 +++
drivers/net/dsa/mv88e6xxx/rmu.c | 50 ++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 15 ++++++++++++
5 files changed, 71 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index b0b08c6f159c6..1f3571061a550 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -17,6 +17,7 @@ mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
+mv88e6xxx-objs += rmu.o
mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o
mv88e6xxx-objs += switchdev.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index dbfbdb982fc00..d6c6834cca2cb 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -41,6 +41,7 @@
#include "phy.h"
#include "port.h"
#include "ptp.h"
+#include "rmu.h"
#include "serdes.h"
#include "smi.h"
#include "tcam.h"
@@ -7265,6 +7266,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.crosschip_lag_change = mv88e6xxx_crosschip_lag_change,
.crosschip_lag_join = mv88e6xxx_crosschip_lag_join,
.crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave,
+ .conduit_state_change = mv88e6xxx_rmu_conduit_state_change,
};
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 12fdcb63252eb..76958b588a908 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -457,6 +457,9 @@ struct mv88e6xxx_chip {
/* Global2 scratch register config data3 */
u8 g2_scratch_config3;
+
+ /* Remote Management Unit state. */
+ struct net_device *rmu_conduit;
};
#define TCAM_MATCH_SIZE 96
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
new file mode 100644
index 0000000000000..64e93e2eaf550
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6xxx Switch Remote Management Unit Support
+ *
+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
+ *
+ */
+
+#include <net/dsa.h>
+#include "chip.h"
+#include "global1.h"
+#include "rmu.h"
+
+void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
+ const struct net_device *conduit,
+ bool operational)
+{
+ struct dsa_port *cpu_dp = conduit->dsa_ptr;
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int port;
+ int ret;
+
+ port = dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
+
+ mv88e6xxx_reg_lock(chip);
+
+ if (operational && chip->info->ops->rmu_enable) {
+ ret = chip->info->ops->rmu_enable(chip, port);
+ if (ret == -EOPNOTSUPP) {
+ dev_info(chip->dev, "RMU: not usable on this board");
+ goto out;
+ } else if (ret < 0) {
+ dev_err(chip->dev, "RMU: unable to enable on port %d %pe",
+ port, ERR_PTR(ret));
+ goto out;
+ }
+
+ WRITE_ONCE(chip->rmu_conduit, (struct net_device *)conduit);
+
+ dev_dbg(chip->dev, "RMU: Enabled on port %d", port);
+ } else {
+ if (chip->info->ops->rmu_disable)
+ chip->info->ops->rmu_disable(chip);
+
+ WRITE_ONCE(chip->rmu_conduit, NULL);
+ }
+
+out:
+ mv88e6xxx_reg_unlock(chip);
+}
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
new file mode 100644
index 0000000000000..71c4fc1d4113f
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Marvell 88E6xxx Switch Remote Management Unit Support
+ *
+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
+ *
+ */
+
+#ifndef _MV88E6XXX_RMU_H_
+#define _MV88E6XXX_RMU_H_
+
+void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
+ const struct net_device *conduit,
+ bool operational);
+#endif /* _MV88E6XXX_RMU_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 06/17] net: dsa: mv88e6xxx: Remove mv88e6xxx_rmu_setup()
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (4 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler Luke Howard
` (11 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
Now that the RMU is enabled/disabled in the master state change
handler, remove the setup of the RMU in the mv88e6xxx_setup().
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d6c6834cca2cb..72c93cb84b7e1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1676,14 +1676,6 @@ static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
return 0;
}
-static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
-{
- if (chip->info->ops->rmu_disable)
- return chip->info->ops->rmu_disable(chip);
-
- return 0;
-}
-
static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
{
if (chip->info->ops->pot_clear)
@@ -4080,10 +4072,6 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
if (err)
goto unlock;
- err = mv88e6xxx_rmu_setup(chip);
- if (err)
- goto unlock;
-
err = mv88e6xxx_rsvd2cpu_setup(chip);
if (err)
goto unlock;
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (5 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 06/17] net: dsa: mv88e6xxx: Remove mv88e6xxx_rmu_setup() Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:25 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 08/17] net: dsa: mv88e6xxx: Add sanity check of received RMU frame Luke Howard
` (10 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
When the tagging protocol handler is attached to the DSA driver, it
can validate it is a supported tagging protocol. It can also setup
data shared between the tagger and the switch driver. Ensure a Mavell
DSA tagger is being connected, and setup the handler from RMU in the
shared data. At this point, the handler is just an empty stub, but
later patches will add the needed functionality.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.c | 6 ++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 3 +++
3 files changed, 27 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 72c93cb84b7e1..fe0d0eb8f0813 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -7183,6 +7183,23 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
return err_sync ? : err_pvt;
}
+static int mv88e6xxx_connect_tag_protocol(struct dsa_switch *ds,
+ enum dsa_tag_protocol proto)
+{
+ struct dsa_tagger_data *tagger_data = ds->tagger_data;
+
+ switch (proto) {
+ case DSA_TAG_PROTO_DSA:
+ case DSA_TAG_PROTO_EDSA:
+ tagger_data->rmu_frame2reg = mv88e6xxx_rmu_frame2reg_handler;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return 0;
+}
+
static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = {
.mac_select_pcs = mv88e6xxx_mac_select_pcs,
.mac_prepare = mv88e6xxx_mac_prepare,
@@ -7255,6 +7272,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.crosschip_lag_join = mv88e6xxx_crosschip_lag_join,
.crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave,
.conduit_state_change = mv88e6xxx_rmu_conduit_state_change,
+ .connect_tag_protocol = mv88e6xxx_connect_tag_protocol,
};
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 64e93e2eaf550..bae0ca6564f7a 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -48,3 +48,9 @@ void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
out:
mv88e6xxx_reg_unlock(chip);
}
+
+void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
+ struct sk_buff *skb,
+ u8 seqno)
+{
+}
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index 71c4fc1d4113f..c60f32480e317 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -12,4 +12,7 @@
void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
const struct net_device *conduit,
bool operational);
+void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
+ struct sk_buff *skb,
+ u8 seqno);
#endif /* _MV88E6XXX_RMU_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 08/17] net: dsa: mv88e6xxx: Add sanity check of received RMU frame
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (6 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU Luke Howard
` (9 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
The received RMU frame is expected to be addressed to the MAC address
of the master interface. The sequence number should also match. Two
formats codes are accepted. Add these basic sanity checks, and drop
the frame is they are incorrect. To aid sequence number checking
introduce the use of the DSA inband helpers and its data structures.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 2 ++
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
drivers/net/dsa/mv88e6xxx/rmu.c | 42 ++++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 9 +++++++++
4 files changed, 54 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index fe0d0eb8f0813..88cc2326ecc0c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -7462,6 +7462,8 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
if (err)
goto out_g1_atu_prob_irq;
+ dsa_inband_init(&chip->rmu_inband, U8_MAX);
+
err = mv88e6xxx_register_switch(chip);
if (err)
goto out_g1_vtu_prob_irq;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 76958b588a908..940ae698659fc 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -460,6 +460,7 @@ struct mv88e6xxx_chip {
/* Remote Management Unit state. */
struct net_device *rmu_conduit;
+ struct dsa_inband rmu_inband;
};
#define TCAM_MATCH_SIZE 96
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index bae0ca6564f7a..49d67d512fb0f 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -53,4 +53,46 @@ void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
struct sk_buff *skb,
u8 seqno)
{
+ struct mv88e6xxx_rmu_header *rmu_header;
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct net_device *conduit;
+ unsigned char *ethhdr;
+ u8 expected_seqno;
+
+ /* Check received destination MAC is the conduit MAC address */
+ conduit = READ_ONCE(chip->rmu_conduit);
+ if (!conduit)
+ goto drop;
+
+ ethhdr = skb_mac_header(skb);
+ if (!ether_addr_equal(conduit->dev_addr, ethhdr)) {
+ dev_dbg_ratelimited(ds->dev, "RMU: mismatched MAC address for request: rx %pM expecting %pM\n",
+ ethhdr, conduit->dev_addr);
+ goto drop;
+ }
+
+ expected_seqno = dsa_inband_seqno(&chip->rmu_inband);
+ if (seqno != expected_seqno) {
+ dev_dbg_ratelimited(ds->dev, "RMU: mismatched seqno for request: rx %d expecting %d\n",
+ seqno, expected_seqno);
+ goto drop;
+ }
+
+ if (skb->len < 4 + sizeof(*rmu_header)) {
+ dev_dbg_ratelimited(ds->dev, "RMU: response too short (%d bytes)\n",
+ skb->len);
+ dsa_inband_complete(&chip->rmu_inband, NULL, 0, -ETIMEDOUT);
+ goto drop;
+ }
+
+ rmu_header = (struct mv88e6xxx_rmu_header *)(skb->data + 4);
+ if (rmu_header->format != MV88E6XXX_RMU_RESP_FORMAT_1 &&
+ rmu_header->format != MV88E6XXX_RMU_RESP_FORMAT_2) {
+ dev_dbg_ratelimited(ds->dev, "RMU: invalid format: rx %d\n",
+ be16_to_cpu(rmu_header->format));
+ goto drop;
+ }
+
+drop:
+ return;
}
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index c60f32480e317..69cd3c2636f3d 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -9,6 +9,15 @@
#ifndef _MV88E6XXX_RMU_H_
#define _MV88E6XXX_RMU_H_
+#define MV88E6XXX_RMU_RESP_FORMAT_1 htons(0x0001)
+#define MV88E6XXX_RMU_RESP_FORMAT_2 htons(0x0002)
+
+struct mv88e6xxx_rmu_header {
+ __be16 format;
+ __be16 prodnr;
+ __be16 code;
+} __packed;
+
void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
const struct net_device *conduit,
bool operational);
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (7 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 08/17] net: dsa: mv88e6xxx: Add sanity check of received RMU frame Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 13:38 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 10/17] net: dsa: mv88e6xxx: Add RMU register read/write/wait for bit Luke Howard
` (8 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
When the RMU is enabled, it is recommended to get the product ID,
which identifies the switch. This is used as a test that communication
with the switch actually works and the RMU can be used. If successful,
mark the RMU usable.
This completes the general infrastructure to send a request and
process the response.
Co-developed: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.h | 10 +++
drivers/net/dsa/mv88e6xxx/rmu.c | 151 ++++++++++++++++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/rmu.h | 11 +++
3 files changed, 170 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 940ae698659fc..07300c25cbd36 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -346,6 +346,15 @@ struct mv88e6xxx_tcam {
struct list_head entries;
};
+enum mv88e6xxx_rmu_state {
+ MV88E6XXX_RMU_DISABLED = 0,
+ MV88E6XXX_RMU_ENABLED = 1,
+ /* Reserved: a future RMU-only mode (e.g. MV88E6XXX_RMU_ONLY_ENABLED)
+ * may be added here to indicate a switch operating purely via RMU
+ * without an MDIO bus.
+ */
+};
+
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
@@ -461,6 +470,7 @@ struct mv88e6xxx_chip {
/* Remote Management Unit state. */
struct net_device *rmu_conduit;
struct dsa_inband rmu_inband;
+ enum mv88e6xxx_rmu_state rmu_state;
};
#define TCAM_MATCH_SIZE 96
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 49d67d512fb0f..65e6bcf4ca938 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -6,11 +6,143 @@
*
*/
+#include <linux/dsa/mv88e6xxx.h>
#include <net/dsa.h>
#include "chip.h"
#include "global1.h"
#include "rmu.h"
+static const u8 mv88e6xxx_rmu_dest_addr[ETH_ALEN] = {
+ 0x01, 0x50, 0x43, 0x00, 0x00, 0x00
+};
+
+static void mv88e6xxx_rmu_create_l2(struct dsa_switch *ds,
+ struct net_device *conduit,
+ struct sk_buff *skb,
+ bool edsa)
+{
+ struct dsa_tagger_data *tagger_data = ds->tagger_data;
+ struct ethhdr *eth;
+ u8 *header;
+
+ /* Create RMU L2 header. */
+ header = skb_push(skb, 2);
+ /* Two bytes of EtherType, which is ignored by the switch */
+ header[0] = 0;
+ header[1] = 0;
+
+ /* Ask tagger to add {E}DSA header */
+ tagger_data->rmu_reg2frame(ds, skb);
+
+ /* Insert RMU MAC destination address */
+ eth = skb_push(skb, ETH_ALEN * 2);
+ memcpy(eth->h_dest, mv88e6xxx_rmu_dest_addr, ETH_ALEN);
+ ether_addr_copy(eth->h_source, conduit->dev_addr);
+ skb_reset_network_header(skb);
+}
+
+static void mv88e6xxx_rmu_fill_seqno(struct sk_buff *skb, u32 seqno, int offset)
+{
+ u8 *dsa_header = skb->data + offset;
+
+ dsa_header[3] = seqno;
+}
+
+/* 2 MAC address, 2 byte Ethertype, 2 bytes padding, to DSA header */
+static void mv88e6xxx_rmu_fill_seqno_edsa(struct sk_buff *skb, u32 seqno)
+{
+ mv88e6xxx_rmu_fill_seqno(skb, seqno, ETH_ALEN * 2 + 2 + 2);
+}
+
+/* 2 MAC address, to DSA header */
+static void mv88e6xxx_rmu_fill_seqno_dsa(struct sk_buff *skb, u32 seqno)
+{
+ mv88e6xxx_rmu_fill_seqno(skb, seqno, ETH_ALEN * 2);
+}
+
+static int mv88e6xxx_rmu_request(struct mv88e6xxx_chip *chip,
+ const void *req, int req_len,
+ void *resp, unsigned int resp_len,
+ int timeout_ms)
+{
+ struct net_device *conduit;
+ struct sk_buff *skb;
+ unsigned char *data;
+ bool edsa;
+
+ /* Capture conduit once: it can be cleared concurrently when the
+ * conduit goes down (e.g. during reboot). Also guard against the
+ * conduit being torn down out from under us, in which case its
+ * dev_addr may already have been released.
+ */
+ conduit = READ_ONCE(chip->rmu_conduit);
+ if (unlikely(!conduit || !conduit->dev_addr)) {
+ dev_err_ratelimited(chip->dev, "RMU: conduit device unavailable");
+ return -EINVAL;
+ }
+
+ skb = dev_alloc_skb(req_len + EDSA_HLEN + 2 * ETH_ALEN + 2);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Insert RMU request message */
+ data = skb_put(skb, req_len);
+ memcpy(data, req, req_len);
+
+ edsa = chip->tag_protocol == DSA_TAG_PROTO_EDSA;
+
+ if (!chip->ds->tagger_data) {
+ kfree_skb(skb);
+ return -EOPNOTSUPP; /* can happen on teardown */
+ }
+
+ mv88e6xxx_rmu_create_l2(chip->ds, conduit, skb, edsa);
+ skb->dev = conduit;
+
+ return dsa_inband_request(&chip->rmu_inband, skb,
+ (edsa ? mv88e6xxx_rmu_fill_seqno_edsa :
+ mv88e6xxx_rmu_fill_seqno_dsa),
+ resp, resp_len, timeout_ms);
+}
+
+static int mv88e6xxx_rmu_get_id(struct mv88e6xxx_chip *chip)
+{
+ const __be16 req[4] = {
+ MV88E6XXX_RMU_REQ_FORMAT_GET_ID,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_GET_ID,
+ MV88E6XXX_RMU_REQ_DATA};
+ struct mv88e6xxx_rmu_header resp;
+ int resp_len;
+ int ret = -1;
+
+ resp_len = sizeof(resp);
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command GET_ID %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ if (ret < resp_len) {
+ dev_err(chip->dev, "RMU: GET_ID returned wrong length: rx %d expecting %d\n",
+ ret, resp_len);
+ return -EPROTO;
+ }
+
+ if (resp.code != MV88E6XXX_RMU_RESP_CODE_GOT_ID) {
+ dev_dbg(chip->dev, "RMU: GET_ID returned wrong code %d\n",
+ be16_to_cpu(resp.code));
+ return -EPROTO;
+ }
+
+ dev_dbg(chip->dev, "RMU: product ID %4x\n", be16_to_cpu(resp.prodnr));
+
+ return 0;
+}
+
void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
const struct net_device *conduit,
bool operational)
@@ -37,11 +169,22 @@ void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
WRITE_ONCE(chip->rmu_conduit, (struct net_device *)conduit);
- dev_dbg(chip->dev, "RMU: Enabled on port %d", port);
+ /* Get the device ID to prove that the RMU works */
+ ret = mv88e6xxx_rmu_get_id(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "RMU: initialization check failed %pe",
+ ERR_PTR(ret));
+ goto out;
+ }
+ chip->rmu_state = MV88E6XXX_RMU_ENABLED;
+
+ dev_info(chip->dev, "RMU: enabled on port %d via conduit device %s",
+ port, chip->rmu_conduit->name);
} else {
if (chip->info->ops->rmu_disable)
chip->info->ops->rmu_disable(chip);
+ chip->rmu_state = MV88E6XXX_RMU_DISABLED;
WRITE_ONCE(chip->rmu_conduit, NULL);
}
@@ -58,6 +201,8 @@ void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
struct net_device *conduit;
unsigned char *ethhdr;
u8 expected_seqno;
+ int resp_len;
+ int err = 0;
/* Check received destination MAC is the conduit MAC address */
conduit = READ_ONCE(chip->rmu_conduit);
@@ -86,13 +231,15 @@ void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
}
rmu_header = (struct mv88e6xxx_rmu_header *)(skb->data + 4);
+ resp_len = skb->len - 4;
if (rmu_header->format != MV88E6XXX_RMU_RESP_FORMAT_1 &&
rmu_header->format != MV88E6XXX_RMU_RESP_FORMAT_2) {
dev_dbg_ratelimited(ds->dev, "RMU: invalid format: rx %d\n",
be16_to_cpu(rmu_header->format));
- goto drop;
+ err = -EPROTO;
}
+ dsa_inband_complete(&chip->rmu_inband, rmu_header, resp_len, err);
drop:
return;
}
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index 69cd3c2636f3d..a81af5a1ad762 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -9,9 +9,20 @@
#ifndef _MV88E6XXX_RMU_H_
#define _MV88E6XXX_RMU_H_
+#define MV88E6XXX_RMU_WAIT_TIME_MS 20
+#define MV88E6XXX_RMU_REQUEST_TIMEOUT_MS 50
+
+#define MV88E6XXX_RMU_REQ_FORMAT_GET_ID htons(0x0000)
+#define MV88E6XXX_RMU_REQ_FORMAT_SOHO htons(0x0001)
+#define MV88E6XXX_RMU_REQ_PAD htons(0x0000)
+#define MV88E6XXX_RMU_REQ_CODE_GET_ID htons(0x0000)
+#define MV88E6XXX_RMU_REQ_DATA htons(0x0000)
+
#define MV88E6XXX_RMU_RESP_FORMAT_1 htons(0x0001)
#define MV88E6XXX_RMU_RESP_FORMAT_2 htons(0x0002)
+#define MV88E6XXX_RMU_RESP_CODE_GOT_ID htons(0x0000)
+
struct mv88e6xxx_rmu_header {
__be16 format;
__be16 prodnr;
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 10/17] net: dsa: mv88e6xxx: Add RMU register read/write/wait for bit
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (8 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure Luke Howard
` (7 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
Add support for reading a register, writing a register, and waiting
for a bit in a register to change, via the remote management unit.
If the RMU is not enabled, return -EOPNOTSUPP, and fall back to MDIO.
Additionally, if the operation times out, fall back to MDIO. Other
errors, such as protocol errors are however reported, rather than
falling back to MDIO.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 18 +++--
drivers/net/dsa/mv88e6xxx/global2.c | 1 +
drivers/net/dsa/mv88e6xxx/rmu.c | 139 ++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 54 +++++++++++++-
4 files changed, 207 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 88cc2326ecc0c..6431d25f3cfa2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -65,7 +65,9 @@ int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
assert_reg_lock(chip);
- err = mv88e6xxx_smi_read(chip, addr, reg, val);
+ err = mv88e6xxx_rmu_read(chip, addr, reg, val);
+ if (mv88e6xxx_rmu_can_mdio_fallback(chip, err))
+ err = mv88e6xxx_smi_read(chip, addr, reg, val);
if (err)
return err;
@@ -81,7 +83,9 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
assert_reg_lock(chip);
- err = mv88e6xxx_smi_write(chip, addr, reg, val);
+ err = mv88e6xxx_rmu_write(chip, addr, reg, val);
+ if (mv88e6xxx_rmu_can_mdio_fallback(chip, err))
+ err = mv88e6xxx_smi_write(chip, addr, reg, val);
if (err)
return err;
@@ -131,8 +135,14 @@ int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
int bit, int val)
{
- return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
- val ? BIT(bit) : 0x0000);
+ int err;
+
+ err = mv88e6xxx_rmu_wait_bit(chip, addr, reg, bit, val);
+
+ if (mv88e6xxx_rmu_can_mdio_fallback(chip, err))
+ err = mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
+ val ? BIT(bit) : 0x0000);
+ return err;
}
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c
index 30a6ffa7817b0..834fdb3503f1c 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -855,6 +855,7 @@ static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
+ MV88E6352_G2_WDOG_CTL_RMU_TIMEOUT |
MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
MV88E6352_G2_WDOG_CTL_QC_ENABLE |
MV88E6352_G2_WDOG_CTL_SWRESET);
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 65e6bcf4ca938..03c6f47814c85 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -105,6 +105,145 @@ static int mv88e6xxx_rmu_request(struct mv88e6xxx_chip *chip,
resp, resp_len, timeout_ms);
}
+int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
+{
+ __be16 req[] = {
+ MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_REG_RW,
+ MV88E6XXX_RMU_REQ_RW_0_WRITE(addr, reg),
+ htons(val),
+ MV88E6XXX_RMU_REQ_RW_0_END,
+ MV88E6XXX_RMU_REQ_RW_1_END,
+ };
+ struct mv88e6xxx_rmu_header resp;
+ int resp_len;
+ int ret = -1;
+
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ return -EOPNOTSUPP;
+
+ resp_len = sizeof(resp);
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command REQ_RW:WRITE %pe addr %d reg %d val %04x\n",
+ ERR_PTR(ret), addr, reg, val);
+ return ret;
+ }
+
+ if (ret < resp_len) {
+ dev_err(chip->dev, "RMU: write returned wrong length: rx %d expecting %d\n",
+ ret, resp_len);
+ return -EPROTO;
+ }
+
+ if (resp.code != MV88E6XXX_RMU_RESP_CODE_REG_RW) {
+ dev_err(chip->dev, "RMU: write returned wrong code %d\n",
+ be16_to_cpu(resp.code));
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
+ u16 *val)
+{
+ __be16 req[] = {
+ MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_REG_RW,
+ MV88E6XXX_RMU_REQ_RW_0_READ(addr, reg),
+ 0,
+ MV88E6XXX_RMU_REQ_RW_0_END,
+ MV88E6XXX_RMU_REQ_RW_1_END,
+ };
+ struct mv88e6xxx_rmu_rw_resp resp;
+ int resp_len;
+ int ret = -1;
+
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ return -EOPNOTSUPP;
+
+ resp_len = sizeof(resp);
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command REQ_RW:READ %pe addr %d reg %d\n",
+ ERR_PTR(ret), addr, reg);
+ return ret;
+ }
+
+ if (ret < resp_len) {
+ dev_err(chip->dev, "RMU: read returned wrong length: rx %d expecting %d\n",
+ ret, resp_len);
+ return -EPROTO;
+ }
+
+ if (resp.rmu_header.code != MV88E6XXX_RMU_RESP_CODE_REG_RW) {
+ dev_err(chip->dev, "RMU: read returned wrong code %d\n",
+ be16_to_cpu(resp.rmu_header.code));
+ return -EPROTO;
+ }
+
+ *val = ntohs(resp.value);
+
+ return 0;
+}
+
+int mv88e6xxx_rmu_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
+ int bit, int val)
+{
+ __be16 req[] = {
+ MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_REG_RW,
+ val ? MV88E6XXX_RMU_REQ_RW_0_WAIT_1(addr, reg) :
+ MV88E6XXX_RMU_REQ_RW_0_WAIT_0(addr, reg),
+ htons((bit & 0xf) << 8),
+ MV88E6XXX_RMU_REQ_RW_0_END,
+ MV88E6XXX_RMU_REQ_RW_1_END,
+ };
+ struct mv88e6xxx_rmu_rw_resp resp;
+ int resp_len;
+ int ret = -1;
+
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ return -EOPNOTSUPP;
+
+ resp_len = sizeof(resp);
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_WAIT_BIT_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command REQ_RW:WAIT %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ if (ret < resp_len) {
+ dev_err(chip->dev, "RMU: wait on bit returned wrong length: rx %d expecting %d\n",
+ ret, resp_len);
+ return -EPROTO;
+ }
+
+ if (resp.rmu_header.code != MV88E6XXX_RMU_RESP_CODE_REG_RW) {
+ dev_err(chip->dev, "RMU: wait on bit returned wrong code %d\n",
+ be16_to_cpu(resp.rmu_header.code));
+ return -EPROTO;
+ }
+
+ if ((ntohs(resp.value) & 0xff) == 0xff) {
+ dev_err(chip->dev, "RMU: wait on bit timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static int mv88e6xxx_rmu_get_id(struct mv88e6xxx_chip *chip)
{
const __be16 req[4] = {
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index a81af5a1ad762..4b9df3119d517 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -11,17 +11,45 @@
#define MV88E6XXX_RMU_WAIT_TIME_MS 20
#define MV88E6XXX_RMU_REQUEST_TIMEOUT_MS 50
+#define MV88E6XXX_RMU_WAIT_BIT_TIMEOUT_MS 1000
#define MV88E6XXX_RMU_REQ_FORMAT_GET_ID htons(0x0000)
#define MV88E6XXX_RMU_REQ_FORMAT_SOHO htons(0x0001)
#define MV88E6XXX_RMU_REQ_PAD htons(0x0000)
#define MV88E6XXX_RMU_REQ_CODE_GET_ID htons(0x0000)
+#define MV88E6XXX_RMU_REQ_CODE_REG_RW htons(0x2000)
#define MV88E6XXX_RMU_REQ_DATA htons(0x0000)
+#define MV88E6XXX_RMU_REQ_RW_0_OP_WAIT_1 (0x7 << 10)
+#define MV88E6XXX_RMU_REQ_RW_0_OP_WAIT_0 (0x4 << 10)
+#define MV88E6XXX_RMU_REQ_RW_0_OP_READ (0x2 << 10)
+#define MV88E6XXX_RMU_REQ_RW_0_OP_WRITE (0x1 << 10)
+
+#define MV88E6XXX_RMU_REQ_RW_0_READ(_addr_, _reg_) \
+ htons(MV88E6XXX_RMU_REQ_RW_0_OP_READ | \
+ ((_addr_) << 5) | \
+ (_reg_))
+#define MV88E6XXX_RMU_REQ_RW_0_WRITE(_addr_, _reg_) \
+ htons(MV88E6XXX_RMU_REQ_RW_0_OP_WRITE | \
+ ((_addr_) << 5) | \
+ (_reg_))
+
+#define MV88E6XXX_RMU_REQ_RW_0_WAIT_0(_addr_, _reg_) \
+ htons(MV88E6XXX_RMU_REQ_RW_0_OP_WAIT_0 | \
+ ((_addr_) << 5) | \
+ (_reg_))
+#define MV88E6XXX_RMU_REQ_RW_0_WAIT_1(_addr_, _reg_) \
+ htons(MV88E6XXX_RMU_REQ_RW_0_OP_WAIT_1 | \
+ ((_addr_) << 5) | \
+ (_reg_))
+
+#define MV88E6XXX_RMU_REQ_RW_0_END htons(0xffff)
+#define MV88E6XXX_RMU_REQ_RW_1_END htons(0xffff)
+
#define MV88E6XXX_RMU_RESP_FORMAT_1 htons(0x0001)
#define MV88E6XXX_RMU_RESP_FORMAT_2 htons(0x0002)
-
#define MV88E6XXX_RMU_RESP_CODE_GOT_ID htons(0x0000)
+#define MV88E6XXX_RMU_RESP_CODE_REG_RW htons(0x2000)
struct mv88e6xxx_rmu_header {
__be16 format;
@@ -29,10 +57,34 @@ struct mv88e6xxx_rmu_header {
__be16 code;
} __packed;
+struct mv88e6xxx_rmu_rw_resp {
+ struct mv88e6xxx_rmu_header rmu_header;
+ __be16 cmd;
+ __be16 value;
+ __be16 end0;
+ __be16 end1;
+} __packed;
+
+int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg,
+ u16 val);
+int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
+ u16 *val);
+int mv88e6xxx_rmu_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
+ int bit, int val);
void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
const struct net_device *conduit,
bool operational);
void mv88e6xxx_rmu_frame2reg_handler(struct dsa_switch *ds,
struct sk_buff *skb,
u8 seqno);
+
+/* RMU register access falls back to MDIO when the operation is unsupported or
+ * times out. @chip is unused today, but threading it through here lets a future
+ * RMU-only mode suppress the fallback without touching any of the call sites.
+ */
+static inline bool
+mv88e6xxx_rmu_can_mdio_fallback(struct mv88e6xxx_chip *chip, int err)
+{
+ return err == -EOPNOTSUPP || err == -ETIMEDOUT;
+}
#endif /* _MV88E6XXX_RMU_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (9 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 10/17] net: dsa: mv88e6xxx: Add RMU register read/write/wait for bit Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-06 7:17 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 12/17] net: dsa: mv88e6xxx: Centralise common statistics check Luke Howard
` (6 subsequent siblings)
17 siblings, 1 reply; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
Different families of switches have different statistics available.
This information is current hard coded into functions, however this
information will also soon be needed when getting statistics from the
RMU. Move it into the info structure.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 6431d25f3cfa2..5c0a1e2b0507d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1303,6 +1303,9 @@ static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
+ if (!(stat->type & chip->info->stats_type))
+ return 0;
+
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
@@ -1312,6 +1315,9 @@ static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
+ if (!(stat->type & chip->info->stats_type))
+ return 0;
+
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
@@ -1321,6 +1327,9 @@ static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
+ if (!(stat->type & chip->info->stats_type))
+ return 0;
+
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
MV88E6XXX_G1_STATS_OP_HIST_RX);
@@ -1331,6 +1340,9 @@ static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
+ if (!(stat->type & chip->info->stats_type))
+ return 0;
+
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
0);
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 12/17] net: dsa: mv88e6xxx: Centralise common statistics check
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (10 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 13/17] net: dsa: mv88e6xxx: Get some MIB stats via the RMU Luke Howard
` (5 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
With moving information about available statistics into the info
structure, the test becomes identical. Consolidate them into a single
test.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 5c0a1e2b0507d..6431d25f3cfa2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1303,9 +1303,6 @@ static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
- if (!(stat->type & chip->info->stats_type))
- return 0;
-
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
@@ -1315,9 +1312,6 @@ static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
- if (!(stat->type & chip->info->stats_type))
- return 0;
-
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
@@ -1327,9 +1321,6 @@ static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
- if (!(stat->type & chip->info->stats_type))
- return 0;
-
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
MV88E6XXX_G1_STATS_OP_HIST_RX);
@@ -1340,9 +1331,6 @@ static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data)
{
- if (!(stat->type & chip->info->stats_type))
- return 0;
-
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
0);
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 13/17] net: dsa: mv88e6xxx: Get some MIB stats via the RMU
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (11 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 12/17] net: dsa: mv88e6xxx: Centralise common statistics check Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 14/17] net: dsa: mv88e6xxx: Time RMU operations and disable if slow Luke Howard
` (4 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
It is possible to access the bank 0 and the port statistics using an
RMU request. Bank 1 stats are not available in this way. Issue an RMU
request to get the statistics which are available, and use the big
table of statistics to decode the reply and return statistics in a way
that is compatible with the MDIO method.
Where bank 1 stats cannot be retrieved via RMU, fall back to individual
register reads and writes.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 15 ++++--
drivers/net/dsa/mv88e6xxx/chip.h | 4 ++
drivers/net/dsa/mv88e6xxx/rmu.c | 101 +++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 20 ++++++++
4 files changed, 137 insertions(+), 3 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 6431d25f3cfa2..531a59093ef97 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1337,9 +1337,9 @@ static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
return 1;
}
-static size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
- const struct mv88e6xxx_hw_stat *stat,
- uint64_t *data)
+size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
int ret = 0;
@@ -1360,6 +1360,15 @@ static size_t mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
{
const struct mv88e6xxx_hw_stat *stat;
size_t i, j;
+ int err;
+
+ err = mv88e6xxx_rmu_stats(chip, port, data, mv88e6xxx_hw_stats,
+ ARRAY_SIZE(mv88e6xxx_hw_stats));
+ if (err > 0)
+ return err;
+
+ if (!mv88e6xxx_rmu_can_mdio_fallback(chip, err))
+ return err;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 07300c25cbd36..7e483ba8c58d9 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -905,4 +905,8 @@ int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
void *priv),
void *priv);
+size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data);
+
#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 03c6f47814c85..88b02030a774f 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -10,6 +10,7 @@
#include <net/dsa.h>
#include "chip.h"
#include "global1.h"
+#include "port.h"
#include "rmu.h"
static const u8 mv88e6xxx_rmu_dest_addr[ETH_ALEN] = {
@@ -105,6 +106,106 @@ static int mv88e6xxx_rmu_request(struct mv88e6xxx_chip *chip,
resp, resp_len, timeout_ms);
}
+int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
+ u64 *data,
+ const struct mv88e6xxx_hw_stat *hw_stats,
+ int num_hw_stats)
+{
+ __be16 req[] = {
+ MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_MIB,
+ htons(port),
+ };
+ const struct mv88e6xxx_hw_stat *stat;
+ struct mv88e6xxx_rmu_mib_resp resp;
+ int i, j, ret;
+ int resp_len;
+ u64 high;
+
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ return -EOPNOTSUPP;
+
+ resp_len = sizeof(resp) - sizeof(resp.data);
+ if (chip->info->stats_type & STATS_TYPE_BANK0)
+ resp_len += MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN;
+ if (chip->info->stats_type & STATS_TYPE_PORT)
+ resp_len += MV88E6XXX_RMU_STATS_TYPE_PORT_LEN;
+ else if (chip->info->stats_type & STATS_TYPE_BANK1)
+ resp_len += MV88E6XXX_RMU_STATS_TYPE_DATA1_LEN;
+
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command MIB %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ if (ret < resp_len) {
+ dev_err(chip->dev, "RMU: MIB returned wrong length: rx %d expecting %d\n",
+ ret, resp_len);
+ return -EPROTO;
+ }
+
+ if (resp.rmu_header.code != MV88E6XXX_RMU_RESP_CODE_MIB) {
+ dev_err(chip->dev, "RMU: MIB returned wrong code %d\n",
+ be16_to_cpu(resp.rmu_header.code));
+ return -EPROTO;
+ }
+
+ for (i = 0, j = 0; i < num_hw_stats; i++) {
+ stat = &hw_stats[i];
+
+ if ((stat->type & chip->info->stats_type) == 0) {
+ /* Not available via RMU, use SMI (if available) */
+ j += mv88e6xxx_stats_get_stat(chip, port, stat, &data[j]);
+ continue;
+ }
+
+ if (stat->type & STATS_TYPE_PORT) {
+ __be16 *port = (__be16 *)resp.data;
+
+ if (chip->info->stats_type & STATS_TYPE_BANK0)
+ port += MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN / 2;
+
+ switch (stat->reg) {
+ case MV88E6XXX_PORT_IN_DISCARD_LO:
+ data[j] = be16_to_cpu(port[0]) << 16;
+ data[j] |= be16_to_cpu(port[1]);
+ break;
+ case MV88E6XXX_PORT_IN_FILTERED:
+ data[j] = be16_to_cpu(port[3]);
+ break;
+ case MV88E6XXX_PORT_OUT_FILTERED:
+ data[j] = be16_to_cpu(port[5]);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (stat->type & (STATS_TYPE_BANK0 | STATS_TYPE_BANK1)) {
+ int reg = stat->reg;
+
+ if (stat->type & STATS_TYPE_BANK1 &&
+ (chip->info->stats_type & STATS_TYPE_BANK0))
+ reg += MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN / 4;
+
+ data[j] = be32_to_cpu(resp.data[reg]);
+ if (stat->size == 8) {
+ high = be32_to_cpu(resp.data[reg + 1]);
+ data[j] |= (high << 32);
+ }
+ }
+
+ j++;
+ }
+
+ return j;
+}
+
int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
{
__be16 req[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index 4b9df3119d517..0865e899cb340 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -17,6 +17,7 @@
#define MV88E6XXX_RMU_REQ_FORMAT_SOHO htons(0x0001)
#define MV88E6XXX_RMU_REQ_PAD htons(0x0000)
#define MV88E6XXX_RMU_REQ_CODE_GET_ID htons(0x0000)
+#define MV88E6XXX_RMU_REQ_CODE_MIB htons(0x1020)
#define MV88E6XXX_RMU_REQ_CODE_REG_RW htons(0x2000)
#define MV88E6XXX_RMU_REQ_DATA htons(0x0000)
@@ -49,6 +50,7 @@
#define MV88E6XXX_RMU_RESP_FORMAT_1 htons(0x0001)
#define MV88E6XXX_RMU_RESP_FORMAT_2 htons(0x0002)
#define MV88E6XXX_RMU_RESP_CODE_GOT_ID htons(0x0000)
+#define MV88E6XXX_RMU_RESP_CODE_MIB htons(0x1020)
#define MV88E6XXX_RMU_RESP_CODE_REG_RW htons(0x2000)
struct mv88e6xxx_rmu_header {
@@ -65,6 +67,24 @@ struct mv88e6xxx_rmu_rw_resp {
__be16 end1;
} __packed;
+/* number of RMU MIB statistics, by type, in octets */
+#define MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN 128
+#define MV88E6XXX_RMU_STATS_TYPE_PORT_LEN 12
+#define MV88E6XXX_RMU_STATS_TYPE_DATA1_LEN 128
+#define MV88E6XXX_RMU_STATS_TYPE_MAX_LEN (MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN + \
+ MV88E6XXX_RMU_STATS_TYPE_DATA1_LEN)
+
+struct mv88e6xxx_rmu_mib_resp {
+ struct mv88e6xxx_rmu_header rmu_header;
+ __be16 swport;
+ __be32 timestamp;
+ __be32 data[MV88E6XXX_RMU_STATS_TYPE_MAX_LEN / 4];
+} __packed;
+
+int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
+ u64 *data,
+ const struct mv88e6xxx_hw_stat *hw_stats,
+ int num_hw_stats);
int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 val);
int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 14/17] net: dsa: mv88e6xxx: Time RMU operations and disable if slow
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (12 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 13/17] net: dsa: mv88e6xxx: Get some MIB stats via the RMU Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 15/17] net: dsa: mv88e6xxx: cancel PTP polling work on .shutdown Luke Howard
` (3 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
From: Andrew Lunn <andrew@lunn.ch>
MII access to the switch generally has consistent latency. Sending and
receiving frames on the other hand has a big variance in
latency. Receiver interrupt coalescence can result in delays of
100us. As a result, the RMU can be slower than MDIO.
Measure the latency of the first 16 read requests performed using the
RMU, and compare it to the latency on an MDIO read. If the RMU is
slower than MDIO, do not use if for single register reads, writes and
waiting for bits to be set. Do however use it for retrieving MIB
values since a single RMU requests replaces a large number of MIDO
transactions.
Testing on ZII Devel C, which uses a FEC, and Marvel 370RD using
mvneta has show RMU is slower than MDIO. ZII RAP however, makes use of
bit banging MDIO and an IGB. IGB by default has a short interrupt
coalesce period, making RMU much faster than bit banging, by around 20
times.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.h | 6 +++++
drivers/net/dsa/mv88e6xxx/rmu.c | 58 ++++++++++++++++++++++++++++++++++++----
2 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 7e483ba8c58d9..fdc87d02469b5 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -355,6 +355,8 @@ enum mv88e6xxx_rmu_state {
*/
};
+#define MV88E6XXX_RMU_IS_SLOW BIT(0)
+
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
@@ -471,6 +473,10 @@ struct mv88e6xxx_chip {
struct net_device *rmu_conduit;
struct dsa_inband rmu_inband;
enum mv88e6xxx_rmu_state rmu_state;
+ u8 rmu_flags;
+ ktime_t rmu_read_latencies[16];
+ u32 rmu_samples;
+ ktime_t smi_read_latency;
};
#define TCAM_MATCH_SIZE 96
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 88b02030a774f..5660372f41ad7 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -221,7 +221,8 @@ int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
int resp_len;
int ret = -1;
- if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED ||
+ (chip->rmu_flags & MV88E6XXX_RMU_IS_SLOW))
return -EOPNOTSUPP;
resp_len = sizeof(resp);
@@ -249,6 +250,33 @@ int mv88e6xxx_rmu_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
return 0;
}
+static void mv88e6xxx_rmu_read_latency(struct mv88e6xxx_chip *chip,
+ ktime_t latency)
+{
+ ktime_t average = 0;
+ int i;
+
+ if (chip->rmu_samples >= ARRAY_SIZE(chip->rmu_read_latencies))
+ return;
+
+ chip->rmu_read_latencies[chip->rmu_samples++] = latency;
+
+ if (chip->rmu_samples == ARRAY_SIZE(chip->rmu_read_latencies)) {
+ for (i = 0; i < ARRAY_SIZE(chip->rmu_read_latencies); i++)
+ average += chip->rmu_read_latencies[i];
+ average = average / ARRAY_SIZE(chip->rmu_read_latencies);
+
+ dev_dbg(chip->dev, "RMU %lldus, smi %lldus\n",
+ div_u64(average, 1000),
+ div_u64(chip->smi_read_latency, 1000));
+
+ if (chip->smi_read_latency < average)
+ chip->rmu_flags |= MV88E6XXX_RMU_IS_SLOW;
+
+ chip->rmu_samples = U32_MAX;
+ }
+}
+
int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 *val)
{
@@ -263,11 +291,15 @@ int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
};
struct mv88e6xxx_rmu_rw_resp resp;
int resp_len;
- int ret = -1;
+ ktime_t start;
+ int ret;
- if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED ||
+ (chip->rmu_flags & MV88E6XXX_RMU_IS_SLOW))
return -EOPNOTSUPP;
+ start = ktime_get();
+
resp_len = sizeof(resp);
ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
&resp, resp_len,
@@ -290,6 +322,8 @@ int mv88e6xxx_rmu_read(struct mv88e6xxx_chip *chip, int addr, int reg,
return -EPROTO;
}
+ mv88e6xxx_rmu_read_latency(chip, ktime_get() - start);
+
*val = ntohs(resp.value);
return 0;
@@ -312,7 +346,8 @@ int mv88e6xxx_rmu_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
int resp_len;
int ret = -1;
- if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED ||
+ (chip->rmu_flags & MV88E6XXX_RMU_IS_SLOW))
return -EOPNOTSUPP;
resp_len = sizeof(resp);
@@ -389,8 +424,10 @@ void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
{
struct dsa_port *cpu_dp = conduit->dsa_ptr;
struct mv88e6xxx_chip *chip = ds->priv;
+ ktime_t start;
int port;
int ret;
+ u16 id;
port = dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
@@ -414,13 +451,24 @@ void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
if (ret < 0) {
dev_err(chip->dev, "RMU: initialization check failed %pe",
ERR_PTR(ret));
- goto out;
+ goto out_disable;
}
+
+ start = ktime_get();
+ ret = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID,
+ &id);
+ if (ret < 0) {
+ dev_err(chip->dev, "RMU: SMI latency read failed %pe",
+ ERR_PTR(ret));
+ goto out_disable;
+ }
+ chip->smi_read_latency = ktime_get() - start;
chip->rmu_state = MV88E6XXX_RMU_ENABLED;
dev_info(chip->dev, "RMU: enabled on port %d via conduit device %s",
port, chip->rmu_conduit->name);
} else {
+out_disable:
if (chip->info->ops->rmu_disable)
chip->info->ops->rmu_disable(chip);
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 15/17] net: dsa: mv88e6xxx: cancel PTP polling work on .shutdown
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (13 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 14/17] net: dsa: mv88e6xxx: Time RMU operations and disable if slow Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 16/17] net: dsa: mv88e6xxx: size ATU snapshot buffer and region by num_macs Luke Howard
` (2 subsequent siblings)
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
DSA core's dsa_switch_shutdown() only closes CPU port conduits and
unlinks DSA uppers; it does not invoke ds->ops->teardown(). On
.shutdown (reboot), the chip's mv88e6xxx_teardown() therefore never
runs, and the PTP overflow / TAI event delayed works are not
cancelled. They continue to fire as the conduit netdev is torn down
by its own driver, racing the teardown and crashing in the RMU
request path when conduit->dev_addr is released.
Factor the work cancellation out of mv88e6xxx_ptp_free() into a new
mv88e6xxx_ptp_shutdown() helper that leaves the PTP clock registered,
and call it from mv88e6xxx_shutdown_common() before
dsa_switch_shutdown(). mv88e6xxx_ptp_free() now calls the helper
itself, so the regular .remove path is unchanged.
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 6 ++++++
drivers/net/dsa/mv88e6xxx/ptp.c | 14 ++++++++++++--
drivers/net/dsa/mv88e6xxx/ptp.h | 5 +++++
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 531a59093ef97..3d92c59de7b5f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -7543,6 +7543,12 @@ static void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
if (!ds)
return;
+ /* DSA core does not call ->teardown on .shutdown, so stop PTP
+ * polling here before the conduit goes away. Otherwise the work
+ * can race teardown and dereference a stale conduit->dev_addr.
+ */
+ mv88e6xxx_ptp_shutdown(ds->priv);
+
dsa_switch_shutdown(ds);
dev_set_drvdata(&mdiodev->dev, NULL);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index f7603573d3a98..f6ce3232d10ff 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -551,14 +551,24 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
return 0;
}
-/* This must never be called holding the register lock */
-void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
+/* Cancel any pending PTP polling work. Safe to call from .shutdown
+ * paths where the PTP clock itself stays registered.
+ * This must never be called holding the register lock.
+ */
+void mv88e6xxx_ptp_shutdown(struct mv88e6xxx_chip *chip)
{
if (chip->ptp_clock) {
cancel_delayed_work_sync(&chip->overflow_work);
if (chip->info->ops->ptp_ops->event_work)
cancel_delayed_work_sync(&chip->tai_event_work);
+ }
+}
+/* This must never be called holding the register lock */
+void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
+{
+ if (chip->ptp_clock) {
+ mv88e6xxx_ptp_shutdown(chip);
ptp_clock_unregister(chip->ptp_clock);
chip->ptp_clock = NULL;
}
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 95bdddb0bf39f..90031b05d2514 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -68,6 +68,7 @@
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_ptp_shutdown(struct mv88e6xxx_chip *chip);
#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
ptp_clock_info)
@@ -87,6 +88,10 @@ static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{
}
+static inline void mv88e6xxx_ptp_shutdown(struct mv88e6xxx_chip *chip)
+{
+}
+
static const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {};
static const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {};
static const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {};
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 16/17] net: dsa: mv88e6xxx: size ATU snapshot buffer and region by num_macs
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (14 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 15/17] net: dsa: mv88e6xxx: cancel PTP polling work on .shutdown Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 17/17] net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink Luke Howard
2026-07-03 8:05 ` [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Paolo Abeni
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
The ATU devlink region and its snapshot buffer are both sized by the
number of forwarding databases, but the ATU can hold up to
mv88e6xxx_num_macs() entries (which is 8192 on the 6352 series).
Fixes: bfb255428966 ("net: dsa: mv88e6xxx: Add devlink regions")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/devlink.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c
index 6f034841883c6..6d7da381f9f38 100644
--- a/drivers/net/dsa/mv88e6xxx/devlink.c
+++ b/drivers/net/dsa/mv88e6xxx/devlink.c
@@ -380,7 +380,7 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
int fid = -1, err = 0, count = 0;
table = kzalloc_objs(struct mv88e6xxx_devlink_atu_entry,
- mv88e6xxx_num_databases(chip));
+ mv88e6xxx_num_macs(chip));
if (!table)
return -ENOMEM;
@@ -776,7 +776,7 @@ int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
switch (i) {
case MV88E6XXX_REGION_ATU:
- size = mv88e6xxx_num_databases(chip) *
+ size = mv88e6xxx_num_macs(chip) *
sizeof(struct mv88e6xxx_devlink_atu_entry);
break;
case MV88E6XXX_REGION_VTU:
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH net-next 17/17] net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (15 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 16/17] net: dsa: mv88e6xxx: size ATU snapshot buffer and region by num_macs Luke Howard
@ 2026-07-03 7:46 ` Luke Howard
2026-07-03 8:05 ` [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Paolo Abeni
17 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-03 7:46 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel, Luke Howard
Support reading an ATU snapshot in a single RMU request.
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.h | 10 +++++
drivers/net/dsa/mv88e6xxx/devlink.c | 67 ++++++++++++++++++++++---------
drivers/net/dsa/mv88e6xxx/rmu.c | 78 +++++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 35 +++++++++++++++++
4 files changed, 171 insertions(+), 19 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index fdc87d02469b5..7bbb649330d55 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -205,6 +205,16 @@ struct mv88e6xxx_stu_entry {
u8 state[DSA_MAX_PORTS];
};
+struct mv88e6xxx_devlink_atu_entry {
+ /* The FID is scattered over multiple registers. */
+ u16 fid;
+ u16 atu_op;
+ u16 atu_data;
+ u16 atu_01;
+ u16 atu_23;
+ u16 atu_45;
+};
+
struct mv88e6xxx_bus_ops;
struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c
index 6d7da381f9f38..5c2a59d1145b8 100644
--- a/drivers/net/dsa/mv88e6xxx/devlink.c
+++ b/drivers/net/dsa/mv88e6xxx/devlink.c
@@ -6,6 +6,7 @@
#include "global1.h"
#include "global2.h"
#include "port.h"
+#include "rmu.h"
static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
{
@@ -307,16 +308,6 @@ static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
* mv88e6xxx generations
*/
-struct mv88e6xxx_devlink_atu_entry {
- /* The FID is scattered over multiple registers. */
- u16 fid;
- u16 atu_op;
- u16 atu_data;
- u16 atu_01;
- u16 atu_23;
- u16 atu_45;
-};
-
static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
int fid,
struct mv88e6xxx_devlink_atu_entry *table,
@@ -369,6 +360,33 @@ static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
return 0;
}
+static int mv88e6xxx_region_atu_snapshot_rmu(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_devlink_atu_entry *table,
+ int *count)
+{
+ unsigned int num_macs = mv88e6xxx_num_macs(chip);
+ u16 cont_code = 0;
+ int err;
+
+ do {
+ if (*count + MV88E6XXX_RMU_MAX_ATU_ENTRIES > num_macs) {
+ err = -ERANGE;
+ break;
+ }
+
+ err = mv88e6xxx_rmu_dump_atu(chip, &table[*count], &cont_code);
+ if (err < 0)
+ break;
+
+ *count += err;
+ } while (cont_code != 0);
+
+ if (err < 0)
+ *count = 0;
+
+ return err;
+}
+
static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
const struct devlink_region_ops *ops,
struct netlink_ext_ack *extack,
@@ -386,18 +404,29 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
mv88e6xxx_reg_lock(chip);
- while (1) {
- fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1);
- if (fid == MV88E6XXX_N_FID)
- break;
+ err = mv88e6xxx_region_atu_snapshot_rmu(chip, table, &count);
+ if (err >= 0) {
+ /* RMU succeeded, use its results */
+ err = 0;
+ } else if (!mv88e6xxx_rmu_can_mdio_fallback(chip, err)) {
+ kfree(table);
+ goto out;
+ } else {
+ while (1) {
+ fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID,
+ fid + 1);
+ if (fid == MV88E6XXX_N_FID)
+ break;
- err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
- &count);
- if (err) {
- kfree(table);
- goto out;
+ err = mv88e6xxx_region_atu_snapshot_fid(chip, fid,
+ table, &count);
+ if (err) {
+ kfree(table);
+ goto out;
+ }
}
}
+
*data = (u8 *)table;
out:
mv88e6xxx_reg_unlock(chip);
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 5660372f41ad7..36422039030cd 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -106,6 +106,84 @@ static int mv88e6xxx_rmu_request(struct mv88e6xxx_chip *chip,
resp, resp_len, timeout_ms);
}
+int mv88e6xxx_rmu_dump_atu(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_devlink_atu_entry *entries,
+ u16 *cont_code)
+{
+ __be16 req[] = {
+ MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+ MV88E6XXX_RMU_REQ_PAD,
+ MV88E6XXX_RMU_REQ_CODE_ATU,
+ htons(*cont_code),
+ };
+ struct mv88e6xxx_rmu_atu_resp resp;
+ int resp_len, count;
+ int ret, i;
+
+ if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+ return -EOPNOTSUPP;
+
+ resp_len = sizeof(resp);
+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+ &resp, resp_len,
+ MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+ if (ret < 0) {
+ dev_dbg(chip->dev, "RMU: error for command DUMP_ATU %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ /* minimum packet length */
+ resp_len = sizeof(struct mv88e6xxx_rmu_header) + sizeof(__be16); /* cont_code */
+
+ if (ret < resp_len || (ret - resp_len) % sizeof(struct mv88e6xxx_rmu_atu_entry)) {
+ dev_err(chip->dev, "RMU: DUMP_ATU returned wrong length: rx %d expecting %zd\n",
+ ret, sizeof(resp));
+ return -EPROTO;
+ }
+
+ count = (ret - resp_len) / sizeof(struct mv88e6xxx_rmu_atu_entry);
+
+ if (resp.rmu_header.code != MV88E6XXX_RMU_RESP_CODE_ATU) {
+ dev_err(chip->dev, "RMU: DUMP_ATU returned wrong code %d\n",
+ be16_to_cpu(resp.rmu_header.code));
+ return -EPROTO;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct mv88e6xxx_rmu_atu_entry *src = &resp.entries[i];
+ struct mv88e6xxx_devlink_atu_entry *dst = &entries[i];
+ u16 tmp;
+
+ tmp = ntohs(src->state_trunk_dpv);
+ if (!MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(tmp)) {
+ *cont_code = 0;
+ return i;
+ }
+
+ dst->atu_data = MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(tmp) & 0xf;
+ if (tmp & MV88E6XXX_RMU_ATU_TRUNK)
+ dst->atu_data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
+ dst->atu_data |= (MV88E6XXX_RMU_ATU_DPV_GET(tmp) &
+ mv88e6xxx_port_mask(chip)) << 4;
+
+ tmp = ntohs(src->pri_fid);
+ dst->fid = MV88E6XXX_RMU_ATU_FID_GET(tmp);
+ dst->atu_op = MV88E6XXX_G1_ATU_OP_GET_NEXT_DB;
+
+ dst->atu_01 = ntohs(src->atu_01);
+ dst->atu_23 = ntohs(src->atu_23);
+ dst->atu_45 = ntohs(src->atu_45);
+ }
+
+ if (i == MV88E6XXX_RMU_MAX_ATU_ENTRIES)
+ *cont_code = ntohs(resp.cont_code);
+ else
+ *cont_code = 0;
+
+ return i;
+}
+
int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
u64 *data,
const struct mv88e6xxx_hw_stat *hw_stats,
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index 0865e899cb340..3a288ff3b113f 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -17,6 +17,7 @@
#define MV88E6XXX_RMU_REQ_FORMAT_SOHO htons(0x0001)
#define MV88E6XXX_RMU_REQ_PAD htons(0x0000)
#define MV88E6XXX_RMU_REQ_CODE_GET_ID htons(0x0000)
+#define MV88E6XXX_RMU_REQ_CODE_ATU htons(0x1000)
#define MV88E6XXX_RMU_REQ_CODE_MIB htons(0x1020)
#define MV88E6XXX_RMU_REQ_CODE_REG_RW htons(0x2000)
#define MV88E6XXX_RMU_REQ_DATA htons(0x0000)
@@ -50,6 +51,7 @@
#define MV88E6XXX_RMU_RESP_FORMAT_1 htons(0x0001)
#define MV88E6XXX_RMU_RESP_FORMAT_2 htons(0x0002)
#define MV88E6XXX_RMU_RESP_CODE_GOT_ID htons(0x0000)
+#define MV88E6XXX_RMU_RESP_CODE_ATU htons(0x1000)
#define MV88E6XXX_RMU_RESP_CODE_MIB htons(0x1020)
#define MV88E6XXX_RMU_RESP_CODE_REG_RW htons(0x2000)
@@ -67,6 +69,34 @@ struct mv88e6xxx_rmu_rw_resp {
__be16 end1;
} __packed;
+struct mv88e6xxx_rmu_atu_entry {
+ __be16 state_trunk_dpv;
+ __be16 atu_01;
+ __be16 atu_23;
+ __be16 atu_45;
+ __be16 pri_fid;
+} __packed;
+
+#define MV88E6XXX_RMU_MAX_ATU_ENTRIES 48
+
+#define MV88E6XXX_RMU_ATU_ENTRY_STATE_MASK GENMASK(15, 12)
+#define MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(p) FIELD_GET(MV88E6XXX_RMU_ATU_ENTRY_STATE_MASK, p)
+#define MV88E6XXX_RMU_ATU_TRUNK 0x0800
+#define MV88E6XXX_RMU_ATU_DPV_MASK GENMASK(10, 0)
+#define MV88E6XXX_RMU_ATU_DPV_GET(p) FIELD_GET(MV88E6XXX_RMU_ATU_DPV_MASK, p)
+
+#define MV88E6XXX_RMU_ATU_PRI_MASK GENMASK(14, 12)
+#define MV88E6XXX_RMU_ATU_PRI_GET(p) FIELD_GET(MV88E6XXX_RMU_ATU_PRI_MASK, p)
+
+#define MV88E6XXX_RMU_ATU_FID_MASK GENMASK(11, 0)
+#define MV88E6XXX_RMU_ATU_FID_GET(p) FIELD_GET(MV88E6XXX_RMU_ATU_FID_MASK, p)
+
+struct mv88e6xxx_rmu_atu_resp {
+ struct mv88e6xxx_rmu_header rmu_header;
+ struct mv88e6xxx_rmu_atu_entry entries[MV88E6XXX_RMU_MAX_ATU_ENTRIES];
+ __be16 cont_code;
+} __packed;
+
/* number of RMU MIB statistics, by type, in octets */
#define MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN 128
#define MV88E6XXX_RMU_STATS_TYPE_PORT_LEN 12
@@ -81,6 +111,11 @@ struct mv88e6xxx_rmu_mib_resp {
__be32 data[MV88E6XXX_RMU_STATS_TYPE_MAX_LEN / 4];
} __packed;
+struct mv88e6xxx_devlink_atu_entry;
+
+int mv88e6xxx_rmu_dump_atu(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_devlink_atu_entry *entries,
+ u16 *cont_code);
int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
u64 *data,
const struct mv88e6xxx_hw_stat *hw_stats,
--
2.43.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
` (16 preceding siblings ...)
2026-07-03 7:46 ` [PATCH net-next 17/17] net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink Luke Howard
@ 2026-07-03 8:05 ` Paolo Abeni
17 siblings, 0 replies; 27+ messages in thread
From: Paolo Abeni @ 2026-07-03 8:05 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Kieran Tyrrell,
Ryan Wilkins, Mattias Forsblad, netdev, linux-kernel
On 7/3/26 9:46 AM, Luke Howard wrote:
> This patch set shephards a series of commits made by Andrew Lunn
> and others to support remotely managing Marvell switches over
> Ethernet (as opposed to MDIO) using the Remote Management Unit
> (RMU).
>
> This is the second of four patch sets: the remaining two add
> support for remote management when MDIO is unavailable.
>
> Signed-off-by: Luke Howard <lukeh@padl.com>
You have already 35 patches pending. Please read carefully:
https://elixir.bootlin.com/linux/v7.1.2/source/Documentation/process/maintainer-netdev.rst
and specifically `Limit patches outstanding on mailing list`
Also note that the limit is supposed to be approached/reached by
submitters with a well known history of positive contributions (i.e.
reviews).
I'm deferring (at least) this series. Please repost only after that the
other pending ones have been processed.
/P
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation.
2026-07-03 7:46 ` [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation Luke Howard
@ 2026-07-03 13:04 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:04 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Mattias Forsblad <mattias.forsblad@gmail.com>
>
>Support connecting Marvell dsa tagger to the switch driver frame2reg
>function to decode received RMU frames.
>
>(Note: during teardown or failed setup, tagger_data may be NULL when
>a late FRAME2REG frame arrives.)
>
>Signed-off-by: Luke Howard <lukeh@padl.com>
>Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Hi,
i believe your sob tag should be the last one
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame
2026-07-03 7:46 ` [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame Luke Howard
@ 2026-07-03 13:06 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:06 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Andrew Lunn <andrew@lunn.ch>
>
>A RMU frame sent to the switch needs a DSA header. Add a helper to the
>tag driver to add such a header to an skbuff, and provide access to
>the helper via the tagger data structure. This keeps most of the
>details of the DSA header in the tag driver.
>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
your tag is missing here; please check tags correctness over the whole series
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches.
2026-07-03 7:46 ` [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches Luke Howard
@ 2026-07-03 13:07 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:07 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Mattias Forsblad <mattias.forsblad@gmail.com>
>
>Add RMU enable and disable functionality for some Marvell SOHO
>switches.
>
>Reviewed-by: Andrew Lunn <andrew@lunn.ch>
>Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
>Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>---
you tag should be the last one
>+int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
>+{
>+ int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
unclear for me why to init it if all allowed scenarios put some values into val?
here and for following
>+
>+ switch (port) {
>+ case 9:
>+ val = MV88E6085_G1_CTL2_RM_ENABLE;
>+ break;
>+ case 10:
>+ val = MV88E6085_G1_CTL2_RM_ENABLE | MV88E6085_G1_CTL2_P10RM;
>+ break;
>+ default:
>+ return -EOPNOTSUPP;
>+ }
>+
>+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
>+ MV88E6085_G1_CTL2_RM_ENABLE, val);
>+}
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler
2026-07-03 7:46 ` [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler Luke Howard
@ 2026-07-03 13:17 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:17 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Andrew Lunn <andrew@lunn.ch>
>
>When the conduit interface comes up, try to enable the RMU. Failing to
>enable the remote management unit is not fatal, not all chips support
>it, and some boards have chips which do support RMU, but with wrong
>port is connected to the CPU.
>
>When the conduit interface goes down, disable the RMU.
>
>Keep track of the conduit interface, so that RMU frames can be sent to
>it.
>
>Co-developed: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
...
>+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
>@@ -0,0 +1,50 @@
>+// SPDX-License-Identifier: GPL-2.0-or-later
>+/*
>+ * Marvell 88E6xxx Switch Remote Management Unit Support
>+ *
>+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
shouldn't present year be put here?
>+ *
>+ */
>+
>+#include <net/dsa.h>
>+#include "chip.h"
>+#include "global1.h"
>+#include "rmu.h"
>+
>+void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
>+ const struct net_device *conduit,
>+ bool operational)
>+{
>+ struct dsa_port *cpu_dp = conduit->dsa_ptr;
>+ struct mv88e6xxx_chip *chip = ds->priv;
>+ int port;
>+ int ret;
could be squashed
>+
>+ port = dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
>+
>+ mv88e6xxx_reg_lock(chip);
>+
>+ if (operational && chip->info->ops->rmu_enable) {
>+ ret = chip->info->ops->rmu_enable(chip, port);
>+ if (ret == -EOPNOTSUPP) {
>+ dev_info(chip->dev, "RMU: not usable on this board");
do this case really needs to be treated different way if the general
case already prints error code?
>+ goto out;
>+ } else if (ret < 0) {
>+ dev_err(chip->dev, "RMU: unable to enable on port %d %pe",
>+ port, ERR_PTR(ret));
>+ goto out;
>+ }
>+
>+ WRITE_ONCE(chip->rmu_conduit, (struct net_device *)conduit);
>+
>+ dev_dbg(chip->dev, "RMU: Enabled on port %d", port);
>+ } else {
>+ if (chip->info->ops->rmu_disable)
>+ chip->info->ops->rmu_disable(chip);
>+
>+ WRITE_ONCE(chip->rmu_conduit, NULL);
>+ }
>+
>+out:
>+ mv88e6xxx_reg_unlock(chip);
>+}
>diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
>new file mode 100644
>index 0000000000000..71c4fc1d4113f
>--- /dev/null
>+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
>@@ -0,0 +1,15 @@
>+/* SPDX-License-Identifier: GPL-2.0+ */
>+/*
>+ * Marvell 88E6xxx Switch Remote Management Unit Support
>+ *
>+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
>+ *
>+ */
>+
>+#ifndef _MV88E6XXX_RMU_H_
>+#define _MV88E6XXX_RMU_H_
>+
>+void mv88e6xxx_rmu_conduit_state_change(struct dsa_switch *ds,
>+ const struct net_device *conduit,
>+ bool operational);
>+#endif /* _MV88E6XXX_RMU_H_ */
>
>--
>2.43.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler
2026-07-03 7:46 ` [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler Luke Howard
@ 2026-07-03 13:25 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:25 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Andrew Lunn <andrew@lunn.ch>
>
>When the tagging protocol handler is attached to the DSA driver, it
>can validate it is a supported tagging protocol. It can also setup
>data shared between the tagger and the switch driver. Ensure a Mavell
s/Mavell/Marvell ?
>DSA tagger is being connected, and setup the handler from RMU in the
>shared data. At this point, the handler is just an empty stub, but
>later patches will add the needed functionality.
>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>---
> drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++++++++++++++
> drivers/net/dsa/mv88e6xxx/rmu.c | 6 ++++++
> drivers/net/dsa/mv88e6xxx/rmu.h | 3 +++
> 3 files changed, 27 insertions(+)
>
>diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>index 72c93cb84b7e1..fe0d0eb8f0813 100644
>--- a/drivers/net/dsa/mv88e6xxx/chip.c
>+++ b/drivers/net/dsa/mv88e6xxx/chip.c
>@@ -7183,6 +7183,23 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
> return err_sync ? : err_pvt;
> }
>
>+static int mv88e6xxx_connect_tag_protocol(struct dsa_switch *ds,
>+ enum dsa_tag_protocol proto)
>+{
>+ struct dsa_tagger_data *tagger_data = ds->tagger_data;
>+
>+ switch (proto) {
>+ case DSA_TAG_PROTO_DSA:
>+ case DSA_TAG_PROTO_EDSA:
>+ tagger_data->rmu_frame2reg = mv88e6xxx_rmu_frame2reg_handler;
>+ break;
>+ default:
>+ return -EPROTONOSUPPORT;
>+ }
do we really need to use switch for 0/1 cases?
>+
>+ return 0;
>+}
>+
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU
2026-07-03 7:46 ` [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU Luke Howard
@ 2026-07-03 13:38 ` Jagielski, Jedrzej
0 siblings, 0 replies; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-03 13:38 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>
>From: Andrew Lunn <andrew@lunn.ch>
>
>When the RMU is enabled, it is recommended to get the product ID,
>which identifies the switch. This is used as a test that communication
>with the switch actually works and the RMU can be used. If successful,
>mark the RMU usable.
>
>This completes the general infrastructure to send a request and
>process the response.
>
>Co-developed: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>Signed-off-by: Luke Howard <lukeh@padl.com>
>---
> drivers/net/dsa/mv88e6xxx/chip.h | 10 +++
> drivers/net/dsa/mv88e6xxx/rmu.c | 151 ++++++++++++++++++++++++++++++++++++++-
> drivers/net/dsa/mv88e6xxx/rmu.h | 11 +++
> 3 files changed, 170 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
>index 940ae698659fc..07300c25cbd36 100644
>--- a/drivers/net/dsa/mv88e6xxx/chip.h
>+++ b/drivers/net/dsa/mv88e6xxx/chip.h
>@@ -346,6 +346,15 @@ struct mv88e6xxx_tcam {
> struct list_head entries;
> };
>
>+enum mv88e6xxx_rmu_state {
>+ MV88E6XXX_RMU_DISABLED = 0,
>+ MV88E6XXX_RMU_ENABLED = 1,
>+ /* Reserved: a future RMU-only mode (e.g. MV88E6XXX_RMU_ONLY_ENABLED)
>+ * may be added here to indicate a switch operating purely via RMU
>+ * without an MDIO bus.
>+ */
As from what i see it's not being extended within the series, can we drop
that comment and use simple bool enabled/disabled in the place of
mv88e6xxx_rmu_state?
or am I missing something and > 2 states are needed
...
>+ return dsa_inband_request(&chip->rmu_inband, skb,
>+ (edsa ? mv88e6xxx_rmu_fill_seqno_edsa :
>+ mv88e6xxx_rmu_fill_seqno_dsa),
>+ resp, resp_len, timeout_ms);
>+}
>+
>+static int mv88e6xxx_rmu_get_id(struct mv88e6xxx_chip *chip)
>+{
>+ const __be16 req[4] = {
>+ MV88E6XXX_RMU_REQ_FORMAT_GET_ID,
>+ MV88E6XXX_RMU_REQ_PAD,
>+ MV88E6XXX_RMU_REQ_CODE_GET_ID,
>+ MV88E6XXX_RMU_REQ_DATA};
>+ struct mv88e6xxx_rmu_header resp;
>+ int resp_len;
>+ int ret = -1;
no need to init
>+
>+ resp_len = sizeof(resp);
>+ ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure
2026-07-03 7:46 ` [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure Luke Howard
@ 2026-07-06 7:17 ` Jagielski, Jedrzej
2026-07-06 9:42 ` Luke Howard
0 siblings, 1 reply; 27+ messages in thread
From: Jagielski, Jedrzej @ 2026-07-06 7:17 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Andrew Lunn <andrew@lunn.ch>
>
>Different families of switches have different statistics available.
>This information is current hard coded into functions, however this
>information will also soon be needed when getting statistics from the
>RMU. Move it into the info structure.
>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>---
> drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
>diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>index 6431d25f3cfa2..5c0a1e2b0507d 100644
>--- a/drivers/net/dsa/mv88e6xxx/chip.c
>+++ b/drivers/net/dsa/mv88e6xxx/chip.c
>@@ -1303,6 +1303,9 @@ static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
Is everything fine with this patch?
There's nothing beside adding checks to some of the functions
(which is reverted in the upcoming patch) what does not
seem to be corresponding to the commit msg
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
> return 1;
>@@ -1312,6 +1315,9 @@ static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
> return 1;
>@@ -1321,6 +1327,9 @@ static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
> MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
>@@ -1331,6 +1340,9 @@ static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
> MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
> 0);
>
>--
>2.43.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure
2026-07-06 7:17 ` Jagielski, Jedrzej
@ 2026-07-06 9:42 ` Luke Howard
0 siblings, 0 replies; 27+ messages in thread
From: Luke Howard @ 2026-07-06 9:42 UTC (permalink / raw)
To: Jagielski, Jedrzej
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King,
Richard Cochran, Florian Fainelli, Cedric Jehasse, Max Holtmann,
Max Hunter, Tyrrell, Kieran, Ryan Wilkins, Mattias Forsblad,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
> Is everything fine with this patch?
> There's nothing beside adding checks to some of the functions
> (which is reverted in the upcoming patch) what does not
> seem to be corresponding to the commit msg
This (Marvell RMU) patch series has been deferred, I’ll note your comments and return to them once the other patch series I have submitted have been processed.
Cheers,
Luke
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2026-07-06 9:42 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03 7:46 [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Luke Howard
2026-07-03 7:46 ` [PATCH net-next 01/17] net: dsa: mv88e6xxx: use lockdep_assert_held() if CONFIG_LOCKDEP Luke Howard
2026-07-03 7:46 ` [PATCH net-next 02/17] net: dsa: mv88e6xxx: Introduce Marvell dsa tagger data operation Luke Howard
2026-07-03 13:04 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 03/17] net: dsa: tag_dsa: Add helper to add DSA header to RMU frame Luke Howard
2026-07-03 13:06 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 04/17] net: dsa: mv88e6xxx: Add RMU enable/disable for select switches Luke Howard
2026-07-03 13:07 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 05/17] net: dsa: mv88e6xxx: Add conduit state change handler Luke Howard
2026-07-03 13:17 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 06/17] net: dsa: mv88e6xxx: Remove mv88e6xxx_rmu_setup() Luke Howard
2026-07-03 7:46 ` [PATCH net-next 07/17] net: dsa: mv88e6xxx: Add connect_tag_protocol handler Luke Howard
2026-07-03 13:25 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 08/17] net: dsa: mv88e6xxx: Add sanity check of received RMU frame Luke Howard
2026-07-03 7:46 ` [PATCH net-next 09/17] net: dsa: mv88e6xxx: Get Product ID when enabling RMU Luke Howard
2026-07-03 13:38 ` Jagielski, Jedrzej
2026-07-03 7:46 ` [PATCH net-next 10/17] net: dsa: mv88e6xxx: Add RMU register read/write/wait for bit Luke Howard
2026-07-03 7:46 ` [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure Luke Howard
2026-07-06 7:17 ` Jagielski, Jedrzej
2026-07-06 9:42 ` Luke Howard
2026-07-03 7:46 ` [PATCH net-next 12/17] net: dsa: mv88e6xxx: Centralise common statistics check Luke Howard
2026-07-03 7:46 ` [PATCH net-next 13/17] net: dsa: mv88e6xxx: Get some MIB stats via the RMU Luke Howard
2026-07-03 7:46 ` [PATCH net-next 14/17] net: dsa: mv88e6xxx: Time RMU operations and disable if slow Luke Howard
2026-07-03 7:46 ` [PATCH net-next 15/17] net: dsa: mv88e6xxx: cancel PTP polling work on .shutdown Luke Howard
2026-07-03 7:46 ` [PATCH net-next 16/17] net: dsa: mv88e6xxx: size ATU snapshot buffer and region by num_macs Luke Howard
2026-07-03 7:46 ` [PATCH net-next 17/17] net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink Luke Howard
2026-07-03 8:05 ` [PATCH net-next 00/17] net: dsa: mv88e6xxx: support for Remote Management Unit Paolo Abeni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox