* [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG
@ 2026-06-10 5:25 Meghana Malladi
2026-06-10 5:25 ` [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support Meghana Malladi
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Meghana Malladi @ 2026-06-10 5:25 UTC (permalink / raw)
To: elfring, haokexin, vadim.fedorenko, devnexen, horms,
jacob.e.keller, m-malladi, arnd, basharath, afd, parvathi,
vladimir.oltean, rogerq, danishanwar, pabeni, kuba, edumazet,
davem, andrew+netdev
Cc: linux-arm-kernel, netdev, linux-kernel, srk, Vignesh Raghavendra
This patch series adds QoS support to the ICSSG PRUETH driver.
The first patch implements mqprio qdisc handling and TC offload hooks
so userspace can request TC mappings and queue counts.
It also integrates a driver-side mechanism to program the firmware
with the IET/FPE preemption mask and to kick the firmware verify state
machine when frame preemption is enabled. The second patch adds ethtool
perations for the MAC Merge (Frame Preemption) sublayer, exposing .get_mm,
.set_mm and .get_mm_stats so admins can view and change MAC Merge
parameters and retrieve preemption statistics.
v6: https://lore.kernel.org/all/20260525182700.3135858-1-m-malladi@ti.com/
MD Danish Anwar (2):
net: ti: icssg-prueth: Add Frame Preemption MAC Merge support
net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
drivers/net/ethernet/ti/Makefile | 3 +-
drivers/net/ethernet/ti/icssg/icssg_common.c | 1 +
drivers/net/ethernet/ti/icssg/icssg_config.h | 9 -
drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 100 +++++++
drivers/net/ethernet/ti/icssg/icssg_prueth.c | 6 +
drivers/net/ethernet/ti/icssg/icssg_prueth.h | 15 +-
drivers/net/ethernet/ti/icssg/icssg_qos.c | 282 ++++++++++++++++++
drivers/net/ethernet/ti/icssg/icssg_qos.h | 68 +++++
drivers/net/ethernet/ti/icssg/icssg_stats.c | 4 +-
drivers/net/ethernet/ti/icssg/icssg_stats.h | 7 +-
.../net/ethernet/ti/icssg/icssg_switch_map.h | 5 +
11 files changed, 480 insertions(+), 20 deletions(-)
create mode 100644 drivers/net/ethernet/ti/icssg/icssg_qos.c
create mode 100644 drivers/net/ethernet/ti/icssg/icssg_qos.h
base-commit: 67ad35a58a88c360136d893cbc4c7f5b14100bb9
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support 2026-06-10 5:25 [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Meghana Malladi @ 2026-06-10 5:25 ` Meghana Malladi 2026-06-15 23:10 ` Jakub Kicinski 2026-06-10 5:25 ` [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge Meghana Malladi 2026-06-12 9:01 ` [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Simon Horman 2 siblings, 1 reply; 9+ messages in thread From: Meghana Malladi @ 2026-06-10 5:25 UTC (permalink / raw) To: elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, m-malladi, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, kuba, edumazet, davem, andrew+netdev Cc: linux-arm-kernel, netdev, linux-kernel, srk, Vignesh Raghavendra From: MD Danish Anwar <danishanwar@ti.com> Introduce QoS infrastructure for Frame Preemption (FPE) support in the ICSSG Ethernet driver. prueth_qos_iet tracks FPE enable/active state and verify state machine status via firmware-reported enum icssg_ietfpe_verify_states. icssg_config_ietfpe() configures IET FPE in firmware, triggers verify state machine based on ethtool MAC Merge parameters. Polls firmware verify status up to 3 times with verify_time_ms intervals and driver handles timeout by logging error and returning. In case of any failure during configuration for enable/disable, IET FPE falls back to disabled state. For MQPRIO qdisc support all queues are express by default later gets override by user-provided preemptible_tcs bitmask via tc qdisc mask. Preempt mask configuration: Maps traffic classes to queue express/preemptible state and applied only when FPE is active (Tx enabled). Verify state machine re-triggers on link up/down events based on fpe_enabled and fpe_active flags, and for memory protection, fpe_lock serializes all FPE state mutations, preventing races between ethtool config, qdisc setup, and link events Signed-off-by: MD Danish Anwar <danishanwar@ti.com> Signed-off-by: Meghana Malladi <m-malladi@ti.com> --- v7-v6: - Replace netif_running() check with emac->link inside icssg_config_ietfpe for link down conditions - Move netdev_set_tc_queue() to emac_tc_setup_mqprio() and fix its handling - Update prueth_qos_mqprio struct to fix the dangling pointer issue All the above changes addresses the comments provided by sashiko - Used readb_poll_timeout() for icssg_iet_verify_wait instead of open coding it as suggested - Fixed plausible checkpatch errors All the above changes addresses the comments provided by Maxime Chevallier <maxime.chevallier@bootlin.com> drivers/net/ethernet/ti/Makefile | 3 +- drivers/net/ethernet/ti/icssg/icssg_common.c | 1 + drivers/net/ethernet/ti/icssg/icssg_config.h | 9 - drivers/net/ethernet/ti/icssg/icssg_prueth.c | 6 + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 8 +- drivers/net/ethernet/ti/icssg/icssg_qos.c | 282 +++++++++++++++++++ drivers/net/ethernet/ti/icssg/icssg_qos.h | 68 +++++ 7 files changed, 364 insertions(+), 13 deletions(-) create mode 100644 drivers/net/ethernet/ti/icssg/icssg_qos.c create mode 100644 drivers/net/ethernet/ti/icssg/icssg_qos.h diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index f4276c9a77620..d19bcd25c9d07 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -46,6 +46,7 @@ icssg-y := icssg/icssg_common.o \ icssg/icssg_config.o \ icssg/icssg_mii_cfg.o \ icssg/icssg_stats.o \ - icssg/icssg_ethtool.o + icssg/icssg_ethtool.o \ + icssg/icssg_qos.o obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index a28a608f9bf4b..c3ee97e96cd50 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -1724,6 +1724,7 @@ void prueth_netdev_exit(struct prueth *prueth, netif_napi_del(&emac->napi_rx); + mutex_destroy(&emac->qos.iet.fpe_lock); pruss_release_mem_region(prueth->pruss, &emac->dram); free_netdev(emac->ndev); prueth->emac[mac] = NULL; diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h index 60d69744ffae2..1ac202f855ed4 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_config.h +++ b/drivers/net/ethernet/ti/icssg/icssg_config.h @@ -323,13 +323,4 @@ struct prueth_fdb_slot { u8 fid; u8 fid_c2; } __packed; - -enum icssg_ietfpe_verify_states { - ICSSG_IETFPE_STATE_UNKNOWN = 0, - ICSSG_IETFPE_STATE_INITIAL, - ICSSG_IETFPE_STATE_VERIFYING, - ICSSG_IETFPE_STATE_SUCCEEDED, - ICSSG_IETFPE_STATE_FAILED, - ICSSG_IETFPE_STATE_DISABLED -}; #endif /* __NET_TI_ICSSG_CONFIG_H */ diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index 591be5c8056b4..39f379df923bf 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -392,6 +392,8 @@ static void emac_adjust_link(struct net_device *ndev) } else { icssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE); } + + icssg_qos_link_state_update(ndev); } if (emac->link) { @@ -1652,6 +1654,7 @@ static const struct net_device_ops emac_netdev_ops = { .ndo_hwtstamp_get = icssg_ndo_get_ts_config, .ndo_hwtstamp_set = icssg_ndo_set_ts_config, .ndo_xsk_wakeup = prueth_xsk_wakeup, + .ndo_setup_tc = icssg_qos_ndo_setup_tc, }; static int prueth_netdev_init(struct prueth *prueth, @@ -1686,6 +1689,8 @@ static int prueth_netdev_init(struct prueth *prueth, INIT_DELAYED_WORK(&emac->stats_work, icssg_stats_work_handler); + icssg_qos_init(ndev); + ret = pruss_request_mem_region(prueth->pruss, port == PRUETH_PORT_MII0 ? PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1, @@ -1793,6 +1798,7 @@ static int prueth_netdev_init(struct prueth *prueth, free: pruss_release_mem_region(prueth->pruss, &emac->dram); free_ndev: + mutex_destroy(&emac->qos.iet.fpe_lock); emac->ndev = NULL; prueth->emac[mac] = NULL; free_netdev(ndev); diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h index df93d15c5b786..f73b8f5fca956 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h @@ -44,10 +44,11 @@ #include "icssg_config.h" #include "icss_iep.h" #include "icssg_switch_map.h" +#include "icssg_qos.h" -#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) -#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN) -#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN) +#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) +#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN) +#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN) #define ICSS_SLICE0 0 #define ICSS_SLICE1 1 @@ -254,6 +255,7 @@ struct prueth_emac { struct bpf_prog *xdp_prog; struct xdp_attachment_info xdpi; int xsk_qid; + struct prueth_qos qos; }; /* The buf includes headroom compatible with both skb and xdpf */ diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c new file mode 100644 index 0000000000000..8b601d6f3d718 --- /dev/null +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments ICSSG PRUETH QoS submodule + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include "icssg_prueth.h" +#include "icssg_switch_map.h" + +static void icssg_iet_set_preempt_mask(struct prueth_emac *emac) +{ + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; + struct prueth_qos_mqprio *p_mqprio = &emac->qos.mqprio; + struct tc_mqprio_qopt *qopt = &p_mqprio->qopt; + struct prueth_qos_iet *iet = &emac->qos.iet; + int prempt_mask = 0, i; + u8 tc, num_tc; + + if (!iet->preemptible_tcs) + goto reset_hw; + + if (iet->fpe_active) { + /* Configure queues for user requested preemptible tc map */ + num_tc = p_mqprio->qopt.num_tc; + for (tc = 0; tc < num_tc; tc++) { + /* check if the tc is preemptive or not */ + if (iet->preemptible_tcs & BIT(tc)) { + /* Set the queues as preemptive queues */ + for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++) { + writeb(BIT(4), + config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + } + } else { + /* Set the queues as express queues */ + for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++) { + writeb(0, + config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + prempt_mask |= BIT(i); + } + } + } + writeb(prempt_mask, config + EXPRESS_PRE_EMPTIVE_Q_MASK); + return; + } + +reset_hw: + /* Reset to default: all queues as express */ + for (i = 0; i < ICSSG_MAX_TC_QUEUES; i++) + writeb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + writeb(ICSSG_EXPRESS_Q_MASK_ALL, config + EXPRESS_PRE_EMPTIVE_Q_MASK); +} + +static int icssg_iet_verify_wait(struct prueth_emac *emac) +{ + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; + struct prueth_qos_iet *iet = &emac->qos.iet; + unsigned long delay_us, timeout_us; + u32 status; + int ret; + + delay_us = iet->verify_time_ms * 1000; + timeout_us = delay_us * ICSSG_IET_VERIFY_ATTEMPTS; + + ret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS, + status, + status == ICSSG_IETFPE_STATE_SUCCEEDED, + delay_us, + timeout_us); + + iet->verify_status = status; + return ret; +} + +/* Direct synchronous configuration of IET FPE. + * Caller must hold iet->fpe_lock. + */ +int icssg_config_ietfpe(struct net_device *ndev, bool enable) +{ + struct prueth_emac *emac = netdev_priv(ndev); + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; + struct prueth_qos_iet *iet = &emac->qos.iet; + int ret; + u8 val; + + lockdep_assert_held(&iet->fpe_lock); + + if (!emac->link) { + netdev_dbg(ndev, "cannot change IET/FPE state when interface is down\n"); + return 0; + } + + /* Update FPE Tx enable bit (PRE_EMPTION_ENABLE_TX) if + * fpe_enabled is set to enable MM in Tx direction + */ + writeb(enable ? 1 : 0, config + PRE_EMPTION_ENABLE_TX); + writew(iet->tx_min_frag_size + ETH_FCS_LEN, + config + PRE_EMPTION_ADD_FRAG_SIZE_LOCAL); + + /* If FPE is to be enabled, first configure MAC Verify state + * machine in firmware as firmware kicks the Verify process + * as soon as ICSSG_EMAC_PORT_PREMPT_TX_ENABLE command is + * received. + */ + if (enable && iet->mac_verify_configure) { + writeb(1, config + PRE_EMPTION_ENABLE_VERIFY); + writel(iet->verify_time_ms, config + PRE_EMPTION_VERIFY_TIME); + } else { + writeb(0, config + PRE_EMPTION_ENABLE_VERIFY); + iet->verify_status = ICSSG_IETFPE_STATE_DISABLED; + } + + /* Send command to enable FPE Tx side. Rx is always enabled */ + ret = icssg_set_port_state(emac, + enable ? ICSSG_EMAC_PORT_PREMPT_TX_ENABLE : + ICSSG_EMAC_PORT_PREMPT_TX_DISABLE); + if (ret) { + netdev_err(ndev, "TX preempt %s command failed\n", + str_enable_disable(enable)); + goto fallback; + } + + if (enable && iet->mac_verify_configure) { + ret = icssg_iet_verify_wait(emac); + if (ret) { + netdev_err(ndev, "MAC Verification failed with timeout\n"); + goto disable_tx; + } + } else if (enable) { + /* Give firmware some time to update + * PRE_EMPTION_ACTIVE_TX state + */ + usleep_range(100, 200); + } + + if (enable) { + val = readb(config + PRE_EMPTION_ACTIVE_TX); + if (val != 1) { + netdev_err(ndev, + "Firmware fails to activate IET/FPE\n"); + ret = -EIO; + goto disable_tx; + } + iet->fpe_active = true; + } else { + iet->fpe_active = false; + } + + icssg_iet_set_preempt_mask(emac); + netdev_dbg(ndev, "IET FPE %s successfully\n", + str_enable_disable(enable)); + return 0; + +disable_tx: + icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE); +fallback: + writeb(0, config + PRE_EMPTION_ENABLE_TX); + writeb(0, config + PRE_EMPTION_ENABLE_VERIFY); + iet->verify_status = ICSSG_IETFPE_STATE_DISABLED; + iet->fpe_active = false; + return ret; +} + +void icssg_qos_init(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + + mutex_init(&iet->fpe_lock); + /* Set default values to prevent garbage values during .get_mm() */ + mutex_lock(&iet->fpe_lock); + iet->verify_time_ms = ICSSG_IET_MAX_VERIFY_TIME; + iet->tx_min_frag_size = ETH_ZLEN; + mutex_unlock(&iet->fpe_lock); +} +EXPORT_SYMBOL_GPL(icssg_qos_init); + +static int icssg_iet_change_preemptible_tcs(struct prueth_emac *emac) +{ + struct prueth_qos_iet *iet = &emac->qos.iet; + int ret; + + mutex_lock(&iet->fpe_lock); + ret = icssg_config_ietfpe(emac->ndev, iet->fpe_enabled); + mutex_unlock(&iet->fpe_lock); + + return ret; +} + +static int emac_tc_query_caps(struct net_device *ndev, void *type_data) +{ + struct tc_query_caps_base *base = type_data; + + switch (base->type) { + case TC_SETUP_QDISC_MQPRIO: { + struct tc_mqprio_caps *caps = base->caps; + + caps->validate_queue_counts = true; + return 0; + } + default: + return -EOPNOTSUPP; + } +} + +static int emac_tc_setup_mqprio(struct net_device *ndev, void *type_data) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_mqprio *p_mqprio = &emac->qos.mqprio; + struct tc_mqprio_qopt_offload *mqprio = type_data; + struct prueth_qos_iet *iet = &emac->qos.iet; + struct tc_mqprio_qopt *qopt = &mqprio->qopt; + int tc, offset, count; + + /* Validate parameters */ + if (qopt->num_tc > ICSSG_MAX_TC_QUEUES) { + netdev_err(ndev, "Number of traffic classes (%u) exceeds hardware limit\n", + qopt->num_tc); + return -EOPNOTSUPP; + } + + if (mqprio->flags & TC_MQPRIO_F_SHAPER) { + netdev_err(ndev, "traffic shaping is not supported\n"); + return -EOPNOTSUPP; + } + + if (mqprio->flags & (TC_MQPRIO_F_MIN_RATE | TC_MQPRIO_F_MAX_RATE)) { + netdev_err(ndev, "per-queue rate limiting is not supported\n"); + return -EOPNOTSUPP; + } + + if (!qopt->num_tc) { + netdev_reset_tc(ndev); + } else { + netdev_set_num_tc(ndev, qopt->num_tc); + + for (tc = 0; tc < qopt->num_tc; tc++) { + count = qopt->count[tc]; + offset = qopt->offset[tc]; + netdev_set_tc_queue(ndev, tc, count, offset); + } + } + + mutex_lock(&iet->fpe_lock); + if (!qopt->num_tc) { + iet->preemptible_tcs = 0; + } else { + memcpy(&p_mqprio->qopt, qopt, sizeof(*qopt)); + iet->preemptible_tcs = mqprio->preemptible_tcs; + } + mutex_unlock(&iet->fpe_lock); + + netdev_dbg(ndev, "dev->num_tc %u dev->real_num_tx_queues %u\n", + ndev->num_tc, ndev->real_num_tx_queues); + + return icssg_iet_change_preemptible_tcs(emac); +} + +int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_QUERY_CAPS: + return emac_tc_query_caps(ndev, type_data); + case TC_SETUP_QDISC_MQPRIO: + return emac_tc_setup_mqprio(ndev, type_data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(icssg_qos_ndo_setup_tc); + +void icssg_qos_link_state_update(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + int ret; + + ret = icssg_iet_change_preemptible_tcs(emac); + if (ret) + netdev_dbg(ndev, "IET FPE %s failed\n", + str_enable_disable(iet->fpe_enabled)); +} +EXPORT_SYMBOL_GPL(icssg_qos_link_state_update); diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h new file mode 100644 index 0000000000000..e826ce4bcfd96 --- /dev/null +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#ifndef __NET_TI_ICSSG_QOS_H +#define __NET_TI_ICSSG_QOS_H + +#include <linux/atomic.h> +#include <linux/netdevice.h> +#include <net/pkt_sched.h> + +#define ICSSG_MAX_TC_QUEUES 8 +#define ICSSG_EXPRESS_Q_MASK_ALL 0xFF +#define ICSSG_IET_MAX_VERIFY_TIME 128 +#define ICSSG_IET_MIN_VERIFY_TIME 1 +#define ICSSG_IET_VERIFY_ATTEMPTS 3 + +/** + * enum icssg_ietfpe_verify_states - status of MM Verify returned by firmware + * @ICSSG_IETFPE_STATE_UNKNOWN: + * verification status is unknown + * @ICSSG_IETFPE_STATE_INITIAL: + * Firmware returns this if verify state diagram is idle + * @ICSSG_IETFPE_STATE_VERIFYING: + * Firmware returns this if verification is ongoing + * @ICSSG_IETFPE_STATE_SUCCEEDED: + * Firmware returns this if verify state diagram completes verification + * @ICSSG_IETFPE_STATE_FAILED: + * Firmware returns this if verify state diagram fails during verification + * @ICSSG_IETFPE_STATE_DISABLED: + * verification is disabled by the driver + */ +enum icssg_ietfpe_verify_states { + ICSSG_IETFPE_STATE_UNKNOWN = 0, + ICSSG_IETFPE_STATE_INITIAL, + ICSSG_IETFPE_STATE_VERIFYING, + ICSSG_IETFPE_STATE_SUCCEEDED, + ICSSG_IETFPE_STATE_FAILED, + ICSSG_IETFPE_STATE_DISABLED +}; + +struct prueth_qos_mqprio { + struct tc_mqprio_qopt qopt; +}; + +struct prueth_qos_iet { + bool fpe_enabled; + bool mac_verify_configure; + u32 tx_min_frag_size; + u32 verify_time_ms; + bool fpe_active; + enum icssg_ietfpe_verify_states verify_status; + /* fpe mutex protects all FPE operations for synchronization */ + struct mutex fpe_lock; + u8 preemptible_tcs; +}; + +struct prueth_qos { + struct prueth_qos_iet iet; + struct prueth_qos_mqprio mqprio; +}; + +void icssg_qos_init(struct net_device *ndev); +void icssg_qos_link_state_update(struct net_device *ndev); +int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data); +int icssg_config_ietfpe(struct net_device *ndev, bool enable); +#endif /* __NET_TI_ICSSG_QOS_H */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support 2026-06-10 5:25 ` [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support Meghana Malladi @ 2026-06-15 23:10 ` Jakub Kicinski 0 siblings, 0 replies; 9+ messages in thread From: Jakub Kicinski @ 2026-06-15 23:10 UTC (permalink / raw) To: m-malladi Cc: Jakub Kicinski, elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, vigneshr This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible. --- net: ti: icssg-prueth: Add Frame Preemption MAC Merge support This patch adds QoS infrastructure for Frame Preemption (FPE) in the ICSSG Ethernet driver, including a verify state machine driver helper, mqprio-based preemptible-tc mapping, and a link-state callback. A follow-up patch in this series wires this up to ethtool's MAC Merge ops. > diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c > --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c > +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c > @@ -392,6 +392,8 @@ static void emac_adjust_link(struct net_device *ndev) > } else { > icssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE); > } > + > + icssg_qos_link_state_update(ndev); > } [Medium] emac_adjust_link() sets emac->link = 0 before reaching this call. Inside icssg_qos_link_state_update() -> icssg_iet_change_preemptible_tcs() -> icssg_config_ietfpe(), the very first check is: if (!emac->link) { netdev_dbg(ndev, "cannot change IET/FPE state ... \n"); return 0; } so on a link-down the IET path returns early without clearing iet->fpe_active or iet->verify_status, even though firmware has already been told ICSSG_EMAC_PORT_DISABLE just above. After the follow-up patch adds get_mm(), would ethtool then report stale tx_active=true and a stale verify_status while the link is down? The commit message states: Verify state machine re-triggers on link up/down events based on fpe_enabled and fpe_active flags Is the link-down half of that contract implemented anywhere? [Medium] A related question on the locking design: emac->link is written here by emac_adjust_link() without taking iet->fpe_lock, but icssg_config_ietfpe() reads emac->link inside the fpe_lock-held critical section. The lockset for writers and readers is disjoint, so fpe_lock does not actually serialize emac->link. Can the following interleaving occur? CPU0 (ndo_setup_tc) CPU1 (emac_adjust_link) mutex_lock(&iet->fpe_lock); reads emac->link == 1 emac->link = 0; icssg_set_port_state(... DISABLE); proceeds to write FPE regs and issue PREMPT_TX_ENABLE mutex_unlock(&iet->fpe_lock); icssg_qos_link_state_update(); sees emac->link == 0, returns leaving stale FPE writes on a port the firmware has just disabled? The commit message says "fpe_lock serializes all FPE state mutations" but emac->link is one of those mutations and is not covered. > diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c > new file mode 100644 > --- /dev/null > +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c > @@ -0,0 +1,282 @@ [ ... ] > +static int icssg_iet_verify_wait(struct prueth_emac *emac) > +{ > + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; > + struct prueth_qos_iet *iet = &emac->qos.iet; > + unsigned long delay_us, timeout_us; > + u32 status; > + int ret; > + > + delay_us = iet->verify_time_ms * 1000; > + timeout_us = delay_us * ICSSG_IET_VERIFY_ATTEMPTS; > + > + ret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS, > + status, > + status == ICSSG_IETFPE_STATE_SUCCEEDED, > + delay_us, > + timeout_us); > + > + iet->verify_status = status; > + return ret; > +} [High] With ICSSG_IET_MAX_VERIFY_TIME = 128 and ICSSG_IET_VERIFY_ATTEMPTS = 3, this can sleep for up to 384ms while iet->fpe_lock is held. fpe_lock is acquired by icssg_iet_change_preemptible_tcs() from two paths: - emac_tc_setup_mqprio() via .ndo_setup_tc, called with RTNL held. - icssg_qos_link_state_update() from emac_adjust_link(), invoked by phylib with phydev->lock held (prueth_emac_common_start() explicitly does mutex_lock(phydev->lock) before calling emac_adjust_link). Once the follow-up patch wires set_mm() to write iet->mac_verify_configure, this sleep becomes reachable from any user with CAP_NET_ADMIN. Should the verify wait be deferred to a workqueue or a completion driven by a firmware notification rather than block under RTNL / phydev->lock for hundreds of milliseconds? Other drivers with MAC Merge support (e.g. fec, stmmac) take the deferred-work approach for the same reason. [Low] The condition only breaks on ICSSG_IETFPE_STATE_SUCCEEDED, but the enum also defines a distinct ICSSG_IETFPE_STATE_FAILED value reported by firmware on a definitive verify failure. With the current condition, would a FAILED state cause the loop to keep polling for the entire timeout and then surface as: netdev_err(ndev, "MAC Verification failed with timeout\n"); even though it was not actually a timeout? Could the cond also break on FAILED so the caller can distinguish the two? > +int icssg_config_ietfpe(struct net_device *ndev, bool enable) > +{ > + struct prueth_emac *emac = netdev_priv(ndev); > + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; > + struct prueth_qos_iet *iet = &emac->qos.iet; > + int ret; > + u8 val; > + > + lockdep_assert_held(&iet->fpe_lock); > + > + if (!emac->link) { > + netdev_dbg(ndev, "cannot change IET/FPE state when interface is down\n"); > + return 0; > + } [ ... ] > + if (enable && iet->mac_verify_configure) { > + ret = icssg_iet_verify_wait(emac); > + if (ret) { > + netdev_err(ndev, "MAC Verification failed with timeout\n"); > + goto disable_tx; > + } > + } else if (enable) { > + /* Give firmware some time to update > + * PRE_EMPTION_ACTIVE_TX state > + */ > + usleep_range(100, 200); > + } > + > + if (enable) { > + val = readb(config + PRE_EMPTION_ACTIVE_TX); > + if (val != 1) { > + netdev_err(ndev, > + "Firmware fails to activate IET/FPE\n"); > + ret = -EIO; > + goto disable_tx; > + } > + iet->fpe_active = true; > + } else { > + iet->fpe_active = false; > + } > + > + icssg_iet_set_preempt_mask(emac); > + netdev_dbg(ndev, "IET FPE %s successfully\n", > + str_enable_disable(enable)); > + return 0; > + > +disable_tx: > + icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE); > +fallback: > + writeb(0, config + PRE_EMPTION_ENABLE_TX); > + writeb(0, config + PRE_EMPTION_ENABLE_VERIFY); > + iet->verify_status = ICSSG_IETFPE_STATE_DISABLED; > + iet->fpe_active = false; > + return ret; > +} [Medium] icssg_set_port_state() only synchronizes the R30 command-done handshake; it does not guarantee firmware has finished updating the PRE_EMPTION_ACTIVE_TX status byte. Is a 100-200us sleep a documented worst-case latency for firmware to publish that byte under load (concurrent Rx, TAS, FDB ageing, link events)? If the byte has not yet been written, this code returns -EIO, mischaracterizing it as "Firmware fails to activate IET/FPE", and the fallback path then writes PRE_EMPTION_ENABLE_TX = 0, defeating the user's enable. icssg_iet_verify_wait() already uses readb_poll_timeout() for an analogous status byte; could the same pattern be applied here with a small millisecond-range timeout? [Medium] The success path always calls icssg_iet_set_preempt_mask(), and on fpe_active=false that helper takes the reset_hw branch and clears all per-queue BIT(4) preemptive markers. The disable_tx and fallback paths do not call icssg_iet_set_preempt_mask(). If FPE was previously active (so EXPRESS_PRE_EMPTIVE_Q_MAP[i] = BIT(4) on some queues) and a subsequent reconfigure fails (verify timeout, or PRE_EMPTION_ACTIVE_TX != 1), the failure paths only clear PRE_EMPTION_ENABLE_TX / PRE_EMPTION_ENABLE_VERIFY but leave the per-queue map and the EXPRESS_PRE_EMPTIVE_Q_MASK with stale preemptive bits. Should the failure paths also call icssg_iet_set_preempt_mask() (after iet->fpe_active is set to false) to keep the queue map and the TX-enable bit consistent? [ ... ] > +EXPORT_SYMBOL_GPL(icssg_qos_init); [ ... ] > +EXPORT_SYMBOL_GPL(icssg_qos_ndo_setup_tc); [ ... ] > +EXPORT_SYMBOL_GPL(icssg_qos_link_state_update); [Low] Per the Makefile change in this patch: icssg-y := icssg/icssg_common.o \ ... icssg/icssg_ethtool.o \ icssg/icssg_qos.o icssg_qos.o is linked into the same icssg.ko module as the only callers (icssg_prueth.c and icssg_common.c). Are there cross-module consumers that need these symbols exported, or can the EXPORT_SYMBOL_GPL lines be dropped since EXPORT_SYMBOL_GPL is only required for cross-module linkage? -- pw-bot: cr ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 2026-06-10 5:25 [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Meghana Malladi 2026-06-10 5:25 ` [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support Meghana Malladi @ 2026-06-10 5:25 ` Meghana Malladi 2026-06-15 23:10 ` Jakub Kicinski 2026-06-12 9:01 ` [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Simon Horman 2 siblings, 1 reply; 9+ messages in thread From: Meghana Malladi @ 2026-06-10 5:25 UTC (permalink / raw) To: elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, m-malladi, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, kuba, edumazet, davem, andrew+netdev Cc: linux-arm-kernel, netdev, linux-kernel, srk, Vignesh Raghavendra From: MD Danish Anwar <danishanwar@ti.com> Add driver support for viewing and changing the MAC Merge sublayer parameters via ethtool ops: .set_mm(), .get_mm() and .get_mm_stats(). The minimum size of non-final mPacket fragments supported by the firmware without leading errors is 64 Bytes (including FCS). Add pa stats registers to check statistics for preemption, which can be dumped using ethtool ops. Fix emac_get_stat_by_name() to return u64 instead of int and return 0 on error instead of -EINVAL. This prevents invalid stat lookups from corrupting output stats with signed error codes cast to u64. Signed-off-by: MD Danish Anwar <danishanwar@ti.com> Signed-off-by: Meghana Malladi <m-malladi@ti.com> --- v7-v6: - Remove icssg_qos_validate_tx_min_frag_size() and icssg_qos_validate_verify_time() as these checks are already handled by ethnl code as suggested by Maxime - Write tx_min_frag_size to the firmware without iet->mac_verify_configure check - Add emac_update_hardware_stats() inside emac_get_mm_stats() to prevent reading stale stats Above changes addresses the comments provided by sashiko drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 100 ++++++++++++++++++ drivers/net/ethernet/ti/icssg/icssg_prueth.h | 7 +- drivers/net/ethernet/ti/icssg/icssg_stats.c | 4 +- drivers/net/ethernet/ti/icssg/icssg_stats.h | 7 +- .../net/ethernet/ti/icssg/icssg_switch_map.h | 5 + 5 files changed, 116 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c index b715af21d23ac..0620782318ab9 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c @@ -294,6 +294,103 @@ static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue, return 0; } +static int emac_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + enum icssg_ietfpe_verify_states verify_status; + + if (emac->is_sr1) + return -EOPNOTSUPP; + + mutex_lock(&iet->fpe_lock); + state->tx_enabled = iet->fpe_enabled; + state->tx_min_frag_size = iet->tx_min_frag_size; + state->verify_enabled = iet->mac_verify_configure; + state->verify_time = iet->verify_time_ms; + state->tx_active = iet->fpe_active; + verify_status = iet->verify_status; + mutex_unlock(&iet->fpe_lock); + + state->rx_min_frag_size = ETH_ZLEN; + state->pmac_enabled = true; + + switch (verify_status) { + case ICSSG_IETFPE_STATE_DISABLED: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; + break; + case ICSSG_IETFPE_STATE_INITIAL: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; + break; + case ICSSG_IETFPE_STATE_VERIFYING: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; + break; + case ICSSG_IETFPE_STATE_SUCCEEDED: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; + break; + case ICSSG_IETFPE_STATE_FAILED: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED; + break; + default: + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN; + break; + } + + /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime + * variable has a range between 1 and 128 ms inclusive. Limit to that. + */ + state->max_verify_time = ETHTOOL_MM_MAX_VERIFY_TIME_MS; + + return 0; +} + +static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + int err; + + if (emac->is_sr1) + return -EOPNOTSUPP; + + if (!cfg->pmac_enabled) { + NL_SET_ERR_MSG_MOD(extack, "preemptible MAC is always enabled"); + return -EOPNOTSUPP; + } + + mutex_lock(&iet->fpe_lock); + iet->verify_time_ms = cfg->verify_time; + iet->tx_min_frag_size = cfg->tx_min_frag_size; + iet->fpe_enabled = cfg->tx_enabled; + iet->mac_verify_configure = cfg->verify_enabled; + err = icssg_config_ietfpe(ndev, cfg->tx_enabled); + mutex_unlock(&iet->fpe_lock); + + return err; +} + +static void emac_get_mm_stats(struct net_device *ndev, + struct ethtool_mm_stats *s) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + if (emac->is_sr1) + return; + + if (!emac->prueth->pa_stats) + return; + + emac_update_hardware_stats(emac); + + /* MACMergeHoldCount stats is not tracked by the firmware */ + s->MACMergeFrameAssOkCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_OK"); + s->MACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_ERR"); + s->MACMergeFragCountRx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_RX"); + s->MACMergeFragCountTx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_TX"); + s->MACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_BAD_FRAG"); +} + const struct ethtool_ops icssg_ethtool_ops = { .get_drvinfo = emac_get_drvinfo, .get_msglevel = emac_get_msglevel, @@ -317,5 +414,8 @@ const struct ethtool_ops icssg_ethtool_ops = { .set_eee = emac_set_eee, .nway_reset = emac_nway_reset, .get_rmon_stats = emac_get_rmon_stats, + .get_mm = emac_get_mm, + .set_mm = emac_set_mm, + .get_mm_stats = emac_get_mm_stats, }; EXPORT_SYMBOL_GPL(icssg_ethtool_ops); diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h index f73b8f5fca956..3dfb2b4368768 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h @@ -45,6 +45,7 @@ #include "icss_iep.h" #include "icssg_switch_map.h" #include "icssg_qos.h" +#include "icssg_stats.h" #define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) #define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN) @@ -58,8 +59,8 @@ #define ICSSG_MAX_RFLOWS 8 /* per slice */ -#define ICSSG_NUM_PA_STATS 32 -#define ICSSG_NUM_MIIG_STATS 60 +#define ICSSG_NUM_PA_STATS ARRAY_SIZE(icssg_all_pa_stats) +#define ICSSG_NUM_MIIG_STATS ARRAY_SIZE(icssg_all_miig_stats) /* Number of ICSSG related stats */ #define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS) #define ICSSG_NUM_STANDARD_STATS 31 @@ -460,7 +461,7 @@ int emac_fdb_flow_id_updated(struct prueth_emac *emac); void icssg_stats_work_handler(struct work_struct *work); void emac_update_hardware_stats(struct prueth_emac *emac); -int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name); +u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name); /* Common functions */ void prueth_cleanup_rx_chns(struct prueth_emac *emac, diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c index 7159baa0155cf..cfdb6f5dc5da1 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_stats.c +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c @@ -74,7 +74,7 @@ void icssg_stats_work_handler(struct work_struct *work) } EXPORT_SYMBOL_GPL(icssg_stats_work_handler); -int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) +u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) { int i; @@ -91,5 +91,5 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) } netdev_err(emac->ndev, "Invalid stats %s\n", stat_name); - return -EINVAL; + return 0; } diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h index 5ec0b38e0c67d..8073deac35c3e 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h @@ -8,8 +8,6 @@ #ifndef __NET_TI_ICSSG_STATS_H #define __NET_TI_ICSSG_STATS_H -#include "icssg_prueth.h" - #define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */ struct miig_stats_regs { @@ -189,6 +187,11 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = { ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED), ICSSG_PA_STATS(FW_INF_DROP_NOTAG), ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER), + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG), + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR), + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX), + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK), + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX), ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR), ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF), ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF), diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h index 7e053b8af3ece..855fd4ed0b3f6 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h +++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h @@ -256,6 +256,11 @@ #define FW_INF_DROP_PRIOTAGGED 0x0148 #define FW_INF_DROP_NOTAG 0x0150 #define FW_INF_DROP_NOTMEMBER 0x0158 +#define FW_PREEMPT_BAD_FRAG 0x0160 +#define FW_PREEMPT_ASSEMBLY_ERR 0x0168 +#define FW_PREEMPT_FRAG_CNT_TX 0x0170 +#define FW_PREEMPT_ASSEMBLY_OK 0x0178 +#define FW_PREEMPT_FRAG_CNT_RX 0x0180 #define FW_RX_EOF_SHORT_FRMERR 0x0188 #define FW_RX_B0_DROP_EARLY_EOF 0x0190 #define FW_TX_JUMBO_FRM_CUTOFF 0x0198 -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 2026-06-10 5:25 ` [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge Meghana Malladi @ 2026-06-15 23:10 ` Jakub Kicinski 2026-06-15 23:39 ` Jakub Kicinski 0 siblings, 1 reply; 9+ messages in thread From: Jakub Kicinski @ 2026-06-15 23:10 UTC (permalink / raw) To: m-malladi Cc: Jakub Kicinski, elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, vigneshr This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible. --- Subject: net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge This patch wires up the ethtool MAC Merge ops (.get_mm, .set_mm, .get_mm_stats) for the ICSSG PRU Ethernet driver and adds five firmware preemption counters that feed both the new MM stats and the existing ethtool -S table. > diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c > index b715af21d23a..0620782318ab 100644 > --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c > +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c > @@ -294,6 +294,103 @@ static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue, [ ... ] > +static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, > + struct netlink_ext_ack *extack) > +{ > + struct prueth_emac *emac = netdev_priv(ndev); > + struct prueth_qos_iet *iet = &emac->qos.iet; > + int err; > + > + if (emac->is_sr1) > + return -EOPNOTSUPP; > + > + if (!cfg->pmac_enabled) { > + NL_SET_ERR_MSG_MOD(extack, "preemptible MAC is always enabled"); > + return -EOPNOTSUPP; > + } > + > + mutex_lock(&iet->fpe_lock); > + iet->verify_time_ms = cfg->verify_time; > + iet->tx_min_frag_size = cfg->tx_min_frag_size; > + iet->fpe_enabled = cfg->tx_enabled; > + iet->mac_verify_configure = cfg->verify_enabled; > + err = icssg_config_ietfpe(ndev, cfg->tx_enabled); > + mutex_unlock(&iet->fpe_lock); > + > + return err; > +} [Medium] Can the cached software state in iet diverge from the hardware here when icssg_config_ietfpe() fails? The new fields (verify_time_ms, tx_min_frag_size, fpe_enabled, mac_verify_configure) are written to iet before icssg_config_ietfpe() is called, but the error paths in icssg_config_ietfpe() only roll back a subset of state: icssg_qos.c:icssg_config_ietfpe() { ... disable_tx: icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE); fallback: writeb(0, config + PRE_EMPTION_ENABLE_TX); writeb(0, config + PRE_EMPTION_ENABLE_VERIFY); iet->verify_status = ICSSG_IETFPE_STATE_DISABLED; iet->fpe_active = false; return ret; } iet->fpe_enabled is left set to cfg->tx_enabled even though the hardware TX preempt path has been disabled. Two follow-on effects appear to come from this: emac_get_mm() reports state->tx_enabled = iet->fpe_enabled, so userspace sees tx_enabled=true after a set_mm that returned an error and left FPE disabled in hardware. icssg_qos_link_state_update() drives icssg_iet_change_preemptible_tcs(), which calls icssg_config_ietfpe(emac->ndev, iet->fpe_enabled) on every link transition, so the failed configuration is retried each link-up without further user action. Would it make sense to stage cfg into local variables, only commit them to iet after icssg_config_ietfpe() returns success, or otherwise restore the previous iet fields on the error return? > +static void emac_get_mm_stats(struct net_device *ndev, > + struct ethtool_mm_stats *s) > +{ > + struct prueth_emac *emac = netdev_priv(ndev); > + > + if (emac->is_sr1) > + return; > + > + if (!emac->prueth->pa_stats) > + return; > + > + emac_update_hardware_stats(emac); > + > + /* MACMergeHoldCount stats is not tracked by the firmware */ > + s->MACMergeFrameAssOkCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_OK"); > + s->MACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_ERR"); > + s->MACMergeFragCountRx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_RX"); > + s->MACMergeFragCountTx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_TX"); > + s->MACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_BAD_FRAG"); > +} [ ... ] > diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h > index 5ec0b38e0c67..8073deac35c3 100644 > --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h > +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h > @@ -189,6 +187,11 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = { > ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED), > ICSSG_PA_STATS(FW_INF_DROP_NOTAG), > ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER), > + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG), > + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR), > + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX), > + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK), > + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX), > ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR), > ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF), > ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF), [Medium] Are these five new entries duplicating values that already have a standard uAPI? The same five firmware counters are exposed through the new .get_mm_stats callback as the standardized MAC Merge stats (MACMergeFrameAssOkCount, MACMergeFrameAssErrorCount, MACMergeFragCountRx, MACMergeFragCountTx, MACMergeFrameSmdErrorCount in struct ethtool_mm_stats), and adding them to icssg_all_pa_stats[] also publishes them via emac_get_strings() / emac_get_ethtool_stats() as ethtool -S strings. Documentation/networking/statistics.rst describes ethtool -S as the private-driver-stats interface; counters that have a standard uAPI are expected to flow only through that uAPI. Could the firmware-register lookup table used by emac_get_stat_by_name() be separated from the ethtool -S string table, so the new preemption counters feed get_mm_stats without also showing up under ethtool -S? ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 2026-06-15 23:10 ` Jakub Kicinski @ 2026-06-15 23:39 ` Jakub Kicinski 2026-06-16 12:54 ` Meghana Malladi 0 siblings, 1 reply; 9+ messages in thread From: Jakub Kicinski @ 2026-06-15 23:39 UTC (permalink / raw) To: m-malladi Cc: elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, vigneshr On Mon, 15 Jun 2026 16:10:41 -0700 Jakub Kicinski wrote: > > diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h > > index 5ec0b38e0c67..8073deac35c3 100644 > > --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h > > +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h > > @@ -189,6 +187,11 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = { > > ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED), > > ICSSG_PA_STATS(FW_INF_DROP_NOTAG), > > ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER), > > + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG), > > + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR), > > + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX), > > + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK), > > + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX), > > ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR), > > ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF), > > ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF), > > [Medium] > Are these five new entries duplicating values that already have a > standard uAPI? > > The same five firmware counters are exposed through the new > .get_mm_stats callback as the standardized MAC Merge stats > (MACMergeFrameAssOkCount, MACMergeFrameAssErrorCount, MACMergeFragCountRx, > MACMergeFragCountTx, MACMergeFrameSmdErrorCount in struct > ethtool_mm_stats), and adding them to icssg_all_pa_stats[] also > publishes them via emac_get_strings() / emac_get_ethtool_stats() as > ethtool -S strings. > > Documentation/networking/statistics.rst describes ethtool -S as the > private-driver-stats interface; counters that have a standard uAPI are > expected to flow only through that uAPI. > > Could the firmware-register lookup table used by emac_get_stat_by_name() > be separated from the ethtool -S string table, so the new preemption > counters feed get_mm_stats without also showing up under ethtool -S? This -- not sure about the other complaints but this one looks legit. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 2026-06-15 23:39 ` Jakub Kicinski @ 2026-06-16 12:54 ` Meghana Malladi 2026-06-16 15:07 ` Jakub Kicinski 0 siblings, 1 reply; 9+ messages in thread From: Meghana Malladi @ 2026-06-16 12:54 UTC (permalink / raw) To: Jakub Kicinski Cc: elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, vigneshr Hi Jakub, On 6/16/26 05:09, Jakub Kicinski wrote: > On Mon, 15 Jun 2026 16:10:41 -0700 Jakub Kicinski wrote: >>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h >>> index 5ec0b38e0c67..8073deac35c3 100644 >>> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h >>> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h >>> @@ -189,6 +187,11 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = { >>> ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED), >>> ICSSG_PA_STATS(FW_INF_DROP_NOTAG), >>> ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER), >>> + ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG), >>> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR), >>> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX), >>> + ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK), >>> + ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX), >>> ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR), >>> ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF), >>> ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF), >> >> [Medium] >> Are these five new entries duplicating values that already have a >> standard uAPI? >> >> The same five firmware counters are exposed through the new >> .get_mm_stats callback as the standardized MAC Merge stats >> (MACMergeFrameAssOkCount, MACMergeFrameAssErrorCount, MACMergeFragCountRx, >> MACMergeFragCountTx, MACMergeFrameSmdErrorCount in struct >> ethtool_mm_stats), and adding them to icssg_all_pa_stats[] also >> publishes them via emac_get_strings() / emac_get_ethtool_stats() as >> ethtool -S strings. >> >> Documentation/networking/statistics.rst describes ethtool -S as the >> private-driver-stats interface; counters that have a standard uAPI are >> expected to flow only through that uAPI. >> >> Could the firmware-register lookup table used by emac_get_stat_by_name() >> be separated from the ethtool -S string table, so the new preemption >> counters feed get_mm_stats without also showing up under ethtool -S? > > This -- not sure about the other complaints but this one looks legit. I agree that this is legit, but right now there is no other place holder other than pa stats to put the mac merge firmware counters. I believe the effort needs to go in re-structuring the hardware and firmware stats implementation to address this issue. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 2026-06-16 12:54 ` Meghana Malladi @ 2026-06-16 15:07 ` Jakub Kicinski 0 siblings, 0 replies; 9+ messages in thread From: Jakub Kicinski @ 2026-06-16 15:07 UTC (permalink / raw) To: Meghana Malladi Cc: elfring, haokexin, vadim.fedorenko, devnexen, horms, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, vigneshr On Tue, 16 Jun 2026 18:24:22 +0530 Meghana Malladi wrote: > >> Could the firmware-register lookup table used by emac_get_stat_by_name() > >> be separated from the ethtool -S string table, so the new preemption > >> counters feed get_mm_stats without also showing up under ethtool -S? > > > > This -- not sure about the other complaints but this one looks legit. > > I agree that this is legit, but right now there is no other place holder > other than pa stats to put the mac merge firmware counters. I believe > the effort needs to go in re-structuring the hardware and firmware stats > implementation to address this issue. icssg_all_miig_stats has a true / false that looks like it's supposed to serve the same purpose? Maybe I don't understand what you're trying to say ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG 2026-06-10 5:25 [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Meghana Malladi 2026-06-10 5:25 ` [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support Meghana Malladi 2026-06-10 5:25 ` [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge Meghana Malladi @ 2026-06-12 9:01 ` Simon Horman 2 siblings, 0 replies; 9+ messages in thread From: Simon Horman @ 2026-06-12 9:01 UTC (permalink / raw) To: Meghana Malladi Cc: elfring, haokexin, vadim.fedorenko, devnexen, jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean, rogerq, danishanwar, pabeni, kuba, edumazet, davem, andrew+netdev, linux-arm-kernel, netdev, linux-kernel, srk, Vignesh Raghavendra On Wed, Jun 10, 2026 at 10:55:09AM +0530, Meghana Malladi wrote: > This patch series adds QoS support to the ICSSG PRUETH driver. > The first patch implements mqprio qdisc handling and TC offload hooks > so userspace can request TC mappings and queue counts. > > It also integrates a driver-side mechanism to program the firmware > with the IET/FPE preemption mask and to kick the firmware verify state > machine when frame preemption is enabled. The second patch adds ethtool > perations for the MAC Merge (Frame Preemption) sublayer, exposing .get_mm, > .set_mm and .get_mm_stats so admins can view and change MAC Merge > parameters and retrieve preemption statistics. > > v6: https://lore.kernel.org/all/20260525182700.3135858-1-m-malladi@ti.com/ > > MD Danish Anwar (2): > net: ti: icssg-prueth: Add Frame Preemption MAC Merge support > net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge Hi Meghana and MD, There is AI-generated review of this patch-set available on both https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/ I would appreciate it if you could look over that with a view to addressing any issues that directly affect this patch-set. ... ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-06-16 15:07 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-10 5:25 [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Meghana Malladi 2026-06-10 5:25 ` [PATCH net-next v7 1/2] net: ti: icssg-prueth: Add Frame Preemption MAC Merge support Meghana Malladi 2026-06-15 23:10 ` Jakub Kicinski 2026-06-10 5:25 ` [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge Meghana Malladi 2026-06-15 23:10 ` Jakub Kicinski 2026-06-15 23:39 ` Jakub Kicinski 2026-06-16 12:54 ` Meghana Malladi 2026-06-16 15:07 ` Jakub Kicinski 2026-06-12 9:01 ` [PATCH net-next v7 0/2] Add Frame Preemption MAC Merge support for ICSSG Simon Horman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox