[PATCH net-next v4 1/2] net: dsa: mv88e6xxx: use the hw tx queues
From: Cedric Jehasse via B4 Relay
Date: Thu May 28 2026 - 12:25:47 EST
From: Cedric Jehasse <cedric.jehasse@xxxxxxxxxx>
When transmitting fill in the PRI field in the dsa tag to select the
egress queue is sent to.
>From the datasheets i've looked at these switches have 4 or 8 transmit
queues per port.
Note: skbs with skb->fw_offload_fwd_mark set use the DSA_CMD_FORWARD
tag. These are processed as normal ingress frames, meaning the queue
they end up in can still be altered by other switch config. eg. priority
overrides, tcam policies.
This isn't done for vlan tagged frames because this would overwrite the
PCP value in the vlan tag (The PRI field in the dsa
tag is used as the PCP value in the vlan tag).
Signed-off-by: Cedric Jehasse <cedric.jehasse@xxxxxxxxxx>
---
drivers/net/dsa/mv88e6xxx/chip.c | 35 +++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
net/dsa/tag_dsa.c | 11 ++++++++++-
3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8ca5fd40df92..ffd4fa41b7c5 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3979,6 +3979,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
chip->ds = ds;
ds->user_mii_bus = mv88e6xxx_default_mdio_bus(chip);
+ ds->num_tx_queues = chip->info->num_tx_queues;
/* Since virtual bridges are mapped in the PVT, the number we support
* depends on the physical switch topology. We need to let DSA figure
@@ -5689,6 +5690,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
*/
.num_ports = 7,
.num_internal_phys = 2,
+ .num_tx_queues = 4,
.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
.max_vid = 4095,
.port_base_addr = 0x8,
@@ -5711,6 +5713,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_databases = 64,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x08,
.phy_base_addr = 0x00,
@@ -5733,6 +5736,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 10,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5757,6 +5761,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 11,
.num_internal_phys = 0,
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x10,
.phy_base_addr = 0x0,
@@ -5778,6 +5783,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 11,
.num_internal_phys = 8,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5803,6 +5809,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 1024,
.num_ports = 3,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5828,6 +5835,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 8,
.num_internal_phys = 0,
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x10,
.phy_base_addr = 0x0,
@@ -5850,6 +5858,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 6,
.num_internal_phys = 5,
.num_gpio = 11,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5875,6 +5884,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 1024,
.num_ports = 6,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5901,6 +5911,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 6,
.num_internal_phys = 0,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5926,6 +5937,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5952,6 +5964,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 7,
.num_internal_phys = 5,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -5977,6 +5990,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6003,6 +6017,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 7,
.num_internal_phys = 5,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6028,6 +6043,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 10,
.num_internal_phys = 0,
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x10,
.phy_base_addr = 0x0,
@@ -6051,6 +6067,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
.num_gpio = 16,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6076,6 +6093,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
.num_gpio = 16,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6100,6 +6118,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6125,6 +6144,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 8,
.internal_phys_offset = 1,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6151,6 +6171,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 8,
.num_tcam_entries = 256,
.internal_phys_offset = 1,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6181,6 +6202,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 7,
.num_internal_phys = 2,
.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x08,
.phy_base_addr = 0x00,
@@ -6205,6 +6227,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 7,
.num_internal_phys = 5,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6230,6 +6253,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_databases = 64,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.port_base_addr = 0x08,
.phy_base_addr = 0x00,
@@ -6254,6 +6278,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 9,
.num_gpio = 16,
.num_tcam_entries = 256,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6282,6 +6307,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 2,
.internal_phys_offset = 3,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6310,6 +6336,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 2,
.internal_phys_offset = 3,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6337,6 +6364,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 5,
.num_ports = 6,
.num_gpio = 11,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6363,6 +6391,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6388,6 +6417,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6414,6 +6444,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 7,
.num_internal_phys = 5,
.num_gpio = 15,
+ .num_tx_queues = 4,
.max_vid = 4095,
.max_sid = 63,
.port_base_addr = 0x10,
@@ -6442,6 +6473,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.invalid_port_mask = BIT(1) | BIT(2) | BIT(8),
.num_internal_phys = 5,
.internal_phys_offset = 3,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6468,6 +6500,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_internal_phys = 9,
.num_gpio = 16,
.num_tcam_entries = 256,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6495,6 +6528,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
.num_gpio = 16,
+ .num_tx_queues = 8,
.max_vid = 8191,
.max_sid = 63,
.port_base_addr = 0x0,
@@ -6521,6 +6555,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 8,
.num_tcam_entries = 256,
+ .num_tx_queues = 8,
.internal_phys_offset = 1,
.max_vid = 8191,
.max_sid = 63,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index cde71828e9d9..19d8eda19b78 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -136,6 +136,7 @@ struct mv88e6xxx_info {
unsigned int num_internal_phys;
unsigned int num_gpio;
unsigned int num_tcam_entries;
+ unsigned int num_tx_queues;
unsigned int max_vid;
unsigned int max_sid;
unsigned int port_base_addr;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 2a2c4fb61a65..cc27b2994c6b 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -179,8 +179,17 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
dsa_header[2] &= ~0x10;
}
} else {
+ u16 queue = skb_get_queue_mapping(skb) & 0x7;
u16 vid;
+ /* The PRI field is 3 bits. According to the documentation the
+ * 2 highest bits specify the egress queue in From_CPU DSA
+ * tagged frames. On devices with 8 queues it's possible to
+ * send to the 8 queues, which means the 3 bits are used.
+ */
+ if (dp->ds->num_tx_queues == 4)
+ queue <<= 1;
+
vid = br_dev ? MV88E6XXX_VID_BRIDGED : MV88E6XXX_VID_STANDALONE;
skb_push(skb, DSA_HLEN + extra);
@@ -191,7 +200,7 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
dsa_header[0] = (cmd << 6) | tag_dev;
dsa_header[1] = tag_port << 3;
- dsa_header[2] = vid >> 8;
+ dsa_header[2] = (queue << 5) | vid >> 8;
dsa_header[3] = vid & 0xff;
}
--
2.43.0