Skip to content

Commit 49a2eb9

Browse files
rogerqdavem330
authored andcommitted
net: ethernet: ti: am65-cpsw-qos: Add Frame Preemption MAC Merge support
Add driver support for viewing / changing the MAC Merge sublayer parameters and seeing the verification state machine's current state via ethtool. As hardware does not support interrupt notification for verification events we resort to polling on link up. On link up we try a couple of times for verification success and if unsuccessful then give up. The Frame Preemption feature is described in the Technical Reference Manual [1] in section: 12.3.1.4.6.7 Intersperced Express Traffic (IET – P802.3br/D2.0) Due to Silicon Errata i2208 [2] we set limit min IET fragment size to 124 (excluding 4 bytes mCRC). [1] AM62x TRM - https://www.ti.com/lit/ug/spruiv7a/spruiv7a.pdf [2] AM62x Silicon Errata - https://www.ti.com/lit/er/sprz487c/sprz487c.pdf Signed-off-by: Roger Quadros <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bc8d62e commit 49a2eb9

File tree

6 files changed

+456
-2
lines changed

6 files changed

+456
-2
lines changed

drivers/net/ethernet/ti/Kconfig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,9 @@ config TI_AM65_CPSW_QOS
139139
depends on TI_K3_AM65_CPSW_NUSS && NET_SCH_TAPRIO && TI_K3_AM65_CPTS
140140
help
141141
This option enables QoS offload features in AM65 CPSW like
142-
Time Aware Shaper (TAS) / Enhanced Scheduled Traffic (EST)
143-
and MQPRIO qdisc offload.
142+
Time Aware Shaper (TAS) / Enhanced Scheduled Traffic (EST),
143+
MQPRIO qdisc offload and Frame-Preemption MAC Merge / Interspersing
144+
Express Traffic (IET).
144145
The EST scheduler runs on CPTS and the TAS/EST schedule is
145146
updated in the Fetch RAM memory of the CPSW.
146147

drivers/net/ethernet/ti/am65-cpsw-ethtool.c

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/pm_runtime.h>
1212

1313
#include "am65-cpsw-nuss.h"
14+
#include "am65-cpsw-qos.h"
1415
#include "cpsw_ale.h"
1516
#include "am65-cpts.h"
1617

@@ -670,6 +671,9 @@ static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev,
670671

671672
stats = port->stat_base;
672673

674+
if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
675+
return;
676+
673677
s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames);
674678
s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames);
675679
s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames);
@@ -740,6 +744,166 @@ static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
740744
return 0;
741745
}
742746

747+
static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable)
748+
{
749+
u32 val;
750+
751+
val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
752+
if (enable)
753+
val |= AM65_CPSW_PN_CTL_IET_PORT_EN;
754+
else
755+
val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN;
756+
757+
writel(val, port->port_base + AM65_CPSW_PN_REG_CTL);
758+
am65_cpsw_iet_common_enable(port->common);
759+
}
760+
761+
static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable)
762+
{
763+
u32 val;
764+
765+
val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
766+
if (enable)
767+
val |= AM65_CPSW_PN_IET_MAC_PENABLE;
768+
else
769+
val &= ~AM65_CPSW_PN_IET_MAC_PENABLE;
770+
771+
writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
772+
}
773+
774+
static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
775+
{
776+
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
777+
struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
778+
u32 port_ctrl, iet_ctrl, iet_status;
779+
u32 add_frag_size;
780+
781+
if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
782+
return -EOPNOTSUPP;
783+
784+
mutex_lock(&priv->mm_lock);
785+
786+
iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
787+
port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
788+
789+
state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE);
790+
state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN);
791+
792+
iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
793+
794+
if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)
795+
state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
796+
else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED)
797+
state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
798+
else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL)
799+
state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
800+
else
801+
state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
802+
803+
add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl);
804+
state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
805+
806+
/* Errata i2208: RX min fragment size cannot be less than 124 */
807+
state->rx_min_frag_size = 124;
808+
809+
/* FPE active if common tx_enabled and verification success or disabled (forced) */
810+
state->tx_active = state->tx_enabled &&
811+
(state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
812+
state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
813+
state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY);
814+
815+
state->verify_time = port->qos.iet.verify_time_ms;
816+
817+
/* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
818+
* variable has a range between 1 and 128 ms inclusive. Limit to that.
819+
*/
820+
state->max_verify_time = 128;
821+
822+
mutex_unlock(&priv->mm_lock);
823+
824+
return 0;
825+
}
826+
827+
static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
828+
struct netlink_ext_ack *extack)
829+
{
830+
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
831+
struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
832+
struct am65_cpsw_iet *iet = &port->qos.iet;
833+
u32 val, add_frag_size;
834+
int err;
835+
836+
if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
837+
return -EOPNOTSUPP;
838+
839+
err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack);
840+
if (err)
841+
return err;
842+
843+
mutex_lock(&priv->mm_lock);
844+
845+
if (cfg->pmac_enabled) {
846+
/* change TX & RX FIFO MAX_BLKS as per TRM recommendation */
847+
if (!iet->original_max_blks)
848+
iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
849+
850+
writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET,
851+
port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
852+
} else if (iet->original_max_blks) {
853+
/* restore RX & TX FIFO MAX_BLKS */
854+
writel(iet->original_max_blks,
855+
port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
856+
}
857+
858+
am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled);
859+
am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled);
860+
861+
val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
862+
if (cfg->verify_enabled) {
863+
val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
864+
/* Reset Verify state machine. Verification won't start here.
865+
* Verification will be done once link-up.
866+
*/
867+
val |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
868+
} else {
869+
val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
870+
/* Clear LINKFAIL to allow verify/response packets */
871+
val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
872+
}
873+
874+
val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK;
875+
val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size);
876+
writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
877+
878+
/* verify_timeout_count can only be set at valid link */
879+
port->qos.iet.verify_time_ms = cfg->verify_time;
880+
881+
/* enable/disable preemption based on link status */
882+
am65_cpsw_iet_commit_preemptible_tcs(port);
883+
884+
mutex_unlock(&priv->mm_lock);
885+
886+
return 0;
887+
}
888+
889+
static void am65_cpsw_get_mm_stats(struct net_device *ndev,
890+
struct ethtool_mm_stats *s)
891+
{
892+
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
893+
void __iomem *base = port->stat_base;
894+
895+
s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK);
896+
s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR);
897+
s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR);
898+
/* CPSW Functional Spec states:
899+
* "The IET stat aMACMergeFragCountRx is derived by adding the
900+
* Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG"
901+
*/
902+
s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount;
903+
s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG);
904+
s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);
905+
}
906+
743907
const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
744908
.begin = am65_cpsw_ethtool_op_begin,
745909
.complete = am65_cpsw_ethtool_op_complete,
@@ -769,4 +933,7 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
769933
.get_eee = am65_cpsw_get_eee,
770934
.set_eee = am65_cpsw_set_eee,
771935
.nway_reset = am65_cpsw_nway_reset,
936+
.get_mm = am65_cpsw_get_mm,
937+
.set_mm = am65_cpsw_set_mm,
938+
.get_mm_stats = am65_cpsw_get_mm_stats,
772939
};

drivers/net/ethernet/ti/am65-cpsw-nuss.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,8 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
21942194
ndev_priv = netdev_priv(port->ndev);
21952195
ndev_priv->port = port;
21962196
ndev_priv->msg_enable = AM65_CPSW_DEBUG;
2197+
mutex_init(&ndev_priv->mm_lock);
2198+
port->qos.link_speed = SPEED_UNKNOWN;
21972199
SET_NETDEV_DEV(port->ndev, dev);
21982200

21992201
eth_hw_addr_set(port->ndev, port->slave.mac_addr);

drivers/net/ethernet/ti/am65-cpsw-nuss.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct am65_cpsw_common {
145145
bool pf_p0_rx_ptype_rrobin;
146146
struct am65_cpts *cpts;
147147
int est_enabled;
148+
bool iet_enabled;
148149

149150
bool is_emac_mode;
150151
u16 br_members;
@@ -170,6 +171,10 @@ struct am65_cpsw_ndev_priv {
170171
struct am65_cpsw_port *port;
171172
struct am65_cpsw_ndev_stats __percpu *stats;
172173
bool offload_fwd_mark;
174+
/* Serialize access to MAC Merge state between ethtool requests
175+
* and link state updates
176+
*/
177+
struct mutex mm_lock;
173178
};
174179

175180
#define am65_ndev_to_priv(ndev) \

0 commit comments

Comments
 (0)