33
33
*/
34
34
35
35
#include <linux/netdevice.h>
36
+ #include <linux/string.h>
36
37
#include <net/dcbnl.h>
37
38
38
39
#include "spectrum.h"
40
+ #include "reg.h"
39
41
40
42
static u8 mlxsw_sp_dcbnl_getdcbx (struct net_device __always_unused * dev )
41
43
{
@@ -48,18 +50,245 @@ static u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
48
50
return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE )) ? 1 : 0 ;
49
51
}
50
52
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
+
51
253
static 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
+
52
257
.getdcbx = mlxsw_sp_dcbnl_getdcbx ,
53
258
.setdcbx = mlxsw_sp_dcbnl_setdcbx ,
54
259
};
55
260
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
+
56
278
int mlxsw_sp_port_dcb_init (struct mlxsw_sp_port * mlxsw_sp_port )
57
279
{
280
+ int err ;
281
+
282
+ err = mlxsw_sp_port_ets_init (mlxsw_sp_port );
283
+ if (err )
284
+ return err ;
285
+
58
286
mlxsw_sp_port -> dev -> dcbnl_ops = & mlxsw_sp_dcbnl_ops ;
59
287
60
288
return 0 ;
61
289
}
62
290
63
291
void mlxsw_sp_port_dcb_fini (struct mlxsw_sp_port * mlxsw_sp_port )
64
292
{
293
+ mlxsw_sp_port_ets_fini (mlxsw_sp_port );
65
294
}
0 commit comments