* [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper
@ 2026-05-26 11:41 Cedric Jehasse via B4 Relay
2026-05-26 11:41 ` [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues Cedric Jehasse via B4 Relay
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Cedric Jehasse via B4 Relay @ 2026-05-26 11:41 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King
Cc: netdev, linux-kernel, Cedric Jehasse
Several of the switch families in this driver have switches with AVB
support. The switches with AVB support have support for Credit based
shaping. This series adds support for the 6352, 6390 and 6393 families.
The difference between the families is:
- total number of queues
- which queues support credit based shaping
- shaping granularity
Eg. setting up 20mbps credit based shaper on a 1GBit link:
tc qdisc add dev p8 parent root handle 100: mqprio \
num_tc 8 \
map 0 0 6 7 0 5 0 0 0 0 0 0 0 0 0 0 \
queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
hw 0
tc qdisc replace dev p8 parent 100:8 cbs locredit -1470 hicredit 30 \
sendslope -980000 idleslope 20000 offload 1
Signed-off-by: Cedric Jehasse <cedric.jehasse@luminex.be>
---
Changes in v2:
- tx_queues defined for all devices (which could be found). Thanks to Marek Behún.
- Link to v1: https://lore.kernel.org/r/20260522-net-next-mv88e6xxx-cbs-v1-0-c87a8e6bcc0c@luminex.be
---
Cedric Jehasse (2):
net: dsa: mv88e6xxx: use the hw tx queues
net: dsa: mv88e6xxx: add support for credit based shaper
drivers/net/dsa/mv88e6xxx/chip.c | 157 ++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 22 +++++
drivers/net/dsa/mv88e6xxx/global2_avb.c | 21 +++++
drivers/net/dsa/mv88e6xxx/port.c | 38 ++++++++
drivers/net/dsa/mv88e6xxx/port.h | 16 ++++
net/dsa/tag_dsa.c | 3 +-
6 files changed, 256 insertions(+), 1 deletion(-)
---
base-commit: 022bdd9c0d036863c4bacd1688b73c6be3001cee
change-id: 20260430-net-next-mv88e6xxx-cbs-2121169caa68
Best regards,
--
Cedric Jehasse <cedric.jehasse@luminex.be>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
2026-05-26 11:41 [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
@ 2026-05-26 11:41 ` Cedric Jehasse via B4 Relay
2026-05-26 12:30 ` Andrew Lunn
2026-05-26 11:41 ` [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
2026-05-26 12:19 ` [PATCH net-next v2 0/2] " Andrew Lunn
2 siblings, 1 reply; 9+ messages in thread
From: Cedric Jehasse via B4 Relay @ 2026-05-26 11:41 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King
Cc: netdev, linux-kernel, Cedric Jehasse
From: Cedric Jehasse <cedric.jehasse@luminex.be>
From the datasheets i've looked at these switches have 4 or 8 transmit
queues per port.
There's a PRI field in the dsa tag used to indicate which egress queue
the frame is to be sent to.
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@luminex.be>
---
drivers/net/dsa/mv88e6xxx/chip.c | 34 ++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
net/dsa/tag_dsa.c | 3 ++-
3 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8ca5fd40df92..70a6d46066e7 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,
@@ -6125,6 +6143,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 +6170,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 +6201,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 +6226,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 +6252,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 +6277,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 +6306,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 +6335,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 +6363,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 +6390,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 +6416,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 +6443,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 +6472,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 +6499,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 +6527,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 +6554,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..96c8fbedbd3b 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -179,6 +179,7 @@ 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;
vid = br_dev ? MV88E6XXX_VID_BRIDGED : MV88E6XXX_VID_STANDALONE;
@@ -191,7 +192,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
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper
2026-05-26 11:41 [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
2026-05-26 11:41 ` [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues Cedric Jehasse via B4 Relay
@ 2026-05-26 11:41 ` Cedric Jehasse via B4 Relay
2026-05-26 15:49 ` Andrew Lunn
2026-05-26 12:19 ` [PATCH net-next v2 0/2] " Andrew Lunn
2 siblings, 1 reply; 9+ messages in thread
From: Cedric Jehasse via B4 Relay @ 2026-05-26 11:41 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King
Cc: netdev, linux-kernel, Cedric Jehasse
From: Cedric Jehasse <cedric.jehasse@luminex.be>
Some of the chips supported by this driver have credit based shaper
support. Support is added for the 6352, 6390 and 6393 families.
This is configured using the Qav registers in the AVB register block.
There are small differences in the Qav registers between the chip
families (eg. the unit used for the rate and number of bits in the
registers). mv88e6xxx_qav_info is introduced to configure this per chip.
Eg. setting up 20mbps credit based shaper on a 1GBit link:
tc qdisc add dev p8 parent root handle 100: mqprio \
num_tc 8 \
map 0 0 6 7 0 5 0 0 0 0 0 0 0 0 0 0 \
queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
hw 0
tc qdisc replace dev p8 parent 100:8 cbs locredit -1470 hicredit 30 \
sendslope -980000 idleslope 20000 offload 1
Note: only idleslope and hicredit can be programmed in the switch
registers, other parameters won't affect settings.
Signed-off-by: Cedric Jehasse <cedric.jehasse@luminex.be>
---
drivers/net/dsa/mv88e6xxx/chip.c | 123 ++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 21 ++++++
drivers/net/dsa/mv88e6xxx/global2_avb.c | 21 ++++++
drivers/net/dsa/mv88e6xxx/port.c | 38 ++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 16 +++++
5 files changed, 219 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 70a6d46066e7..8e6f8217b77f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -32,6 +32,7 @@
#include <linux/gpio/consumer.h>
#include <linux/phylink.h>
#include <net/dsa.h>
+#include <net/pkt_sched.h>
#include "chip.h"
#include "devlink.h"
@@ -5015,6 +5016,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_ether_type = mv88e6351_port_set_ether_type,
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_set_scheduling_mode = mv88e6352_port_set_scheduling_mode,
.port_pause_limit = mv88e6097_port_pause_limit,
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
@@ -5446,6 +5448,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_ether_type = mv88e6351_port_set_ether_type,
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_set_scheduling_mode = mv88e6352_port_set_scheduling_mode,
.port_pause_limit = mv88e6097_port_pause_limit,
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
@@ -5515,6 +5518,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_get_cmode = mv88e6352_port_get_cmode,
.port_set_cmode = mv88e6390_port_set_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
+ .port_set_scheduling_mode = mv88e6390_port_set_scheduling_mode,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -5580,6 +5584,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_get_cmode = mv88e6352_port_get_cmode,
.port_set_cmode = mv88e6390x_port_set_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
+ .port_set_scheduling_mode = mv88e6390_port_set_scheduling_mode,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -5637,6 +5642,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.port_set_ether_type = mv88e6393x_port_set_ether_type,
.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_set_scheduling_mode = mv88e6390_port_set_scheduling_mode,
.port_pause_limit = mv88e6390_port_pause_limit,
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
@@ -5679,6 +5685,22 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.tcam_ops = &mv88e6393_tcam_ops,
};
+static const struct mv88e6xxx_qav_info mv88e6352_qav_info = {
+ .max_rate = 1000000,
+ .rate_unit = 32,
+ .rate_mask = GENMASK(14, 0),
+ .hi_limit_mask = GENMASK(14, 0),
+ .queue_mask = GENMASK(3, 0),
+};
+
+static const struct mv88e6xxx_qav_info mv88e6390_qav_info = {
+ .max_rate = 4000000,
+ .rate_unit = 64,
+ .rate_mask = GENMASK(15, 0),
+ .hi_limit_mask = GENMASK(13, 0),
+ .queue_mask = GENMASK(7, 0),
+};
+
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
[MV88E6020] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6020,
@@ -6242,6 +6264,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.multi_chip = true,
.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
.ptp_support = true,
+ .qav = &mv88e6352_qav_info,
.ops = &mv88e6240_ops,
},
@@ -6459,6 +6482,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.multi_chip = true,
.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
.ptp_support = true,
+ .qav = &mv88e6352_qav_info,
.ops = &mv88e6352_ops,
},
[MV88E6361] = {
@@ -6516,6 +6540,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.multi_chip = true,
.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
.ptp_support = true,
+ .qav = &mv88e6390_qav_info,
.ops = &mv88e6390_ops,
},
[MV88E6390X] = {
@@ -6543,6 +6568,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.multi_chip = true,
.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
.ptp_support = true,
+ .qav = &mv88e6390_qav_info,
.ops = &mv88e6390x_ops,
},
@@ -6571,6 +6597,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.pvt = true,
.multi_chip = true,
.ptp_support = true,
+ .qav = &mv88e6390_qav_info,
.ops = &mv88e6393x_ops,
},
};
@@ -7192,6 +7219,101 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
return err_sync ? : err_pvt;
}
+static int mv88e6xxx_setup_tc_cbs(struct dsa_switch *ds, int port,
+ struct tc_cbs_qopt_offload *cbs)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ const struct mv88e6xxx_ops *ops = chip->info->ops;
+ const struct mv88e6xxx_avb_ops *avb_ops;
+ const struct mv88e6xxx_qav_info *qav;
+ int rate_reg;
+ int hilimit_reg;
+ u8 queue_bit;
+ u16 rate = 0;
+ u16 hi_limit;
+ int err;
+
+ avb_ops = ops->avb_ops;
+ qav = chip->info->qav;
+ if (!qav || !avb_ops || !avb_ops->port_qav_write ||
+ !ops->port_set_scheduling_mode)
+ return -EOPNOTSUPP;
+
+ if (!dsa_is_user_port(ds, port))
+ return -EOPNOTSUPP;
+
+ if (cbs->queue < 0 || cbs->queue >= chip->info->num_tx_queues)
+ return -EINVAL;
+
+ if (!(qav->queue_mask & BIT(cbs->queue)))
+ return -EOPNOTSUPP;
+
+ queue_bit = BIT(cbs->queue);
+ rate_reg = cbs->queue * 2;
+ hilimit_reg = rate_reg + 1;
+
+ if (cbs->enable) {
+ if (cbs->idleslope <= 0 ||
+ cbs->idleslope > qav->max_rate ||
+ cbs->sendslope >= 0 || cbs->hicredit <= 0 ||
+ cbs->hicredit > qav->hi_limit_mask)
+ return -ERANGE;
+
+ rate = DIV_ROUND_UP(cbs->idleslope, qav->rate_unit);
+ if (rate > qav->rate_mask)
+ return -ERANGE;
+ }
+
+ mv88e6xxx_reg_lock(chip);
+
+ if (!cbs->enable) {
+ err = avb_ops->port_qav_write(chip, port, rate_reg, 0);
+ if (err)
+ goto unlock;
+
+ if (!(chip->ports[port].cbs_active_queues & ~queue_bit)) {
+ err = ops->port_set_scheduling_mode(chip, port, 0);
+ if (err)
+ goto unlock;
+ }
+ chip->ports[port].cbs_active_queues &= ~queue_bit;
+ goto unlock;
+ }
+
+ hi_limit = cbs->hicredit & qav->hi_limit_mask;
+ err = avb_ops->port_qav_write(chip, port, hilimit_reg, hi_limit);
+ if (err)
+ goto unlock;
+
+ err = avb_ops->port_qav_write(chip, port, rate_reg, rate);
+ if (err)
+ goto unlock;
+
+ err = ops->port_set_scheduling_mode(chip, port,
+ chip->info->num_tx_queues - 1);
+ if (err) {
+ avb_ops->port_qav_write(chip, port, rate_reg, 0);
+ goto unlock;
+ }
+ chip->ports[port].cbs_active_queues |= queue_bit;
+
+unlock:
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
+static int mv88e6xxx_port_setup_tc(struct dsa_switch *ds, int port,
+ enum tc_setup_type type, void *type_data)
+{
+ switch (type) {
+ case TC_SETUP_QDISC_CBS:
+ return mv88e6xxx_setup_tc_cbs(ds, port, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = {
.mac_select_pcs = mv88e6xxx_mac_select_pcs,
.mac_prepare = mv88e6xxx_mac_prepare,
@@ -7251,6 +7373,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get,
.port_txtstamp = mv88e6xxx_port_txtstamp,
.port_rxtstamp = mv88e6xxx_port_rxtstamp,
+ .port_setup_tc = mv88e6xxx_port_setup_tc,
.cls_flower_add = mv88e6xxx_cls_flower_add,
.cls_flower_del = mv88e6xxx_cls_flower_del,
.get_ts_info = mv88e6xxx_get_ts_info,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 19d8eda19b78..81c9fb2f0e92 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -125,6 +125,7 @@ enum mv88e6xxx_edsa_support {
};
struct mv88e6xxx_ops;
+struct mv88e6xxx_qav_info;
struct mv88e6xxx_info {
enum mv88e6xxx_family family;
@@ -177,6 +178,9 @@ struct mv88e6xxx_info {
/* Supports PTP */
bool ptp_support;
+ /* 802.1Qav credit based shaping */
+ const struct mv88e6xxx_qav_info *qav;
+
/* Internal PHY start index. 0 means that internal PHYs range starts at
* port 0, 1 means internal PHYs range starts at port 1, etc
*/
@@ -304,6 +308,9 @@ struct mv88e6xxx_port {
/* MacAuth Bypass control flag */
bool mab;
+
+ /* Queues with CBS currently enabled. */
+ u8 cbs_active_queues;
};
enum mv88e6xxx_region_id {
@@ -607,6 +614,8 @@ struct mv88e6xxx_ops {
size_t size);
int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port);
+ int (*port_set_scheduling_mode)(struct mv88e6xxx_chip *chip, int port,
+ u8 mode);
int (*port_pause_limit)(struct mv88e6xxx_chip *chip, int port, u8 in,
u8 out);
int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port);
@@ -764,6 +773,10 @@ struct mv88e6xxx_avb_ops {
int (*tai_read)(struct mv88e6xxx_chip *chip, int addr, u16 *data,
int len);
int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
+
+ /* Access port-scoped 802.1Qav registers */
+ int (*port_qav_write)(struct mv88e6xxx_chip *chip, int port, int addr,
+ u16 data);
};
struct mv88e6xxx_ptp_ops {
@@ -799,6 +812,14 @@ struct mv88e6xxx_tcam_ops {
int (*flush_tcam)(struct mv88e6xxx_chip *chip);
};
+struct mv88e6xxx_qav_info {
+ u32 max_rate; /* in kbps */
+ u16 rate_unit; /* in kbps */
+ u16 rate_mask; /* QPri Rate valid bits mask */
+ u16 hi_limit_mask; /* Qpri Hi Limit bits mask*/
+ u8 queue_mask; /* supported queues bitmask */
+};
+
static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip)
{
return chip->info->max_sid > 0 &&
diff --git a/drivers/net/dsa/mv88e6xxx/global2_avb.c b/drivers/net/dsa/mv88e6xxx/global2_avb.c
index 657783e043ff..6b54e275d21a 100644
--- a/drivers/net/dsa/mv88e6xxx/global2_avb.c
+++ b/drivers/net/dsa/mv88e6xxx/global2_avb.c
@@ -110,6 +110,15 @@ static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
return mv88e6xxx_g2_avb_write(chip, writeop, data);
}
+static int mv88e6352_g2_avb_port_qav_write(struct mv88e6xxx_chip *chip,
+ int port, int addr, u16 data)
+{
+ u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
+ (MV88E6352_G2_AVB_CMD_BLOCK_QAV << 5) | addr;
+
+ return mv88e6xxx_g2_avb_write(chip, writeop, data);
+}
+
static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
u16 *data, int len)
{
@@ -149,6 +158,7 @@ const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
.ptp_write = mv88e6352_g2_avb_ptp_write,
.tai_read = mv88e6352_g2_avb_tai_read,
.tai_write = mv88e6352_g2_avb_tai_write,
+ .port_qav_write = mv88e6352_g2_avb_port_qav_write,
};
static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
@@ -174,6 +184,7 @@ const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
.ptp_write = mv88e6352_g2_avb_ptp_write,
.tai_read = mv88e6165_g2_avb_tai_read,
.tai_write = mv88e6165_g2_avb_tai_write,
+ .port_qav_write = mv88e6352_g2_avb_port_qav_write,
};
static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
@@ -197,6 +208,15 @@ static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
return mv88e6xxx_g2_avb_write(chip, writeop, data);
}
+static int mv88e6390_g2_avb_port_qav_write(struct mv88e6xxx_chip *chip,
+ int port, int addr, u16 data)
+{
+ u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
+ (MV88E6352_G2_AVB_CMD_BLOCK_QAV << 5) | addr;
+
+ return mv88e6xxx_g2_avb_write(chip, writeop, data);
+}
+
static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
u16 *data, int len)
{
@@ -236,4 +256,5 @@ const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
.ptp_write = mv88e6390_g2_avb_ptp_write,
.tai_read = mv88e6390_g2_avb_tai_read,
.tai_write = mv88e6390_g2_avb_tai_write,
+ .port_qav_write = mv88e6390_g2_avb_port_qav_write,
};
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index c90117d2dd83..79422b8b01c8 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1348,6 +1348,44 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
0x0001);
}
+int mv88e6352_port_set_scheduling_mode(struct mv88e6xxx_chip *chip, int port,
+ u8 mode)
+{
+ u16 reg;
+ int err;
+
+ if (mode > 3)
+ return -EINVAL;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
+ ®);
+ if (err)
+ return err;
+
+ reg &= ~MV88E6XXX_PORT_EGRESS_RATE_CTL2_SCHEDULE_MASK;
+ reg |= mode << MV88E6XXX_PORT_EGRESS_RATE_CTL2_SCHEDULE_SHIFT;
+
+ return mv88e6xxx_port_write(chip, port,
+ MV88E6XXX_PORT_EGRESS_RATE_CTL2, reg);
+}
+
+int mv88e6390_port_set_scheduling_mode(struct mv88e6xxx_chip *chip, int port,
+ u8 mode)
+{
+ u16 reg;
+
+ if (mode > MV88E6390_PORT_QUEUE_CTL_SCHEDULE_MASK)
+ return -EINVAL;
+
+ reg = MV88E6390_PORT_QUEUE_CTL_UPDATE |
+ (MV88E6390_PORT_QUEUE_CTL_SCHEDULE <<
+ MV88E6390_PORT_QUEUE_CTL_PTR_SHIFT) |
+ (mode & MV88E6390_PORT_QUEUE_CTL_SCHEDULE_MASK);
+
+ return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_QUEUE_CTL,
+ reg);
+}
+
/* Offset 0x0B: Port Association Vector */
int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index f6041f91215e..c4b0ec1990b3 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -241,6 +241,18 @@
/* Offset 0x0A: Egress Rate Control 2 */
#define MV88E6XXX_PORT_EGRESS_RATE_CTL2 0x0a
+#define MV88E6XXX_PORT_EGRESS_RATE_CTL2_SCHEDULE_MASK 0x3000
+#define MV88E6XXX_PORT_EGRESS_RATE_CTL2_SCHEDULE_SHIFT 12
+
+/* Offset 0x1C: Port Queue Control */
+#define MV88E6390_PORT_QUEUE_CTL 0x1c
+#define MV88E6390_PORT_QUEUE_CTL_UPDATE 0x8000
+#define MV88E6390_PORT_QUEUE_CTL_PTR_MASK 0x7f00
+#define MV88E6390_PORT_QUEUE_CTL_PTR_SHIFT 8
+#define MV88E6390_PORT_QUEUE_CTL_DATA_MASK 0x00ff
+#define MV88E6390_PORT_QUEUE_CTL_SCHEDULE 0x00
+#define MV88E6390_PORT_QUEUE_CTL_SCHEDULE_MASK 0x07
+
/* Offset 0x0B: Port Association Vector */
#define MV88E6XXX_PORT_ASSOC_VECTOR 0x0b
@@ -569,6 +581,10 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
size_t size);
int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
+int mv88e6352_port_set_scheduling_mode(struct mv88e6xxx_chip *chip, int port,
+ u8 mode);
+int mv88e6390_port_set_scheduling_mode(struct mv88e6xxx_chip *chip, int port,
+ u8 mode);
int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
u16 pav);
int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper
2026-05-26 11:41 [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
2026-05-26 11:41 ` [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues Cedric Jehasse via B4 Relay
2026-05-26 11:41 ` [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
@ 2026-05-26 12:19 ` Andrew Lunn
2 siblings, 0 replies; 9+ messages in thread
From: Andrew Lunn @ 2026-05-26 12:19 UTC (permalink / raw)
To: cedric.jehasse, Luke Howard, Marek Behún
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Russell King, netdev, linux-kernel
On Tue, May 26, 2026 at 01:41:13PM +0200, Cedric Jehasse via B4 Relay wrote:
> Several of the switch families in this driver have switches with AVB
> support. The switches with AVB support have support for Credit based
> shaping. This series adds support for the 6352, 6390 and 6393 families.
Both Luke and Marek showed interest in your patches. So it is a good
idea to add them to the Cc: list. Comments or Reviewed-by: from them
will help get your patches merged.
Andrew
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
2026-05-26 11:41 ` [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues Cedric Jehasse via B4 Relay
@ 2026-05-26 12:30 ` Andrew Lunn
2026-05-26 13:21 ` Cedric Jehasse
0 siblings, 1 reply; 9+ messages in thread
From: Andrew Lunn @ 2026-05-26 12:30 UTC (permalink / raw)
To: cedric.jehasse
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Russell King, netdev, linux-kernel
On Tue, May 26, 2026 at 01:41:14PM +0200, Cedric Jehasse via B4 Relay wrote:
> From: Cedric Jehasse <cedric.jehasse@luminex.be>
>
> >From the datasheets i've looked at these switches have 4 or 8 transmit
> queues per port.
> There's a PRI field in the dsa tag used to indicate which egress queue
> the frame is to be sent to.
> 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).
Maybe a bit more context would be good here. This patch is about
frames the host is sending to the switch. Looking at just the commit
message this was not obvious. It was only when i looked at the tagger
change did i understand that.
Does DSA_CMD_FORWARD vs DSA_CMD_FROM_CPU make a difference here? Does
DSA_CMD_FROM_CPU skip some classification stages in the switch, where
as DSA_CMD_FORWARD might pass through more stages in the switch and
have the queue over written by the hardware?
Andrew
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
2026-05-26 12:30 ` Andrew Lunn
@ 2026-05-26 13:21 ` Cedric Jehasse
2026-05-26 14:15 ` Andrew Lunn
0 siblings, 1 reply; 9+ messages in thread
From: Cedric Jehasse @ 2026-05-26 13:21 UTC (permalink / raw)
To: Andrew Lunn
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Russell King, netdev, linux-kernel,
lukeh, Marek Behún
From: Andrew Lunn <andrew@lunn.ch>
Sent: Tuesday, May 26, 2026 2:30 PM
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Tuesday, May 26, 2026 2:30 PM
> To: Cedric Jehasse
> Cc: Vladimir Oltean; David S. Miller; Eric Dumazet; Jakub Kicinski; Paolo Abeni; Simon Horman; Russell King; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
>
> On Tue, May 26, 2026 at 01:41:14PM +0200, Cedric Jehasse via B4 Relay wrote:
> > From: Cedric Jehasse <cedric.jehasse@luminex.be>
> >
> > >From the datasheets i've looked at these switches have 4 or 8 transmit
> > queues per port.
> > There's a PRI field in the dsa tag used to indicate which egress queue
> > the frame is to be sent to.
> > 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).
>
> Maybe a bit more context would be good here. This patch is about
> frames the host is sending to the switch. Looking at just the commit
> message this was not obvious. It was only when i looked at the tagger
> change did i understand that.
>
> Does DSA_CMD_FORWARD vs DSA_CMD_FROM_CPU make a difference here? Does
> DSA_CMD_FROM_CPU skip some classification stages in the switch, where
> as DSA_CMD_FORWARD might pass through more stages in the switch and
> have the queue over written by the hardware?
>
> Andrew
Yes, this is what the documentation says on DSA_CMD_FORWARD:
> Used for frames that are forwarded in a normal way (ingress and egress filtering is performed on these frames).
And on DSA_CMD_FROM_CPU:
> Used for frames that need to tunnel through Blocked ports (like BPDU's). No ingress or egress filtering is perfromed.
> Frames egress out the Trg_Port tagged or untagged determined by Trg_Tagged.
Cedric
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
2026-05-26 13:21 ` Cedric Jehasse
@ 2026-05-26 14:15 ` Andrew Lunn
0 siblings, 0 replies; 9+ messages in thread
From: Andrew Lunn @ 2026-05-26 14:15 UTC (permalink / raw)
To: Cedric Jehasse
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Russell King, netdev, linux-kernel,
lukeh, Marek Behún
On Tue, May 26, 2026 at 01:21:02PM +0000, Cedric Jehasse wrote:
>
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Tuesday, May 26, 2026 2:30 PM
> > From: Andrew Lunn <andrew@lunn.ch>
> > Sent: Tuesday, May 26, 2026 2:30 PM
> > To: Cedric Jehasse
> > Cc: Vladimir Oltean; David S. Miller; Eric Dumazet; Jakub Kicinski; Paolo Abeni; Simon Horman; Russell King; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues
> >
> > On Tue, May 26, 2026 at 01:41:14PM +0200, Cedric Jehasse via B4 Relay wrote:
> > > From: Cedric Jehasse <cedric.jehasse@luminex.be>
> > >
> > > >From the datasheets i've looked at these switches have 4 or 8 transmit
> > > queues per port.
> > > There's a PRI field in the dsa tag used to indicate which egress queue
> > > the frame is to be sent to.
> > > 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).
> >
> > Maybe a bit more context would be good here. This patch is about
> > frames the host is sending to the switch. Looking at just the commit
> > message this was not obvious. It was only when i looked at the tagger
> > change did i understand that.
> >
> > Does DSA_CMD_FORWARD vs DSA_CMD_FROM_CPU make a difference here? Does
> > DSA_CMD_FROM_CPU skip some classification stages in the switch, where
> > as DSA_CMD_FORWARD might pass through more stages in the switch and
> > have the queue over written by the hardware?
> >
> > Andrew
>
> Yes, this is what the documentation says on DSA_CMD_FORWARD:
> > Used for frames that are forwarded in a normal way (ingress and egress filtering is performed on these frames).
>
> And on DSA_CMD_FROM_CPU:
> > Used for frames that need to tunnel through Blocked ports (like BPDU's). No ingress or egress filtering is perfromed.
> > Frames egress out the Trg_Port tagged or untagged determined by Trg_Tagged.
And are there any implications because of this? Could it be you do the
setup you suggest, and it gets ignored because of FORWARD vs FROM_CPU?
Or it is applied to some traffic and not others?
Again, this might be something to mention in the commit message?
Andrew
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper
2026-05-26 11:41 ` [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
@ 2026-05-26 15:49 ` Andrew Lunn
2026-05-27 9:38 ` Cedric Jehasse
0 siblings, 1 reply; 9+ messages in thread
From: Andrew Lunn @ 2026-05-26 15:49 UTC (permalink / raw)
To: cedric.jehasse
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Russell King, netdev, linux-kernel
> +static int mv88e6xxx_setup_tc_cbs(struct dsa_switch *ds, int port,
> + struct tc_cbs_qopt_offload *cbs)
> +{
> + struct mv88e6xxx_chip *chip = ds->priv;
> + const struct mv88e6xxx_ops *ops = chip->info->ops;
> + const struct mv88e6xxx_avb_ops *avb_ops;
> + const struct mv88e6xxx_qav_info *qav;
Reverse Christmas tree. Longest first please.
> + int rate_reg;
> + int hilimit_reg;
> + u8 queue_bit;
> + u16 rate = 0;
> + u16 hi_limit;
> + int err;
> +
> + avb_ops = ops->avb_ops;
> + qav = chip->info->qav;
You might be able to move this into the variable declarations? But not
always, depending on reverse Christmas.
> + if (!qav || !avb_ops || !avb_ops->port_qav_write ||
> + !ops->port_set_scheduling_mode)
> + return -EOPNOTSUPP;
> +
> + if (!dsa_is_user_port(ds, port))
> + return -EOPNOTSUPP;
> +
> + if (cbs->queue < 0 || cbs->queue >= chip->info->num_tx_queues)
> + return -EINVAL;
> +
> + if (!(qav->queue_mask & BIT(cbs->queue)))
> + return -EOPNOTSUPP;
> +
> + queue_bit = BIT(cbs->queue);
> + rate_reg = cbs->queue * 2;
> + hilimit_reg = rate_reg + 1;
> +
> + if (cbs->enable) {
> + if (cbs->idleslope <= 0 ||
> + cbs->idleslope > qav->max_rate ||
> + cbs->sendslope >= 0 || cbs->hicredit <= 0 ||
> + cbs->hicredit > qav->hi_limit_mask)
> + return -ERANGE;
> +
> + rate = DIV_ROUND_UP(cbs->idleslope, qav->rate_unit);
In the commit message, you mentioned 20Mbps, for a 1G link. Does the
link speed actually matter? I don't see it here.
Andrew
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper
2026-05-26 15:49 ` Andrew Lunn
@ 2026-05-27 9:38 ` Cedric Jehasse
0 siblings, 0 replies; 9+ messages in thread
From: Cedric Jehasse @ 2026-05-27 9:38 UTC (permalink / raw)
To: Andrew Lunn
Cc: cedric.jehasse, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Russell King, netdev,
linux-kernel
>
> > + if (!qav || !avb_ops || !avb_ops->port_qav_write ||
> > + !ops->port_set_scheduling_mode)
> > + return -EOPNOTSUPP;
> > +
> > + if (!dsa_is_user_port(ds, port))
> > + return -EOPNOTSUPP;
> > +
> > + if (cbs->queue < 0 || cbs->queue >= chip->info->num_tx_queues)
> > + return -EINVAL;
> > +
> > + if (!(qav->queue_mask & BIT(cbs->queue)))
> > + return -EOPNOTSUPP;
> > +
> > + queue_bit = BIT(cbs->queue);
> > + rate_reg = cbs->queue * 2;
> > + hilimit_reg = rate_reg + 1;
> > +
> > + if (cbs->enable) {
> > + if (cbs->idleslope <= 0 ||
> > + cbs->idleslope > qav->max_rate ||
> > + cbs->sendslope >= 0 || cbs->hicredit <= 0 ||
> > + cbs->hicredit > qav->hi_limit_mask)
> > + return -ERANGE;
> > +
> > + rate = DIV_ROUND_UP(cbs->idleslope, qav->rate_unit);
>
> In the commit message, you mentioned 20Mbps, for a 1G link. Does the
> link speed actually matter? I don't see it here.
>
> Andrew
>
According to the cbs manpage: sendslope = idleslope - port_transmit_rate.
In the commit message i've used the example from the manpage, which would be
correct for any network interface.
But the commit message mentions only idleslope and hicredit can be programmed
in the switch.
So for Marvell switches the link speed doesn't matter.
Sorry if you've received html mails. Something seems to have changed overnight,
breaking plain text e-mails on my work account.
Cedric
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-27 9:38 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-26 11:41 [PATCH net-next v2 0/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
2026-05-26 11:41 ` [PATCH net-next v2 1/2] net: dsa: mv88e6xxx: use the hw tx queues Cedric Jehasse via B4 Relay
2026-05-26 12:30 ` Andrew Lunn
2026-05-26 13:21 ` Cedric Jehasse
2026-05-26 14:15 ` Andrew Lunn
2026-05-26 11:41 ` [PATCH net-next v2 2/2] net: dsa: mv88e6xxx: add support for credit based shaper Cedric Jehasse via B4 Relay
2026-05-26 15:49 ` Andrew Lunn
2026-05-27 9:38 ` Cedric Jehasse
2026-05-26 12:19 ` [PATCH net-next v2 0/2] " Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®