[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260204140044.4086725-3-m-malladi@ti.com>
Date: Wed, 4 Feb 2026 19:30:44 +0530
From: Meghana Malladi <m-malladi@...com>
To: <vadim.fedorenko@...ux.dev>, <jacob.e.keller@...el.com>,
<horms@...nel.org>, <parvathi@...thit.com>, <afd@...com>, <m-malladi@...com>,
<vladimir.oltean@....com>, <rogerq@...nel.org>, <danishanwar@...com>,
<pabeni@...hat.com>, <kuba@...nel.org>, <edumazet@...gle.com>,
<davem@...emloft.net>, <andrew+netdev@...n.ch>
CC: <linux-arm-kernel@...ts.infradead.org>, <netdev@...r.kernel.org>,
<linux-kernel@...r.kernel.org>, <srk@...com>, Vignesh Raghavendra
<vigneshr@...com>
Subject: [PATCH net-next v2 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
From: MD Danish Anwar <danishanwar@...com>
Add driver support for viewing / changing the MAC Merge sublayer
parameters and dump the Mac Merge stats 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 (in octets). Add a check to ensure
user passed tx_min_frag_size argument via ethtool, honors this .
Add pa stats registers to check statistics for preemption, which can be
dumped using ethtool ops.
Signed-off-by: MD Danish Anwar <danishanwar@...com>
Signed-off-by: Meghana Malladi <m-malladi@...com>
---
v2-v1:
- Following changes have been done as suggested by Vladimir Oltean <vladimir.oltean@....com>
* Add sanity check to ensure valid min_frag_size is requested by the user.
* Add comments wherever applicable w.r.t min_frag_size.
* Make it uniform to return all valures from the driver for .get_mm()
* Use ETHTOOL_MM_MAX_VERIFY_TIME_MS macro for 128
* Use NL_SET_ERR_MSG_MOD() wherever applicable
* Re-schedule the iet work thread whenever there .set_mm() get called
based on fpe_enabled flag.
drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 86 ++++++++++++++++++-
drivers/net/ethernet/ti/icssg/icssg_prueth.h | 3 +-
drivers/net/ethernet/ti/icssg/icssg_qos.h | 20 +++++
drivers/net/ethernet/ti/icssg/icssg_stats.c | 1 -
drivers/net/ethernet/ti/icssg/icssg_stats.h | 5 ++
.../net/ethernet/ti/icssg/icssg_switch_map.h | 5 ++
6 files changed, 117 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
index b715af21d23a..3c4ff154f6d1 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
@@ -6,7 +6,6 @@
*/
#include "icssg_prueth.h"
-#include "icssg_stats.h"
static void emac_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
@@ -294,6 +293,88 @@ 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;
+
+ state->tx_enabled = iet->fpe_enabled;
+ state->pmac_enabled = true;
+ state->tx_min_frag_size = iet->tx_min_frag_size;
+ /* 64Bytes is the minimum fragment size supported
+ * by the firmware. <64B leads to min frame errors
+ */
+ state->rx_min_frag_size = 64;
+ state->tx_active = iet->fpe_active;
+ state->verify_enabled = iet->mac_verify_configure;
+ state->verify_time = iet->verify_time_ms;
+
+ switch (iet->verify_status) {
+ case ICSSG_IETFPE_STATE_DISABLED:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+ 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 (!cfg->pmac_enabled)
+ NL_SET_ERR_MSG_MOD(extack, "preemptible MAC is always enabled");
+
+ err = icssg_qos_frag_size_min_to_add(cfg->tx_min_frag_size, extack);
+ if (err)
+ return err;
+
+ 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;
+
+ /* Re-trigger the state machine to incorporate the updated configuration */
+ if (iet->fpe_enabled)
+ atomic_set(&iet->enable_fpe_config, 1);
+ else
+ atomic_set(&iet->enable_fpe_config, 0);
+
+ schedule_work(&iet->fpe_config_task);
+
+ return 0;
+}
+
+static void emac_get_mm_stats(struct net_device *ndev,
+ struct ethtool_mm_stats *s)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ 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 +398,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 7a586038adf8..1309af6aab78 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,7 +59,7 @@
#define ICSSG_MAX_RFLOWS 8 /* per slice */
-#define ICSSG_NUM_PA_STATS 32
+#define ICSSG_NUM_PA_STATS ARRAY_SIZE(icssg_all_pa_stats)
#define ICSSG_NUM_MIIG_STATS 60
/* Number of ICSSG related stats */
#define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h
index 8aa79b68ad54..b18a93f9181a 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_qos.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h
@@ -55,4 +55,24 @@ void icssg_qos_link_up(struct net_device *ndev);
void icssg_qos_link_down(struct net_device *ndev);
int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
+static inline int icssg_qos_frag_size_min_to_add(u32 min_frag_size,
+ struct netlink_ext_ack *extack)
+{
+ /* The minimum size of the non-final mPacket supported
+ * by the firmware is 64B and multiples of 64B.
+ */
+ if (min_frag_size < 64) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "tx_min_frag_size must be at least 64 bytes");
+ return -EINVAL;
+ }
+
+ if (min_frag_size % (ETH_ZLEN + ETH_FCS_LEN)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "tx_min_frag_size must be a multiple of 64 bytes");
+ return -EINVAL;
+ }
+
+ return 0;
+}
#endif /* __NET_TI_ICSSG_QOS_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index 7159baa0155c..d27e1c48976f 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -6,7 +6,6 @@
*/
#include "icssg_prueth.h"
-#include "icssg_stats.h"
#include <linux/regmap.h>
#define ICSSG_TX_PACKET_OFFSET 0xA0
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 5ec0b38e0c67..f35ae1b4f846 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -189,6 +189,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 7e053b8af3ec..855fd4ed0b3f 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
Powered by blists - more mailing lists