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+
743981const 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