1 /****************************************************************************** 2 3 Copyright (c) 2013-2018, 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_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 if (etscfg->prioritytable[i] == I40E_CEE_PGID_STRICT) 351 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; 352 else 353 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; 354 } 355 356 /* Number of TCs supported (1 octet) */ 357 etscfg->maxtcs = buf[offset]; 358 } 359 360 /** 361 * i40e_parse_cee_pfccfg_tlv 362 * @tlv: CEE DCBX PFC CFG TLV 363 * @dcbcfg: Local store to update PFC CFG data 364 * 365 * Parses CEE DCBX PFC CFG TLV 366 **/ 367 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv, 368 struct i40e_dcbx_config *dcbcfg) 369 { 370 u8 *buf = tlv->tlvinfo; 371 372 if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK) 373 dcbcfg->pfc.willing = 1; 374 375 /* ------------------------ 376 * | PFC Enable | PFC TCs | 377 * ------------------------ 378 * | 1 octet | 1 octet | 379 */ 380 dcbcfg->pfc.pfcenable = buf[0]; 381 dcbcfg->pfc.pfccap = buf[1]; 382 } 383 384 /** 385 * i40e_parse_cee_app_tlv 386 * @tlv: CEE DCBX APP TLV 387 * @dcbcfg: Local store to update APP PRIO data 388 * 389 * Parses CEE DCBX APP PRIO TLV 390 **/ 391 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv, 392 struct i40e_dcbx_config *dcbcfg) 393 { 394 u16 length, typelength, offset = 0; 395 struct i40e_cee_app_prio *app; 396 u8 i; 397 398 typelength = I40E_NTOHS(tlv->hdr.typelen); 399 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 400 I40E_LLDP_TLV_LEN_SHIFT); 401 402 dcbcfg->numapps = length / sizeof(*app); 403 if (!dcbcfg->numapps) 404 return; 405 if (dcbcfg->numapps > I40E_DCBX_MAX_APPS) 406 dcbcfg->numapps = I40E_DCBX_MAX_APPS; 407 408 for (i = 0; i < dcbcfg->numapps; i++) { 409 u8 up, selector; 410 411 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset); 412 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) { 413 if (app->prio_map & BIT(up)) 414 break; 415 } 416 dcbcfg->app[i].priority = up; 417 418 /* Get Selector from lower 2 bits, and convert to IEEE */ 419 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK); 420 switch (selector) { 421 case I40E_CEE_APP_SEL_ETHTYPE: 422 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 423 break; 424 case I40E_CEE_APP_SEL_TCPIP: 425 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; 426 break; 427 default: 428 /* Keep selector as it is for unknown types */ 429 dcbcfg->app[i].selector = selector; 430 } 431 432 dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol); 433 /* Move to next app */ 434 offset += sizeof(*app); 435 } 436 } 437 438 /** 439 * i40e_parse_cee_tlv 440 * @tlv: CEE DCBX TLV 441 * @dcbcfg: Local store to update DCBX config data 442 * 443 * Get the TLV subtype and send it to parsing function 444 * based on the subtype value 445 **/ 446 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv, 447 struct i40e_dcbx_config *dcbcfg) 448 { 449 u16 len, tlvlen, sublen, typelength; 450 struct i40e_cee_feat_tlv *sub_tlv; 451 u8 subtype, feat_tlv_count = 0; 452 u32 ouisubtype; 453 454 ouisubtype = I40E_NTOHL(tlv->ouisubtype); 455 subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >> 456 I40E_LLDP_TLV_SUBTYPE_SHIFT); 457 /* Return if not CEE DCBX */ 458 if (subtype != I40E_CEE_DCBX_TYPE) 459 return; 460 461 typelength = I40E_NTOHS(tlv->typelength); 462 tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 463 I40E_LLDP_TLV_LEN_SHIFT); 464 len = sizeof(tlv->typelength) + sizeof(ouisubtype) + 465 sizeof(struct i40e_cee_ctrl_tlv); 466 /* Return if no CEE DCBX Feature TLVs */ 467 if (tlvlen <= len) 468 return; 469 470 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len); 471 while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) { 472 typelength = I40E_NTOHS(sub_tlv->hdr.typelen); 473 sublen = (u16)((typelength & 474 I40E_LLDP_TLV_LEN_MASK) >> 475 I40E_LLDP_TLV_LEN_SHIFT); 476 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> 477 I40E_LLDP_TLV_TYPE_SHIFT); 478 switch (subtype) { 479 case I40E_CEE_SUBTYPE_PG_CFG: 480 i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg); 481 break; 482 case I40E_CEE_SUBTYPE_PFC_CFG: 483 i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg); 484 break; 485 case I40E_CEE_SUBTYPE_APP_PRI: 486 i40e_parse_cee_app_tlv(sub_tlv, dcbcfg); 487 break; 488 default: 489 return; /* Invalid Sub-type return */ 490 } 491 feat_tlv_count++; 492 /* Move to next sub TLV */ 493 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv + 494 sizeof(sub_tlv->hdr.typelen) + 495 sublen); 496 } 497 } 498 499 /** 500 * i40e_parse_org_tlv 501 * @tlv: Organization specific TLV 502 * @dcbcfg: Local store to update ETS REC data 503 * 504 * Currently only IEEE 802.1Qaz TLV is supported, all others 505 * will be returned 506 **/ 507 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv, 508 struct i40e_dcbx_config *dcbcfg) 509 { 510 u32 ouisubtype; 511 u32 oui; 512 513 ouisubtype = I40E_NTOHL(tlv->ouisubtype); 514 oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >> 515 I40E_LLDP_TLV_OUI_SHIFT); 516 switch (oui) { 517 case I40E_IEEE_8021QAZ_OUI: 518 i40e_parse_ieee_tlv(tlv, dcbcfg); 519 break; 520 case I40E_CEE_DCBX_OUI: 521 i40e_parse_cee_tlv(tlv, dcbcfg); 522 break; 523 default: 524 break; 525 } 526 } 527 528 /** 529 * i40e_lldp_to_dcb_config 530 * @lldpmib: LLDPDU to be parsed 531 * @dcbcfg: store for LLDPDU data 532 * 533 * Parse DCB configuration from the LLDPDU 534 **/ 535 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib, 536 struct i40e_dcbx_config *dcbcfg) 537 { 538 enum i40e_status_code ret = I40E_SUCCESS; 539 struct i40e_lldp_org_tlv *tlv; 540 u16 type; 541 u16 length; 542 u16 typelength; 543 u16 offset = 0; 544 545 if (!lldpmib || !dcbcfg) 546 return I40E_ERR_PARAM; 547 548 /* set to the start of LLDPDU */ 549 lldpmib += I40E_LLDP_MIB_HLEN; 550 tlv = (struct i40e_lldp_org_tlv *)lldpmib; 551 while (1) { 552 typelength = I40E_NTOHS(tlv->typelength); 553 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> 554 I40E_LLDP_TLV_TYPE_SHIFT); 555 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 556 I40E_LLDP_TLV_LEN_SHIFT); 557 offset += sizeof(typelength) + length; 558 559 /* END TLV or beyond LLDPDU size */ 560 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE)) 561 break; 562 563 switch (type) { 564 case I40E_TLV_TYPE_ORG: 565 i40e_parse_org_tlv(tlv, dcbcfg); 566 break; 567 default: 568 break; 569 } 570 571 /* Move to next TLV */ 572 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv + 573 sizeof(tlv->typelength) + 574 length); 575 } 576 577 return ret; 578 } 579 580 /** 581 * i40e_aq_get_dcb_config 582 * @hw: pointer to the hw struct 583 * @mib_type: mib type for the query 584 * @bridgetype: bridge type for the query (remote) 585 * @dcbcfg: store for LLDPDU data 586 * 587 * Query DCB configuration from the Firmware 588 **/ 589 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type, 590 u8 bridgetype, 591 struct i40e_dcbx_config *dcbcfg) 592 { 593 enum i40e_status_code ret = I40E_SUCCESS; 594 struct i40e_virt_mem mem; 595 u8 *lldpmib; 596 597 /* Allocate the LLDPDU */ 598 ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); 599 if (ret) 600 return ret; 601 602 lldpmib = (u8 *)mem.va; 603 ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type, 604 (void *)lldpmib, I40E_LLDPDU_SIZE, 605 NULL, NULL, NULL); 606 if (ret) 607 goto free_mem; 608 609 /* Parse LLDP MIB to get dcb configuration */ 610 ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg); 611 612 free_mem: 613 i40e_free_virt_mem(hw, &mem); 614 return ret; 615 } 616 617 /** 618 * i40e_cee_to_dcb_v1_config 619 * @cee_cfg: pointer to CEE v1 response configuration struct 620 * @dcbcfg: DCB configuration struct 621 * 622 * Convert CEE v1 configuration from firmware to DCB configuration 623 **/ 624 static void i40e_cee_to_dcb_v1_config( 625 struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg, 626 struct i40e_dcbx_config *dcbcfg) 627 { 628 u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status); 629 u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio); 630 u8 i, tc, err; 631 632 /* CEE PG data to ETS config */ 633 dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; 634 635 /* Note that the FW creates the oper_prio_tc nibbles reversed 636 * from those in the CEE Priority Group sub-TLV. 637 */ 638 for (i = 0; i < 4; i++) { 639 tc = (u8)((cee_cfg->oper_prio_tc[i] & 640 I40E_CEE_PGID_PRIO_0_MASK) >> 641 I40E_CEE_PGID_PRIO_0_SHIFT); 642 dcbcfg->etscfg.prioritytable[i*2] = tc; 643 tc = (u8)((cee_cfg->oper_prio_tc[i] & 644 I40E_CEE_PGID_PRIO_1_MASK) >> 645 I40E_CEE_PGID_PRIO_1_SHIFT); 646 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; 647 } 648 649 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 650 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; 651 652 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { 653 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { 654 /* Map it to next empty TC */ 655 dcbcfg->etscfg.prioritytable[i] = 656 cee_cfg->oper_num_tc - 1; 657 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; 658 } else { 659 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; 660 } 661 } 662 663 /* CEE PFC data to ETS config */ 664 dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; 665 dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; 666 667 status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >> 668 I40E_AQC_CEE_APP_STATUS_SHIFT; 669 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 670 /* Add APPs if Error is False */ 671 if (!err) { 672 /* CEE operating configuration supports FCoE/iSCSI/FIP only */ 673 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS; 674 675 /* FCoE APP */ 676 dcbcfg->app[0].priority = 677 (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> 678 I40E_AQC_CEE_APP_FCOE_SHIFT; 679 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE; 680 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE; 681 682 /* iSCSI APP */ 683 dcbcfg->app[1].priority = 684 (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> 685 I40E_AQC_CEE_APP_ISCSI_SHIFT; 686 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP; 687 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI; 688 689 /* FIP APP */ 690 dcbcfg->app[2].priority = 691 (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> 692 I40E_AQC_CEE_APP_FIP_SHIFT; 693 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE; 694 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP; 695 } 696 } 697 698 /** 699 * i40e_cee_to_dcb_config 700 * @cee_cfg: pointer to CEE configuration struct 701 * @dcbcfg: DCB configuration struct 702 * 703 * Convert CEE configuration from firmware to DCB configuration 704 **/ 705 static void i40e_cee_to_dcb_config( 706 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg, 707 struct i40e_dcbx_config *dcbcfg) 708 { 709 u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status); 710 u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio); 711 u8 i, tc, err, sync, oper; 712 713 /* CEE PG data to ETS config */ 714 dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; 715 716 /* Note that the FW creates the oper_prio_tc nibbles reversed 717 * from those in the CEE Priority Group sub-TLV. 718 */ 719 for (i = 0; i < 4; i++) { 720 tc = (u8)((cee_cfg->oper_prio_tc[i] & 721 I40E_CEE_PGID_PRIO_0_MASK) >> 722 I40E_CEE_PGID_PRIO_0_SHIFT); 723 dcbcfg->etscfg.prioritytable[i*2] = tc; 724 tc = (u8)((cee_cfg->oper_prio_tc[i] & 725 I40E_CEE_PGID_PRIO_1_MASK) >> 726 I40E_CEE_PGID_PRIO_1_SHIFT); 727 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; 728 } 729 730 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 731 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; 732 733 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { 734 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { 735 /* Map it to next empty TC */ 736 dcbcfg->etscfg.prioritytable[i] = 737 cee_cfg->oper_num_tc - 1; 738 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; 739 } else { 740 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; 741 } 742 } 743 744 /* CEE PFC data to ETS config */ 745 dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; 746 dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; 747 748 i = 0; 749 status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >> 750 I40E_AQC_CEE_FCOE_STATUS_SHIFT; 751 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 752 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 753 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 754 /* Add FCoE APP if Error is False and Oper/Sync is True */ 755 if (!err && sync && oper) { 756 /* FCoE APP */ 757 dcbcfg->app[i].priority = 758 (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> 759 I40E_AQC_CEE_APP_FCOE_SHIFT; 760 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 761 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE; 762 i++; 763 } 764 765 status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >> 766 I40E_AQC_CEE_ISCSI_STATUS_SHIFT; 767 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 768 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 769 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 770 /* Add iSCSI APP if Error is False and Oper/Sync is True */ 771 if (!err && sync && oper) { 772 /* iSCSI APP */ 773 dcbcfg->app[i].priority = 774 (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> 775 I40E_AQC_CEE_APP_ISCSI_SHIFT; 776 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; 777 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI; 778 i++; 779 } 780 781 status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >> 782 I40E_AQC_CEE_FIP_STATUS_SHIFT; 783 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 784 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 785 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 786 /* Add FIP APP if Error is False and Oper/Sync is True */ 787 if (!err && sync && oper) { 788 /* FIP APP */ 789 dcbcfg->app[i].priority = 790 (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> 791 I40E_AQC_CEE_APP_FIP_SHIFT; 792 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 793 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP; 794 i++; 795 } 796 dcbcfg->numapps = i; 797 } 798 799 /** 800 * i40e_get_ieee_dcb_config 801 * @hw: pointer to the hw struct 802 * 803 * Get IEEE mode DCB configuration from the Firmware 804 **/ 805 static enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw) 806 { 807 enum i40e_status_code ret = I40E_SUCCESS; 808 809 /* IEEE mode */ 810 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE; 811 /* Get Local DCB Config */ 812 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, 813 &hw->local_dcbx_config); 814 if (ret) 815 goto out; 816 817 /* Get Remote DCB Config */ 818 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, 819 I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, 820 &hw->remote_dcbx_config); 821 /* Don't treat ENOENT as an error for Remote MIBs */ 822 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 823 ret = I40E_SUCCESS; 824 825 out: 826 return ret; 827 } 828 829 /** 830 * i40e_get_dcb_config 831 * @hw: pointer to the hw struct 832 * 833 * Get DCB configuration from the Firmware 834 **/ 835 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw) 836 { 837 enum i40e_status_code ret = I40E_SUCCESS; 838 struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg; 839 struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg; 840 841 /* If Firmware version < v4.33 on X710/XL710, IEEE only */ 842 if ((hw->mac.type == I40E_MAC_XL710) && 843 (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 844 (hw->aq.fw_maj_ver < 4))) 845 return i40e_get_ieee_dcb_config(hw); 846 847 /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */ 848 if ((hw->mac.type == I40E_MAC_XL710) && 849 ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) { 850 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg, 851 sizeof(cee_v1_cfg), NULL); 852 if (ret == I40E_SUCCESS) { 853 /* CEE mode */ 854 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; 855 hw->local_dcbx_config.tlv_status = 856 LE16_TO_CPU(cee_v1_cfg.tlv_status); 857 i40e_cee_to_dcb_v1_config(&cee_v1_cfg, 858 &hw->local_dcbx_config); 859 } 860 } else { 861 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg, 862 sizeof(cee_cfg), NULL); 863 if (ret == I40E_SUCCESS) { 864 /* CEE mode */ 865 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; 866 hw->local_dcbx_config.tlv_status = 867 LE32_TO_CPU(cee_cfg.tlv_status); 868 i40e_cee_to_dcb_config(&cee_cfg, 869 &hw->local_dcbx_config); 870 } 871 } 872 873 /* CEE mode not enabled try querying IEEE data */ 874 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 875 return i40e_get_ieee_dcb_config(hw); 876 877 if (ret != I40E_SUCCESS) 878 goto out; 879 880 /* Get CEE DCB Desired Config */ 881 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, 882 &hw->desired_dcbx_config); 883 if (ret) 884 goto out; 885 886 /* Get Remote DCB Config */ 887 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, 888 I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, 889 &hw->remote_dcbx_config); 890 /* Don't treat ENOENT as an error for Remote MIBs */ 891 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 892 ret = I40E_SUCCESS; 893 894 out: 895 return ret; 896 } 897 898 /** 899 * i40e_init_dcb 900 * @hw: pointer to the hw struct 901 * @enable_mib_change: enable mib change event 902 * 903 * Update DCB configuration from the Firmware 904 **/ 905 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change) 906 { 907 enum i40e_status_code ret = I40E_SUCCESS; 908 struct i40e_lldp_variables lldp_cfg; 909 u8 adminstatus = 0; 910 911 if (!hw->func_caps.dcb) 912 return I40E_NOT_SUPPORTED; 913 914 /* Read LLDP NVM area */ 915 if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) { 916 u8 offset = 0; 917 918 if (hw->mac.type == I40E_MAC_XL710) 919 offset = I40E_LLDP_CURRENT_STATUS_XL710_OFFSET; 920 else if (hw->mac.type == I40E_MAC_X722) 921 offset = I40E_LLDP_CURRENT_STATUS_X722_OFFSET; 922 else 923 return I40E_NOT_SUPPORTED; 924 925 ret = i40e_read_nvm_module_data(hw, 926 I40E_SR_EMP_SR_SETTINGS_PTR, 927 offset, 928 I40E_LLDP_CURRENT_STATUS_OFFSET, 929 I40E_LLDP_CURRENT_STATUS_SIZE, 930 &lldp_cfg.adminstatus); 931 } else { 932 ret = i40e_read_lldp_cfg(hw, &lldp_cfg); 933 } 934 if (ret) 935 return I40E_ERR_NOT_READY; 936 937 /* Get the LLDP AdminStatus for the current port */ 938 adminstatus = lldp_cfg.adminstatus >> (hw->port * 4); 939 adminstatus &= 0xF; 940 941 /* LLDP agent disabled */ 942 if (!adminstatus) { 943 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED; 944 return I40E_ERR_NOT_READY; 945 } 946 947 /* Get DCBX status */ 948 ret = i40e_get_dcbx_status(hw, &hw->dcbx_status); 949 if (ret) 950 return ret; 951 952 /* Check the DCBX Status */ 953 if (hw->dcbx_status == I40E_DCBX_STATUS_DONE || 954 hw->dcbx_status == I40E_DCBX_STATUS_IN_PROGRESS) { 955 /* Get current DCBX configuration */ 956 ret = i40e_get_dcb_config(hw); 957 if (ret) 958 return ret; 959 } else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) { 960 return I40E_ERR_NOT_READY; 961 } 962 963 /* Configure the LLDP MIB change event */ 964 if (enable_mib_change) 965 ret = i40e_aq_cfg_lldp_mib_change_event(hw, TRUE, NULL); 966 967 return ret; 968 } 969 970 /** 971 * i40e_get_fw_lldp_status 972 * @hw: pointer to the hw struct 973 * @lldp_status: pointer to the status enum 974 * 975 * Get status of FW Link Layer Discovery Protocol (LLDP) Agent. 976 * Status of agent is reported via @lldp_status parameter. 977 **/ 978 enum i40e_status_code 979 i40e_get_fw_lldp_status(struct i40e_hw *hw, 980 enum i40e_get_fw_lldp_status_resp *lldp_status) 981 { 982 enum i40e_status_code ret; 983 struct i40e_virt_mem mem; 984 u8 *lldpmib; 985 986 if (!lldp_status) 987 return I40E_ERR_PARAM; 988 989 /* Allocate buffer for the LLDPDU */ 990 ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); 991 if (ret) 992 return ret; 993 994 lldpmib = (u8 *)mem.va; 995 ret = i40e_aq_get_lldp_mib(hw, 0, 0, (void *)lldpmib, 996 I40E_LLDPDU_SIZE, NULL, NULL, NULL); 997 998 if (ret == I40E_SUCCESS) { 999 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED; 1000 } else if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) { 1001 /* MIB is not available yet but the agent is running */ 1002 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED; 1003 ret = I40E_SUCCESS; 1004 } else if (hw->aq.asq_last_status == I40E_AQ_RC_EPERM) { 1005 *lldp_status = I40E_GET_FW_LLDP_STATUS_DISABLED; 1006 ret = I40E_SUCCESS; 1007 } 1008 1009 i40e_free_virt_mem(hw, &mem); 1010 return ret; 1011 } 1012 1013 1014 /** 1015 * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format 1016 * @tlv: Fill the ETS config data in IEEE format 1017 * @dcbcfg: Local store which holds the DCB Config 1018 * 1019 * Prepare IEEE 802.1Qaz ETS CFG TLV 1020 **/ 1021 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv, 1022 struct i40e_dcbx_config *dcbcfg) 1023 { 1024 u8 priority0, priority1, maxtcwilling = 0; 1025 struct i40e_dcb_ets_config *etscfg; 1026 u16 offset = 0, typelength, i; 1027 u8 *buf = tlv->tlvinfo; 1028 u32 ouisubtype; 1029 1030 typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | 1031 I40E_IEEE_ETS_TLV_LENGTH); 1032 tlv->typelength = I40E_HTONS(typelength); 1033 1034 ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | 1035 I40E_IEEE_SUBTYPE_ETS_CFG); 1036 tlv->ouisubtype = I40E_HTONL(ouisubtype); 1037 1038 /* First Octet post subtype 1039 * -------------------------- 1040 * |will-|CBS | Re- | Max | 1041 * |ing | |served| TCs | 1042 * -------------------------- 1043 * |1bit | 1bit|3 bits|3bits| 1044 */ 1045 etscfg = &dcbcfg->etscfg; 1046 if (etscfg->willing) 1047 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT); 1048 maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK; 1049 buf[offset] = maxtcwilling; 1050 1051 /* Move offset to Priority Assignment Table */ 1052 offset++; 1053 1054 /* Priority Assignment Table (4 octets) 1055 * Octets:| 1 | 2 | 3 | 4 | 1056 * ----------------------------------------- 1057 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| 1058 * ----------------------------------------- 1059 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| 1060 * ----------------------------------------- 1061 */ 1062 for (i = 0; i < 4; i++) { 1063 priority0 = etscfg->prioritytable[i * 2] & 0xF; 1064 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF; 1065 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) | 1066 priority1; 1067 offset++; 1068 } 1069 1070 /* TC Bandwidth Table (8 octets) 1071 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1072 * --------------------------------- 1073 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 1074 * --------------------------------- 1075 */ 1076 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 1077 buf[offset++] = etscfg->tcbwtable[i]; 1078 1079 /* TSA Assignment Table (8 octets) 1080 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1081 * --------------------------------- 1082 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 1083 * --------------------------------- 1084 */ 1085 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 1086 buf[offset++] = etscfg->tsatable[i]; 1087 } 1088 1089 /** 1090 * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format 1091 * @tlv: Fill ETS Recommended TLV in IEEE format 1092 * @dcbcfg: Local store which holds the DCB Config 1093 * 1094 * Prepare IEEE 802.1Qaz ETS REC TLV 1095 **/ 1096 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv, 1097 struct i40e_dcbx_config *dcbcfg) 1098 { 1099 struct i40e_dcb_ets_config *etsrec; 1100 u16 offset = 0, typelength, i; 1101 u8 priority0, priority1; 1102 u8 *buf = tlv->tlvinfo; 1103 u32 ouisubtype; 1104 1105 typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | 1106 I40E_IEEE_ETS_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_ETS_REC); 1111 tlv->ouisubtype = I40E_HTONL(ouisubtype); 1112 1113 etsrec = &dcbcfg->etsrec; 1114 /* First Octet is reserved */ 1115 /* Move offset to Priority Assignment Table */ 1116 offset++; 1117 1118 /* Priority Assignment Table (4 octets) 1119 * Octets:| 1 | 2 | 3 | 4 | 1120 * ----------------------------------------- 1121 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| 1122 * ----------------------------------------- 1123 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| 1124 * ----------------------------------------- 1125 */ 1126 for (i = 0; i < 4; i++) { 1127 priority0 = etsrec->prioritytable[i * 2] & 0xF; 1128 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF; 1129 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) | 1130 priority1; 1131 offset++; 1132 } 1133 1134 /* TC Bandwidth Table (8 octets) 1135 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1136 * --------------------------------- 1137 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 1138 * --------------------------------- 1139 */ 1140 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 1141 buf[offset++] = etsrec->tcbwtable[i]; 1142 1143 /* TSA Assignment Table (8 octets) 1144 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1145 * --------------------------------- 1146 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 1147 * --------------------------------- 1148 */ 1149 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 1150 buf[offset++] = etsrec->tsatable[i]; 1151 } 1152 1153 /** 1154 * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format 1155 * @tlv: Fill PFC TLV in IEEE format 1156 * @dcbcfg: Local store to get PFC CFG data 1157 * 1158 * Prepare IEEE 802.1Qaz PFC CFG TLV 1159 **/ 1160 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv, 1161 struct i40e_dcbx_config *dcbcfg) 1162 { 1163 u8 *buf = tlv->tlvinfo; 1164 u32 ouisubtype; 1165 u16 typelength; 1166 1167 typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | 1168 I40E_IEEE_PFC_TLV_LENGTH); 1169 tlv->typelength = I40E_HTONS(typelength); 1170 1171 ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | 1172 I40E_IEEE_SUBTYPE_PFC_CFG); 1173 tlv->ouisubtype = I40E_HTONL(ouisubtype); 1174 1175 /* ---------------------------------------- 1176 * |will-|MBC | Re- | PFC | PFC Enable | 1177 * |ing | |served| cap | | 1178 * ----------------------------------------- 1179 * |1bit | 1bit|2 bits|4bits| 1 octet | 1180 */ 1181 if (dcbcfg->pfc.willing) 1182 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT); 1183 1184 if (dcbcfg->pfc.mbc) 1185 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT); 1186 1187 buf[0] |= dcbcfg->pfc.pfccap & 0xF; 1188 buf[1] = dcbcfg->pfc.pfcenable; 1189 } 1190 1191 /** 1192 * i40e_add_ieee_app_pri_tlv - Prepare APP TLV in IEEE format 1193 * @tlv: Fill APP TLV in IEEE format 1194 * @dcbcfg: Local store to get APP CFG data 1195 * 1196 * Prepare IEEE 802.1Qaz APP CFG TLV 1197 **/ 1198 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv, 1199 struct i40e_dcbx_config *dcbcfg) 1200 { 1201 u16 typelength, length, offset = 0; 1202 u8 priority, selector, i = 0; 1203 u8 *buf = tlv->tlvinfo; 1204 u32 ouisubtype; 1205 1206 /* No APP TLVs then just return */ 1207 if (dcbcfg->numapps == 0) 1208 return; 1209 ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) | 1210 I40E_IEEE_SUBTYPE_APP_PRI); 1211 tlv->ouisubtype = I40E_HTONL(ouisubtype); 1212 1213 /* Move offset to App Priority Table */ 1214 offset++; 1215 /* Application Priority Table (3 octets) 1216 * Octets:| 1 | 2 | 3 | 1217 * ----------------------------------------- 1218 * |Priority|Rsrvd| Sel | Protocol ID | 1219 * ----------------------------------------- 1220 * Bits:|23 21|20 19|18 16|15 0| 1221 * ----------------------------------------- 1222 */ 1223 while (i < dcbcfg->numapps) { 1224 priority = dcbcfg->app[i].priority & 0x7; 1225 selector = dcbcfg->app[i].selector & 0x7; 1226 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector; 1227 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF; 1228 buf[offset + 2] = dcbcfg->app[i].protocolid & 0xFF; 1229 /* Move to next app */ 1230 offset += 3; 1231 i++; 1232 if (i >= I40E_DCBX_MAX_APPS) 1233 break; 1234 } 1235 /* length includes size of ouisubtype + 1 reserved + 3*numapps */ 1236 length = sizeof(tlv->ouisubtype) + 1 + (i*3); 1237 typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) | 1238 (length & 0x1FF)); 1239 tlv->typelength = I40E_HTONS(typelength); 1240 } 1241 1242 /** 1243 * i40e_add_dcb_tlv - Add all IEEE TLVs 1244 * @tlv: pointer to org tlv 1245 * 1246 * add tlv information 1247 **/ 1248 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv, 1249 struct i40e_dcbx_config *dcbcfg, 1250 u16 tlvid) 1251 { 1252 switch (tlvid) { 1253 case I40E_IEEE_TLV_ID_ETS_CFG: 1254 i40e_add_ieee_ets_tlv(tlv, dcbcfg); 1255 break; 1256 case I40E_IEEE_TLV_ID_ETS_REC: 1257 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg); 1258 break; 1259 case I40E_IEEE_TLV_ID_PFC_CFG: 1260 i40e_add_ieee_pfc_tlv(tlv, dcbcfg); 1261 break; 1262 case I40E_IEEE_TLV_ID_APP_PRI: 1263 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg); 1264 break; 1265 default: 1266 break; 1267 } 1268 } 1269 1270 /** 1271 * i40e_set_dcb_config - Set the local LLDP MIB to FW 1272 * @hw: pointer to the hw struct 1273 * 1274 * Set DCB configuration to the Firmware 1275 **/ 1276 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw) 1277 { 1278 enum i40e_status_code ret = I40E_SUCCESS; 1279 struct i40e_dcbx_config *dcbcfg; 1280 struct i40e_virt_mem mem; 1281 u8 mib_type, *lldpmib; 1282 u16 miblen; 1283 1284 /* update the hw local config */ 1285 dcbcfg = &hw->local_dcbx_config; 1286 /* Allocate the LLDPDU */ 1287 ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); 1288 if (ret) 1289 return ret; 1290 1291 mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB; 1292 if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) { 1293 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS << 1294 SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT; 1295 } 1296 lldpmib = (u8 *)mem.va; 1297 ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg); 1298 ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL); 1299 1300 i40e_free_virt_mem(hw, &mem); 1301 return ret; 1302 } 1303 1304 /** 1305 * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format 1306 * @lldpmib: pointer to mib to be output 1307 * @miblen: pointer to u16 for length of lldpmib 1308 * @dcbcfg: store for LLDPDU data 1309 * 1310 * send DCB configuration to FW 1311 **/ 1312 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen, 1313 struct i40e_dcbx_config *dcbcfg) 1314 { 1315 u16 length, offset = 0, tlvid = I40E_TLV_ID_START; 1316 enum i40e_status_code ret = I40E_SUCCESS; 1317 struct i40e_lldp_org_tlv *tlv; 1318 u16 typelength; 1319 1320 tlv = (struct i40e_lldp_org_tlv *)lldpmib; 1321 while (1) { 1322 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++); 1323 typelength = I40E_NTOHS(tlv->typelength); 1324 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 1325 I40E_LLDP_TLV_LEN_SHIFT); 1326 if (length) 1327 offset += length + 2; 1328 /* END TLV or beyond LLDPDU size */ 1329 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) || 1330 (offset > I40E_LLDPDU_SIZE)) 1331 break; 1332 /* Move to next TLV */ 1333 if (length) 1334 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv + 1335 sizeof(tlv->typelength) + length); 1336 } 1337 *miblen = offset; 1338 return ret; 1339 } 1340 1341 1342 /** 1343 * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM 1344 * @hw: pointer to the HW structure 1345 * @lldp_cfg: pointer to hold lldp configuration variables 1346 * @module: address of the module pointer 1347 * @word_offset: offset of LLDP configuration 1348 * 1349 * Reads the LLDP configuration data from NVM using passed addresses 1350 **/ 1351 static enum i40e_status_code _i40e_read_lldp_cfg(struct i40e_hw *hw, 1352 struct i40e_lldp_variables *lldp_cfg, 1353 u8 module, u32 word_offset) 1354 { 1355 u32 address, offset = (2 * word_offset); 1356 enum i40e_status_code ret; 1357 __le16 raw_mem; 1358 u16 mem; 1359 1360 ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 1361 if (ret != I40E_SUCCESS) 1362 return ret; 1363 1364 ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem, 1365 TRUE, NULL); 1366 i40e_release_nvm(hw); 1367 if (ret != I40E_SUCCESS) 1368 return ret; 1369 1370 mem = LE16_TO_CPU(raw_mem); 1371 /* Check if this pointer needs to be read in word size or 4K sector 1372 * units. 1373 */ 1374 if (mem & I40E_PTR_TYPE) 1375 address = (0x7FFF & mem) * 4096; 1376 else 1377 address = (0x7FFF & mem) * 2; 1378 1379 ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 1380 if (ret != I40E_SUCCESS) 1381 goto err_lldp_cfg; 1382 1383 ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem, 1384 TRUE, NULL); 1385 i40e_release_nvm(hw); 1386 if (ret != I40E_SUCCESS) 1387 return ret; 1388 1389 mem = LE16_TO_CPU(raw_mem); 1390 offset = mem + word_offset; 1391 offset *= 2; 1392 1393 ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 1394 if (ret != I40E_SUCCESS) 1395 goto err_lldp_cfg; 1396 1397 ret = i40e_aq_read_nvm(hw, 0, address + offset, 1398 sizeof(struct i40e_lldp_variables), lldp_cfg, 1399 TRUE, NULL); 1400 i40e_release_nvm(hw); 1401 1402 err_lldp_cfg: 1403 return ret; 1404 } 1405 1406 /** 1407 * i40e_read_lldp_cfg - read LLDP Configuration data from NVM 1408 * @hw: pointer to the HW structure 1409 * @lldp_cfg: pointer to hold lldp configuration variables 1410 * 1411 * Reads the LLDP configuration data from NVM 1412 **/ 1413 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw, 1414 struct i40e_lldp_variables *lldp_cfg) 1415 { 1416 enum i40e_status_code ret = I40E_SUCCESS; 1417 u32 mem; 1418 1419 if (!lldp_cfg) 1420 return I40E_ERR_PARAM; 1421 1422 ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 1423 if (ret != I40E_SUCCESS) 1424 return ret; 1425 1426 ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem), 1427 &mem, TRUE, NULL); 1428 i40e_release_nvm(hw); 1429 if (ret != I40E_SUCCESS) 1430 return ret; 1431 1432 /* Read a bit that holds information whether we are running flat or 1433 * structured NVM image. Flat image has LLDP configuration in shadow 1434 * ram, so there is a need to pass different addresses for both cases. 1435 */ 1436 if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) { 1437 /* Flat NVM case */ 1438 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR, 1439 I40E_SR_LLDP_CFG_PTR); 1440 } else { 1441 /* Good old structured NVM image */ 1442 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR, 1443 I40E_NVM_LLDP_CFG_PTR); 1444 } 1445 1446 return ret; 1447 } 1448