]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2001-2018 | |
3 | */ | |
7c673cae FG |
4 | |
5 | #include "i40e_adminq.h" | |
6 | #include "i40e_prototype.h" | |
7 | #include "i40e_dcb.h" | |
8 | ||
9 | /** | |
10 | * i40e_get_dcbx_status | |
11 | * @hw: pointer to the hw struct | |
12 | * @status: Embedded DCBX Engine Status | |
13 | * | |
14 | * Get the DCBX status from the Firmware | |
15 | **/ | |
16 | enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status) | |
17 | { | |
18 | u32 reg; | |
19 | ||
20 | if (!status) | |
21 | return I40E_ERR_PARAM; | |
22 | ||
23 | reg = rd32(hw, I40E_PRTDCB_GENS); | |
24 | *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >> | |
25 | I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT); | |
26 | ||
27 | return I40E_SUCCESS; | |
28 | } | |
29 | ||
30 | /** | |
31 | * i40e_parse_ieee_etscfg_tlv | |
32 | * @tlv: IEEE 802.1Qaz ETS CFG TLV | |
33 | * @dcbcfg: Local store to update ETS CFG data | |
34 | * | |
35 | * Parses IEEE 802.1Qaz ETS CFG TLV | |
36 | **/ | |
37 | static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv, | |
38 | struct i40e_dcbx_config *dcbcfg) | |
39 | { | |
40 | struct i40e_dcb_ets_config *etscfg; | |
41 | u8 *buf = tlv->tlvinfo; | |
42 | u16 offset = 0; | |
43 | u8 priority; | |
44 | int i; | |
45 | ||
46 | /* First Octet post subtype | |
47 | * -------------------------- | |
48 | * |will-|CBS | Re- | Max | | |
49 | * |ing | |served| TCs | | |
50 | * -------------------------- | |
51 | * |1bit | 1bit|3 bits|3bits| | |
52 | */ | |
53 | etscfg = &dcbcfg->etscfg; | |
54 | etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >> | |
55 | I40E_IEEE_ETS_WILLING_SHIFT); | |
56 | etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >> | |
57 | I40E_IEEE_ETS_CBS_SHIFT); | |
58 | etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >> | |
59 | I40E_IEEE_ETS_MAXTC_SHIFT); | |
60 | ||
61 | /* Move offset to Priority Assignment Table */ | |
62 | offset++; | |
63 | ||
64 | /* Priority Assignment Table (4 octets) | |
65 | * Octets:| 1 | 2 | 3 | 4 | | |
66 | * ----------------------------------------- | |
67 | * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| | |
68 | * ----------------------------------------- | |
69 | * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| | |
70 | * ----------------------------------------- | |
71 | */ | |
72 | for (i = 0; i < 4; i++) { | |
73 | priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >> | |
74 | I40E_IEEE_ETS_PRIO_1_SHIFT); | |
75 | etscfg->prioritytable[i * 2] = priority; | |
76 | priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >> | |
77 | I40E_IEEE_ETS_PRIO_0_SHIFT); | |
78 | etscfg->prioritytable[i * 2 + 1] = priority; | |
79 | offset++; | |
80 | } | |
81 | ||
82 | /* TC Bandwidth Table (8 octets) | |
83 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
84 | * --------------------------------- | |
85 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
86 | * --------------------------------- | |
87 | */ | |
88 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
89 | etscfg->tcbwtable[i] = buf[offset++]; | |
90 | ||
91 | /* TSA Assignment Table (8 octets) | |
92 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
93 | * --------------------------------- | |
94 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
95 | * --------------------------------- | |
96 | */ | |
97 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
98 | etscfg->tsatable[i] = buf[offset++]; | |
99 | } | |
100 | ||
101 | /** | |
102 | * i40e_parse_ieee_etsrec_tlv | |
103 | * @tlv: IEEE 802.1Qaz ETS REC TLV | |
104 | * @dcbcfg: Local store to update ETS REC data | |
105 | * | |
106 | * Parses IEEE 802.1Qaz ETS REC TLV | |
107 | **/ | |
108 | static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv, | |
109 | struct i40e_dcbx_config *dcbcfg) | |
110 | { | |
111 | u8 *buf = tlv->tlvinfo; | |
112 | u16 offset = 0; | |
113 | u8 priority; | |
114 | int i; | |
115 | ||
116 | /* Move offset to priority table */ | |
117 | offset++; | |
118 | ||
119 | /* Priority Assignment Table (4 octets) | |
120 | * Octets:| 1 | 2 | 3 | 4 | | |
121 | * ----------------------------------------- | |
122 | * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| | |
123 | * ----------------------------------------- | |
124 | * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| | |
125 | * ----------------------------------------- | |
126 | */ | |
127 | for (i = 0; i < 4; i++) { | |
128 | priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >> | |
129 | I40E_IEEE_ETS_PRIO_1_SHIFT); | |
130 | dcbcfg->etsrec.prioritytable[i*2] = priority; | |
131 | priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >> | |
132 | I40E_IEEE_ETS_PRIO_0_SHIFT); | |
133 | dcbcfg->etsrec.prioritytable[i*2 + 1] = priority; | |
134 | offset++; | |
135 | } | |
136 | ||
137 | /* TC Bandwidth Table (8 octets) | |
138 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
139 | * --------------------------------- | |
140 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
141 | * --------------------------------- | |
142 | */ | |
143 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
144 | dcbcfg->etsrec.tcbwtable[i] = buf[offset++]; | |
145 | ||
146 | /* TSA Assignment Table (8 octets) | |
147 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
148 | * --------------------------------- | |
149 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
150 | * --------------------------------- | |
151 | */ | |
152 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
153 | dcbcfg->etsrec.tsatable[i] = buf[offset++]; | |
154 | } | |
155 | ||
156 | /** | |
157 | * i40e_parse_ieee_pfccfg_tlv | |
158 | * @tlv: IEEE 802.1Qaz PFC CFG TLV | |
159 | * @dcbcfg: Local store to update PFC CFG data | |
160 | * | |
161 | * Parses IEEE 802.1Qaz PFC CFG TLV | |
162 | **/ | |
163 | static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv, | |
164 | struct i40e_dcbx_config *dcbcfg) | |
165 | { | |
166 | u8 *buf = tlv->tlvinfo; | |
167 | ||
168 | /* ---------------------------------------- | |
169 | * |will-|MBC | Re- | PFC | PFC Enable | | |
170 | * |ing | |served| cap | | | |
171 | * ----------------------------------------- | |
172 | * |1bit | 1bit|2 bits|4bits| 1 octet | | |
173 | */ | |
174 | dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >> | |
175 | I40E_IEEE_PFC_WILLING_SHIFT); | |
176 | dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >> | |
177 | I40E_IEEE_PFC_MBC_SHIFT); | |
178 | dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >> | |
179 | I40E_IEEE_PFC_CAP_SHIFT); | |
180 | dcbcfg->pfc.pfcenable = buf[1]; | |
181 | } | |
182 | ||
183 | /** | |
184 | * i40e_parse_ieee_app_tlv | |
185 | * @tlv: IEEE 802.1Qaz APP TLV | |
186 | * @dcbcfg: Local store to update APP PRIO data | |
187 | * | |
188 | * Parses IEEE 802.1Qaz APP PRIO TLV | |
189 | **/ | |
190 | static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv, | |
191 | struct i40e_dcbx_config *dcbcfg) | |
192 | { | |
193 | u16 typelength; | |
194 | u16 offset = 0; | |
195 | u16 length; | |
196 | int i = 0; | |
197 | u8 *buf; | |
198 | ||
199 | typelength = I40E_NTOHS(tlv->typelength); | |
200 | length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> | |
201 | I40E_LLDP_TLV_LEN_SHIFT); | |
202 | buf = tlv->tlvinfo; | |
203 | ||
204 | /* The App priority table starts 5 octets after TLV header */ | |
205 | length -= (sizeof(tlv->ouisubtype) + 1); | |
206 | ||
207 | /* Move offset to App Priority Table */ | |
208 | offset++; | |
209 | ||
210 | /* Application Priority Table (3 octets) | |
211 | * Octets:| 1 | 2 | 3 | | |
212 | * ----------------------------------------- | |
213 | * |Priority|Rsrvd| Sel | Protocol ID | | |
214 | * ----------------------------------------- | |
215 | * Bits:|23 21|20 19|18 16|15 0| | |
216 | * ----------------------------------------- | |
217 | */ | |
218 | while (offset < length) { | |
219 | dcbcfg->app[i].priority = (u8)((buf[offset] & | |
220 | I40E_IEEE_APP_PRIO_MASK) >> | |
221 | I40E_IEEE_APP_PRIO_SHIFT); | |
222 | dcbcfg->app[i].selector = (u8)((buf[offset] & | |
223 | I40E_IEEE_APP_SEL_MASK) >> | |
224 | I40E_IEEE_APP_SEL_SHIFT); | |
225 | dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) | | |
226 | buf[offset + 2]; | |
227 | /* Move to next app */ | |
228 | offset += 3; | |
229 | i++; | |
230 | if (i >= I40E_DCBX_MAX_APPS) | |
231 | break; | |
232 | } | |
233 | ||
234 | dcbcfg->numapps = i; | |
235 | } | |
236 | ||
237 | /** | |
238 | * i40e_parse_ieee_etsrec_tlv | |
239 | * @tlv: IEEE 802.1Qaz TLV | |
240 | * @dcbcfg: Local store to update ETS REC data | |
241 | * | |
242 | * Get the TLV subtype and send it to parsing function | |
243 | * based on the subtype value | |
244 | **/ | |
245 | static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv, | |
246 | struct i40e_dcbx_config *dcbcfg) | |
247 | { | |
248 | u32 ouisubtype; | |
249 | u8 subtype; | |
250 | ||
251 | ouisubtype = I40E_NTOHL(tlv->ouisubtype); | |
252 | subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >> | |
253 | I40E_LLDP_TLV_SUBTYPE_SHIFT); | |
254 | switch (subtype) { | |
255 | case I40E_IEEE_SUBTYPE_ETS_CFG: | |
256 | i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg); | |
257 | break; | |
258 | case I40E_IEEE_SUBTYPE_ETS_REC: | |
259 | i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg); | |
260 | break; | |
261 | case I40E_IEEE_SUBTYPE_PFC_CFG: | |
262 | i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg); | |
263 | break; | |
264 | case I40E_IEEE_SUBTYPE_APP_PRI: | |
265 | i40e_parse_ieee_app_tlv(tlv, dcbcfg); | |
266 | break; | |
267 | default: | |
268 | break; | |
269 | } | |
270 | } | |
271 | ||
272 | /** | |
273 | * i40e_parse_cee_pgcfg_tlv | |
274 | * @tlv: CEE DCBX PG CFG TLV | |
275 | * @dcbcfg: Local store to update ETS CFG data | |
276 | * | |
277 | * Parses CEE DCBX PG CFG TLV | |
278 | **/ | |
279 | static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv, | |
280 | struct i40e_dcbx_config *dcbcfg) | |
281 | { | |
282 | struct i40e_dcb_ets_config *etscfg; | |
283 | u8 *buf = tlv->tlvinfo; | |
284 | u16 offset = 0; | |
285 | u8 priority; | |
286 | int i; | |
287 | ||
288 | etscfg = &dcbcfg->etscfg; | |
289 | ||
290 | if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK) | |
291 | etscfg->willing = 1; | |
292 | ||
293 | etscfg->cbs = 0; | |
294 | /* Priority Group Table (4 octets) | |
295 | * Octets:| 1 | 2 | 3 | 4 | | |
296 | * ----------------------------------------- | |
297 | * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| | |
298 | * ----------------------------------------- | |
299 | * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| | |
300 | * ----------------------------------------- | |
301 | */ | |
302 | for (i = 0; i < 4; i++) { | |
303 | priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >> | |
304 | I40E_CEE_PGID_PRIO_1_SHIFT); | |
305 | etscfg->prioritytable[i * 2] = priority; | |
306 | priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >> | |
307 | I40E_CEE_PGID_PRIO_0_SHIFT); | |
308 | etscfg->prioritytable[i * 2 + 1] = priority; | |
309 | offset++; | |
310 | } | |
311 | ||
312 | /* PG Percentage Table (8 octets) | |
313 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
314 | * --------------------------------- | |
315 | * |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7| | |
316 | * --------------------------------- | |
317 | */ | |
318 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
319 | etscfg->tcbwtable[i] = buf[offset++]; | |
320 | ||
321 | /* Number of TCs supported (1 octet) */ | |
322 | etscfg->maxtcs = buf[offset]; | |
323 | } | |
324 | ||
325 | /** | |
326 | * i40e_parse_cee_pfccfg_tlv | |
327 | * @tlv: CEE DCBX PFC CFG TLV | |
328 | * @dcbcfg: Local store to update PFC CFG data | |
329 | * | |
330 | * Parses CEE DCBX PFC CFG TLV | |
331 | **/ | |
332 | static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv, | |
333 | struct i40e_dcbx_config *dcbcfg) | |
334 | { | |
335 | u8 *buf = tlv->tlvinfo; | |
336 | ||
337 | if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK) | |
338 | dcbcfg->pfc.willing = 1; | |
339 | ||
340 | /* ------------------------ | |
341 | * | PFC Enable | PFC TCs | | |
342 | * ------------------------ | |
343 | * | 1 octet | 1 octet | | |
344 | */ | |
345 | dcbcfg->pfc.pfcenable = buf[0]; | |
346 | dcbcfg->pfc.pfccap = buf[1]; | |
347 | } | |
348 | ||
349 | /** | |
350 | * i40e_parse_cee_app_tlv | |
351 | * @tlv: CEE DCBX APP TLV | |
352 | * @dcbcfg: Local store to update APP PRIO data | |
353 | * | |
354 | * Parses CEE DCBX APP PRIO TLV | |
355 | **/ | |
356 | static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv, | |
357 | struct i40e_dcbx_config *dcbcfg) | |
358 | { | |
359 | u16 length, typelength, offset = 0; | |
360 | struct i40e_cee_app_prio *app; | |
361 | u8 i; | |
362 | ||
363 | typelength = I40E_NTOHS(tlv->hdr.typelen); | |
364 | length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> | |
365 | I40E_LLDP_TLV_LEN_SHIFT); | |
366 | ||
367 | dcbcfg->numapps = length / sizeof(*app); | |
368 | if (!dcbcfg->numapps) | |
369 | return; | |
11fdf7f2 TL |
370 | if (dcbcfg->numapps > I40E_DCBX_MAX_APPS) |
371 | dcbcfg->numapps = I40E_DCBX_MAX_APPS; | |
7c673cae FG |
372 | |
373 | for (i = 0; i < dcbcfg->numapps; i++) { | |
374 | u8 up, selector; | |
375 | ||
376 | app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset); | |
377 | for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) { | |
378 | if (app->prio_map & BIT(up)) | |
379 | break; | |
380 | } | |
381 | dcbcfg->app[i].priority = up; | |
382 | ||
383 | /* Get Selector from lower 2 bits, and convert to IEEE */ | |
384 | selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK); | |
385 | switch (selector) { | |
386 | case I40E_CEE_APP_SEL_ETHTYPE: | |
387 | dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; | |
388 | break; | |
389 | case I40E_CEE_APP_SEL_TCPIP: | |
390 | dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; | |
391 | break; | |
392 | default: | |
393 | /* Keep selector as it is for unknown types */ | |
394 | dcbcfg->app[i].selector = selector; | |
395 | } | |
396 | ||
397 | dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol); | |
398 | /* Move to next app */ | |
399 | offset += sizeof(*app); | |
400 | } | |
401 | } | |
402 | ||
403 | /** | |
404 | * i40e_parse_cee_tlv | |
405 | * @tlv: CEE DCBX TLV | |
406 | * @dcbcfg: Local store to update DCBX config data | |
407 | * | |
408 | * Get the TLV subtype and send it to parsing function | |
409 | * based on the subtype value | |
410 | **/ | |
411 | static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv, | |
412 | struct i40e_dcbx_config *dcbcfg) | |
413 | { | |
414 | u16 len, tlvlen, sublen, typelength; | |
415 | struct i40e_cee_feat_tlv *sub_tlv; | |
416 | u8 subtype, feat_tlv_count = 0; | |
417 | u32 ouisubtype; | |
418 | ||
419 | ouisubtype = I40E_NTOHL(tlv->ouisubtype); | |
420 | subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >> | |
421 | I40E_LLDP_TLV_SUBTYPE_SHIFT); | |
422 | /* Return if not CEE DCBX */ | |
423 | if (subtype != I40E_CEE_DCBX_TYPE) | |
424 | return; | |
425 | ||
426 | typelength = I40E_NTOHS(tlv->typelength); | |
427 | tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> | |
428 | I40E_LLDP_TLV_LEN_SHIFT); | |
429 | len = sizeof(tlv->typelength) + sizeof(ouisubtype) + | |
430 | sizeof(struct i40e_cee_ctrl_tlv); | |
431 | /* Return if no CEE DCBX Feature TLVs */ | |
432 | if (tlvlen <= len) | |
433 | return; | |
434 | ||
435 | sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len); | |
436 | while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) { | |
437 | typelength = I40E_NTOHS(sub_tlv->hdr.typelen); | |
438 | sublen = (u16)((typelength & | |
439 | I40E_LLDP_TLV_LEN_MASK) >> | |
440 | I40E_LLDP_TLV_LEN_SHIFT); | |
441 | subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> | |
442 | I40E_LLDP_TLV_TYPE_SHIFT); | |
443 | switch (subtype) { | |
444 | case I40E_CEE_SUBTYPE_PG_CFG: | |
445 | i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg); | |
446 | break; | |
447 | case I40E_CEE_SUBTYPE_PFC_CFG: | |
448 | i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg); | |
449 | break; | |
450 | case I40E_CEE_SUBTYPE_APP_PRI: | |
451 | i40e_parse_cee_app_tlv(sub_tlv, dcbcfg); | |
452 | break; | |
453 | default: | |
454 | return; /* Invalid Sub-type return */ | |
455 | } | |
456 | feat_tlv_count++; | |
457 | /* Move to next sub TLV */ | |
458 | sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv + | |
459 | sizeof(sub_tlv->hdr.typelen) + | |
460 | sublen); | |
461 | } | |
462 | } | |
463 | ||
464 | /** | |
465 | * i40e_parse_org_tlv | |
466 | * @tlv: Organization specific TLV | |
467 | * @dcbcfg: Local store to update ETS REC data | |
468 | * | |
469 | * Currently only IEEE 802.1Qaz TLV is supported, all others | |
470 | * will be returned | |
471 | **/ | |
472 | static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv, | |
473 | struct i40e_dcbx_config *dcbcfg) | |
474 | { | |
475 | u32 ouisubtype; | |
476 | u32 oui; | |
477 | ||
478 | ouisubtype = I40E_NTOHL(tlv->ouisubtype); | |
479 | oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >> | |
480 | I40E_LLDP_TLV_OUI_SHIFT); | |
481 | switch (oui) { | |
482 | case I40E_IEEE_8021QAZ_OUI: | |
483 | i40e_parse_ieee_tlv(tlv, dcbcfg); | |
484 | break; | |
485 | case I40E_CEE_DCBX_OUI: | |
486 | i40e_parse_cee_tlv(tlv, dcbcfg); | |
487 | break; | |
488 | default: | |
489 | break; | |
490 | } | |
491 | } | |
492 | ||
493 | /** | |
494 | * i40e_lldp_to_dcb_config | |
495 | * @lldpmib: LLDPDU to be parsed | |
496 | * @dcbcfg: store for LLDPDU data | |
497 | * | |
498 | * Parse DCB configuration from the LLDPDU | |
499 | **/ | |
500 | enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib, | |
501 | struct i40e_dcbx_config *dcbcfg) | |
502 | { | |
503 | enum i40e_status_code ret = I40E_SUCCESS; | |
504 | struct i40e_lldp_org_tlv *tlv; | |
505 | u16 type; | |
506 | u16 length; | |
507 | u16 typelength; | |
508 | u16 offset = 0; | |
509 | ||
510 | if (!lldpmib || !dcbcfg) | |
511 | return I40E_ERR_PARAM; | |
512 | ||
513 | /* set to the start of LLDPDU */ | |
514 | lldpmib += I40E_LLDP_MIB_HLEN; | |
515 | tlv = (struct i40e_lldp_org_tlv *)lldpmib; | |
516 | while (1) { | |
517 | typelength = I40E_NTOHS(tlv->typelength); | |
518 | type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> | |
519 | I40E_LLDP_TLV_TYPE_SHIFT); | |
520 | length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> | |
521 | I40E_LLDP_TLV_LEN_SHIFT); | |
522 | offset += sizeof(typelength) + length; | |
523 | ||
524 | /* END TLV or beyond LLDPDU size */ | |
525 | if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE)) | |
526 | break; | |
527 | ||
528 | switch (type) { | |
529 | case I40E_TLV_TYPE_ORG: | |
530 | i40e_parse_org_tlv(tlv, dcbcfg); | |
531 | break; | |
532 | default: | |
533 | break; | |
534 | } | |
535 | ||
536 | /* Move to next TLV */ | |
537 | tlv = (struct i40e_lldp_org_tlv *)((char *)tlv + | |
538 | sizeof(tlv->typelength) + | |
539 | length); | |
540 | } | |
541 | ||
542 | return ret; | |
543 | } | |
544 | ||
545 | /** | |
546 | * i40e_aq_get_dcb_config | |
547 | * @hw: pointer to the hw struct | |
548 | * @mib_type: mib type for the query | |
549 | * @bridgetype: bridge type for the query (remote) | |
550 | * @dcbcfg: store for LLDPDU data | |
551 | * | |
552 | * Query DCB configuration from the Firmware | |
553 | **/ | |
554 | enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type, | |
555 | u8 bridgetype, | |
556 | struct i40e_dcbx_config *dcbcfg) | |
557 | { | |
558 | enum i40e_status_code ret = I40E_SUCCESS; | |
559 | struct i40e_virt_mem mem; | |
560 | u8 *lldpmib; | |
561 | ||
562 | /* Allocate the LLDPDU */ | |
563 | ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); | |
564 | if (ret) | |
565 | return ret; | |
566 | ||
567 | lldpmib = (u8 *)mem.va; | |
568 | ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type, | |
569 | (void *)lldpmib, I40E_LLDPDU_SIZE, | |
570 | NULL, NULL, NULL); | |
571 | if (ret) | |
572 | goto free_mem; | |
573 | ||
574 | /* Parse LLDP MIB to get dcb configuration */ | |
575 | ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg); | |
576 | ||
577 | free_mem: | |
578 | i40e_free_virt_mem(hw, &mem); | |
579 | return ret; | |
580 | } | |
581 | ||
582 | /** | |
583 | * i40e_cee_to_dcb_v1_config | |
584 | * @cee_cfg: pointer to CEE v1 response configuration struct | |
585 | * @dcbcfg: DCB configuration struct | |
586 | * | |
587 | * Convert CEE v1 configuration from firmware to DCB configuration | |
588 | **/ | |
589 | static void i40e_cee_to_dcb_v1_config( | |
590 | struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg, | |
591 | struct i40e_dcbx_config *dcbcfg) | |
592 | { | |
593 | u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status); | |
594 | u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio); | |
595 | u8 i, tc, err; | |
596 | ||
597 | /* CEE PG data to ETS config */ | |
598 | dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; | |
599 | ||
600 | /* Note that the FW creates the oper_prio_tc nibbles reversed | |
601 | * from those in the CEE Priority Group sub-TLV. | |
602 | */ | |
603 | for (i = 0; i < 4; i++) { | |
604 | tc = (u8)((cee_cfg->oper_prio_tc[i] & | |
605 | I40E_CEE_PGID_PRIO_0_MASK) >> | |
606 | I40E_CEE_PGID_PRIO_0_SHIFT); | |
607 | dcbcfg->etscfg.prioritytable[i*2] = tc; | |
608 | tc = (u8)((cee_cfg->oper_prio_tc[i] & | |
609 | I40E_CEE_PGID_PRIO_1_MASK) >> | |
610 | I40E_CEE_PGID_PRIO_1_SHIFT); | |
611 | dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; | |
612 | } | |
613 | ||
614 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
615 | dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; | |
616 | ||
617 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { | |
618 | if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { | |
619 | /* Map it to next empty TC */ | |
620 | dcbcfg->etscfg.prioritytable[i] = | |
621 | cee_cfg->oper_num_tc - 1; | |
622 | dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; | |
623 | } else { | |
624 | dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; | |
625 | } | |
626 | } | |
627 | ||
628 | /* CEE PFC data to ETS config */ | |
629 | dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; | |
630 | dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; | |
631 | ||
632 | status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >> | |
633 | I40E_AQC_CEE_APP_STATUS_SHIFT; | |
634 | err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; | |
635 | /* Add APPs if Error is False */ | |
636 | if (!err) { | |
637 | /* CEE operating configuration supports FCoE/iSCSI/FIP only */ | |
638 | dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS; | |
639 | ||
640 | /* FCoE APP */ | |
641 | dcbcfg->app[0].priority = | |
642 | (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> | |
643 | I40E_AQC_CEE_APP_FCOE_SHIFT; | |
644 | dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE; | |
645 | dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE; | |
646 | ||
647 | /* iSCSI APP */ | |
648 | dcbcfg->app[1].priority = | |
649 | (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> | |
650 | I40E_AQC_CEE_APP_ISCSI_SHIFT; | |
651 | dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP; | |
652 | dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI; | |
653 | ||
654 | /* FIP APP */ | |
655 | dcbcfg->app[2].priority = | |
656 | (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> | |
657 | I40E_AQC_CEE_APP_FIP_SHIFT; | |
658 | dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE; | |
659 | dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP; | |
660 | } | |
661 | } | |
662 | ||
663 | /** | |
664 | * i40e_cee_to_dcb_config | |
665 | * @cee_cfg: pointer to CEE configuration struct | |
666 | * @dcbcfg: DCB configuration struct | |
667 | * | |
668 | * Convert CEE configuration from firmware to DCB configuration | |
669 | **/ | |
670 | static void i40e_cee_to_dcb_config( | |
671 | struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg, | |
672 | struct i40e_dcbx_config *dcbcfg) | |
673 | { | |
674 | u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status); | |
675 | u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio); | |
676 | u8 i, tc, err, sync, oper; | |
677 | ||
678 | /* CEE PG data to ETS config */ | |
679 | dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; | |
680 | ||
681 | /* Note that the FW creates the oper_prio_tc nibbles reversed | |
682 | * from those in the CEE Priority Group sub-TLV. | |
683 | */ | |
684 | for (i = 0; i < 4; i++) { | |
685 | tc = (u8)((cee_cfg->oper_prio_tc[i] & | |
686 | I40E_CEE_PGID_PRIO_0_MASK) >> | |
687 | I40E_CEE_PGID_PRIO_0_SHIFT); | |
688 | dcbcfg->etscfg.prioritytable[i*2] = tc; | |
689 | tc = (u8)((cee_cfg->oper_prio_tc[i] & | |
690 | I40E_CEE_PGID_PRIO_1_MASK) >> | |
691 | I40E_CEE_PGID_PRIO_1_SHIFT); | |
692 | dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; | |
693 | } | |
694 | ||
695 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
696 | dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; | |
697 | ||
698 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { | |
699 | if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { | |
700 | /* Map it to next empty TC */ | |
701 | dcbcfg->etscfg.prioritytable[i] = | |
702 | cee_cfg->oper_num_tc - 1; | |
703 | dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; | |
704 | } else { | |
705 | dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; | |
706 | } | |
707 | } | |
708 | ||
709 | /* CEE PFC data to ETS config */ | |
710 | dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; | |
711 | dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; | |
712 | ||
713 | i = 0; | |
714 | status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >> | |
715 | I40E_AQC_CEE_FCOE_STATUS_SHIFT; | |
716 | err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; | |
717 | sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; | |
718 | oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; | |
719 | /* Add FCoE APP if Error is False and Oper/Sync is True */ | |
720 | if (!err && sync && oper) { | |
721 | /* FCoE APP */ | |
722 | dcbcfg->app[i].priority = | |
723 | (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> | |
724 | I40E_AQC_CEE_APP_FCOE_SHIFT; | |
725 | dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; | |
726 | dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE; | |
727 | i++; | |
728 | } | |
729 | ||
730 | status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >> | |
731 | I40E_AQC_CEE_ISCSI_STATUS_SHIFT; | |
732 | err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; | |
733 | sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; | |
734 | oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; | |
735 | /* Add iSCSI APP if Error is False and Oper/Sync is True */ | |
736 | if (!err && sync && oper) { | |
737 | /* iSCSI APP */ | |
738 | dcbcfg->app[i].priority = | |
739 | (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> | |
740 | I40E_AQC_CEE_APP_ISCSI_SHIFT; | |
741 | dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; | |
742 | dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI; | |
743 | i++; | |
744 | } | |
745 | ||
746 | status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >> | |
747 | I40E_AQC_CEE_FIP_STATUS_SHIFT; | |
748 | err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; | |
749 | sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; | |
750 | oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; | |
751 | /* Add FIP APP if Error is False and Oper/Sync is True */ | |
752 | if (!err && sync && oper) { | |
753 | /* FIP APP */ | |
754 | dcbcfg->app[i].priority = | |
755 | (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> | |
756 | I40E_AQC_CEE_APP_FIP_SHIFT; | |
757 | dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; | |
758 | dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP; | |
759 | i++; | |
760 | } | |
761 | dcbcfg->numapps = i; | |
762 | } | |
763 | ||
764 | /** | |
765 | * i40e_get_ieee_dcb_config | |
766 | * @hw: pointer to the hw struct | |
767 | * | |
768 | * Get IEEE mode DCB configuration from the Firmware | |
769 | **/ | |
770 | STATIC enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw) | |
771 | { | |
772 | enum i40e_status_code ret = I40E_SUCCESS; | |
773 | ||
774 | /* IEEE mode */ | |
775 | hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE; | |
776 | /* Get Local DCB Config */ | |
777 | ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, | |
778 | &hw->local_dcbx_config); | |
779 | if (ret) | |
780 | goto out; | |
781 | ||
782 | /* Get Remote DCB Config */ | |
783 | ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, | |
784 | I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, | |
785 | &hw->remote_dcbx_config); | |
786 | /* Don't treat ENOENT as an error for Remote MIBs */ | |
787 | if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) | |
788 | ret = I40E_SUCCESS; | |
789 | ||
790 | out: | |
791 | return ret; | |
792 | } | |
793 | ||
794 | /** | |
795 | * i40e_get_dcb_config | |
796 | * @hw: pointer to the hw struct | |
797 | * | |
798 | * Get DCB configuration from the Firmware | |
799 | **/ | |
800 | enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw) | |
801 | { | |
802 | enum i40e_status_code ret = I40E_SUCCESS; | |
803 | struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg; | |
804 | struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg; | |
805 | ||
806 | /* If Firmware version < v4.33 on X710/XL710, IEEE only */ | |
807 | if ((hw->mac.type == I40E_MAC_XL710) && | |
808 | (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || | |
809 | (hw->aq.fw_maj_ver < 4))) | |
810 | return i40e_get_ieee_dcb_config(hw); | |
811 | ||
812 | /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */ | |
813 | if ((hw->mac.type == I40E_MAC_XL710) && | |
814 | ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) { | |
815 | ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg, | |
816 | sizeof(cee_v1_cfg), NULL); | |
817 | if (ret == I40E_SUCCESS) { | |
818 | /* CEE mode */ | |
819 | hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; | |
820 | hw->local_dcbx_config.tlv_status = | |
821 | LE16_TO_CPU(cee_v1_cfg.tlv_status); | |
822 | i40e_cee_to_dcb_v1_config(&cee_v1_cfg, | |
823 | &hw->local_dcbx_config); | |
824 | } | |
825 | } else { | |
826 | ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg, | |
827 | sizeof(cee_cfg), NULL); | |
828 | if (ret == I40E_SUCCESS) { | |
829 | /* CEE mode */ | |
830 | hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; | |
831 | hw->local_dcbx_config.tlv_status = | |
832 | LE32_TO_CPU(cee_cfg.tlv_status); | |
833 | i40e_cee_to_dcb_config(&cee_cfg, | |
834 | &hw->local_dcbx_config); | |
835 | } | |
836 | } | |
837 | ||
838 | /* CEE mode not enabled try querying IEEE data */ | |
839 | if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) | |
840 | return i40e_get_ieee_dcb_config(hw); | |
841 | ||
842 | if (ret != I40E_SUCCESS) | |
843 | goto out; | |
844 | ||
845 | /* Get CEE DCB Desired Config */ | |
846 | ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, | |
847 | &hw->desired_dcbx_config); | |
848 | if (ret) | |
849 | goto out; | |
850 | ||
851 | /* Get Remote DCB Config */ | |
852 | ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, | |
853 | I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, | |
854 | &hw->remote_dcbx_config); | |
855 | /* Don't treat ENOENT as an error for Remote MIBs */ | |
856 | if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) | |
857 | ret = I40E_SUCCESS; | |
858 | ||
859 | out: | |
860 | return ret; | |
861 | } | |
862 | ||
863 | /** | |
864 | * i40e_init_dcb | |
865 | * @hw: pointer to the hw struct | |
866 | * | |
867 | * Update DCB configuration from the Firmware | |
868 | **/ | |
869 | enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw) | |
870 | { | |
871 | enum i40e_status_code ret = I40E_SUCCESS; | |
872 | struct i40e_lldp_variables lldp_cfg; | |
873 | u8 adminstatus = 0; | |
874 | ||
875 | if (!hw->func_caps.dcb) | |
876 | return ret; | |
877 | ||
878 | /* Read LLDP NVM area */ | |
879 | ret = i40e_read_lldp_cfg(hw, &lldp_cfg); | |
880 | if (ret) | |
881 | return ret; | |
882 | ||
883 | /* Get the LLDP AdminStatus for the current port */ | |
884 | adminstatus = lldp_cfg.adminstatus >> (hw->port * 4); | |
885 | adminstatus &= 0xF; | |
886 | ||
887 | /* LLDP agent disabled */ | |
888 | if (!adminstatus) { | |
889 | hw->dcbx_status = I40E_DCBX_STATUS_DISABLED; | |
890 | return ret; | |
891 | } | |
892 | ||
893 | /* Get DCBX status */ | |
894 | ret = i40e_get_dcbx_status(hw, &hw->dcbx_status); | |
895 | if (ret) | |
896 | return ret; | |
897 | ||
898 | /* Check the DCBX Status */ | |
899 | switch (hw->dcbx_status) { | |
900 | case I40E_DCBX_STATUS_DONE: | |
901 | case I40E_DCBX_STATUS_IN_PROGRESS: | |
902 | /* Get current DCBX configuration */ | |
903 | ret = i40e_get_dcb_config(hw); | |
904 | if (ret) | |
905 | return ret; | |
906 | break; | |
907 | case I40E_DCBX_STATUS_DISABLED: | |
908 | return ret; | |
909 | case I40E_DCBX_STATUS_NOT_STARTED: | |
910 | case I40E_DCBX_STATUS_MULTIPLE_PEERS: | |
911 | default: | |
912 | break; | |
913 | } | |
914 | ||
915 | /* Configure the LLDP MIB change event */ | |
916 | ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL); | |
917 | if (ret) | |
918 | return ret; | |
919 | ||
920 | return ret; | |
921 | } | |
922 | ||
923 | /** | |
924 | * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format | |
925 | * @tlv: Fill the ETS config data in IEEE format | |
926 | * @dcbcfg: Local store which holds the DCB Config | |
927 | * | |
928 | * Prepare IEEE 802.1Qaz ETS CFG TLV | |
929 | **/ | |
930 | static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv, | |
931 | struct i40e_dcbx_config *dcbcfg) | |
932 | { | |
933 | u8 priority0, priority1, maxtcwilling = 0; | |
934 | struct i40e_dcb_ets_config *etscfg; | |
935 | u16 offset = 0, typelength, i; | |
936 | u8 *buf = tlv->tlvinfo; | |
937 | u32 ouisubtype; | |
938 | ||
939 | typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | | |
940 | I40E_IEEE_ETS_TLV_LENGTH); | |
941 | tlv->typelength = I40E_HTONS(typelength); | |
942 | ||
943 | ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | | |
944 | I40E_IEEE_SUBTYPE_ETS_CFG); | |
945 | tlv->ouisubtype = I40E_HTONL(ouisubtype); | |
946 | ||
947 | /* First Octet post subtype | |
948 | * -------------------------- | |
949 | * |will-|CBS | Re- | Max | | |
950 | * |ing | |served| TCs | | |
951 | * -------------------------- | |
952 | * |1bit | 1bit|3 bits|3bits| | |
953 | */ | |
954 | etscfg = &dcbcfg->etscfg; | |
955 | if (etscfg->willing) | |
956 | maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT); | |
957 | maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK; | |
958 | buf[offset] = maxtcwilling; | |
959 | ||
960 | /* Move offset to Priority Assignment Table */ | |
961 | offset++; | |
962 | ||
963 | /* Priority Assignment Table (4 octets) | |
964 | * Octets:| 1 | 2 | 3 | 4 | | |
965 | * ----------------------------------------- | |
966 | * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| | |
967 | * ----------------------------------------- | |
968 | * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| | |
969 | * ----------------------------------------- | |
970 | */ | |
971 | for (i = 0; i < 4; i++) { | |
972 | priority0 = etscfg->prioritytable[i * 2] & 0xF; | |
973 | priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF; | |
974 | buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) | | |
975 | priority1; | |
976 | offset++; | |
977 | } | |
978 | ||
979 | /* TC Bandwidth Table (8 octets) | |
980 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
981 | * --------------------------------- | |
982 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
983 | * --------------------------------- | |
984 | */ | |
985 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
986 | buf[offset++] = etscfg->tcbwtable[i]; | |
987 | ||
988 | /* TSA Assignment Table (8 octets) | |
989 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
990 | * --------------------------------- | |
991 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
992 | * --------------------------------- | |
993 | */ | |
994 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
995 | buf[offset++] = etscfg->tsatable[i]; | |
996 | } | |
997 | ||
998 | /** | |
999 | * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format | |
1000 | * @tlv: Fill ETS Recommended TLV in IEEE format | |
1001 | * @dcbcfg: Local store which holds the DCB Config | |
1002 | * | |
1003 | * Prepare IEEE 802.1Qaz ETS REC TLV | |
1004 | **/ | |
1005 | static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv, | |
1006 | struct i40e_dcbx_config *dcbcfg) | |
1007 | { | |
1008 | struct i40e_dcb_ets_config *etsrec; | |
1009 | u16 offset = 0, typelength, i; | |
1010 | u8 priority0, priority1; | |
1011 | u8 *buf = tlv->tlvinfo; | |
1012 | u32 ouisubtype; | |
1013 | ||
1014 | typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | | |
1015 | I40E_IEEE_ETS_TLV_LENGTH); | |
1016 | tlv->typelength = I40E_HTONS(typelength); | |
1017 | ||
1018 | ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | | |
1019 | I40E_IEEE_SUBTYPE_ETS_REC); | |
1020 | tlv->ouisubtype = I40E_HTONL(ouisubtype); | |
1021 | ||
1022 | etsrec = &dcbcfg->etsrec; | |
1023 | /* First Octet is reserved */ | |
1024 | /* Move offset to Priority Assignment Table */ | |
1025 | offset++; | |
1026 | ||
1027 | /* Priority Assignment Table (4 octets) | |
1028 | * Octets:| 1 | 2 | 3 | 4 | | |
1029 | * ----------------------------------------- | |
1030 | * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| | |
1031 | * ----------------------------------------- | |
1032 | * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| | |
1033 | * ----------------------------------------- | |
1034 | */ | |
1035 | for (i = 0; i < 4; i++) { | |
1036 | priority0 = etsrec->prioritytable[i * 2] & 0xF; | |
1037 | priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF; | |
1038 | buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) | | |
1039 | priority1; | |
1040 | offset++; | |
1041 | } | |
1042 | ||
1043 | /* TC Bandwidth Table (8 octets) | |
1044 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
1045 | * --------------------------------- | |
1046 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
1047 | * --------------------------------- | |
1048 | */ | |
1049 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
1050 | buf[offset++] = etsrec->tcbwtable[i]; | |
1051 | ||
1052 | /* TSA Assignment Table (8 octets) | |
1053 | * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |
1054 | * --------------------------------- | |
1055 | * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| | |
1056 | * --------------------------------- | |
1057 | */ | |
1058 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) | |
1059 | buf[offset++] = etsrec->tsatable[i]; | |
1060 | } | |
1061 | ||
1062 | /** | |
1063 | * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format | |
1064 | * @tlv: Fill PFC TLV in IEEE format | |
1065 | * @dcbcfg: Local store to get PFC CFG data | |
1066 | * | |
1067 | * Prepare IEEE 802.1Qaz PFC CFG TLV | |
1068 | **/ | |
1069 | static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv, | |
1070 | struct i40e_dcbx_config *dcbcfg) | |
1071 | { | |
1072 | u8 *buf = tlv->tlvinfo; | |
1073 | u32 ouisubtype; | |
1074 | u16 typelength; | |
1075 | ||
1076 | typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | | |
1077 | I40E_IEEE_PFC_TLV_LENGTH); | |
1078 | tlv->typelength = I40E_HTONS(typelength); | |
1079 | ||
1080 | ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | | |
1081 | I40E_IEEE_SUBTYPE_PFC_CFG); | |
1082 | tlv->ouisubtype = I40E_HTONL(ouisubtype); | |
1083 | ||
1084 | /* ---------------------------------------- | |
1085 | * |will-|MBC | Re- | PFC | PFC Enable | | |
1086 | * |ing | |served| cap | | | |
1087 | * ----------------------------------------- | |
1088 | * |1bit | 1bit|2 bits|4bits| 1 octet | | |
1089 | */ | |
1090 | if (dcbcfg->pfc.willing) | |
1091 | buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT); | |
1092 | ||
1093 | if (dcbcfg->pfc.mbc) | |
1094 | buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT); | |
1095 | ||
1096 | buf[0] |= dcbcfg->pfc.pfccap & 0xF; | |
1097 | buf[1] = dcbcfg->pfc.pfcenable; | |
1098 | } | |
1099 | ||
1100 | /** | |
1101 | * i40e_add_ieee_app_pri_tlv - Prepare APP TLV in IEEE format | |
1102 | * @tlv: Fill APP TLV in IEEE format | |
1103 | * @dcbcfg: Local store to get APP CFG data | |
1104 | * | |
1105 | * Prepare IEEE 802.1Qaz APP CFG TLV | |
1106 | **/ | |
1107 | static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv, | |
1108 | struct i40e_dcbx_config *dcbcfg) | |
1109 | { | |
1110 | u16 typelength, length, offset = 0; | |
1111 | u8 priority, selector, i = 0; | |
1112 | u8 *buf = tlv->tlvinfo; | |
1113 | u32 ouisubtype; | |
1114 | ||
1115 | /* No APP TLVs then just return */ | |
1116 | if (dcbcfg->numapps == 0) | |
1117 | return; | |
1118 | ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | | |
1119 | I40E_IEEE_SUBTYPE_APP_PRI); | |
1120 | tlv->ouisubtype = I40E_HTONL(ouisubtype); | |
1121 | ||
1122 | /* Move offset to App Priority Table */ | |
1123 | offset++; | |
1124 | /* Application Priority Table (3 octets) | |
1125 | * Octets:| 1 | 2 | 3 | | |
1126 | * ----------------------------------------- | |
1127 | * |Priority|Rsrvd| Sel | Protocol ID | | |
1128 | * ----------------------------------------- | |
1129 | * Bits:|23 21|20 19|18 16|15 0| | |
1130 | * ----------------------------------------- | |
1131 | */ | |
1132 | while (i < dcbcfg->numapps) { | |
1133 | priority = dcbcfg->app[i].priority & 0x7; | |
1134 | selector = dcbcfg->app[i].selector & 0x7; | |
1135 | buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector; | |
1136 | buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF; | |
1137 | buf[offset + 2] = dcbcfg->app[i].protocolid & 0xFF; | |
1138 | /* Move to next app */ | |
1139 | offset += 3; | |
1140 | i++; | |
1141 | if (i >= I40E_DCBX_MAX_APPS) | |
1142 | break; | |
1143 | } | |
1144 | /* length includes size of ouisubtype + 1 reserved + 3*numapps */ | |
1145 | length = sizeof(tlv->ouisubtype) + 1 + (i*3); | |
1146 | typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | | |
1147 | (length & 0x1FF)); | |
1148 | tlv->typelength = I40E_HTONS(typelength); | |
1149 | } | |
1150 | ||
1151 | /** | |
1152 | * i40e_add_dcb_tlv - Add all IEEE TLVs | |
1153 | * @tlv: pointer to org tlv | |
1154 | * | |
1155 | * add tlv information | |
1156 | **/ | |
1157 | static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv, | |
1158 | struct i40e_dcbx_config *dcbcfg, | |
1159 | u16 tlvid) | |
1160 | { | |
1161 | switch (tlvid) { | |
1162 | case I40E_IEEE_TLV_ID_ETS_CFG: | |
1163 | i40e_add_ieee_ets_tlv(tlv, dcbcfg); | |
1164 | break; | |
1165 | case I40E_IEEE_TLV_ID_ETS_REC: | |
1166 | i40e_add_ieee_etsrec_tlv(tlv, dcbcfg); | |
1167 | break; | |
1168 | case I40E_IEEE_TLV_ID_PFC_CFG: | |
1169 | i40e_add_ieee_pfc_tlv(tlv, dcbcfg); | |
1170 | break; | |
1171 | case I40E_IEEE_TLV_ID_APP_PRI: | |
1172 | i40e_add_ieee_app_pri_tlv(tlv, dcbcfg); | |
1173 | break; | |
1174 | default: | |
1175 | break; | |
1176 | } | |
1177 | } | |
1178 | ||
1179 | /** | |
1180 | * i40e_set_dcb_config - Set the local LLDP MIB to FW | |
1181 | * @hw: pointer to the hw struct | |
1182 | * | |
1183 | * Set DCB configuration to the Firmware | |
1184 | **/ | |
1185 | enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw) | |
1186 | { | |
1187 | enum i40e_status_code ret = I40E_SUCCESS; | |
1188 | struct i40e_dcbx_config *dcbcfg; | |
1189 | struct i40e_virt_mem mem; | |
1190 | u8 mib_type, *lldpmib; | |
1191 | u16 miblen; | |
1192 | ||
1193 | /* update the hw local config */ | |
1194 | dcbcfg = &hw->local_dcbx_config; | |
1195 | /* Allocate the LLDPDU */ | |
1196 | ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); | |
1197 | if (ret) | |
1198 | return ret; | |
1199 | ||
1200 | mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB; | |
1201 | if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) { | |
1202 | mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS << | |
1203 | SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT; | |
1204 | } | |
1205 | lldpmib = (u8 *)mem.va; | |
1206 | ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg); | |
1207 | ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL); | |
1208 | ||
1209 | i40e_free_virt_mem(hw, &mem); | |
1210 | return ret; | |
1211 | } | |
1212 | ||
1213 | /** | |
1214 | * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format | |
1215 | * @hw: pointer to the hw struct | |
1216 | * @dcbcfg: store for LLDPDU data | |
1217 | * | |
1218 | * send DCB configuration to FW | |
1219 | **/ | |
1220 | enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen, | |
1221 | struct i40e_dcbx_config *dcbcfg) | |
1222 | { | |
1223 | u16 length, offset = 0, tlvid = I40E_TLV_ID_START; | |
1224 | enum i40e_status_code ret = I40E_SUCCESS; | |
1225 | struct i40e_lldp_org_tlv *tlv; | |
1226 | u16 typelength; | |
1227 | ||
1228 | tlv = (struct i40e_lldp_org_tlv *)lldpmib; | |
1229 | while (1) { | |
1230 | i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++); | |
1231 | typelength = I40E_NTOHS(tlv->typelength); | |
1232 | length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> | |
1233 | I40E_LLDP_TLV_LEN_SHIFT); | |
1234 | if (length) | |
1235 | offset += length + 2; | |
1236 | /* END TLV or beyond LLDPDU size */ | |
1237 | if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) || | |
1238 | (offset > I40E_LLDPDU_SIZE)) | |
1239 | break; | |
1240 | /* Move to next TLV */ | |
1241 | if (length) | |
1242 | tlv = (struct i40e_lldp_org_tlv *)((char *)tlv + | |
1243 | sizeof(tlv->typelength) + length); | |
1244 | } | |
1245 | *miblen = offset; | |
1246 | return ret; | |
1247 | } | |
1248 | ||
1249 | ||
11fdf7f2 TL |
1250 | /** |
1251 | * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM | |
1252 | * @hw: pointer to the HW structure | |
1253 | * @lldp_cfg: pointer to hold lldp configuration variables | |
1254 | * @module: address of the module pointer | |
1255 | * @word_offset: offset of LLDP configuration | |
1256 | * | |
1257 | * Reads the LLDP configuration data from NVM using passed addresses | |
1258 | **/ | |
1259 | static enum i40e_status_code _i40e_read_lldp_cfg(struct i40e_hw *hw, | |
1260 | struct i40e_lldp_variables *lldp_cfg, | |
1261 | u8 module, u32 word_offset) | |
1262 | { | |
1263 | u32 address, offset = (2 * word_offset); | |
1264 | enum i40e_status_code ret; | |
9f95a23c | 1265 | __le16 raw_mem; |
11fdf7f2 TL |
1266 | u16 mem; |
1267 | ||
1268 | ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | |
1269 | if (ret != I40E_SUCCESS) | |
1270 | return ret; | |
1271 | ||
9f95a23c TL |
1272 | ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem, |
1273 | true, NULL); | |
11fdf7f2 TL |
1274 | i40e_release_nvm(hw); |
1275 | if (ret != I40E_SUCCESS) | |
1276 | return ret; | |
1277 | ||
9f95a23c | 1278 | mem = LE16_TO_CPU(raw_mem); |
11fdf7f2 TL |
1279 | /* Check if this pointer needs to be read in word size or 4K sector |
1280 | * units. | |
1281 | */ | |
1282 | if (mem & I40E_PTR_TYPE) | |
1283 | address = (0x7FFF & mem) * 4096; | |
1284 | else | |
1285 | address = (0x7FFF & mem) * 2; | |
1286 | ||
1287 | ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | |
1288 | if (ret != I40E_SUCCESS) | |
1289 | goto err_lldp_cfg; | |
1290 | ||
9f95a23c TL |
1291 | ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem, |
1292 | true, NULL); | |
11fdf7f2 TL |
1293 | i40e_release_nvm(hw); |
1294 | if (ret != I40E_SUCCESS) | |
1295 | return ret; | |
1296 | ||
9f95a23c | 1297 | mem = LE16_TO_CPU(raw_mem); |
11fdf7f2 TL |
1298 | offset = mem + word_offset; |
1299 | offset *= 2; | |
1300 | ||
1301 | ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | |
1302 | if (ret != I40E_SUCCESS) | |
1303 | goto err_lldp_cfg; | |
1304 | ||
1305 | ret = i40e_aq_read_nvm(hw, 0, address + offset, | |
1306 | sizeof(struct i40e_lldp_variables), lldp_cfg, | |
1307 | true, NULL); | |
1308 | i40e_release_nvm(hw); | |
1309 | ||
1310 | err_lldp_cfg: | |
1311 | return ret; | |
1312 | } | |
1313 | ||
7c673cae FG |
1314 | /** |
1315 | * i40e_read_lldp_cfg - read LLDP Configuration data from NVM | |
1316 | * @hw: pointer to the HW structure | |
1317 | * @lldp_cfg: pointer to hold lldp configuration variables | |
1318 | * | |
1319 | * Reads the LLDP configuration data from NVM | |
1320 | **/ | |
1321 | enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw, | |
1322 | struct i40e_lldp_variables *lldp_cfg) | |
1323 | { | |
1324 | enum i40e_status_code ret = I40E_SUCCESS; | |
11fdf7f2 | 1325 | u32 mem; |
7c673cae FG |
1326 | |
1327 | if (!lldp_cfg) | |
1328 | return I40E_ERR_PARAM; | |
1329 | ||
1330 | ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | |
1331 | if (ret != I40E_SUCCESS) | |
11fdf7f2 | 1332 | return ret; |
7c673cae | 1333 | |
11fdf7f2 TL |
1334 | ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem), |
1335 | &mem, true, NULL); | |
7c673cae | 1336 | i40e_release_nvm(hw); |
11fdf7f2 TL |
1337 | if (ret != I40E_SUCCESS) |
1338 | return ret; | |
1339 | ||
1340 | /* Read a bit that holds information whether we are running flat or | |
1341 | * structured NVM image. Flat image has LLDP configuration in shadow | |
1342 | * ram, so there is a need to pass different addresses for both cases. | |
1343 | */ | |
1344 | if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) { | |
1345 | /* Flat NVM case */ | |
1346 | ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR, | |
1347 | I40E_SR_LLDP_CFG_PTR); | |
1348 | } else { | |
1349 | /* Good old structured NVM image */ | |
1350 | ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR, | |
1351 | I40E_NVM_LLDP_CFG_PTR); | |
1352 | } | |
7c673cae | 1353 | |
7c673cae FG |
1354 | return ret; |
1355 | } |