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