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