blob: bb4e7ebc405947f7706fdbd6e6f47b873177da57 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 3426e5e4339f124f00eef8815b56a80481364550 Mon Sep 17 00:00:00 2001
2From: Po Liu <po.liu@nxp.com>
3Date: Mon, 25 Nov 2019 05:56:56 +0000
4Subject: [PATCH] enetc: add support Credit Based Shaper(CBS) for hardware
5 offload
6
7The ENETC hardware support the Credit Based Shaper(CBS) which part
8of the IEEE-802.1Qav. The CBS driver was loaded by the sch_cbs
9interface when set in the QOS in the kernel.
10
11Here is an example command to set 20Mbits bandwidth in 1Gbits port
12for taffic class 7:
13
14tc qdisc add dev eth0 root handle 1: mqprio \
15 num_tc 8 map 0 1 2 3 4 5 6 7 hw 1
16
17tc qdisc replace dev eth0 parent 1:8 cbs \
18 locredit -1470 hicredit 30 \
19 sendslope -980000 idleslope 20000 offload 1
20
21Signed-off-by: Po Liu <Po.Liu@nxp.com>
22Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
23Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
24Signed-off-by: David S. Miller <davem@davemloft.net>
25---
26 drivers/net/ethernet/freescale/enetc/Kconfig | 4 +-
27 drivers/net/ethernet/freescale/enetc/enetc.c | 2 +
28 drivers/net/ethernet/freescale/enetc/enetc.h | 2 +
29 drivers/net/ethernet/freescale/enetc/enetc_hw.h | 4 +
30 drivers/net/ethernet/freescale/enetc/enetc_qos.c | 128 +++++++++++++++++++++++
31 5 files changed, 138 insertions(+), 2 deletions(-)
32
33--- a/drivers/net/ethernet/freescale/enetc/Kconfig
34+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
35@@ -53,10 +53,10 @@ config FSL_ENETC_HW_TIMESTAMPING
36
37 config FSL_ENETC_QOS
38 bool "ENETC hardware Time-sensitive Network support"
39- depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
40+ depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
41 help
42 There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
43 /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
44 enable/disable from user space via Qos commands(tc). In the kernel
45 side, it can be loaded by Qos driver. Currently, it is only support
46- taprio(802.1Qbv).
47+ taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
48--- a/drivers/net/ethernet/freescale/enetc/enetc.c
49+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
50@@ -1521,6 +1521,8 @@ int enetc_setup_tc(struct net_device *nd
51 return enetc_setup_tc_mqprio(ndev, type_data);
52 case TC_SETUP_QDISC_TAPRIO:
53 return enetc_setup_tc_taprio(ndev, type_data);
54+ case TC_SETUP_QDISC_CBS:
55+ return enetc_setup_tc_cbs(ndev, type_data);
56 default:
57 return -EOPNOTSUPP;
58 }
59--- a/drivers/net/ethernet/freescale/enetc/enetc.h
60+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
61@@ -260,7 +260,9 @@ int enetc_send_cmd(struct enetc_si *si,
62 #ifdef CONFIG_FSL_ENETC_QOS
63 int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
64 void enetc_sched_speed_set(struct net_device *ndev);
65+int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
66 #else
67 #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
68 #define enetc_sched_speed_set(ndev) (void)0
69+#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
70 #endif
71--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
72+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
73@@ -185,6 +185,8 @@ enum enetc_bdr_type {TX, RX};
74 #define ENETC_PSICFGR0_SIVC(bmp) (((bmp) & 0xff) << 24) /* VLAN_TYPE */
75
76 #define ENETC_PTCCBSR0(n) (0x1110 + (n) * 8) /* n = 0 to 7*/
77+#define ENETC_CBSE BIT(31)
78+#define ENETC_CBS_BW_MASK GENMASK(6, 0)
79 #define ENETC_PTCCBSR1(n) (0x1114 + (n) * 8) /* n = 0 to 7*/
80 #define ENETC_RSSHASH_KEY_SIZE 40
81 #define ENETC_PRSSCAPR 0x1404
82@@ -679,6 +681,8 @@ struct enetc_cbd {
83 u8 status_flags;
84 };
85
86+#define ENETC_CLK 400000000ULL
87+
88 /* port time gating control register */
89 #define ENETC_QBV_PTGCR_OFFSET 0x11a00
90 #define ENETC_QBV_TGE BIT(31)
91--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
92+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
93@@ -4,6 +4,7 @@
94 #include "enetc.h"
95
96 #include <net/pkt_sched.h>
97+#include <linux/math64.h>
98
99 static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
100 {
101@@ -170,3 +171,130 @@ int enetc_setup_tc_taprio(struct net_dev
102
103 return err;
104 }
105+
106+static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc)
107+{
108+ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE;
109+}
110+
111+static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc)
112+{
113+ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK;
114+}
115+
116+int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
117+{
118+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
119+ struct tc_cbs_qopt_offload *cbs = type_data;
120+ u32 port_transmit_rate = priv->speed;
121+ u8 tc_nums = netdev_get_num_tc(ndev);
122+ struct enetc_si *si = priv->si;
123+ u32 hi_credit_bit, hi_credit_reg;
124+ u32 max_interference_size;
125+ u32 port_frame_max_size;
126+ u32 tc_max_sized_frame;
127+ u8 tc = cbs->queue;
128+ u8 prio_top, prio_next;
129+ int bw_sum = 0;
130+ u8 bw;
131+
132+ prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
133+ prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
134+
135+ /* Support highest prio and second prio tc in cbs mode */
136+ if (tc != prio_top && tc != prio_next)
137+ return -EOPNOTSUPP;
138+
139+ if (!cbs->enable) {
140+ /* Make sure the other TC that are numerically
141+ * lower than this TC have been disabled.
142+ */
143+ if (tc == prio_top &&
144+ enetc_get_cbs_enable(&si->hw, prio_next)) {
145+ dev_err(&ndev->dev,
146+ "Disable TC%d before disable TC%d\n",
147+ prio_next, tc);
148+ return -EINVAL;
149+ }
150+
151+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
152+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
153+
154+ return 0;
155+ }
156+
157+ if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L ||
158+ cbs->idleslope < 0 || cbs->sendslope > 0)
159+ return -EOPNOTSUPP;
160+
161+ port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
162+
163+ bw = cbs->idleslope / (port_transmit_rate * 10UL);
164+
165+ /* Make sure the other TC that are numerically
166+ * higher than this TC have been enabled.
167+ */
168+ if (tc == prio_next) {
169+ if (!enetc_get_cbs_enable(&si->hw, prio_top)) {
170+ dev_err(&ndev->dev,
171+ "Enable TC%d first before enable TC%d\n",
172+ prio_top, prio_next);
173+ return -EINVAL;
174+ }
175+ bw_sum += enetc_get_cbs_bw(&si->hw, prio_top);
176+ }
177+
178+ if (bw_sum + bw >= 100) {
179+ dev_err(&ndev->dev,
180+ "The sum of all CBS Bandwidth can't exceed 100\n");
181+ return -EINVAL;
182+ }
183+
184+ tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
185+
186+ /* For top prio TC, the max_interfrence_size is maxSizedFrame.
187+ *
188+ * For next prio TC, the max_interfrence_size is calculated as below:
189+ *
190+ * max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra)
191+ *
192+ * - RA: idleSlope for AVB Class A
193+ * - R0: port transmit rate
194+ * - M0: maximum sized frame for the port
195+ * - MA: maximum sized frame for AVB Class A
196+ */
197+
198+ if (tc == prio_top) {
199+ max_interference_size = port_frame_max_size * 8;
200+ } else {
201+ u32 m0, ma, r0, ra;
202+
203+ m0 = port_frame_max_size * 8;
204+ ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8;
205+ ra = enetc_get_cbs_bw(&si->hw, prio_top) *
206+ port_transmit_rate * 10000ULL;
207+ r0 = port_transmit_rate * 1000000ULL;
208+ max_interference_size = m0 + ma +
209+ (u32)div_u64((u64)ra * m0, r0 - ra);
210+ }
211+
212+ /* hiCredit bits calculate by:
213+ *
214+ * maxSizedFrame * (idleSlope/portTxRate)
215+ */
216+ hi_credit_bit = max_interference_size * bw / 100;
217+
218+ /* hiCredit bits to hiCredit register need to calculated as:
219+ *
220+ * (enetClockFrequency / portTransmitRate) * 100
221+ */
222+ hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
223+ port_transmit_rate * 1000000ULL);
224+
225+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
226+
227+ /* Set bw register and enable this traffic class */
228+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE);
229+
230+ return 0;
231+}