77 */
88
99#include <linux/pm_runtime.h>
10+ #include <linux/math.h>
1011#include <linux/time.h>
12+ #include <linux/units.h>
1113#include <net/pkt_cls.h>
1214
1315#include "am65-cpsw-nuss.h"
1416#include "am65-cpsw-qos.h"
1517#include "am65-cpts.h"
1618#include "cpsw_ale.h"
1719
20+ #define TO_MBPS (x ) DIV_ROUND_UP((x), BYTES_PER_MBIT)
21+
1822enum timer_act {
1923 TACT_PROG , /* need program timer */
2024 TACT_NEED_STOP , /* need stop first */
@@ -31,6 +35,232 @@ am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq)
3135 return ir ;
3236}
3337
38+ static void am65_cpsw_tx_pn_shaper_reset (struct am65_cpsw_port * port )
39+ {
40+ int prio ;
41+
42+ for (prio = 0 ; prio < AM65_CPSW_PN_FIFO_PRIO_NUM ; prio ++ ) {
43+ writel (0 , port -> port_base + AM65_CPSW_PN_REG_PRI_CIR (prio ));
44+ writel (0 , port -> port_base + AM65_CPSW_PN_REG_PRI_EIR (prio ));
45+ }
46+ }
47+
48+ static void am65_cpsw_tx_pn_shaper_apply (struct am65_cpsw_port * port )
49+ {
50+ struct am65_cpsw_mqprio * p_mqprio = & port -> qos .mqprio ;
51+ struct am65_cpsw_common * common = port -> common ;
52+ struct tc_mqprio_qopt_offload * mqprio ;
53+ bool enable , shaper_susp = false;
54+ u32 rate_mbps ;
55+ int tc , prio ;
56+
57+ mqprio = & p_mqprio -> mqprio_hw ;
58+ /* takes care of no link case as well */
59+ if (p_mqprio -> max_rate_total > port -> qos .link_speed )
60+ shaper_susp = true;
61+
62+ am65_cpsw_tx_pn_shaper_reset (port );
63+
64+ enable = p_mqprio -> shaper_en && !shaper_susp ;
65+ if (!enable )
66+ return ;
67+
68+ /* Rate limit is specified per Traffic Class but
69+ * for CPSW, rate limit can be applied per priority
70+ * at port FIFO.
71+ *
72+ * We have assigned the same priority (TCn) to all queues
73+ * of a Traffic Class so they share the same shaper
74+ * bandwidth.
75+ */
76+ for (tc = 0 ; tc < mqprio -> qopt .num_tc ; tc ++ ) {
77+ prio = tc ;
78+
79+ rate_mbps = TO_MBPS (mqprio -> min_rate [tc ]);
80+ rate_mbps = am65_cpsw_qos_tx_rate_calc (rate_mbps ,
81+ common -> bus_freq );
82+ writel (rate_mbps ,
83+ port -> port_base + AM65_CPSW_PN_REG_PRI_CIR (prio ));
84+
85+ rate_mbps = 0 ;
86+
87+ if (mqprio -> max_rate [tc ]) {
88+ rate_mbps = mqprio -> max_rate [tc ] - mqprio -> min_rate [tc ];
89+ rate_mbps = TO_MBPS (rate_mbps );
90+ rate_mbps = am65_cpsw_qos_tx_rate_calc (rate_mbps ,
91+ common -> bus_freq );
92+ }
93+
94+ writel (rate_mbps ,
95+ port -> port_base + AM65_CPSW_PN_REG_PRI_EIR (prio ));
96+ }
97+ }
98+
99+ static int am65_cpsw_mqprio_verify_shaper (struct am65_cpsw_port * port ,
100+ struct tc_mqprio_qopt_offload * mqprio )
101+ {
102+ struct am65_cpsw_mqprio * p_mqprio = & port -> qos .mqprio ;
103+ struct netlink_ext_ack * extack = mqprio -> extack ;
104+ u64 min_rate_total = 0 , max_rate_total = 0 ;
105+ u32 min_rate_msk = 0 , max_rate_msk = 0 ;
106+ bool has_min_rate , has_max_rate ;
107+ int num_tc , i ;
108+
109+ if (!(mqprio -> flags & TC_MQPRIO_F_SHAPER ))
110+ return 0 ;
111+
112+ if (mqprio -> shaper != TC_MQPRIO_SHAPER_BW_RATE )
113+ return 0 ;
114+
115+ has_min_rate = !!(mqprio -> flags & TC_MQPRIO_F_MIN_RATE );
116+ has_max_rate = !!(mqprio -> flags & TC_MQPRIO_F_MAX_RATE );
117+
118+ if (!has_min_rate && has_max_rate ) {
119+ NL_SET_ERR_MSG_MOD (extack , "min_rate is required with max_rate" );
120+ return - EOPNOTSUPP ;
121+ }
122+
123+ if (!has_min_rate )
124+ return 0 ;
125+
126+ num_tc = mqprio -> qopt .num_tc ;
127+
128+ for (i = num_tc - 1 ; i >= 0 ; i -- ) {
129+ u32 ch_msk ;
130+
131+ if (mqprio -> min_rate [i ])
132+ min_rate_msk |= BIT (i );
133+ min_rate_total += mqprio -> min_rate [i ];
134+
135+ if (has_max_rate ) {
136+ if (mqprio -> max_rate [i ])
137+ max_rate_msk |= BIT (i );
138+ max_rate_total += mqprio -> max_rate [i ];
139+
140+ if (!mqprio -> min_rate [i ] && mqprio -> max_rate [i ]) {
141+ NL_SET_ERR_MSG_FMT_MOD (extack ,
142+ "TX tc%d rate max>0 but min=0" ,
143+ i );
144+ return - EINVAL ;
145+ }
146+
147+ if (mqprio -> max_rate [i ] &&
148+ mqprio -> max_rate [i ] < mqprio -> min_rate [i ]) {
149+ NL_SET_ERR_MSG_FMT_MOD (extack ,
150+ "TX tc%d rate min(%llu)>max(%llu)" ,
151+ i , mqprio -> min_rate [i ],
152+ mqprio -> max_rate [i ]);
153+ return - EINVAL ;
154+ }
155+ }
156+
157+ ch_msk = GENMASK (num_tc - 1 , i );
158+ if ((min_rate_msk & BIT (i )) && (min_rate_msk ^ ch_msk )) {
159+ NL_SET_ERR_MSG_FMT_MOD (extack ,
160+ "Min rate must be set sequentially hi->lo tx_rate_msk%x" ,
161+ min_rate_msk );
162+ return - EINVAL ;
163+ }
164+
165+ if ((max_rate_msk & BIT (i )) && (max_rate_msk ^ ch_msk )) {
166+ NL_SET_ERR_MSG_FMT_MOD (extack ,
167+ "Max rate must be set sequentially hi->lo tx_rate_msk%x" ,
168+ max_rate_msk );
169+ return - EINVAL ;
170+ }
171+ }
172+
173+ min_rate_total = TO_MBPS (min_rate_total );
174+ max_rate_total = TO_MBPS (max_rate_total );
175+
176+ p_mqprio -> shaper_en = true;
177+ p_mqprio -> max_rate_total = max_t (u64 , min_rate_total , max_rate_total );
178+
179+ return 0 ;
180+ }
181+
182+ static void am65_cpsw_reset_tc_mqprio (struct net_device * ndev )
183+ {
184+ struct am65_cpsw_port * port = am65_ndev_to_port (ndev );
185+ struct am65_cpsw_mqprio * p_mqprio = & port -> qos .mqprio ;
186+
187+ p_mqprio -> shaper_en = false;
188+ p_mqprio -> max_rate_total = 0 ;
189+
190+ am65_cpsw_tx_pn_shaper_reset (port );
191+ netdev_reset_tc (ndev );
192+
193+ /* Reset all Queue priorities to 0 */
194+ writel (0 , port -> port_base + AM65_CPSW_PN_REG_TX_PRI_MAP );
195+ }
196+
197+ static int am65_cpsw_setup_mqprio (struct net_device * ndev , void * type_data )
198+ {
199+ struct am65_cpsw_port * port = am65_ndev_to_port (ndev );
200+ struct am65_cpsw_mqprio * p_mqprio = & port -> qos .mqprio ;
201+ struct tc_mqprio_qopt_offload * mqprio = type_data ;
202+ struct am65_cpsw_common * common = port -> common ;
203+ struct tc_mqprio_qopt * qopt = & mqprio -> qopt ;
204+ int i , tc , offset , count , prio , ret ;
205+ u8 num_tc = qopt -> num_tc ;
206+ u32 tx_prio_map = 0 ;
207+
208+ memcpy (& p_mqprio -> mqprio_hw , mqprio , sizeof (* mqprio ));
209+
210+ ret = pm_runtime_get_sync (common -> dev );
211+ if (ret < 0 ) {
212+ pm_runtime_put_noidle (common -> dev );
213+ return ret ;
214+ }
215+
216+ if (!num_tc ) {
217+ am65_cpsw_reset_tc_mqprio (ndev );
218+ ret = 0 ;
219+ goto exit_put ;
220+ }
221+
222+ ret = am65_cpsw_mqprio_verify_shaper (port , mqprio );
223+ if (ret )
224+ goto exit_put ;
225+
226+ netdev_set_num_tc (ndev , num_tc );
227+
228+ /* Multiple Linux priorities can map to a Traffic Class
229+ * A Traffic Class can have multiple contiguous Queues,
230+ * Queues get mapped to Channels (thread_id),
231+ * if not VLAN tagged, thread_id is used as packet_priority
232+ * if VLAN tagged. VLAN priority is used as packet_priority
233+ * packet_priority gets mapped to header_priority in p0_rx_pri_map,
234+ * header_priority gets mapped to switch_priority in pn_tx_pri_map.
235+ * As p0_rx_pri_map is left at defaults (0x76543210), we can
236+ * assume that Queue_n gets mapped to header_priority_n. We can then
237+ * set the switch priority in pn_tx_pri_map.
238+ */
239+
240+ for (tc = 0 ; tc < num_tc ; tc ++ ) {
241+ prio = tc ;
242+
243+ /* For simplicity we assign the same priority (TCn) to
244+ * all queues of a Traffic Class.
245+ */
246+ for (i = qopt -> offset [tc ]; i < qopt -> offset [tc ] + qopt -> count [tc ]; i ++ )
247+ tx_prio_map |= prio << (4 * i );
248+
249+ count = qopt -> count [tc ];
250+ offset = qopt -> offset [tc ];
251+ netdev_set_tc_queue (ndev , tc , count , offset );
252+ }
253+
254+ writel (tx_prio_map , port -> port_base + AM65_CPSW_PN_REG_TX_PRI_MAP );
255+
256+ am65_cpsw_tx_pn_shaper_apply (port );
257+
258+ exit_put :
259+ pm_runtime_put (common -> dev );
260+
261+ return ret ;
262+ }
263+
34264static int am65_cpsw_port_est_enabled (struct am65_cpsw_port * port )
35265{
36266 return port -> qos .est_oper || port -> qos .est_admin ;
@@ -414,6 +644,8 @@ static void am65_cpsw_taprio_destroy(struct net_device *ndev)
414644
415645 port -> qos .est_oper = NULL ;
416646 port -> qos .est_admin = NULL ;
647+
648+ am65_cpsw_reset_tc_mqprio (ndev );
417649}
418650
419651static void am65_cpsw_cp_taprio (struct tc_taprio_qopt_offload * from ,
@@ -462,6 +694,10 @@ static int am65_cpsw_taprio_replace(struct net_device *ndev,
462694 if (!est_new )
463695 return - ENOMEM ;
464696
697+ ret = am65_cpsw_setup_mqprio (ndev , & taprio -> mqprio );
698+ if (ret )
699+ return ret ;
700+
465701 am65_cpsw_cp_taprio (taprio , & est_new -> taprio );
466702
467703 am65_cpsw_est_update_state (ndev );
@@ -505,6 +741,7 @@ static int am65_cpsw_taprio_replace(struct net_device *ndev,
505741 return 0 ;
506742
507743fail :
744+ am65_cpsw_reset_tc_mqprio (ndev );
508745 devm_kfree (& ndev -> dev , est_new );
509746 return ret ;
510747}
@@ -515,7 +752,6 @@ static void am65_cpsw_est_link_up(struct net_device *ndev, int link_speed)
515752 ktime_t cur_time ;
516753 s64 delta ;
517754
518- port -> qos .link_speed = link_speed ;
519755 if (!am65_cpsw_port_est_enabled (port ))
520756 return ;
521757
@@ -559,6 +795,14 @@ static int am65_cpsw_tc_query_caps(struct net_device *ndev, void *type_data)
559795 struct tc_query_caps_base * base = type_data ;
560796
561797 switch (base -> type ) {
798+ case TC_SETUP_QDISC_MQPRIO : {
799+ struct tc_mqprio_caps * caps = base -> caps ;
800+
801+ caps -> validate_queue_counts = true;
802+
803+ return 0 ;
804+ }
805+
562806 case TC_SETUP_QDISC_TAPRIO : {
563807 struct tc_taprio_caps * caps = base -> caps ;
564808
@@ -857,6 +1101,8 @@ int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
8571101 return am65_cpsw_tc_query_caps (ndev , type_data );
8581102 case TC_SETUP_QDISC_TAPRIO :
8591103 return am65_cpsw_setup_taprio (ndev , type_data );
1104+ case TC_SETUP_QDISC_MQPRIO :
1105+ return am65_cpsw_setup_mqprio (ndev , type_data );
8601106 case TC_SETUP_BLOCK :
8611107 return am65_cpsw_qos_setup_tc_block (ndev , type_data );
8621108 default :
@@ -868,6 +1114,9 @@ void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed)
8681114{
8691115 struct am65_cpsw_port * port = am65_ndev_to_port (ndev );
8701116
1117+ port -> qos .link_speed = link_speed ;
1118+ am65_cpsw_tx_pn_shaper_apply (port );
1119+
8711120 am65_cpsw_est_link_up (ndev , link_speed );
8721121 port -> qos .link_down_time = 0 ;
8731122}
@@ -876,8 +1125,9 @@ void am65_cpsw_qos_link_down(struct net_device *ndev)
8761125{
8771126 struct am65_cpsw_port * port = am65_ndev_to_port (ndev );
8781127
1128+ port -> qos .link_speed = SPEED_UNKNOWN ;
1129+ am65_cpsw_tx_pn_shaper_apply (port );
1130+
8791131 if (!port -> qos .link_down_time )
8801132 port -> qos .link_down_time = ktime_get ();
881-
882- port -> qos .link_speed = SPEED_UNKNOWN ;
8831133}
0 commit comments