aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLCPD Auto Merger2020-12-17 03:29:19 -0600
committerLCPD Auto Merger2020-12-17 03:29:19 -0600
commit73039d258adb0cac813342cc7e746e22295765fe (patch)
treec6d0d46f2ce4c372b64a1753284237c724148286
parent308ea579aed3cef3629be124c9cdea5b4c36eac0 (diff)
parent5b2c8c1f5a4d16a13f7fe9a67f1303a039884111 (diff)
downloadkernel-ti-linux-5.4.y.tar.gz
kernel-ti-linux-5.4.y.tar.xz
kernel-ti-linux-5.4.y.zip
Merged TI feature connectivity into ti-linux-5.4.y07.02.00.001ti-linux-5.4.y
TI-Feature: connectivity TI-Branch: connectivity-ti-linux-5.4.y * 'connectivity-ti-linux-5.4.y' of ssh://bitbucket.itg.ti.com/lcpdpublicdom/connectivity: HACK: net: ethernet: ti: am65-cpsw-nuss: add debugfs to cfg cut-thru params net: ethernet: ti: am65-cpsw: add cut-thru support for am64 cpsw3g Signed-off-by: LCPD Auto Merger <lcpd_integration@list.ti.com>
-rw-r--r--drivers/net/ethernet/ti/Makefile2
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-ethtool.c18
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c22
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h10
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-qos.c140
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-qos.h15
-rw-r--r--drivers/net/ethernet/ti/am65-debugfs.c152
7 files changed, 351 insertions, 8 deletions
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 8f98f3a72867..0d22e2e5b676 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
22keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o cpsw_ale.o 22keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o cpsw_ale.o
23 23
24obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o 24obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
25ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o 25ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o am65-debugfs.o
26ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o 26ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
27obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o 27obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
28 28
diff --git a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
index b84f4052ba04..7d1c350c995f 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
@@ -379,6 +379,8 @@ static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = {
379 "iet-frame-preemption", 379 "iet-frame-preemption",
380#define AM65_CPSW_PRIV_IET_MAC_VERIFY BIT(2) 380#define AM65_CPSW_PRIV_IET_MAC_VERIFY BIT(2)
381 "iet-mac-verify", 381 "iet-mac-verify",
382#define AM65_CPSW_PRIV_CUT_THRU BIT(3)
383 "cut-thru",
382}; 384};
383 385
384static int am65_cpsw_ethtool_op_begin(struct net_device *ndev) 386static int am65_cpsw_ethtool_op_begin(struct net_device *ndev)
@@ -738,6 +740,8 @@ static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
738 priv_flags |= AM65_CPSW_PRIV_IET_FRAME_PREEMPTION; 740 priv_flags |= AM65_CPSW_PRIV_IET_FRAME_PREEMPTION;
739 if (iet->mac_verify_configured) 741 if (iet->mac_verify_configured)
740 priv_flags |= AM65_CPSW_PRIV_IET_MAC_VERIFY; 742 priv_flags |= AM65_CPSW_PRIV_IET_MAC_VERIFY;
743 if (port->qos.cut_thru.enable)
744 priv_flags |= AM65_CPSW_PRIV_CUT_THRU;
741 745
742 return priv_flags; 746 return priv_flags;
743} 747}
@@ -747,11 +751,12 @@ static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
747 struct am65_cpsw_common *common = am65_ndev_to_common(ndev); 751 struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
748 struct am65_cpsw_port *port = am65_ndev_to_port(ndev); 752 struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
749 struct am65_cpsw_iet *iet = &port->qos.iet; 753 struct am65_cpsw_iet *iet = &port->qos.iet;
750 int rrobin, iet_fpe, mac_verify; 754 int rrobin, iet_fpe, mac_verify, cut_thru;
751 755
752 rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN); 756 rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
753 iet_fpe = !!(flags & AM65_CPSW_PRIV_IET_FRAME_PREEMPTION); 757 iet_fpe = !!(flags & AM65_CPSW_PRIV_IET_FRAME_PREEMPTION);
754 mac_verify = !!(flags & AM65_CPSW_PRIV_IET_MAC_VERIFY); 758 mac_verify = !!(flags & AM65_CPSW_PRIV_IET_MAC_VERIFY);
759 cut_thru = !!(flags & AM65_CPSW_PRIV_CUT_THRU);
755 760
756 if (common->usage_count) 761 if (common->usage_count)
757 return -EBUSY; 762 return -EBUSY;
@@ -772,9 +777,20 @@ static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
772 return -EINVAL; 777 return -EINVAL;
773 } 778 }
774 779
780 if (cut_thru && !(common->pdata.quirks & AM64_CPSW_QUIRK_CUT_THRU)) {
781 netdev_err(ndev, "Cut-Thru not supported\n");
782 return -EOPNOTSUPP;
783 }
784
785 if (cut_thru && common->is_emac_mode) {
786 netdev_err(ndev, "Enable switch mode for cut-thru\n");
787 return -EINVAL;
788 }
789
775 common->pf_p0_rx_ptype_rrobin = rrobin; 790 common->pf_p0_rx_ptype_rrobin = rrobin;
776 iet->fpe_configured = iet_fpe; 791 iet->fpe_configured = iet_fpe;
777 iet->mac_verify_configured = mac_verify; 792 iet->mac_verify_configured = mac_verify;
793 port->qos.cut_thru.enable = cut_thru;
778 794
779 return 0; 795 return 0;
780} 796}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 6c90f2af3d42..8c00afb61920 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -193,7 +193,7 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev)
193 193
194 cpsw_sl_ctl_set(port->slave.mac_sl, mac_control); 194 cpsw_sl_ctl_set(port->slave.mac_sl, mac_control);
195 195
196 am65_cpsw_qos_link_up(ndev, phy->speed); 196 am65_cpsw_qos_link_up(ndev, phy->speed, phy->duplex);
197 197
198 /* enable forwarding */ 198 /* enable forwarding */
199 cpsw_ale_control_set(common->ale, port->port_id, 199 cpsw_ale_control_set(common->ale, port->port_id,
@@ -597,6 +597,7 @@ static int am65_cpsw_nuss_ndo_slave_stop(struct net_device *ndev)
597 597
598 /* Clean up IET */ 598 /* Clean up IET */
599 am65_cpsw_qos_iet_cleanup(ndev); 599 am65_cpsw_qos_iet_cleanup(ndev);
600 am65_cpsw_qos_cut_thru_cleanup(port);
600 601
601 if (port->slave.phy) 602 if (port->slave.phy)
602 phy_stop(port->slave.phy); 603 phy_stop(port->slave.phy);
@@ -692,6 +693,7 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
692 693
693 /* Initialize IET */ 694 /* Initialize IET */
694 am65_cpsw_qos_iet_init(ndev); 695 am65_cpsw_qos_iet_init(ndev);
696 am65_cpsw_qos_cut_thru_init(port);
695 697
696 /* restore vlan configurations */ 698 /* restore vlan configurations */
697 vlan_for_each(ndev, cpsw_restore_vlans, port); 699 vlan_for_each(ndev, cpsw_restore_vlans, port);
@@ -2432,8 +2434,10 @@ static int am65_cpsw_dl_switch_mode_set(struct devlink *dl, u32 id,
2432 2434
2433 port = am65_ndev_to_port(sl_ndev); 2435 port = am65_ndev_to_port(sl_ndev);
2434 port->slave.port_vlan = 0; 2436 port->slave.port_vlan = 0;
2435 if (netif_running(sl_ndev)) 2437 if (netif_running(sl_ndev)) {
2436 am65_cpsw_init_port_emac_ale(port); 2438 am65_cpsw_init_port_emac_ale(port);
2439 am65_cpsw_qos_cut_thru_cleanup(port);
2440 }
2437 } 2441 }
2438 } 2442 }
2439 cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_BYPASS, 0); 2443 cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_BYPASS, 0);
@@ -2572,6 +2576,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
2572 for (i = 0; i < common->port_num; i++) { 2576 for (i = 0; i < common->port_num; i++) {
2573 port = &common->ports[i]; 2577 port = &common->ports[i];
2574 2578
2579 ret = am65_cpsw_nuss_register_port_debugfs(port);
2580 if (ret)
2581 goto err_cleanup_ndev;
2582
2575 if (!port->ndev) 2583 if (!port->ndev)
2576 continue; 2584 continue;
2577 2585
@@ -2645,7 +2653,7 @@ static const struct am65_cpsw_pdata j721e_pdata = {
2645}; 2653};
2646 2654
2647static const struct am65_cpsw_pdata am64x_cpswxg_pdata = { 2655static const struct am65_cpsw_pdata am64x_cpswxg_pdata = {
2648 .quirks = 0, 2656 .quirks = AM64_CPSW_QUIRK_CUT_THRU,
2649 .ale_dev_id = "am64-cpswxg", 2657 .ale_dev_id = "am64-cpswxg",
2650 .fdqring_mode = K3_RINGACC_RING_MODE_RING, 2658 .fdqring_mode = K3_RINGACC_RING_MODE_RING,
2651}; 2659};
@@ -2807,10 +2815,16 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
2807 if (ret) 2815 if (ret)
2808 goto err_of_clear; 2816 goto err_of_clear;
2809 2817
2810 ret = am65_cpsw_nuss_register_ndevs(common); 2818 ret = am65_cpsw_nuss_register_debugfs(common);
2811 if (ret) 2819 if (ret)
2812 goto err_of_clear; 2820 goto err_of_clear;
2813 2821
2822 ret = am65_cpsw_nuss_register_ndevs(common);
2823 if (ret) {
2824 am65_cpsw_nuss_unregister_debugfs(common);
2825 goto err_of_clear;
2826 }
2827
2814 pm_runtime_put(dev); 2828 pm_runtime_put(dev);
2815 return 0; 2829 return 0;
2816 2830
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index a7fc3c0971c6..de98be1b79f9 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -6,6 +6,7 @@
6#ifndef AM65_CPSW_NUSS_H_ 6#ifndef AM65_CPSW_NUSS_H_
7#define AM65_CPSW_NUSS_H_ 7#define AM65_CPSW_NUSS_H_
8 8
9#include <linux/debugfs.h>
9#include <linux/if_ether.h> 10#include <linux/if_ether.h>
10#include <linux/kernel.h> 11#include <linux/kernel.h>
11#include <linux/module.h> 12#include <linux/module.h>
@@ -53,6 +54,7 @@ struct am65_cpsw_port {
53 bool rx_ts_enabled; 54 bool rx_ts_enabled;
54 struct am65_cpsw_qos qos; 55 struct am65_cpsw_qos qos;
55 struct devlink_port devlink_port; 56 struct devlink_port devlink_port;
57 struct dentry *debugfs_port;
56}; 58};
57 59
58struct am65_cpsw_host { 60struct am65_cpsw_host {
@@ -84,6 +86,7 @@ struct am65_cpsw_rx_chn {
84}; 86};
85 87
86#define AM65_CPSW_QUIRK_I2027_NO_TX_CSUM BIT(0) 88#define AM65_CPSW_QUIRK_I2027_NO_TX_CSUM BIT(0)
89#define AM64_CPSW_QUIRK_CUT_THRU BIT(1)
87 90
88struct am65_cpsw_pdata { 91struct am65_cpsw_pdata {
89 u32 quirks; 92 u32 quirks;
@@ -135,6 +138,7 @@ struct am65_cpsw_common {
135 struct am65_cpts *cpts; 138 struct am65_cpts *cpts;
136 int est_enabled; 139 int est_enabled;
137 int iet_enabled; 140 int iet_enabled;
141 unsigned int cut_thru_enabled;
138 142
139 bool is_emac_mode; 143 bool is_emac_mode;
140 u16 br_members; 144 u16 br_members;
@@ -143,6 +147,8 @@ struct am65_cpsw_common {
143 struct net_device *hw_bridge_dev; 147 struct net_device *hw_bridge_dev;
144 struct notifier_block am65_cpsw_netdevice_nb; 148 struct notifier_block am65_cpsw_netdevice_nb;
145 unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; 149 unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
150
151 struct dentry *debugfs_root;
146}; 152};
147 153
148struct am65_cpsw_ndev_stats { 154struct am65_cpsw_ndev_stats {
@@ -187,4 +193,8 @@ int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx);
187 193
188bool am65_cpsw_port_dev_check(const struct net_device *dev); 194bool am65_cpsw_port_dev_check(const struct net_device *dev);
189 195
196int am65_cpsw_nuss_register_port_debugfs(struct am65_cpsw_port *port);
197int am65_cpsw_nuss_register_debugfs(struct am65_cpsw_common *common);
198void am65_cpsw_nuss_unregister_debugfs(struct am65_cpsw_common *common);
199
190#endif /* AM65_CPSW_NUSS_H_ */ 200#endif /* AM65_CPSW_NUSS_H_ */
diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.c b/drivers/net/ethernet/ti/am65-cpsw-qos.c
index d5215bf6a00d..a23dafd50839 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-qos.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-qos.c
@@ -7,6 +7,7 @@
7 * Interspersed Express Traffic (IET - P802.3br/D2.0) 7 * Interspersed Express Traffic (IET - P802.3br/D2.0)
8 */ 8 */
9 9
10#include <linux/bitfield.h>
10#include <linux/pm_runtime.h> 11#include <linux/pm_runtime.h>
11#include <linux/time.h> 12#include <linux/time.h>
12 13
@@ -15,6 +16,7 @@
15#include "am65-cpts.h" 16#include "am65-cpts.h"
16 17
17#define AM65_CPSW_REG_CTL 0x004 18#define AM65_CPSW_REG_CTL 0x004
19#define AM65_CPSW_REG_FREQ 0x05c
18#define AM65_CPSW_PN_REG_CTL 0x004 20#define AM65_CPSW_PN_REG_CTL 0x004
19#define AM65_CPSW_PN_REG_MAX_BLKS 0x008 21#define AM65_CPSW_PN_REG_MAX_BLKS 0x008
20#define AM65_CPSW_PN_REG_IET_CTRL 0x040 22#define AM65_CPSW_PN_REG_IET_CTRL 0x040
@@ -23,9 +25,13 @@
23#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 25#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
24#define AM65_CPSW_PN_REG_EST_CTL 0x060 26#define AM65_CPSW_PN_REG_EST_CTL 0x060
25 27
28#define AM64_CPSW_PN_CUT_THRU 0x3C0
29#define AM64_CPSW_PN_SPEED 0x3C4
30
26/* AM65_CPSW_REG_CTL register fields */ 31/* AM65_CPSW_REG_CTL register fields */
27#define AM65_CPSW_CTL_IET_EN BIT(17) 32#define AM65_CPSW_CTL_IET_EN BIT(17)
28#define AM65_CPSW_CTL_EST_EN BIT(18) 33#define AM65_CPSW_CTL_EST_EN BIT(18)
34#define AM64_CPSW_CTL_CUT_THRU_EN BIT(19)
29 35
30/* AM65_CPSW_PN_REG_CTL register fields */ 36/* AM65_CPSW_PN_REG_CTL register fields */
31#define AM65_CPSW_PN_CTL_IET_PORT_EN BIT(16) 37#define AM65_CPSW_PN_CTL_IET_PORT_EN BIT(16)
@@ -73,6 +79,15 @@
73#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0) 79#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0)
74#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK 80#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK
75 81
82/* Cut-Thru AM64_CPSW_PN_CUT_THRU */
83#define AM64_PN_CUT_THRU_TX_PRI GENMASK(7, 0)
84#define AM64_PN_CUT_THRU_RX_PRI GENMASK(15, 8)
85
86/* Cut-Thru AM64_CPSW_PN_SPEED */
87#define AM64_PN_SPEED_VAL GENMASK(3, 0)
88#define AM64_PN_SPEED_AUTO_EN BIT(8)
89#define AM64_PN_AUTO_SPEED GENMASK(15, 12)
90
76/* AM65_CPSW_PN_REG_MAX_BLKS fields for IET and No IET cases */ 91/* AM65_CPSW_PN_REG_MAX_BLKS fields for IET and No IET cases */
77/* 7 blocks for pn_rx_max_blks, 13 for pn_tx_max_blks*/ 92/* 7 blocks for pn_rx_max_blks, 13 for pn_tx_max_blks*/
78#define AM65_CPSW_PN_TX_RX_MAX_BLKS_IET 0xD07 93#define AM65_CPSW_PN_TX_RX_MAX_BLKS_IET 0xD07
@@ -84,6 +99,9 @@ enum timer_act {
84 TACT_SKIP_PROG, /* just buffer can be updated */ 99 TACT_SKIP_PROG, /* just buffer can be updated */
85}; 100};
86 101
102/* number of traffic classes (fifos) per port */
103#define AM65_CPSW_PN_TC_NUM 8
104
87/* Fetch command count it's number of bytes in Gigabit mode or nibbles in 105/* Fetch command count it's number of bytes in Gigabit mode or nibbles in
88 * 10/100Mb mode. So, having speed and time in ns, recalculate ns to number of 106 * 10/100Mb mode. So, having speed and time in ns, recalculate ns to number of
89 * bytes/nibbles that can be sent while transmission on given speed. 107 * bytes/nibbles that can be sent while transmission on given speed.
@@ -907,12 +925,16 @@ static void am65_cpsw_iet_link_up(struct net_device *ndev)
907 } 925 }
908} 926}
909 927
910void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed) 928static void am65_cpsw_cut_thru_link_up(struct am65_cpsw_port *port);
929
930void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed, int duplex)
911{ 931{
912 struct am65_cpsw_port *port = am65_ndev_to_port(ndev); 932 struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
913 933
914 port->qos.link_speed = link_speed; 934 port->qos.link_speed = link_speed;
935 port->qos.duplex = duplex;
915 am65_cpsw_iet_link_up(ndev); 936 am65_cpsw_iet_link_up(ndev);
937 am65_cpsw_cut_thru_link_up(port);
916 938
917 if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) 939 if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
918 return; 940 return;
@@ -934,3 +956,119 @@ void am65_cpsw_qos_link_down(struct net_device *ndev)
934 956
935 port->qos.link_speed = SPEED_UNKNOWN; 957 port->qos.link_speed = SPEED_UNKNOWN;
936} 958}
959
960static void am65_cpsw_cut_thru_dump(struct am65_cpsw_port *port)
961{
962 struct am65_cpsw_common *common = port->common;
963 u32 contro, cut_thru, speed;
964
965 contro = readl(common->cpsw_base + AM65_CPSW_REG_CTL);
966 cut_thru = readl(port->port_base + AM64_CPSW_PN_CUT_THRU);
967 speed = readl(port->port_base + AM64_CPSW_PN_SPEED);
968 dev_dbg(common->dev, "Port%u: cut_thru dump control:%08x cut_thru:%08x hwspeed:%08x\n",
969 port->port_id, contro, cut_thru, speed);
970}
971
972static void am65_cpsw_cut_thru_enable(struct am65_cpsw_common *common)
973{
974 u32 val;
975
976 if (common->cut_thru_enabled) {
977 common->cut_thru_enabled++;
978 return;
979 }
980
981 /* Populate CPSW VBUS freq for auto speed detection */
982 writel(common->bus_freq / 1000000,
983 common->cpsw_base + AM65_CPSW_REG_FREQ);
984
985 val = readl(common->cpsw_base + AM65_CPSW_REG_CTL);
986 val |= AM64_CPSW_CTL_CUT_THRU_EN;
987 writel(val, common->cpsw_base + AM65_CPSW_REG_CTL);
988 common->cut_thru_enabled++;
989}
990
991void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port)
992{
993 struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru;
994 struct am65_cpsw_common *common = port->common;
995
996 /* Enable cut_thr only if user has enabled priv flag */
997 if (!cut_thru->enable)
998 return;
999
1000 if (common->is_emac_mode) {
1001 cut_thru->enable = false;
1002 dev_info(common->dev, "Disable cut-thru, need Switch mode\n");
1003 return;
1004 }
1005
1006 am65_cpsw_cut_thru_enable(common);
1007
1008 /* en auto speed */
1009 writel(AM64_PN_SPEED_AUTO_EN, port->port_base + AM64_CPSW_PN_SPEED);
1010 dev_info(common->dev, "Init cut_thru\n");
1011 am65_cpsw_cut_thru_dump(port);
1012}
1013
1014static void am65_cpsw_cut_thru_disable(struct am65_cpsw_common *common)
1015{
1016 u32 val;
1017
1018 if (--common->cut_thru_enabled)
1019 return;
1020
1021 val = readl(common->cpsw_base + AM65_CPSW_REG_CTL);
1022 val &= ~AM64_CPSW_CTL_CUT_THRU_EN;
1023 writel(val, common->cpsw_base + AM65_CPSW_REG_CTL);
1024}
1025
1026void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port)
1027{
1028 struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru;
1029 struct am65_cpsw_common *common = port->common;
1030
1031 if (!cut_thru->enable)
1032 return;
1033
1034 writel(0, port->port_base + AM64_CPSW_PN_CUT_THRU);
1035 writel(0, port->port_base + AM64_CPSW_PN_SPEED);
1036
1037 am65_cpsw_cut_thru_disable(common);
1038 dev_info(common->dev, "Cleanup cut_thru\n");
1039 am65_cpsw_cut_thru_dump(port);
1040}
1041
1042static void am65_cpsw_cut_thru_link_up(struct am65_cpsw_port *port)
1043{
1044 struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru;
1045 struct am65_cpsw_common *common = port->common;
1046 u32 val, speed;
1047
1048 if (!cut_thru->enable)
1049 return;
1050
1051 val = readl(port->port_base + AM64_CPSW_PN_SPEED);
1052 speed = FIELD_GET(AM64_PN_AUTO_SPEED, val);
1053 if (!speed) {
1054 dev_err(common->dev,
1055 "Port%u: cut_thru no speed detected\n", port->port_id);
1056 return;
1057 }
1058
1059 val = FIELD_PREP(AM64_PN_CUT_THRU_TX_PRI, cut_thru->tx_pri_mask) |
1060 FIELD_PREP(AM64_PN_CUT_THRU_RX_PRI, cut_thru->rx_pri_mask);
1061
1062 if (port->qos.duplex) {
1063 writel(val, port->port_base + AM64_CPSW_PN_CUT_THRU);
1064 dev_info(common->dev, "Port%u: Enable cut_thru rx:%08x tx:%08x hwspeed:%u (%08x)\n",
1065 port->port_id,
1066 cut_thru->rx_pri_mask, cut_thru->tx_pri_mask,
1067 speed, val);
1068 } else {
1069 writel(0, port->port_base + AM64_CPSW_PN_CUT_THRU);
1070 dev_info(common->dev, "Port%u: Disable cut_thru duplex=%d\n",
1071 port->port_id, port->qos.duplex);
1072 }
1073 am65_cpsw_cut_thru_dump(port);
1074}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.h b/drivers/net/ethernet/ti/am65-cpsw-qos.h
index 53efcd7d278c..8599759f6b08 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-qos.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-qos.h
@@ -8,6 +8,8 @@
8#include <linux/netdevice.h> 8#include <linux/netdevice.h>
9#include <net/pkt_sched.h> 9#include <net/pkt_sched.h>
10 10
11struct am65_cpsw_port;
12
11struct am65_cpsw_est { 13struct am65_cpsw_est {
12 int buf; 14 int buf;
13 /* has to be the last one */ 15 /* has to be the last one */
@@ -30,18 +32,29 @@ struct am65_cpsw_iet {
30 u32 mask; 32 u32 mask;
31}; 33};
32 34
35struct am65_cpsw_cut_thru {
36 unsigned int rx_pri_mask;
37 unsigned int tx_pri_mask;
38 bool enable;
39};
40
33struct am65_cpsw_qos { 41struct am65_cpsw_qos {
34 struct am65_cpsw_est *est_admin; 42 struct am65_cpsw_est *est_admin;
35 struct am65_cpsw_est *est_oper; 43 struct am65_cpsw_est *est_oper;
36 ktime_t link_down_time; 44 ktime_t link_down_time;
37 int link_speed; 45 int link_speed;
46 int duplex;
38 struct am65_cpsw_iet iet; 47 struct am65_cpsw_iet iet;
48 struct am65_cpsw_cut_thru cut_thru;
39}; 49};
40 50
41int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, 51int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
42 void *type_data); 52 void *type_data);
43void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed); 53void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed, int duplex);
44void am65_cpsw_qos_link_down(struct net_device *ndev); 54void am65_cpsw_qos_link_down(struct net_device *ndev);
45void am65_cpsw_qos_iet_init(struct net_device *ndev); 55void am65_cpsw_qos_iet_init(struct net_device *ndev);
46void am65_cpsw_qos_iet_cleanup(struct net_device *ndev); 56void am65_cpsw_qos_iet_cleanup(struct net_device *ndev);
57void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port);
58void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port);
59
47#endif /* AM65_CPSW_QOS_H_ */ 60#endif /* AM65_CPSW_QOS_H_ */
diff --git a/drivers/net/ethernet/ti/am65-debugfs.c b/drivers/net/ethernet/ti/am65-debugfs.c
new file mode 100644
index 000000000000..f8435c1852ec
--- /dev/null
+++ b/drivers/net/ethernet/ti/am65-debugfs.c
@@ -0,0 +1,152 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Texas Instruments K3 AM65 Ethernet debugfs submodule
3 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
4 */
5
6#include <linux/bitfield.h>
7#include <linux/debugfs.h>
8
9#include "am65-cpsw-nuss.h"
10
11int am65_cpsw_nuss_register_debugfs(struct am65_cpsw_common *common)
12{
13 common->debugfs_root = debugfs_create_dir(dev_name(common->dev), NULL);
14 if (IS_ERR(common->debugfs_root))
15 return PTR_ERR(common->debugfs_root);
16
17 return 0;
18}
19
20void am65_cpsw_nuss_unregister_debugfs(struct am65_cpsw_common *common)
21{
22 debugfs_remove_recursive(common->debugfs_root);
23}
24
25static int
26cut_thru_tx_pri_mask_get(void *data, u64 *val)
27{
28 struct am65_cpsw_port *port = data;
29 struct am65_cpsw_cut_thru *cut_thru;
30 int ret = -EINVAL;
31
32 read_lock(&dev_base_lock);
33 cut_thru = &port->qos.cut_thru;
34 if (port->ndev->reg_state == NETREG_REGISTERED) {
35 *val = cut_thru->tx_pri_mask;
36 ret = 0;
37 }
38 read_unlock(&dev_base_lock);
39
40 return ret;
41}
42
43static int
44cut_thru_tx_pri_mask_set(void *data, u64 val)
45{
46 struct am65_cpsw_cut_thru *cut_thru;
47 struct am65_cpsw_port *port = data;
48 struct am65_cpsw_common *common;
49 int ret = 0;
50
51 if (val & ~GENMASK(7, 0))
52 return -EINVAL;
53
54 if (!rtnl_trylock())
55 return restart_syscall();
56
57 common = port->common;
58 cut_thru = &port->qos.cut_thru;
59
60 if (cut_thru->enable) {
61 dev_err(common->dev, "Port%u: can't set cut-thru tx_pri_mask while cut-thru enabled\n",
62 port->port_id);
63 ret = -EINVAL;
64 goto err;
65 }
66 cut_thru->tx_pri_mask = val;
67
68err:
69 rtnl_unlock();
70 return ret;
71}
72
73DEFINE_DEBUGFS_ATTRIBUTE(fops_cut_thru_tx_pri_mask, cut_thru_tx_pri_mask_get,
74 cut_thru_tx_pri_mask_set, "%llx\n");
75
76static int
77cut_thru_rx_pri_mask_get(void *data, u64 *val)
78{
79 struct am65_cpsw_port *port = data;
80 struct am65_cpsw_cut_thru *cut_thru;
81 int ret = -EINVAL;
82
83 read_lock(&dev_base_lock);
84 cut_thru = &port->qos.cut_thru;
85 if (port->ndev->reg_state == NETREG_REGISTERED) {
86 *val = cut_thru->rx_pri_mask;
87 ret = 0;
88 }
89 read_unlock(&dev_base_lock);
90
91 return ret;
92}
93
94static int
95cut_thru_rx_pri_mask_set(void *data, u64 val)
96{
97 struct am65_cpsw_cut_thru *cut_thru;
98 struct am65_cpsw_port *port = data;
99 struct am65_cpsw_common *common;
100 int ret = 0;
101
102 if (val & ~GENMASK(7, 0))
103 return -EINVAL;
104
105 if (!rtnl_trylock())
106 return restart_syscall();
107
108 common = port->common;
109 cut_thru = &port->qos.cut_thru;
110
111 if (cut_thru->enable) {
112 dev_err(common->dev, "Port%u: can't set cut-thru rx_pri_mask while cut-thru enabled\n",
113 port->port_id);
114 ret = -EINVAL;
115 goto err;
116 }
117 cut_thru->rx_pri_mask = val;
118
119err:
120 rtnl_unlock();
121 return ret;
122}
123
124DEFINE_DEBUGFS_ATTRIBUTE(fops_cut_thru_rx_pri_mask, cut_thru_rx_pri_mask_get,
125 cut_thru_rx_pri_mask_set, "%llx\n");
126
127int am65_cpsw_nuss_register_port_debugfs(struct am65_cpsw_port *port)
128{
129 struct am65_cpsw_common *common = port->common;
130 char dirn[32];
131
132 scnprintf(dirn, sizeof(dirn), "Port%x", port->port_id);
133 port->debugfs_port = debugfs_create_dir(dirn, common->debugfs_root);
134 if (IS_ERR(port->debugfs_port))
135 return PTR_ERR(port->debugfs_port);
136
137 debugfs_create_bool("disabled", 0400,
138 port->debugfs_port, &port->disabled);
139 if (port->disabled)
140 return 0;
141
142 if (common->pdata.quirks & AM64_CPSW_QUIRK_CUT_THRU) {
143 debugfs_create_file("cut_thru_tx_pri_mask", 0600,
144 port->debugfs_port,
145 port, &fops_cut_thru_tx_pri_mask);
146 debugfs_create_file("cut_thru_rx_pri_mask", 0600,
147 port->debugfs_port,
148 port, &fops_cut_thru_rx_pri_mask);
149 }
150
151 return 0;
152}