1 // SPDX-License-Identifier: GPL-2.0 2 /******************************************************************************* 3 * 4 * Intel Ethernet Controller XL710 Family Linux Driver 5 * Copyright(c) 2013 - 2017 Intel Corporation. 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms and conditions of the GNU General Public License, 9 * version 2, as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * The full GNU General Public License is included in this distribution in 20 * the file called "COPYING". 21 * 22 * Contact Information: 23 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 25 * 26 ******************************************************************************/ 27 28 #include "i40e_adminq.h" 29 #include "i40e_prototype.h" 30 #include "i40e_dcb.h" 31 32 /** 33 * i40e_get_dcbx_status 34 * @hw: pointer to the hw struct 35 * @status: Embedded DCBX Engine Status 36 * 37 * Get the DCBX status from the Firmware 38 **/ 39 i40e_status i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status) 40 { 41 u32 reg; 42 43 if (!status) 44 return I40E_ERR_PARAM; 45 46 reg = rd32(hw, I40E_PRTDCB_GENS); 47 *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >> 48 I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT); 49 50 return 0; 51 } 52 53 /** 54 * i40e_parse_ieee_etscfg_tlv 55 * @tlv: IEEE 802.1Qaz ETS CFG TLV 56 * @dcbcfg: Local store to update ETS CFG data 57 * 58 * Parses IEEE 802.1Qaz ETS CFG TLV 59 **/ 60 static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv, 61 struct i40e_dcbx_config *dcbcfg) 62 { 63 struct i40e_dcb_ets_config *etscfg; 64 u8 *buf = tlv->tlvinfo; 65 u16 offset = 0; 66 u8 priority; 67 int i; 68 69 /* First Octet post subtype 70 * -------------------------- 71 * |will-|CBS | Re- | Max | 72 * |ing | |served| TCs | 73 * -------------------------- 74 * |1bit | 1bit|3 bits|3bits| 75 */ 76 etscfg = &dcbcfg->etscfg; 77 etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >> 78 I40E_IEEE_ETS_WILLING_SHIFT); 79 etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >> 80 I40E_IEEE_ETS_CBS_SHIFT); 81 etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >> 82 I40E_IEEE_ETS_MAXTC_SHIFT); 83 84 /* Move offset to Priority Assignment Table */ 85 offset++; 86 87 /* Priority Assignment Table (4 octets) 88 * Octets:| 1 | 2 | 3 | 4 | 89 * ----------------------------------------- 90 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| 91 * ----------------------------------------- 92 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| 93 * ----------------------------------------- 94 */ 95 for (i = 0; i < 4; i++) { 96 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >> 97 I40E_IEEE_ETS_PRIO_1_SHIFT); 98 etscfg->prioritytable[i * 2] = priority; 99 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >> 100 I40E_IEEE_ETS_PRIO_0_SHIFT); 101 etscfg->prioritytable[i * 2 + 1] = priority; 102 offset++; 103 } 104 105 /* TC Bandwidth Table (8 octets) 106 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 107 * --------------------------------- 108 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 109 * --------------------------------- 110 */ 111 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 112 etscfg->tcbwtable[i] = buf[offset++]; 113 114 /* TSA Assignment Table (8 octets) 115 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 116 * --------------------------------- 117 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 118 * --------------------------------- 119 */ 120 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 121 etscfg->tsatable[i] = buf[offset++]; 122 } 123 124 /** 125 * i40e_parse_ieee_etsrec_tlv 126 * @tlv: IEEE 802.1Qaz ETS REC TLV 127 * @dcbcfg: Local store to update ETS REC data 128 * 129 * Parses IEEE 802.1Qaz ETS REC TLV 130 **/ 131 static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv, 132 struct i40e_dcbx_config *dcbcfg) 133 { 134 u8 *buf = tlv->tlvinfo; 135 u16 offset = 0; 136 u8 priority; 137 int i; 138 139 /* Move offset to priority table */ 140 offset++; 141 142 /* Priority Assignment Table (4 octets) 143 * Octets:| 1 | 2 | 3 | 4 | 144 * ----------------------------------------- 145 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| 146 * ----------------------------------------- 147 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| 148 * ----------------------------------------- 149 */ 150 for (i = 0; i < 4; i++) { 151 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >> 152 I40E_IEEE_ETS_PRIO_1_SHIFT); 153 dcbcfg->etsrec.prioritytable[i*2] = priority; 154 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >> 155 I40E_IEEE_ETS_PRIO_0_SHIFT); 156 dcbcfg->etsrec.prioritytable[i*2 + 1] = priority; 157 offset++; 158 } 159 160 /* TC Bandwidth Table (8 octets) 161 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 162 * --------------------------------- 163 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 164 * --------------------------------- 165 */ 166 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 167 dcbcfg->etsrec.tcbwtable[i] = buf[offset++]; 168 169 /* TSA Assignment Table (8 octets) 170 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 171 * --------------------------------- 172 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7| 173 * --------------------------------- 174 */ 175 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 176 dcbcfg->etsrec.tsatable[i] = buf[offset++]; 177 } 178 179 /** 180 * i40e_parse_ieee_pfccfg_tlv 181 * @tlv: IEEE 802.1Qaz PFC CFG TLV 182 * @dcbcfg: Local store to update PFC CFG data 183 * 184 * Parses IEEE 802.1Qaz PFC CFG TLV 185 **/ 186 static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv, 187 struct i40e_dcbx_config *dcbcfg) 188 { 189 u8 *buf = tlv->tlvinfo; 190 191 /* ---------------------------------------- 192 * |will-|MBC | Re- | PFC | PFC Enable | 193 * |ing | |served| cap | | 194 * ----------------------------------------- 195 * |1bit | 1bit|2 bits|4bits| 1 octet | 196 */ 197 dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >> 198 I40E_IEEE_PFC_WILLING_SHIFT); 199 dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >> 200 I40E_IEEE_PFC_MBC_SHIFT); 201 dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >> 202 I40E_IEEE_PFC_CAP_SHIFT); 203 dcbcfg->pfc.pfcenable = buf[1]; 204 } 205 206 /** 207 * i40e_parse_ieee_app_tlv 208 * @tlv: IEEE 802.1Qaz APP TLV 209 * @dcbcfg: Local store to update APP PRIO data 210 * 211 * Parses IEEE 802.1Qaz APP PRIO TLV 212 **/ 213 static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv, 214 struct i40e_dcbx_config *dcbcfg) 215 { 216 u16 typelength; 217 u16 offset = 0; 218 u16 length; 219 int i = 0; 220 u8 *buf; 221 222 typelength = ntohs(tlv->typelength); 223 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 224 I40E_LLDP_TLV_LEN_SHIFT); 225 buf = tlv->tlvinfo; 226 227 /* The App priority table starts 5 octets after TLV header */ 228 length -= (sizeof(tlv->ouisubtype) + 1); 229 230 /* Move offset to App Priority Table */ 231 offset++; 232 233 /* Application Priority Table (3 octets) 234 * Octets:| 1 | 2 | 3 | 235 * ----------------------------------------- 236 * |Priority|Rsrvd| Sel | Protocol ID | 237 * ----------------------------------------- 238 * Bits:|23 21|20 19|18 16|15 0| 239 * ----------------------------------------- 240 */ 241 while (offset < length) { 242 dcbcfg->app[i].priority = (u8)((buf[offset] & 243 I40E_IEEE_APP_PRIO_MASK) >> 244 I40E_IEEE_APP_PRIO_SHIFT); 245 dcbcfg->app[i].selector = (u8)((buf[offset] & 246 I40E_IEEE_APP_SEL_MASK) >> 247 I40E_IEEE_APP_SEL_SHIFT); 248 dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) | 249 buf[offset + 2]; 250 /* Move to next app */ 251 offset += 3; 252 i++; 253 if (i >= I40E_DCBX_MAX_APPS) 254 break; 255 } 256 257 dcbcfg->numapps = i; 258 } 259 260 /** 261 * i40e_parse_ieee_etsrec_tlv 262 * @tlv: IEEE 802.1Qaz TLV 263 * @dcbcfg: Local store to update ETS REC data 264 * 265 * Get the TLV subtype and send it to parsing function 266 * based on the subtype value 267 **/ 268 static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv, 269 struct i40e_dcbx_config *dcbcfg) 270 { 271 u32 ouisubtype; 272 u8 subtype; 273 274 ouisubtype = ntohl(tlv->ouisubtype); 275 subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >> 276 I40E_LLDP_TLV_SUBTYPE_SHIFT); 277 switch (subtype) { 278 case I40E_IEEE_SUBTYPE_ETS_CFG: 279 i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg); 280 break; 281 case I40E_IEEE_SUBTYPE_ETS_REC: 282 i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg); 283 break; 284 case I40E_IEEE_SUBTYPE_PFC_CFG: 285 i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg); 286 break; 287 case I40E_IEEE_SUBTYPE_APP_PRI: 288 i40e_parse_ieee_app_tlv(tlv, dcbcfg); 289 break; 290 default: 291 break; 292 } 293 } 294 295 /** 296 * i40e_parse_cee_pgcfg_tlv 297 * @tlv: CEE DCBX PG CFG TLV 298 * @dcbcfg: Local store to update ETS CFG data 299 * 300 * Parses CEE DCBX PG CFG TLV 301 **/ 302 static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv, 303 struct i40e_dcbx_config *dcbcfg) 304 { 305 struct i40e_dcb_ets_config *etscfg; 306 u8 *buf = tlv->tlvinfo; 307 u16 offset = 0; 308 u8 priority; 309 int i; 310 311 etscfg = &dcbcfg->etscfg; 312 313 if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK) 314 etscfg->willing = 1; 315 316 etscfg->cbs = 0; 317 /* Priority Group Table (4 octets) 318 * Octets:| 1 | 2 | 3 | 4 | 319 * ----------------------------------------- 320 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7| 321 * ----------------------------------------- 322 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0| 323 * ----------------------------------------- 324 */ 325 for (i = 0; i < 4; i++) { 326 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >> 327 I40E_CEE_PGID_PRIO_1_SHIFT); 328 etscfg->prioritytable[i * 2] = priority; 329 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >> 330 I40E_CEE_PGID_PRIO_0_SHIFT); 331 etscfg->prioritytable[i * 2 + 1] = priority; 332 offset++; 333 } 334 335 /* PG Percentage Table (8 octets) 336 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 337 * --------------------------------- 338 * |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7| 339 * --------------------------------- 340 */ 341 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 342 etscfg->tcbwtable[i] = buf[offset++]; 343 344 /* Number of TCs supported (1 octet) */ 345 etscfg->maxtcs = buf[offset]; 346 } 347 348 /** 349 * i40e_parse_cee_pfccfg_tlv 350 * @tlv: CEE DCBX PFC CFG TLV 351 * @dcbcfg: Local store to update PFC CFG data 352 * 353 * Parses CEE DCBX PFC CFG TLV 354 **/ 355 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv, 356 struct i40e_dcbx_config *dcbcfg) 357 { 358 u8 *buf = tlv->tlvinfo; 359 360 if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK) 361 dcbcfg->pfc.willing = 1; 362 363 /* ------------------------ 364 * | PFC Enable | PFC TCs | 365 * ------------------------ 366 * | 1 octet | 1 octet | 367 */ 368 dcbcfg->pfc.pfcenable = buf[0]; 369 dcbcfg->pfc.pfccap = buf[1]; 370 } 371 372 /** 373 * i40e_parse_cee_app_tlv 374 * @tlv: CEE DCBX APP TLV 375 * @dcbcfg: Local store to update APP PRIO data 376 * 377 * Parses CEE DCBX APP PRIO TLV 378 **/ 379 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv, 380 struct i40e_dcbx_config *dcbcfg) 381 { 382 u16 length, typelength, offset = 0; 383 struct i40e_cee_app_prio *app; 384 u8 i; 385 386 typelength = ntohs(tlv->hdr.typelen); 387 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 388 I40E_LLDP_TLV_LEN_SHIFT); 389 390 dcbcfg->numapps = length / sizeof(*app); 391 392 if (!dcbcfg->numapps) 393 return; 394 if (dcbcfg->numapps > I40E_DCBX_MAX_APPS) 395 dcbcfg->numapps = I40E_DCBX_MAX_APPS; 396 397 for (i = 0; i < dcbcfg->numapps; i++) { 398 u8 up, selector; 399 400 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset); 401 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) { 402 if (app->prio_map & BIT(up)) 403 break; 404 } 405 dcbcfg->app[i].priority = up; 406 407 /* Get Selector from lower 2 bits, and convert to IEEE */ 408 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK); 409 switch (selector) { 410 case I40E_CEE_APP_SEL_ETHTYPE: 411 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 412 break; 413 case I40E_CEE_APP_SEL_TCPIP: 414 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; 415 break; 416 default: 417 /* Keep selector as it is for unknown types */ 418 dcbcfg->app[i].selector = selector; 419 } 420 421 dcbcfg->app[i].protocolid = ntohs(app->protocol); 422 /* Move to next app */ 423 offset += sizeof(*app); 424 } 425 } 426 427 /** 428 * i40e_parse_cee_tlv 429 * @tlv: CEE DCBX TLV 430 * @dcbcfg: Local store to update DCBX config data 431 * 432 * Get the TLV subtype and send it to parsing function 433 * based on the subtype value 434 **/ 435 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv, 436 struct i40e_dcbx_config *dcbcfg) 437 { 438 u16 len, tlvlen, sublen, typelength; 439 struct i40e_cee_feat_tlv *sub_tlv; 440 u8 subtype, feat_tlv_count = 0; 441 u32 ouisubtype; 442 443 ouisubtype = ntohl(tlv->ouisubtype); 444 subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >> 445 I40E_LLDP_TLV_SUBTYPE_SHIFT); 446 /* Return if not CEE DCBX */ 447 if (subtype != I40E_CEE_DCBX_TYPE) 448 return; 449 450 typelength = ntohs(tlv->typelength); 451 tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 452 I40E_LLDP_TLV_LEN_SHIFT); 453 len = sizeof(tlv->typelength) + sizeof(ouisubtype) + 454 sizeof(struct i40e_cee_ctrl_tlv); 455 /* Return if no CEE DCBX Feature TLVs */ 456 if (tlvlen <= len) 457 return; 458 459 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len); 460 while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) { 461 typelength = ntohs(sub_tlv->hdr.typelen); 462 sublen = (u16)((typelength & 463 I40E_LLDP_TLV_LEN_MASK) >> 464 I40E_LLDP_TLV_LEN_SHIFT); 465 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> 466 I40E_LLDP_TLV_TYPE_SHIFT); 467 switch (subtype) { 468 case I40E_CEE_SUBTYPE_PG_CFG: 469 i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg); 470 break; 471 case I40E_CEE_SUBTYPE_PFC_CFG: 472 i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg); 473 break; 474 case I40E_CEE_SUBTYPE_APP_PRI: 475 i40e_parse_cee_app_tlv(sub_tlv, dcbcfg); 476 break; 477 default: 478 return; /* Invalid Sub-type return */ 479 } 480 feat_tlv_count++; 481 /* Move to next sub TLV */ 482 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv + 483 sizeof(sub_tlv->hdr.typelen) + 484 sublen); 485 } 486 } 487 488 /** 489 * i40e_parse_org_tlv 490 * @tlv: Organization specific TLV 491 * @dcbcfg: Local store to update ETS REC data 492 * 493 * Currently only IEEE 802.1Qaz TLV is supported, all others 494 * will be returned 495 **/ 496 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv, 497 struct i40e_dcbx_config *dcbcfg) 498 { 499 u32 ouisubtype; 500 u32 oui; 501 502 ouisubtype = ntohl(tlv->ouisubtype); 503 oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >> 504 I40E_LLDP_TLV_OUI_SHIFT); 505 switch (oui) { 506 case I40E_IEEE_8021QAZ_OUI: 507 i40e_parse_ieee_tlv(tlv, dcbcfg); 508 break; 509 case I40E_CEE_DCBX_OUI: 510 i40e_parse_cee_tlv(tlv, dcbcfg); 511 break; 512 default: 513 break; 514 } 515 } 516 517 /** 518 * i40e_lldp_to_dcb_config 519 * @lldpmib: LLDPDU to be parsed 520 * @dcbcfg: store for LLDPDU data 521 * 522 * Parse DCB configuration from the LLDPDU 523 **/ 524 i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib, 525 struct i40e_dcbx_config *dcbcfg) 526 { 527 i40e_status ret = 0; 528 struct i40e_lldp_org_tlv *tlv; 529 u16 type; 530 u16 length; 531 u16 typelength; 532 u16 offset = 0; 533 534 if (!lldpmib || !dcbcfg) 535 return I40E_ERR_PARAM; 536 537 /* set to the start of LLDPDU */ 538 lldpmib += ETH_HLEN; 539 tlv = (struct i40e_lldp_org_tlv *)lldpmib; 540 while (1) { 541 typelength = ntohs(tlv->typelength); 542 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> 543 I40E_LLDP_TLV_TYPE_SHIFT); 544 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> 545 I40E_LLDP_TLV_LEN_SHIFT); 546 offset += sizeof(typelength) + length; 547 548 /* END TLV or beyond LLDPDU size */ 549 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE)) 550 break; 551 552 switch (type) { 553 case I40E_TLV_TYPE_ORG: 554 i40e_parse_org_tlv(tlv, dcbcfg); 555 break; 556 default: 557 break; 558 } 559 560 /* Move to next TLV */ 561 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv + 562 sizeof(tlv->typelength) + 563 length); 564 } 565 566 return ret; 567 } 568 569 /** 570 * i40e_aq_get_dcb_config 571 * @hw: pointer to the hw struct 572 * @mib_type: mib type for the query 573 * @bridgetype: bridge type for the query (remote) 574 * @dcbcfg: store for LLDPDU data 575 * 576 * Query DCB configuration from the Firmware 577 **/ 578 i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type, 579 u8 bridgetype, 580 struct i40e_dcbx_config *dcbcfg) 581 { 582 i40e_status ret = 0; 583 struct i40e_virt_mem mem; 584 u8 *lldpmib; 585 586 /* Allocate the LLDPDU */ 587 ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE); 588 if (ret) 589 return ret; 590 591 lldpmib = (u8 *)mem.va; 592 ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type, 593 (void *)lldpmib, I40E_LLDPDU_SIZE, 594 NULL, NULL, NULL); 595 if (ret) 596 goto free_mem; 597 598 /* Parse LLDP MIB to get dcb configuration */ 599 ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg); 600 601 free_mem: 602 i40e_free_virt_mem(hw, &mem); 603 return ret; 604 } 605 606 /** 607 * i40e_cee_to_dcb_v1_config 608 * @cee_cfg: pointer to CEE v1 response configuration struct 609 * @dcbcfg: DCB configuration struct 610 * 611 * Convert CEE v1 configuration from firmware to DCB configuration 612 **/ 613 static void i40e_cee_to_dcb_v1_config( 614 struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg, 615 struct i40e_dcbx_config *dcbcfg) 616 { 617 u16 status, tlv_status = le16_to_cpu(cee_cfg->tlv_status); 618 u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio); 619 u8 i, tc, err; 620 621 /* CEE PG data to ETS config */ 622 dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; 623 624 /* Note that the FW creates the oper_prio_tc nibbles reversed 625 * from those in the CEE Priority Group sub-TLV. 626 */ 627 for (i = 0; i < 4; i++) { 628 tc = (u8)((cee_cfg->oper_prio_tc[i] & 629 I40E_CEE_PGID_PRIO_0_MASK) >> 630 I40E_CEE_PGID_PRIO_0_SHIFT); 631 dcbcfg->etscfg.prioritytable[i * 2] = tc; 632 tc = (u8)((cee_cfg->oper_prio_tc[i] & 633 I40E_CEE_PGID_PRIO_1_MASK) >> 634 I40E_CEE_PGID_PRIO_1_SHIFT); 635 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; 636 } 637 638 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 639 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; 640 641 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { 642 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { 643 /* Map it to next empty TC */ 644 dcbcfg->etscfg.prioritytable[i] = 645 cee_cfg->oper_num_tc - 1; 646 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; 647 } else { 648 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; 649 } 650 } 651 652 /* CEE PFC data to ETS config */ 653 dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; 654 dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; 655 656 status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >> 657 I40E_AQC_CEE_APP_STATUS_SHIFT; 658 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 659 /* Add APPs if Error is False */ 660 if (!err) { 661 /* CEE operating configuration supports FCoE/iSCSI/FIP only */ 662 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS; 663 664 /* FCoE APP */ 665 dcbcfg->app[0].priority = 666 (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> 667 I40E_AQC_CEE_APP_FCOE_SHIFT; 668 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE; 669 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE; 670 671 /* iSCSI APP */ 672 dcbcfg->app[1].priority = 673 (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> 674 I40E_AQC_CEE_APP_ISCSI_SHIFT; 675 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP; 676 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI; 677 678 /* FIP APP */ 679 dcbcfg->app[2].priority = 680 (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> 681 I40E_AQC_CEE_APP_FIP_SHIFT; 682 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE; 683 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP; 684 } 685 } 686 687 /** 688 * i40e_cee_to_dcb_config 689 * @cee_cfg: pointer to CEE configuration struct 690 * @dcbcfg: DCB configuration struct 691 * 692 * Convert CEE configuration from firmware to DCB configuration 693 **/ 694 static void i40e_cee_to_dcb_config( 695 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg, 696 struct i40e_dcbx_config *dcbcfg) 697 { 698 u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status); 699 u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio); 700 u8 i, tc, err, sync, oper; 701 702 /* CEE PG data to ETS config */ 703 dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; 704 705 /* Note that the FW creates the oper_prio_tc nibbles reversed 706 * from those in the CEE Priority Group sub-TLV. 707 */ 708 for (i = 0; i < 4; i++) { 709 tc = (u8)((cee_cfg->oper_prio_tc[i] & 710 I40E_CEE_PGID_PRIO_0_MASK) >> 711 I40E_CEE_PGID_PRIO_0_SHIFT); 712 dcbcfg->etscfg.prioritytable[i * 2] = tc; 713 tc = (u8)((cee_cfg->oper_prio_tc[i] & 714 I40E_CEE_PGID_PRIO_1_MASK) >> 715 I40E_CEE_PGID_PRIO_1_SHIFT); 716 dcbcfg->etscfg.prioritytable[i * 2 + 1] = tc; 717 } 718 719 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) 720 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i]; 721 722 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { 723 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) { 724 /* Map it to next empty TC */ 725 dcbcfg->etscfg.prioritytable[i] = 726 cee_cfg->oper_num_tc - 1; 727 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT; 728 } else { 729 dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS; 730 } 731 } 732 733 /* CEE PFC data to ETS config */ 734 dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en; 735 dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; 736 737 i = 0; 738 status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >> 739 I40E_AQC_CEE_FCOE_STATUS_SHIFT; 740 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 741 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 742 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 743 /* Add FCoE APP if Error is False and Oper/Sync is True */ 744 if (!err && sync && oper) { 745 /* FCoE APP */ 746 dcbcfg->app[i].priority = 747 (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >> 748 I40E_AQC_CEE_APP_FCOE_SHIFT; 749 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 750 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE; 751 i++; 752 } 753 754 status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >> 755 I40E_AQC_CEE_ISCSI_STATUS_SHIFT; 756 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 757 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 758 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 759 /* Add iSCSI APP if Error is False and Oper/Sync is True */ 760 if (!err && sync && oper) { 761 /* iSCSI APP */ 762 dcbcfg->app[i].priority = 763 (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >> 764 I40E_AQC_CEE_APP_ISCSI_SHIFT; 765 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP; 766 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI; 767 i++; 768 } 769 770 status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >> 771 I40E_AQC_CEE_FIP_STATUS_SHIFT; 772 err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0; 773 sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0; 774 oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0; 775 /* Add FIP APP if Error is False and Oper/Sync is True */ 776 if (!err && sync && oper) { 777 /* FIP APP */ 778 dcbcfg->app[i].priority = 779 (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >> 780 I40E_AQC_CEE_APP_FIP_SHIFT; 781 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE; 782 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP; 783 i++; 784 } 785 dcbcfg->numapps = i; 786 } 787 788 /** 789 * i40e_get_ieee_dcb_config 790 * @hw: pointer to the hw struct 791 * 792 * Get IEEE mode DCB configuration from the Firmware 793 **/ 794 static i40e_status i40e_get_ieee_dcb_config(struct i40e_hw *hw) 795 { 796 i40e_status ret = 0; 797 798 /* IEEE mode */ 799 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE; 800 /* Get Local DCB Config */ 801 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, 802 &hw->local_dcbx_config); 803 if (ret) 804 goto out; 805 806 /* Get Remote DCB Config */ 807 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, 808 I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, 809 &hw->remote_dcbx_config); 810 /* Don't treat ENOENT as an error for Remote MIBs */ 811 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 812 ret = 0; 813 814 out: 815 return ret; 816 } 817 818 /** 819 * i40e_get_dcb_config 820 * @hw: pointer to the hw struct 821 * 822 * Get DCB configuration from the Firmware 823 **/ 824 i40e_status i40e_get_dcb_config(struct i40e_hw *hw) 825 { 826 i40e_status ret = 0; 827 struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg; 828 struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg; 829 830 /* If Firmware version < v4.33 on X710/XL710, IEEE only */ 831 if ((hw->mac.type == I40E_MAC_XL710) && 832 (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 833 (hw->aq.fw_maj_ver < 4))) 834 return i40e_get_ieee_dcb_config(hw); 835 836 /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */ 837 if ((hw->mac.type == I40E_MAC_XL710) && 838 ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) { 839 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg, 840 sizeof(cee_v1_cfg), NULL); 841 if (!ret) { 842 /* CEE mode */ 843 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; 844 hw->local_dcbx_config.tlv_status = 845 le16_to_cpu(cee_v1_cfg.tlv_status); 846 i40e_cee_to_dcb_v1_config(&cee_v1_cfg, 847 &hw->local_dcbx_config); 848 } 849 } else { 850 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg, 851 sizeof(cee_cfg), NULL); 852 if (!ret) { 853 /* CEE mode */ 854 hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; 855 hw->local_dcbx_config.tlv_status = 856 le32_to_cpu(cee_cfg.tlv_status); 857 i40e_cee_to_dcb_config(&cee_cfg, 858 &hw->local_dcbx_config); 859 } 860 } 861 862 /* CEE mode not enabled try querying IEEE data */ 863 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 864 return i40e_get_ieee_dcb_config(hw); 865 866 if (ret) 867 goto out; 868 869 /* Get CEE DCB Desired Config */ 870 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0, 871 &hw->desired_dcbx_config); 872 if (ret) 873 goto out; 874 875 /* Get Remote DCB Config */ 876 ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE, 877 I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, 878 &hw->remote_dcbx_config); 879 /* Don't treat ENOENT as an error for Remote MIBs */ 880 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) 881 ret = 0; 882 883 out: 884 return ret; 885 } 886 887 /** 888 * i40e_init_dcb 889 * @hw: pointer to the hw struct 890 * 891 * Update DCB configuration from the Firmware 892 **/ 893 i40e_status i40e_init_dcb(struct i40e_hw *hw) 894 { 895 i40e_status ret = 0; 896 struct i40e_lldp_variables lldp_cfg; 897 u8 adminstatus = 0; 898 899 if (!hw->func_caps.dcb) 900 return ret; 901 902 /* Read LLDP NVM area */ 903 ret = i40e_read_lldp_cfg(hw, &lldp_cfg); 904 if (ret) 905 return ret; 906 907 /* Get the LLDP AdminStatus for the current port */ 908 adminstatus = lldp_cfg.adminstatus >> (hw->port * 4); 909 adminstatus &= 0xF; 910 911 /* LLDP agent disabled */ 912 if (!adminstatus) { 913 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED; 914 return ret; 915 } 916 917 /* Get DCBX status */ 918 ret = i40e_get_dcbx_status(hw, &hw->dcbx_status); 919 if (ret) 920 return ret; 921 922 /* Check the DCBX Status */ 923 switch (hw->dcbx_status) { 924 case I40E_DCBX_STATUS_DONE: 925 case I40E_DCBX_STATUS_IN_PROGRESS: 926 /* Get current DCBX configuration */ 927 ret = i40e_get_dcb_config(hw); 928 if (ret) 929 return ret; 930 break; 931 case I40E_DCBX_STATUS_DISABLED: 932 return ret; 933 case I40E_DCBX_STATUS_NOT_STARTED: 934 case I40E_DCBX_STATUS_MULTIPLE_PEERS: 935 default: 936 break; 937 } 938 939 /* Configure the LLDP MIB change event */ 940 ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL); 941 if (ret) 942 return ret; 943 944 return ret; 945 } 946 947 /** 948 * i40e_read_lldp_cfg - read LLDP Configuration data from NVM 949 * @hw: pointer to the HW structure 950 * @lldp_cfg: pointer to hold lldp configuration variables 951 * 952 * Reads the LLDP configuration data from NVM 953 **/ 954 i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw, 955 struct i40e_lldp_variables *lldp_cfg) 956 { 957 i40e_status ret = 0; 958 u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR); 959 960 if (!lldp_cfg) 961 return I40E_ERR_PARAM; 962 963 ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 964 if (ret) 965 goto err_lldp_cfg; 966 967 ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset, 968 sizeof(struct i40e_lldp_variables), 969 (u8 *)lldp_cfg, 970 true, NULL); 971 i40e_release_nvm(hw); 972 973 err_lldp_cfg: 974 return ret; 975 } 976