3333 */
3434
3535#include <linux/netdevice.h>
36+ #include <linux/string.h>
3637#include <net/dcbnl.h>
3738
3839#include "spectrum.h"
40+ #include "reg.h"
3941
4042static u8 mlxsw_sp_dcbnl_getdcbx (struct net_device __always_unused * dev )
4143{
@@ -48,18 +50,245 @@ static u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
4850 return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE )) ? 1 : 0 ;
4951}
5052
53+ static int mlxsw_sp_dcbnl_ieee_getets (struct net_device * dev ,
54+ struct ieee_ets * ets )
55+ {
56+ struct mlxsw_sp_port * mlxsw_sp_port = netdev_priv (dev );
57+
58+ memcpy (ets , mlxsw_sp_port -> dcb .ets , sizeof (* ets ));
59+
60+ return 0 ;
61+ }
62+
63+ static int mlxsw_sp_port_ets_validate (struct mlxsw_sp_port * mlxsw_sp_port ,
64+ struct ieee_ets * ets )
65+ {
66+ struct net_device * dev = mlxsw_sp_port -> dev ;
67+ bool has_ets_tc = false;
68+ int i , tx_bw_sum = 0 ;
69+
70+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ ) {
71+ switch (ets -> tc_tsa [i ]) {
72+ case IEEE_8021QAZ_TSA_STRICT :
73+ break ;
74+ case IEEE_8021QAZ_TSA_ETS :
75+ has_ets_tc = true;
76+ tx_bw_sum += ets -> tc_tx_bw [i ];
77+ break ;
78+ default :
79+ netdev_err (dev , "Only strict priority and ETS are supported\n" );
80+ return - EINVAL ;
81+ }
82+
83+ if (ets -> prio_tc [i ] >= IEEE_8021QAZ_MAX_TCS ) {
84+ netdev_err (dev , "Invalid TC\n" );
85+ return - EINVAL ;
86+ }
87+ }
88+
89+ if (has_ets_tc && tx_bw_sum != 100 ) {
90+ netdev_err (dev , "Total ETS bandwidth should equal 100\n" );
91+ return - EINVAL ;
92+ }
93+
94+ return 0 ;
95+ }
96+
97+ static int mlxsw_sp_port_pg_prio_map (struct mlxsw_sp_port * mlxsw_sp_port ,
98+ u8 * prio_tc )
99+ {
100+ char pptb_pl [MLXSW_REG_PPTB_LEN ];
101+ int i ;
102+
103+ mlxsw_reg_pptb_pack (pptb_pl , mlxsw_sp_port -> local_port );
104+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ )
105+ mlxsw_reg_pptb_prio_to_buff_set (pptb_pl , i , prio_tc [i ]);
106+ return mlxsw_reg_write (mlxsw_sp_port -> mlxsw_sp -> core , MLXSW_REG (pptb ),
107+ pptb_pl );
108+ }
109+
110+ static bool mlxsw_sp_ets_has_pg (u8 * prio_tc , u8 pg )
111+ {
112+ int i ;
113+
114+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ )
115+ if (prio_tc [i ] == pg )
116+ return true;
117+ return false;
118+ }
119+
120+ static int mlxsw_sp_port_pg_destroy (struct mlxsw_sp_port * mlxsw_sp_port ,
121+ u8 * old_prio_tc , u8 * new_prio_tc )
122+ {
123+ struct mlxsw_sp * mlxsw_sp = mlxsw_sp_port -> mlxsw_sp ;
124+ char pbmc_pl [MLXSW_REG_PBMC_LEN ];
125+ int err , i ;
126+
127+ mlxsw_reg_pbmc_pack (pbmc_pl , mlxsw_sp_port -> local_port , 0 , 0 );
128+ err = mlxsw_reg_query (mlxsw_sp -> core , MLXSW_REG (pbmc ), pbmc_pl );
129+ if (err )
130+ return err ;
131+
132+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ ) {
133+ u8 pg = old_prio_tc [i ];
134+
135+ if (!mlxsw_sp_ets_has_pg (new_prio_tc , pg ))
136+ mlxsw_reg_pbmc_lossy_buffer_pack (pbmc_pl , pg , 0 );
137+ }
138+
139+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (pbmc ), pbmc_pl );
140+ }
141+
142+ static int mlxsw_sp_port_headroom_set (struct mlxsw_sp_port * mlxsw_sp_port ,
143+ struct ieee_ets * ets )
144+ {
145+ struct ieee_ets * my_ets = mlxsw_sp_port -> dcb .ets ;
146+ struct net_device * dev = mlxsw_sp_port -> dev ;
147+ int err ;
148+
149+ /* Create the required PGs, but don't destroy existing ones, as
150+ * traffic is still directed to them.
151+ */
152+ err = __mlxsw_sp_port_headroom_set (mlxsw_sp_port , dev -> mtu ,
153+ ets -> prio_tc );
154+ if (err ) {
155+ netdev_err (dev , "Failed to configure port's headroom\n" );
156+ return err ;
157+ }
158+
159+ err = mlxsw_sp_port_pg_prio_map (mlxsw_sp_port , ets -> prio_tc );
160+ if (err ) {
161+ netdev_err (dev , "Failed to set PG-priority mapping\n" );
162+ goto err_port_prio_pg_map ;
163+ }
164+
165+ err = mlxsw_sp_port_pg_destroy (mlxsw_sp_port , my_ets -> prio_tc ,
166+ ets -> prio_tc );
167+ if (err )
168+ netdev_warn (dev , "Failed to remove ununsed PGs\n" );
169+
170+ return 0 ;
171+
172+ err_port_prio_pg_map :
173+ mlxsw_sp_port_pg_destroy (mlxsw_sp_port , ets -> prio_tc , my_ets -> prio_tc );
174+ return err ;
175+ }
176+
177+ static int __mlxsw_sp_dcbnl_ieee_setets (struct mlxsw_sp_port * mlxsw_sp_port ,
178+ struct ieee_ets * ets )
179+ {
180+ struct ieee_ets * my_ets = mlxsw_sp_port -> dcb .ets ;
181+ struct net_device * dev = mlxsw_sp_port -> dev ;
182+ int i , err ;
183+
184+ /* Egress configuration. */
185+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ ) {
186+ bool dwrr = ets -> tc_tsa [i ] == IEEE_8021QAZ_TSA_ETS ;
187+ u8 weight = ets -> tc_tx_bw [i ];
188+
189+ err = mlxsw_sp_port_ets_set (mlxsw_sp_port ,
190+ MLXSW_REG_QEEC_HIERARCY_SUBGROUP , i ,
191+ 0 , dwrr , weight );
192+ if (err ) {
193+ netdev_err (dev , "Failed to link subgroup ETS element %d to group\n" ,
194+ i );
195+ goto err_port_ets_set ;
196+ }
197+ }
198+
199+ for (i = 0 ; i < IEEE_8021QAZ_MAX_TCS ; i ++ ) {
200+ err = mlxsw_sp_port_prio_tc_set (mlxsw_sp_port , i ,
201+ ets -> prio_tc [i ]);
202+ if (err ) {
203+ netdev_err (dev , "Failed to map prio %d to TC %d\n" , i ,
204+ ets -> prio_tc [i ]);
205+ goto err_port_prio_tc_set ;
206+ }
207+ }
208+
209+ /* Ingress configuration. */
210+ err = mlxsw_sp_port_headroom_set (mlxsw_sp_port , ets );
211+ if (err )
212+ goto err_port_headroom_set ;
213+
214+ return 0 ;
215+
216+ err_port_headroom_set :
217+ i = IEEE_8021QAZ_MAX_TCS ;
218+ err_port_prio_tc_set :
219+ for (i -- ; i >= 0 ; i -- )
220+ mlxsw_sp_port_prio_tc_set (mlxsw_sp_port , i , my_ets -> prio_tc [i ]);
221+ i = IEEE_8021QAZ_MAX_TCS ;
222+ err_port_ets_set :
223+ for (i -- ; i >= 0 ; i -- ) {
224+ bool dwrr = my_ets -> tc_tsa [i ] == IEEE_8021QAZ_TSA_ETS ;
225+ u8 weight = my_ets -> tc_tx_bw [i ];
226+
227+ err = mlxsw_sp_port_ets_set (mlxsw_sp_port ,
228+ MLXSW_REG_QEEC_HIERARCY_SUBGROUP , i ,
229+ 0 , dwrr , weight );
230+ }
231+ return err ;
232+ }
233+
234+ static int mlxsw_sp_dcbnl_ieee_setets (struct net_device * dev ,
235+ struct ieee_ets * ets )
236+ {
237+ struct mlxsw_sp_port * mlxsw_sp_port = netdev_priv (dev );
238+ int err ;
239+
240+ err = mlxsw_sp_port_ets_validate (mlxsw_sp_port , ets );
241+ if (err )
242+ return err ;
243+
244+ err = __mlxsw_sp_dcbnl_ieee_setets (mlxsw_sp_port , ets );
245+ if (err )
246+ return err ;
247+
248+ memcpy (mlxsw_sp_port -> dcb .ets , ets , sizeof (* ets ));
249+
250+ return 0 ;
251+ }
252+
51253static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
254+ .ieee_getets = mlxsw_sp_dcbnl_ieee_getets ,
255+ .ieee_setets = mlxsw_sp_dcbnl_ieee_setets ,
256+
52257 .getdcbx = mlxsw_sp_dcbnl_getdcbx ,
53258 .setdcbx = mlxsw_sp_dcbnl_setdcbx ,
54259};
55260
261+ static int mlxsw_sp_port_ets_init (struct mlxsw_sp_port * mlxsw_sp_port )
262+ {
263+ mlxsw_sp_port -> dcb .ets = kzalloc (sizeof (* mlxsw_sp_port -> dcb .ets ),
264+ GFP_KERNEL );
265+ if (!mlxsw_sp_port -> dcb .ets )
266+ return - ENOMEM ;
267+
268+ mlxsw_sp_port -> dcb .ets -> ets_cap = IEEE_8021QAZ_MAX_TCS ;
269+
270+ return 0 ;
271+ }
272+
273+ static void mlxsw_sp_port_ets_fini (struct mlxsw_sp_port * mlxsw_sp_port )
274+ {
275+ kfree (mlxsw_sp_port -> dcb .ets );
276+ }
277+
56278int mlxsw_sp_port_dcb_init (struct mlxsw_sp_port * mlxsw_sp_port )
57279{
280+ int err ;
281+
282+ err = mlxsw_sp_port_ets_init (mlxsw_sp_port );
283+ if (err )
284+ return err ;
285+
58286 mlxsw_sp_port -> dev -> dcbnl_ops = & mlxsw_sp_dcbnl_ops ;
59287
60288 return 0 ;
61289}
62290
63291void mlxsw_sp_port_dcb_fini (struct mlxsw_sp_port * mlxsw_sp_port )
64292{
293+ mlxsw_sp_port_ets_fini (mlxsw_sp_port );
65294}
0 commit comments