net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge 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: Meghana Malladi <m-malladi@ti.com> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c index b715af21..2176536 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,100 @@ 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; + + if (emac->is_sr1) + return -EOPNOTSUPP; + + 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 (emac->is_sr1) + return -EOPNOTSUPP; + + 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); + + if (emac->is_sr1) + return; + + if (!emac->prueth->pa_stats) + return; + + 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 +410,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 39f378b..20e6c5d 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
diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h index 653dbb5..bf84cc1 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_qos.h +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h
@@ -57,4 +57,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 7159baa..d27e1c4 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 5ec0b38e..f35ae1b 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 7e053b8..855fd4ed 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