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) --- drivers/net/dsa/microchip/ksz8.c | 159 ++++++++++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_common.c | 124 ++----------------------- drivers/net/dsa/microchip/ksz_common.h | 7 ++ 3 files changed, 171 insertions(+), 119 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index ad7c7a6e1d31..472cc62ea747 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -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 port’s 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, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b54aea92b67d..2846041d97a5 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -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 port’s 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; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 245329b6e0e9..7aa4a69d06ef 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -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); -- 2.54.0