net: dsa: microchip: handle KSZ8-specific tc setup in ksz8.c

The setup of QDISC_ETS isn't the same for the KSZ8 switches than for
the other switches. It leads to is_ksz8() branches in the common code.

Move the KSZ8-specific portions into ksz8.c by creating two setup_tc()
functions, one dedicated to the KSZ87xx family that only handles the
TC_SETUP_QDISC_CBS case, one for the rest of the KSZ8 that handles both
TC_SETUP_QDISC_CBS and TC_SETUP_QDISC_ETS cases.
It remains some is_kszXXXX() branches because inside the ksz88xx family,
only the ksz88x3 switches support QDISC_ETS.

Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
Link: https://patch.msgid.link/20260702-clean-ksz-4th-v1-7-93441e695fa4@bootlin.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Bastien Curutchet (Schneider Electric)
2026-07-02 11:07:29 +02:00
committed by Paolo Abeni
parent ab4b571d44
commit 610106257c
3 changed files with 171 additions and 119 deletions

View File

@@ -1782,6 +1782,159 @@ static void ksz8_port_mirror_del(struct dsa_switch *ds, int port,
PORT_MIRROR_SNIFFER, false);
}
static u8 ksz8463_tc_ctrl(int port, int queue)
{
u8 reg;
reg = 0xC8 + port * 4;
reg += ((3 - queue) / 2) * 2;
reg++;
reg -= (queue & 1);
return reg;
}
/**
* ksz88x3_tc_ets_add - Configure ETS (Enhanced Transmission Selection)
* for a port on KSZ88x3 switch
* @dev: Pointer to the KSZ switch device structure
* @port: Port number to configure
* @p: Pointer to offload replace parameters describing ETS bands and mapping
*
* The KSZ88x3 supports two scheduling modes: Strict Priority and
* Weighted Fair Queuing (WFQ). Both modes have fixed behavior:
* - No configurable queue-to-priority mapping
* - No weight adjustment in WFQ mode
*
* This function configures the switch to use strict priority mode by
* clearing the WFQ enable bit for all queues associated with ETS bands.
* If strict priority is not explicitly requested, the switch will default
* to WFQ mode.
*
* Return: 0 on success, or a negative error code on failure
*/
static int ksz88x3_tc_ets_add(struct ksz_device *dev, int port,
struct tc_ets_qopt_offload_replace_params *p)
{
int ret, band;
/* Only strict priority mode is supported for now.
* WFQ is implicitly enabled when strict mode is disabled.
*/
for (band = 0; band < p->bands; band++) {
int queue = ksz_ets_band_to_queue(p, band);
u8 reg;
/* Calculate TXQ Split Control register address for this
* port/queue
*/
reg = KSZ8873_TXQ_SPLIT_CTRL_REG(port, queue);
if (ksz_is_ksz8463(dev))
reg = ksz8463_tc_ctrl(port, queue);
/* Clear WFQ enable bit to select strict priority scheduling */
ret = ksz_rmw8(dev, reg, KSZ8873_TXQ_WFQ_ENABLE, 0);
if (ret)
return ret;
}
return 0;
}
/**
* ksz88x3_tc_ets_del - Reset ETS (Enhanced Transmission Selection) config
* for a port on KSZ88x3 switch
* @dev: Pointer to the KSZ switch device structure
* @port: Port number to reset
*
* The KSZ88x3 supports only fixed scheduling modes: Strict Priority or
* Weighted Fair Queuing (WFQ), with no reconfiguration of weights or
* queue mapping. This function resets the ports scheduling mode to
* the default, which is WFQ, by enabling the WFQ bit for all queues.
*
* Return: 0 on success, or a negative error code on failure
*/
static int ksz88x3_tc_ets_del(struct ksz_device *dev, int port)
{
int ret, queue;
/* Iterate over all transmit queues for this port */
for (queue = 0; queue < dev->info->num_tx_queues; queue++) {
u8 reg;
/* Calculate TXQ Split Control register address for this
* port/queue
*/
reg = KSZ8873_TXQ_SPLIT_CTRL_REG(port, queue);
if (ksz_is_ksz8463(dev))
reg = ksz8463_tc_ctrl(port, queue);
/* Set WFQ enable bit to revert back to default scheduling
* mode
*/
ret = ksz_rmw8(dev, reg, KSZ8873_TXQ_WFQ_ENABLE,
KSZ8873_TXQ_WFQ_ENABLE);
if (ret)
return ret;
}
return 0;
}
static int ksz8_tc_setup_qdisc_ets(struct dsa_switch *ds, int port,
struct tc_ets_qopt_offload *qopt)
{
struct ksz_device *dev = ds->priv;
int ret;
if (!(ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)))
return -EOPNOTSUPP;
if (qopt->parent != TC_H_ROOT) {
dev_err(dev->dev, "Parent should be \"root\"\n");
return -EOPNOTSUPP;
}
switch (qopt->command) {
case TC_ETS_REPLACE:
ret = ksz_tc_ets_validate(dev, port, &qopt->replace_params);
if (ret)
return ret;
return ksz88x3_tc_ets_add(dev, port, &qopt->replace_params);
case TC_ETS_DESTROY:
return ksz88x3_tc_ets_del(dev, port);
case TC_ETS_STATS:
case TC_ETS_GRAFT:
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
}
static int ksz87xx_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type, void *type_data)
{
switch (type) {
case TC_SETUP_QDISC_CBS:
return ksz_setup_tc_cbs(ds, port, type_data);
default:
return -EOPNOTSUPP;
}
}
static int ksz8_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type, void *type_data)
{
switch (type) {
case TC_SETUP_QDISC_CBS:
return ksz_setup_tc_cbs(ds, port, type_data);
case TC_SETUP_QDISC_ETS:
return ksz8_tc_setup_qdisc_ets(ds, port, type_data);
default:
return -EOPNOTSUPP;
}
}
static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
{
struct ksz_port *p = &dev->ports[port];
@@ -2645,7 +2798,7 @@ const struct dsa_switch_ops ksz8463_switch_ops = {
.port_hwtstamp_set = ksz_hwtstamp_set,
.port_txtstamp = ksz_port_txtstamp,
.port_rxtstamp = ksz_port_rxtstamp,
.port_setup_tc = ksz_setup_tc,
.port_setup_tc = ksz8_setup_tc,
.port_get_default_prio = ksz_port_get_default_prio,
.port_set_default_prio = ksz_port_set_default_prio,
.port_get_dscp_prio = ksz_port_get_dscp_prio,
@@ -2695,7 +2848,7 @@ const struct dsa_switch_ops ksz87xx_switch_ops = {
.port_hwtstamp_set = ksz_hwtstamp_set,
.port_txtstamp = ksz_port_txtstamp,
.port_rxtstamp = ksz_port_rxtstamp,
.port_setup_tc = ksz_setup_tc,
.port_setup_tc = ksz87xx_setup_tc,
.port_get_default_prio = ksz_port_get_default_prio,
.port_set_default_prio = ksz_port_set_default_prio,
.port_get_dscp_prio = ksz_port_get_dscp_prio,
@@ -2748,7 +2901,7 @@ const struct dsa_switch_ops ksz88xx_switch_ops = {
.port_hwtstamp_set = ksz_hwtstamp_set,
.port_txtstamp = ksz_port_txtstamp,
.port_rxtstamp = ksz_port_rxtstamp,
.port_setup_tc = ksz_setup_tc,
.port_setup_tc = ksz8_setup_tc,
.port_get_default_prio = ksz_port_get_default_prio,
.port_set_default_prio = ksz_port_set_default_prio,
.port_get_dscp_prio = ksz_port_get_dscp_prio,

View File

@@ -3097,8 +3097,8 @@ static int ksz_setup_tc_mode(struct ksz_device *dev, int port, u8 scheduler,
FIELD_PREP(MTI_SHAPING_M, shaper));
}
static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
struct tc_cbs_qopt_offload *qopt)
int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
struct tc_cbs_qopt_offload *qopt)
{
struct ksz_device *dev = ds->priv;
int ret;
@@ -3163,8 +3163,8 @@ static int ksz_disable_egress_rate_limit(struct ksz_device *dev, int port)
return 0;
}
static int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
int band)
int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
int band)
{
/* Compared to queues, bands prioritize packets differently. In strict
* priority mode, the lowest priority is assigned to Queue 0 while the
@@ -3173,104 +3173,6 @@ static int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
return p->bands - 1 - band;
}
static u8 ksz8463_tc_ctrl(int port, int queue)
{
u8 reg;
reg = 0xC8 + port * 4;
reg += ((3 - queue) / 2) * 2;
reg++;
reg -= (queue & 1);
return reg;
}
/**
* ksz88x3_tc_ets_add - Configure ETS (Enhanced Transmission Selection)
* for a port on KSZ88x3 switch
* @dev: Pointer to the KSZ switch device structure
* @port: Port number to configure
* @p: Pointer to offload replace parameters describing ETS bands and mapping
*
* The KSZ88x3 supports two scheduling modes: Strict Priority and
* Weighted Fair Queuing (WFQ). Both modes have fixed behavior:
* - No configurable queue-to-priority mapping
* - No weight adjustment in WFQ mode
*
* This function configures the switch to use strict priority mode by
* clearing the WFQ enable bit for all queues associated with ETS bands.
* If strict priority is not explicitly requested, the switch will default
* to WFQ mode.
*
* Return: 0 on success, or a negative error code on failure
*/
static int ksz88x3_tc_ets_add(struct ksz_device *dev, int port,
struct tc_ets_qopt_offload_replace_params *p)
{
int ret, band;
/* Only strict priority mode is supported for now.
* WFQ is implicitly enabled when strict mode is disabled.
*/
for (band = 0; band < p->bands; band++) {
int queue = ksz_ets_band_to_queue(p, band);
u8 reg;
/* Calculate TXQ Split Control register address for this
* port/queue
*/
reg = KSZ8873_TXQ_SPLIT_CTRL_REG(port, queue);
if (ksz_is_ksz8463(dev))
reg = ksz8463_tc_ctrl(port, queue);
/* Clear WFQ enable bit to select strict priority scheduling */
ret = ksz_rmw8(dev, reg, KSZ8873_TXQ_WFQ_ENABLE, 0);
if (ret)
return ret;
}
return 0;
}
/**
* ksz88x3_tc_ets_del - Reset ETS (Enhanced Transmission Selection) config
* for a port on KSZ88x3 switch
* @dev: Pointer to the KSZ switch device structure
* @port: Port number to reset
*
* The KSZ88x3 supports only fixed scheduling modes: Strict Priority or
* Weighted Fair Queuing (WFQ), with no reconfiguration of weights or
* queue mapping. This function resets the ports scheduling mode to
* the default, which is WFQ, by enabling the WFQ bit for all queues.
*
* Return: 0 on success, or a negative error code on failure
*/
static int ksz88x3_tc_ets_del(struct ksz_device *dev, int port)
{
int ret, queue;
/* Iterate over all transmit queues for this port */
for (queue = 0; queue < dev->info->num_tx_queues; queue++) {
u8 reg;
/* Calculate TXQ Split Control register address for this
* port/queue
*/
reg = KSZ8873_TXQ_SPLIT_CTRL_REG(port, queue);
if (ksz_is_ksz8463(dev))
reg = ksz8463_tc_ctrl(port, queue);
/* Set WFQ enable bit to revert back to default scheduling
* mode
*/
ret = ksz_rmw8(dev, reg, KSZ8873_TXQ_WFQ_ENABLE,
KSZ8873_TXQ_WFQ_ENABLE);
if (ret)
return ret;
}
return 0;
}
static int ksz_queue_set_strict(struct ksz_device *dev, int port, int queue)
{
int ret;
@@ -3363,8 +3265,8 @@ static int ksz_tc_ets_del(struct ksz_device *dev, int port)
return ksz9477_set_default_prio_queue_mapping(dev, port);
}
static int ksz_tc_ets_validate(struct ksz_device *dev, int port,
struct tc_ets_qopt_offload_replace_params *p)
int ksz_tc_ets_validate(struct ksz_device *dev, int port,
struct tc_ets_qopt_offload_replace_params *p)
{
int band;
@@ -3405,9 +3307,6 @@ static int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port,
struct ksz_device *dev = ds->priv;
int ret;
if (is_ksz8(dev) && !(ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)))
return -EOPNOTSUPP;
if (qopt->parent != TC_H_ROOT) {
dev_err(dev->dev, "Parent should be \"root\"\n");
return -EOPNOTSUPP;
@@ -3419,16 +3318,9 @@ static int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port,
if (ret)
return ret;
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev))
return ksz88x3_tc_ets_add(dev, port,
&qopt->replace_params);
else
return ksz_tc_ets_add(dev, port, &qopt->replace_params);
return ksz_tc_ets_add(dev, port, &qopt->replace_params);
case TC_ETS_DESTROY:
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev))
return ksz88x3_tc_ets_del(dev, port);
else
return ksz_tc_ets_del(dev, port);
return ksz_tc_ets_del(dev, port);
case TC_ETS_STATS:
case TC_ETS_GRAFT:
return -EOPNOTSUPP;

View File

@@ -14,6 +14,7 @@
#include <linux/phy.h>
#include <linux/regmap.h>
#include <net/dsa.h>
#include <net/pkt_cls.h>
#include <linux/irq.h>
#include <linux/platform_data/microchip-ksz.h>
@@ -481,6 +482,12 @@ void ksz_phylink_mac_link_down(struct phylink_config *config,
int ksz_set_mac_eee(struct dsa_switch *ds, int port,
struct ethtool_keee *e);
int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
int band);
int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
struct tc_cbs_qopt_offload *qopt);
int ksz_tc_ets_validate(struct ksz_device *dev, int port,
struct tc_ets_qopt_offload_replace_params *p);
int ksz_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type, void *type_data);