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