Skip to content

Commit d11db8a

Browse files
committed
Merge branch 'am65-cpsw-preemption-coalescing'
Roger Quadros says: ==================== net: ethernet: am65-cpsw: Add mqprio, frame preemption & coalescing This series adds mqprio qdisc offload in channel mode, Frame Preemption MAC merge support and RX/TX coalesing for AM65 CPSW driver. In v11 following changes were made - Fix patch "net: ethernet: ti: am65-cpsw: add mqprio qdisc offload in channel mode" by including units.h Changelog information in each patch file. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 2437c0f + e4918f9 commit d11db8a

File tree

9 files changed

+1100
-187
lines changed

9 files changed

+1100
-187
lines changed

drivers/net/ethernet/ti/Kconfig

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,16 @@ config TI_K3_AM65_CPTS
134134
protocol, Ethernet Enhanced Scheduled Traffic Operations (CPTS_ESTFn)
135135
and PCIe Subsystem Precision Time Measurement (PTM).
136136

137-
config TI_AM65_CPSW_TAS
138-
bool "Enable TAS offload in AM65 CPSW"
137+
config TI_AM65_CPSW_QOS
138+
bool "Enable QoS offload features in AM65 CPSW"
139139
depends on TI_K3_AM65_CPSW_NUSS && NET_SCH_TAPRIO && TI_K3_AM65_CPTS
140140
help
141-
Say y here to support Time Aware Shaper(TAS) offload in AM65 CPSW.
142-
AM65 CPSW hardware supports Enhanced Scheduled Traffic (EST)
143-
defined in IEEE 802.1Q 2018. The EST scheduler runs on CPTS and the
144-
TAS/EST schedule is updated in the Fetch RAM memory of the CPSW.
141+
This option enables QoS offload features in AM65 CPSW like
142+
Time Aware Shaper (TAS) / Enhanced Scheduled Traffic (EST),
143+
MQPRIO qdisc offload and Frame-Preemption MAC Merge / Interspersing
144+
Express Traffic (IET).
145+
The EST scheduler runs on CPTS and the TAS/EST schedule is
146+
updated in the Fetch RAM memory of the CPSW.
145147

146148
config TI_KEYSTONE_NETCP
147149
tristate "TI Keystone NETCP Core Support"

drivers/net/ethernet/ti/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.
2626
obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o
2727

2828
obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
29-
ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o am65-cpsw-qos.o
29+
ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o
30+
ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o
3031
ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
3132
obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
3233

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

Lines changed: 246 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,240 @@ 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+
907+
static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
908+
struct kernel_ethtool_coalesce *kernel_coal,
909+
struct netlink_ext_ack *extack)
910+
{
911+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
912+
struct am65_cpsw_tx_chn *tx_chn;
913+
914+
tx_chn = &common->tx_chns[0];
915+
916+
coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000;
917+
coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
918+
919+
return 0;
920+
}
921+
922+
static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
923+
struct ethtool_coalesce *coal)
924+
{
925+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
926+
struct am65_cpsw_tx_chn *tx_chn;
927+
928+
if (queue >= AM65_CPSW_MAX_TX_QUEUES)
929+
return -EINVAL;
930+
931+
tx_chn = &common->tx_chns[queue];
932+
933+
coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
934+
935+
return 0;
936+
}
937+
938+
static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
939+
struct kernel_ethtool_coalesce *kernel_coal,
940+
struct netlink_ext_ack *extack)
941+
{
942+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
943+
struct am65_cpsw_tx_chn *tx_chn;
944+
945+
tx_chn = &common->tx_chns[0];
946+
947+
if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)
948+
return -EINVAL;
949+
950+
if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)
951+
return -EINVAL;
952+
953+
common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;
954+
tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
955+
956+
return 0;
957+
}
958+
959+
static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
960+
struct ethtool_coalesce *coal)
961+
{
962+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
963+
struct am65_cpsw_tx_chn *tx_chn;
964+
965+
if (queue >= AM65_CPSW_MAX_TX_QUEUES)
966+
return -EINVAL;
967+
968+
tx_chn = &common->tx_chns[queue];
969+
970+
if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) {
971+
dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n",
972+
queue);
973+
coal->tx_coalesce_usecs = 20;
974+
}
975+
976+
tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
977+
978+
return 0;
979+
}
980+
743981
const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
744982
.begin = am65_cpsw_ethtool_op_begin,
745983
.complete = am65_cpsw_ethtool_op_complete,
@@ -758,6 +996,11 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
758996
.get_ts_info = am65_cpsw_get_ethtool_ts_info,
759997
.get_priv_flags = am65_cpsw_get_ethtool_priv_flags,
760998
.set_priv_flags = am65_cpsw_set_ethtool_priv_flags,
999+
.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
1000+
.get_coalesce = am65_cpsw_get_coalesce,
1001+
.set_coalesce = am65_cpsw_set_coalesce,
1002+
.get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,
1003+
.set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,
7611004

7621005
.get_link = ethtool_op_get_link,
7631006
.get_link_ksettings = am65_cpsw_get_link_ksettings,
@@ -769,4 +1012,7 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
7691012
.get_eee = am65_cpsw_get_eee,
7701013
.set_eee = am65_cpsw_set_eee,
7711014
.nway_reset = am65_cpsw_nway_reset,
1015+
.get_mm = am65_cpsw_get_mm,
1016+
.set_mm = am65_cpsw_set_mm,
1017+
.get_mm_stats = am65_cpsw_get_mm_stats,
7721018
};

0 commit comments

Comments
 (0)