1642 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2019, Intel Corporation. */3 4#include "ice_common.h"5#include "ice_sched.h"6#include "ice_dcb.h"7 8/**9 * ice_aq_get_lldp_mib10 * @hw: pointer to the HW struct11 * @bridge_type: type of bridge requested12 * @mib_type: Local, Remote or both Local and Remote MIBs13 * @buf: pointer to the caller-supplied buffer to store the MIB block14 * @buf_size: size of the buffer (in bytes)15 * @local_len: length of the returned Local LLDP MIB16 * @remote_len: length of the returned Remote LLDP MIB17 * @cd: pointer to command details structure or NULL18 *19 * Requests the complete LLDP MIB (entire packet). (0x0A00)20 */21static int22ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,23 u16 buf_size, u16 *local_len, u16 *remote_len,24 struct ice_sq_cd *cd)25{26 struct ice_aqc_lldp_get_mib *cmd;27 struct ice_aq_desc desc;28 int status;29 30 cmd = &desc.params.lldp_get_mib;31 32 if (buf_size == 0 || !buf)33 return -EINVAL;34 35 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);36 37 cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;38 cmd->type |= FIELD_PREP(ICE_AQ_LLDP_BRID_TYPE_M, bridge_type);39 40 desc.datalen = cpu_to_le16(buf_size);41 42 status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);43 if (!status) {44 if (local_len)45 *local_len = le16_to_cpu(cmd->local_len);46 if (remote_len)47 *remote_len = le16_to_cpu(cmd->remote_len);48 }49 50 return status;51}52 53/**54 * ice_aq_cfg_lldp_mib_change55 * @hw: pointer to the HW struct56 * @ena_update: Enable or Disable event posting57 * @cd: pointer to command details structure or NULL58 *59 * Enable or Disable posting of an event on ARQ when LLDP MIB60 * associated with the interface changes (0x0A01)61 */62static int63ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,64 struct ice_sq_cd *cd)65{66 struct ice_aqc_lldp_set_mib_change *cmd;67 struct ice_aq_desc desc;68 69 cmd = &desc.params.lldp_set_event;70 71 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change);72 73 if (!ena_update)74 cmd->command |= ICE_AQ_LLDP_MIB_UPDATE_DIS;75 else76 cmd->command |= FIELD_PREP(ICE_AQ_LLDP_MIB_PENDING_M,77 ICE_AQ_LLDP_MIB_PENDING_ENABLE);78 79 return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);80}81 82/**83 * ice_aq_stop_lldp84 * @hw: pointer to the HW struct85 * @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown86 * False if LLDP Agent needs to be Stopped87 * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across88 * reboots89 * @cd: pointer to command details structure or NULL90 *91 * Stop or Shutdown the embedded LLDP Agent (0x0A05)92 */93int94ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,95 struct ice_sq_cd *cd)96{97 struct ice_aqc_lldp_stop *cmd;98 struct ice_aq_desc desc;99 100 cmd = &desc.params.lldp_stop;101 102 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop);103 104 if (shutdown_lldp_agent)105 cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;106 107 if (persist)108 cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;109 110 return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);111}112 113/**114 * ice_aq_start_lldp115 * @hw: pointer to the HW struct116 * @persist: True if Start of LLDP Agent needs to be persistent across reboots117 * @cd: pointer to command details structure or NULL118 *119 * Start the embedded LLDP Agent on all ports. (0x0A06)120 */121int ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd)122{123 struct ice_aqc_lldp_start *cmd;124 struct ice_aq_desc desc;125 126 cmd = &desc.params.lldp_start;127 128 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_start);129 130 cmd->command = ICE_AQ_LLDP_AGENT_START;131 132 if (persist)133 cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_ENA;134 135 return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);136}137 138/**139 * ice_get_dcbx_status140 * @hw: pointer to the HW struct141 *142 * Get the DCBX status from the Firmware143 */144static u8 ice_get_dcbx_status(struct ice_hw *hw)145{146 u32 reg;147 148 reg = rd32(hw, PRTDCB_GENS);149 return FIELD_GET(PRTDCB_GENS_DCBX_STATUS_M, reg);150}151 152/**153 * ice_parse_ieee_ets_common_tlv154 * @buf: Data buffer to be parsed for ETS CFG/REC data155 * @ets_cfg: Container to store parsed data156 *157 * Parses the common data of IEEE 802.1Qaz ETS CFG/REC TLV158 */159static void160ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)161{162 u8 offset = 0;163 int i;164 165 /* Priority Assignment Table (4 octets)166 * Octets:| 1 | 2 | 3 | 4 |167 * -----------------------------------------168 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|169 * -----------------------------------------170 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|171 * -----------------------------------------172 */173 for (i = 0; i < 4; i++) {174 ets_cfg->prio_table[i * 2] =175 FIELD_GET(ICE_IEEE_ETS_PRIO_1_M, buf[offset]);176 ets_cfg->prio_table[i * 2 + 1] =177 FIELD_GET(ICE_IEEE_ETS_PRIO_0_M, buf[offset]);178 offset++;179 }180 181 /* TC Bandwidth Table (8 octets)182 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |183 * ---------------------------------184 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|185 * ---------------------------------186 *187 * TSA Assignment Table (8 octets)188 * Octets:| 9 | 10| 11| 12| 13| 14| 15| 16|189 * ---------------------------------190 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|191 * ---------------------------------192 */193 ice_for_each_traffic_class(i) {194 ets_cfg->tcbwtable[i] = buf[offset];195 ets_cfg->tsatable[i] = buf[ICE_MAX_TRAFFIC_CLASS + offset++];196 }197}198 199/**200 * ice_parse_ieee_etscfg_tlv201 * @tlv: IEEE 802.1Qaz ETS CFG TLV202 * @dcbcfg: Local store to update ETS CFG data203 *204 * Parses IEEE 802.1Qaz ETS CFG TLV205 */206static void207ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,208 struct ice_dcbx_cfg *dcbcfg)209{210 struct ice_dcb_ets_cfg *etscfg;211 u8 *buf = tlv->tlvinfo;212 213 /* First Octet post subtype214 * --------------------------215 * |will-|CBS | Re- | Max |216 * |ing | |served| TCs |217 * --------------------------218 * |1bit | 1bit|3 bits|3bits|219 */220 etscfg = &dcbcfg->etscfg;221 etscfg->willing = FIELD_GET(ICE_IEEE_ETS_WILLING_M, buf[0]);222 etscfg->cbs = FIELD_GET(ICE_IEEE_ETS_CBS_M, buf[0]);223 etscfg->maxtcs = FIELD_GET(ICE_IEEE_ETS_MAXTC_M, buf[0]);224 225 /* Begin parsing at Priority Assignment Table (offset 1 in buf) */226 ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);227}228 229/**230 * ice_parse_ieee_etsrec_tlv231 * @tlv: IEEE 802.1Qaz ETS REC TLV232 * @dcbcfg: Local store to update ETS REC data233 *234 * Parses IEEE 802.1Qaz ETS REC TLV235 */236static void237ice_parse_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,238 struct ice_dcbx_cfg *dcbcfg)239{240 u8 *buf = tlv->tlvinfo;241 242 /* Begin parsing at Priority Assignment Table (offset 1 in buf) */243 ice_parse_ieee_ets_common_tlv(&buf[1], &dcbcfg->etsrec);244}245 246/**247 * ice_parse_ieee_pfccfg_tlv248 * @tlv: IEEE 802.1Qaz PFC CFG TLV249 * @dcbcfg: Local store to update PFC CFG data250 *251 * Parses IEEE 802.1Qaz PFC CFG TLV252 */253static void254ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,255 struct ice_dcbx_cfg *dcbcfg)256{257 u8 *buf = tlv->tlvinfo;258 259 /* ----------------------------------------260 * |will-|MBC | Re- | PFC | PFC Enable |261 * |ing | |served| cap | |262 * -----------------------------------------263 * |1bit | 1bit|2 bits|4bits| 1 octet |264 */265 dcbcfg->pfc.willing = FIELD_GET(ICE_IEEE_PFC_WILLING_M, buf[0]);266 dcbcfg->pfc.mbc = FIELD_GET(ICE_IEEE_PFC_MBC_M, buf[0]);267 dcbcfg->pfc.pfccap = FIELD_GET(ICE_IEEE_PFC_CAP_M, buf[0]);268 dcbcfg->pfc.pfcena = buf[1];269}270 271/**272 * ice_parse_ieee_app_tlv273 * @tlv: IEEE 802.1Qaz APP TLV274 * @dcbcfg: Local store to update APP PRIO data275 *276 * Parses IEEE 802.1Qaz APP PRIO TLV277 */278static void279ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,280 struct ice_dcbx_cfg *dcbcfg)281{282 u16 offset = 0;283 u16 typelen;284 int i = 0;285 u16 len;286 u8 *buf;287 288 typelen = ntohs(tlv->typelen);289 len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);290 buf = tlv->tlvinfo;291 292 /* Removing sizeof(ouisubtype) and reserved byte from len.293 * Remaining len div 3 is number of APP TLVs.294 */295 len -= (sizeof(tlv->ouisubtype) + 1);296 297 /* Move offset to App Priority Table */298 offset++;299 300 /* Application Priority Table (3 octets)301 * Octets:| 1 | 2 | 3 |302 * -----------------------------------------303 * |Priority|Rsrvd| Sel | Protocol ID |304 * -----------------------------------------305 * Bits:|23 21|20 19|18 16|15 0|306 * -----------------------------------------307 */308 while (offset < len) {309 dcbcfg->app[i].priority = FIELD_GET(ICE_IEEE_APP_PRIO_M,310 buf[offset]);311 dcbcfg->app[i].selector = FIELD_GET(ICE_IEEE_APP_SEL_M,312 buf[offset]);313 dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |314 buf[offset + 2];315 /* Move to next app */316 offset += 3;317 i++;318 if (i >= ICE_DCBX_MAX_APPS)319 break;320 }321 322 dcbcfg->numapps = i;323}324 325/**326 * ice_parse_ieee_tlv327 * @tlv: IEEE 802.1Qaz TLV328 * @dcbcfg: Local store to update ETS REC data329 *330 * Get the TLV subtype and send it to parsing function331 * based on the subtype value332 */333static void334ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)335{336 u32 ouisubtype;337 u8 subtype;338 339 ouisubtype = ntohl(tlv->ouisubtype);340 subtype = FIELD_GET(ICE_LLDP_TLV_SUBTYPE_M, ouisubtype);341 switch (subtype) {342 case ICE_IEEE_SUBTYPE_ETS_CFG:343 ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);344 break;345 case ICE_IEEE_SUBTYPE_ETS_REC:346 ice_parse_ieee_etsrec_tlv(tlv, dcbcfg);347 break;348 case ICE_IEEE_SUBTYPE_PFC_CFG:349 ice_parse_ieee_pfccfg_tlv(tlv, dcbcfg);350 break;351 case ICE_IEEE_SUBTYPE_APP_PRI:352 ice_parse_ieee_app_tlv(tlv, dcbcfg);353 break;354 default:355 break;356 }357}358 359/**360 * ice_parse_cee_pgcfg_tlv361 * @tlv: CEE DCBX PG CFG TLV362 * @dcbcfg: Local store to update ETS CFG data363 *364 * Parses CEE DCBX PG CFG TLV365 */366static void367ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,368 struct ice_dcbx_cfg *dcbcfg)369{370 struct ice_dcb_ets_cfg *etscfg;371 u8 *buf = tlv->tlvinfo;372 u16 offset = 0;373 int i;374 375 etscfg = &dcbcfg->etscfg;376 377 if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)378 etscfg->willing = 1;379 380 etscfg->cbs = 0;381 /* Priority Group Table (4 octets)382 * Octets:| 1 | 2 | 3 | 4 |383 * -----------------------------------------384 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|385 * -----------------------------------------386 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|387 * -----------------------------------------388 */389 for (i = 0; i < 4; i++) {390 etscfg->prio_table[i * 2] =391 FIELD_GET(ICE_CEE_PGID_PRIO_1_M, buf[offset]);392 etscfg->prio_table[i * 2 + 1] =393 FIELD_GET(ICE_CEE_PGID_PRIO_0_M, buf[offset]);394 offset++;395 }396 397 /* PG Percentage Table (8 octets)398 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |399 * ---------------------------------400 * |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|401 * ---------------------------------402 */403 ice_for_each_traffic_class(i) {404 etscfg->tcbwtable[i] = buf[offset++];405 406 if (etscfg->prio_table[i] == ICE_CEE_PGID_STRICT)407 dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;408 else409 dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;410 }411 412 /* Number of TCs supported (1 octet) */413 etscfg->maxtcs = buf[offset];414}415 416/**417 * ice_parse_cee_pfccfg_tlv418 * @tlv: CEE DCBX PFC CFG TLV419 * @dcbcfg: Local store to update PFC CFG data420 *421 * Parses CEE DCBX PFC CFG TLV422 */423static void424ice_parse_cee_pfccfg_tlv(struct ice_cee_feat_tlv *tlv,425 struct ice_dcbx_cfg *dcbcfg)426{427 u8 *buf = tlv->tlvinfo;428 429 if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)430 dcbcfg->pfc.willing = 1;431 432 /* ------------------------433 * | PFC Enable | PFC TCs |434 * ------------------------435 * | 1 octet | 1 octet |436 */437 dcbcfg->pfc.pfcena = buf[0];438 dcbcfg->pfc.pfccap = buf[1];439}440 441/**442 * ice_parse_cee_app_tlv443 * @tlv: CEE DCBX APP TLV444 * @dcbcfg: Local store to update APP PRIO data445 *446 * Parses CEE DCBX APP PRIO TLV447 */448static void449ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)450{451 u16 len, typelen, offset = 0;452 struct ice_cee_app_prio *app;453 u8 i;454 455 typelen = ntohs(tlv->hdr.typelen);456 len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);457 458 dcbcfg->numapps = len / sizeof(*app);459 if (!dcbcfg->numapps)460 return;461 if (dcbcfg->numapps > ICE_DCBX_MAX_APPS)462 dcbcfg->numapps = ICE_DCBX_MAX_APPS;463 464 for (i = 0; i < dcbcfg->numapps; i++) {465 u8 up, selector;466 467 app = (struct ice_cee_app_prio *)(tlv->tlvinfo + offset);468 for (up = 0; up < ICE_MAX_USER_PRIORITY; up++)469 if (app->prio_map & BIT(up))470 break;471 472 dcbcfg->app[i].priority = up;473 474 /* Get Selector from lower 2 bits, and convert to IEEE */475 selector = (app->upper_oui_sel & ICE_CEE_APP_SELECTOR_M);476 switch (selector) {477 case ICE_CEE_APP_SEL_ETHTYPE:478 dcbcfg->app[i].selector = ICE_APP_SEL_ETHTYPE;479 break;480 case ICE_CEE_APP_SEL_TCPIP:481 dcbcfg->app[i].selector = ICE_APP_SEL_TCPIP;482 break;483 default:484 /* Keep selector as it is for unknown types */485 dcbcfg->app[i].selector = selector;486 }487 488 dcbcfg->app[i].prot_id = ntohs(app->protocol);489 /* Move to next app */490 offset += sizeof(*app);491 }492}493 494/**495 * ice_parse_cee_tlv496 * @tlv: CEE DCBX TLV497 * @dcbcfg: Local store to update DCBX config data498 *499 * Get the TLV subtype and send it to parsing function500 * based on the subtype value501 */502static void503ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)504{505 struct ice_cee_feat_tlv *sub_tlv;506 u8 subtype, feat_tlv_count = 0;507 u16 len, tlvlen, typelen;508 u32 ouisubtype;509 510 ouisubtype = ntohl(tlv->ouisubtype);511 subtype = FIELD_GET(ICE_LLDP_TLV_SUBTYPE_M, ouisubtype);512 /* Return if not CEE DCBX */513 if (subtype != ICE_CEE_DCBX_TYPE)514 return;515 516 typelen = ntohs(tlv->typelen);517 tlvlen = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);518 len = sizeof(tlv->typelen) + sizeof(ouisubtype) +519 sizeof(struct ice_cee_ctrl_tlv);520 /* Return if no CEE DCBX Feature TLVs */521 if (tlvlen <= len)522 return;523 524 sub_tlv = (struct ice_cee_feat_tlv *)((char *)tlv + len);525 while (feat_tlv_count < ICE_CEE_MAX_FEAT_TYPE) {526 u16 sublen;527 528 typelen = ntohs(sub_tlv->hdr.typelen);529 sublen = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);530 subtype = FIELD_GET(ICE_LLDP_TLV_TYPE_M, typelen);531 switch (subtype) {532 case ICE_CEE_SUBTYPE_PG_CFG:533 ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);534 break;535 case ICE_CEE_SUBTYPE_PFC_CFG:536 ice_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);537 break;538 case ICE_CEE_SUBTYPE_APP_PRI:539 ice_parse_cee_app_tlv(sub_tlv, dcbcfg);540 break;541 default:542 return; /* Invalid Sub-type return */543 }544 feat_tlv_count++;545 /* Move to next sub TLV */546 sub_tlv = (struct ice_cee_feat_tlv *)547 ((char *)sub_tlv + sizeof(sub_tlv->hdr.typelen) +548 sublen);549 }550}551 552/**553 * ice_parse_org_tlv554 * @tlv: Organization specific TLV555 * @dcbcfg: Local store to update ETS REC data556 *557 * Currently IEEE 802.1Qaz and CEE DCBX TLV are supported, others558 * will be returned559 */560static void561ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)562{563 u32 ouisubtype;564 u32 oui;565 566 ouisubtype = ntohl(tlv->ouisubtype);567 oui = FIELD_GET(ICE_LLDP_TLV_OUI_M, ouisubtype);568 switch (oui) {569 case ICE_IEEE_8021QAZ_OUI:570 ice_parse_ieee_tlv(tlv, dcbcfg);571 break;572 case ICE_CEE_DCBX_OUI:573 ice_parse_cee_tlv(tlv, dcbcfg);574 break;575 default:576 break; /* Other OUIs not supported */577 }578}579 580/**581 * ice_lldp_to_dcb_cfg582 * @lldpmib: LLDPDU to be parsed583 * @dcbcfg: store for LLDPDU data584 *585 * Parse DCB configuration from the LLDPDU586 */587static int ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)588{589 struct ice_lldp_org_tlv *tlv;590 u16 offset = 0;591 int ret = 0;592 u16 typelen;593 u16 type;594 u16 len;595 596 if (!lldpmib || !dcbcfg)597 return -EINVAL;598 599 /* set to the start of LLDPDU */600 lldpmib += ETH_HLEN;601 tlv = (struct ice_lldp_org_tlv *)lldpmib;602 while (1) {603 typelen = ntohs(tlv->typelen);604 type = FIELD_GET(ICE_LLDP_TLV_TYPE_M, typelen);605 len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);606 offset += sizeof(typelen) + len;607 608 /* END TLV or beyond LLDPDU size */609 if (type == ICE_TLV_TYPE_END || offset > ICE_LLDPDU_SIZE)610 break;611 612 switch (type) {613 case ICE_TLV_TYPE_ORG:614 ice_parse_org_tlv(tlv, dcbcfg);615 break;616 default:617 break;618 }619 620 /* Move to next TLV */621 tlv = (struct ice_lldp_org_tlv *)622 ((char *)tlv + sizeof(tlv->typelen) + len);623 }624 625 return ret;626}627 628/**629 * ice_aq_get_dcb_cfg630 * @hw: pointer to the HW struct631 * @mib_type: MIB type for the query632 * @bridgetype: bridge type for the query (remote)633 * @dcbcfg: store for LLDPDU data634 *635 * Query DCB configuration from the firmware636 */637int638ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,639 struct ice_dcbx_cfg *dcbcfg)640{641 u8 *lldpmib;642 int ret;643 644 /* Allocate the LLDPDU */645 lldpmib = devm_kzalloc(ice_hw_to_dev(hw), ICE_LLDPDU_SIZE, GFP_KERNEL);646 if (!lldpmib)647 return -ENOMEM;648 649 ret = ice_aq_get_lldp_mib(hw, bridgetype, mib_type, (void *)lldpmib,650 ICE_LLDPDU_SIZE, NULL, NULL, NULL);651 652 if (!ret)653 /* Parse LLDP MIB to get DCB configuration */654 ret = ice_lldp_to_dcb_cfg(lldpmib, dcbcfg);655 656 devm_kfree(ice_hw_to_dev(hw), lldpmib);657 658 return ret;659}660 661/**662 * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW663 * @hw: pointer to the HW struct664 * @start_dcbx_agent: True if DCBX Agent needs to be started665 * False if DCBX Agent needs to be stopped666 * @dcbx_agent_status: FW indicates back the DCBX agent status667 * True if DCBX Agent is active668 * False if DCBX Agent is stopped669 * @cd: pointer to command details structure or NULL670 *671 * Start/Stop the embedded dcbx Agent. In case that this wrapper function672 * returns 0, caller will need to check if FW returns back the same673 * value as stated in dcbx_agent_status, and react accordingly. (0x0A09)674 */675int676ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,677 bool *dcbx_agent_status, struct ice_sq_cd *cd)678{679 struct ice_aqc_lldp_stop_start_specific_agent *cmd;680 struct ice_aq_desc desc;681 u16 opcode;682 int status;683 684 cmd = &desc.params.lldp_agent_ctrl;685 686 opcode = ice_aqc_opc_lldp_stop_start_specific_agent;687 688 ice_fill_dflt_direct_cmd_desc(&desc, opcode);689 690 if (start_dcbx_agent)691 cmd->command = ICE_AQC_START_STOP_AGENT_START_DCBX;692 693 status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);694 695 *dcbx_agent_status = false;696 697 if (!status &&698 cmd->command == ICE_AQC_START_STOP_AGENT_START_DCBX)699 *dcbx_agent_status = true;700 701 return status;702}703 704/**705 * ice_aq_get_cee_dcb_cfg706 * @hw: pointer to the HW struct707 * @buff: response buffer that stores CEE operational configuration708 * @cd: pointer to command details structure or NULL709 *710 * Get CEE DCBX mode operational configuration from firmware (0x0A07)711 */712static int713ice_aq_get_cee_dcb_cfg(struct ice_hw *hw,714 struct ice_aqc_get_cee_dcb_cfg_resp *buff,715 struct ice_sq_cd *cd)716{717 struct ice_aq_desc desc;718 719 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg);720 721 return ice_aq_send_cmd(hw, &desc, (void *)buff, sizeof(*buff), cd);722}723 724/**725 * ice_aq_set_pfc_mode - Set PFC mode726 * @hw: pointer to the HW struct727 * @pfc_mode: value of PFC mode to set728 * @cd: pointer to command details structure or NULL729 *730 * This AQ call configures the PFC mode to DSCP-based PFC mode or731 * VLAN-based PFC (0x0303)732 */733int ice_aq_set_pfc_mode(struct ice_hw *hw, u8 pfc_mode, struct ice_sq_cd *cd)734{735 struct ice_aqc_set_query_pfc_mode *cmd;736 struct ice_aq_desc desc;737 int status;738 739 if (pfc_mode > ICE_AQC_PFC_DSCP_BASED_PFC)740 return -EINVAL;741 742 cmd = &desc.params.set_query_pfc_mode;743 744 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_pfc_mode);745 746 cmd->pfc_mode = pfc_mode;747 748 status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);749 if (status)750 return status;751 752 /* FW will write the PFC mode set back into cmd->pfc_mode, but if DCB is753 * disabled, FW will write back 0 to cmd->pfc_mode. After the AQ has754 * been executed, check if cmd->pfc_mode is what was requested. If not,755 * return an error.756 */757 if (cmd->pfc_mode != pfc_mode)758 return -EOPNOTSUPP;759 760 return 0;761}762 763/**764 * ice_cee_to_dcb_cfg765 * @cee_cfg: pointer to CEE configuration struct766 * @pi: port information structure767 *768 * Convert CEE configuration from firmware to DCB configuration769 */770static void771ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,772 struct ice_port_info *pi)773{774 u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);775 u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift, j;776 u8 i, err, sync, oper, app_index, ice_app_sel_type;777 u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);778 u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift;779 struct ice_dcbx_cfg *cmp_dcbcfg, *dcbcfg;780 u16 ice_app_prot_id_type;781 782 dcbcfg = &pi->qos_cfg.local_dcbx_cfg;783 dcbcfg->dcbx_mode = ICE_DCBX_MODE_CEE;784 dcbcfg->tlv_status = tlv_status;785 786 /* CEE PG data */787 dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;788 789 /* Note that the FW creates the oper_prio_tc nibbles reversed790 * from those in the CEE Priority Group sub-TLV.791 */792 for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {793 dcbcfg->etscfg.prio_table[i * 2] =794 FIELD_GET(ICE_CEE_PGID_PRIO_0_M,795 cee_cfg->oper_prio_tc[i]);796 dcbcfg->etscfg.prio_table[i * 2 + 1] =797 FIELD_GET(ICE_CEE_PGID_PRIO_1_M,798 cee_cfg->oper_prio_tc[i]);799 }800 801 ice_for_each_traffic_class(i) {802 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];803 804 if (dcbcfg->etscfg.prio_table[i] == ICE_CEE_PGID_STRICT) {805 /* Map it to next empty TC */806 dcbcfg->etscfg.prio_table[i] = cee_cfg->oper_num_tc - 1;807 dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;808 } else {809 dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;810 }811 }812 813 /* CEE PFC data */814 dcbcfg->pfc.pfcena = cee_cfg->oper_pfc_en;815 dcbcfg->pfc.pfccap = ICE_MAX_TRAFFIC_CLASS;816 817 /* CEE APP TLV data */818 if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)819 cmp_dcbcfg = &pi->qos_cfg.desired_dcbx_cfg;820 else821 cmp_dcbcfg = &pi->qos_cfg.remote_dcbx_cfg;822 823 app_index = 0;824 for (i = 0; i < 3; i++) {825 if (i == 0) {826 /* FCoE APP */827 ice_aqc_cee_status_mask = ICE_AQC_CEE_FCOE_STATUS_M;828 ice_aqc_cee_status_shift = ICE_AQC_CEE_FCOE_STATUS_S;829 ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FCOE_M;830 ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FCOE_S;831 ice_app_sel_type = ICE_APP_SEL_ETHTYPE;832 ice_app_prot_id_type = ETH_P_FCOE;833 } else if (i == 1) {834 /* iSCSI APP */835 ice_aqc_cee_status_mask = ICE_AQC_CEE_ISCSI_STATUS_M;836 ice_aqc_cee_status_shift = ICE_AQC_CEE_ISCSI_STATUS_S;837 ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_ISCSI_M;838 ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_ISCSI_S;839 ice_app_sel_type = ICE_APP_SEL_TCPIP;840 ice_app_prot_id_type = ISCSI_LISTEN_PORT;841 842 for (j = 0; j < cmp_dcbcfg->numapps; j++) {843 u16 prot_id = cmp_dcbcfg->app[j].prot_id;844 u8 sel = cmp_dcbcfg->app[j].selector;845 846 if (sel == ICE_APP_SEL_TCPIP &&847 (prot_id == ISCSI_LISTEN_PORT ||848 prot_id == ICE_APP_PROT_ID_ISCSI_860)) {849 ice_app_prot_id_type = prot_id;850 break;851 }852 }853 } else {854 /* FIP APP */855 ice_aqc_cee_status_mask = ICE_AQC_CEE_FIP_STATUS_M;856 ice_aqc_cee_status_shift = ICE_AQC_CEE_FIP_STATUS_S;857 ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FIP_M;858 ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FIP_S;859 ice_app_sel_type = ICE_APP_SEL_ETHTYPE;860 ice_app_prot_id_type = ETH_P_FIP;861 }862 863 status = (tlv_status & ice_aqc_cee_status_mask) >>864 ice_aqc_cee_status_shift;865 err = (status & ICE_TLV_STATUS_ERR) ? 1 : 0;866 sync = (status & ICE_TLV_STATUS_SYNC) ? 1 : 0;867 oper = (status & ICE_TLV_STATUS_OPER) ? 1 : 0;868 /* Add FCoE/iSCSI/FIP APP if Error is False and869 * Oper/Sync is True870 */871 if (!err && sync && oper) {872 dcbcfg->app[app_index].priority =873 (app_prio & ice_aqc_cee_app_mask) >>874 ice_aqc_cee_app_shift;875 dcbcfg->app[app_index].selector = ice_app_sel_type;876 dcbcfg->app[app_index].prot_id = ice_app_prot_id_type;877 app_index++;878 }879 }880 881 dcbcfg->numapps = app_index;882}883 884/**885 * ice_get_ieee_or_cee_dcb_cfg886 * @pi: port information structure887 * @dcbx_mode: mode of DCBX (IEEE or CEE)888 *889 * Get IEEE or CEE mode DCB configuration from the Firmware890 */891static int ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode)892{893 struct ice_dcbx_cfg *dcbx_cfg = NULL;894 int ret;895 896 if (!pi)897 return -EINVAL;898 899 if (dcbx_mode == ICE_DCBX_MODE_IEEE)900 dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;901 else if (dcbx_mode == ICE_DCBX_MODE_CEE)902 dcbx_cfg = &pi->qos_cfg.desired_dcbx_cfg;903 904 /* Get Local DCB Config in case of ICE_DCBX_MODE_IEEE905 * or get CEE DCB Desired Config in case of ICE_DCBX_MODE_CEE906 */907 ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_LOCAL,908 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);909 if (ret)910 goto out;911 912 /* Get Remote DCB Config */913 dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;914 ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,915 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);916 /* Don't treat ENOENT as an error for Remote MIBs */917 if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)918 ret = 0;919 920out:921 return ret;922}923 924/**925 * ice_get_dcb_cfg926 * @pi: port information structure927 *928 * Get DCB configuration from the Firmware929 */930int ice_get_dcb_cfg(struct ice_port_info *pi)931{932 struct ice_aqc_get_cee_dcb_cfg_resp cee_cfg;933 struct ice_dcbx_cfg *dcbx_cfg;934 int ret;935 936 if (!pi)937 return -EINVAL;938 939 ret = ice_aq_get_cee_dcb_cfg(pi->hw, &cee_cfg, NULL);940 if (!ret) {941 /* CEE mode */942 ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE);943 ice_cee_to_dcb_cfg(&cee_cfg, pi);944 } else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) {945 /* CEE mode not enabled try querying IEEE data */946 dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;947 dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;948 ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_IEEE);949 }950 951 return ret;952}953 954/**955 * ice_get_dcb_cfg_from_mib_change956 * @pi: port information structure957 * @event: pointer to the admin queue receive event958 *959 * Set DCB configuration from received MIB Change event960 */961void ice_get_dcb_cfg_from_mib_change(struct ice_port_info *pi,962 struct ice_rq_event_info *event)963{964 struct ice_dcbx_cfg *dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;965 struct ice_aqc_lldp_get_mib *mib;966 u8 change_type, dcbx_mode;967 968 mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw;969 970 change_type = FIELD_GET(ICE_AQ_LLDP_MIB_TYPE_M, mib->type);971 if (change_type == ICE_AQ_LLDP_MIB_REMOTE)972 dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;973 974 dcbx_mode = FIELD_GET(ICE_AQ_LLDP_DCBX_M, mib->type);975 976 switch (dcbx_mode) {977 case ICE_AQ_LLDP_DCBX_IEEE:978 dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;979 ice_lldp_to_dcb_cfg(event->msg_buf, dcbx_cfg);980 break;981 982 case ICE_AQ_LLDP_DCBX_CEE:983 pi->qos_cfg.desired_dcbx_cfg = pi->qos_cfg.local_dcbx_cfg;984 ice_cee_to_dcb_cfg((struct ice_aqc_get_cee_dcb_cfg_resp *)985 event->msg_buf, pi);986 break;987 }988}989 990/**991 * ice_init_dcb992 * @hw: pointer to the HW struct993 * @enable_mib_change: enable MIB change event994 *995 * Update DCB configuration from the Firmware996 */997int ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)998{999 struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;1000 int ret = 0;1001 1002 if (!hw->func_caps.common_cap.dcb)1003 return -EOPNOTSUPP;1004 1005 qos_cfg->is_sw_lldp = true;1006 1007 /* Get DCBX status */1008 qos_cfg->dcbx_status = ice_get_dcbx_status(hw);1009 1010 if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DONE ||1011 qos_cfg->dcbx_status == ICE_DCBX_STATUS_IN_PROGRESS ||1012 qos_cfg->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {1013 /* Get current DCBX configuration */1014 ret = ice_get_dcb_cfg(hw->port_info);1015 if (ret)1016 return ret;1017 qos_cfg->is_sw_lldp = false;1018 } else if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS) {1019 return -EBUSY;1020 }1021 1022 /* Configure the LLDP MIB change event */1023 if (enable_mib_change) {1024 ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);1025 if (ret)1026 qos_cfg->is_sw_lldp = true;1027 }1028 1029 return ret;1030}1031 1032/**1033 * ice_cfg_lldp_mib_change1034 * @hw: pointer to the HW struct1035 * @ena_mib: enable/disable MIB change event1036 *1037 * Configure (disable/enable) MIB1038 */1039int ice_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_mib)1040{1041 struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;1042 int ret;1043 1044 if (!hw->func_caps.common_cap.dcb)1045 return -EOPNOTSUPP;1046 1047 /* Get DCBX status */1048 qos_cfg->dcbx_status = ice_get_dcbx_status(hw);1049 1050 if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS)1051 return -EBUSY;1052 1053 ret = ice_aq_cfg_lldp_mib_change(hw, ena_mib, NULL);1054 if (!ret)1055 qos_cfg->is_sw_lldp = !ena_mib;1056 1057 return ret;1058}1059 1060/**1061 * ice_add_ieee_ets_common_tlv1062 * @buf: Data buffer to be populated with ice_dcb_ets_cfg data1063 * @ets_cfg: Container for ice_dcb_ets_cfg data1064 *1065 * Populate the TLV buffer with ice_dcb_ets_cfg data1066 */1067static void1068ice_add_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)1069{1070 u8 priority0, priority1;1071 u8 offset = 0;1072 int i;1073 1074 /* Priority Assignment Table (4 octets)1075 * Octets:| 1 | 2 | 3 | 4 |1076 * -----------------------------------------1077 * |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|1078 * -----------------------------------------1079 * Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|1080 * -----------------------------------------1081 */1082 for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {1083 priority0 = ets_cfg->prio_table[i * 2] & 0xF;1084 priority1 = ets_cfg->prio_table[i * 2 + 1] & 0xF;1085 buf[offset] = (priority0 << ICE_IEEE_ETS_PRIO_1_S) | priority1;1086 offset++;1087 }1088 1089 /* TC Bandwidth Table (8 octets)1090 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |1091 * ---------------------------------1092 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|1093 * ---------------------------------1094 *1095 * TSA Assignment Table (8 octets)1096 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |1097 * ---------------------------------1098 * |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|1099 * ---------------------------------1100 */1101 ice_for_each_traffic_class(i) {1102 buf[offset] = ets_cfg->tcbwtable[i];1103 buf[ICE_MAX_TRAFFIC_CLASS + offset] = ets_cfg->tsatable[i];1104 offset++;1105 }1106}1107 1108/**1109 * ice_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format1110 * @tlv: Fill the ETS config data in IEEE format1111 * @dcbcfg: Local store which holds the DCB Config1112 *1113 * Prepare IEEE 802.1Qaz ETS CFG TLV1114 */1115static void1116ice_add_ieee_ets_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)1117{1118 struct ice_dcb_ets_cfg *etscfg;1119 u8 *buf = tlv->tlvinfo;1120 u8 maxtcwilling = 0;1121 u32 ouisubtype;1122 u16 typelen;1123 1124 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1125 ICE_IEEE_ETS_TLV_LEN);1126 tlv->typelen = htons(typelen);1127 1128 ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |1129 ICE_IEEE_SUBTYPE_ETS_CFG);1130 tlv->ouisubtype = htonl(ouisubtype);1131 1132 /* First Octet post subtype1133 * --------------------------1134 * |will-|CBS | Re- | Max |1135 * |ing | |served| TCs |1136 * --------------------------1137 * |1bit | 1bit|3 bits|3bits|1138 */1139 etscfg = &dcbcfg->etscfg;1140 if (etscfg->willing)1141 maxtcwilling = BIT(ICE_IEEE_ETS_WILLING_S);1142 maxtcwilling |= etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;1143 buf[0] = maxtcwilling;1144 1145 /* Begin adding at Priority Assignment Table (offset 1 in buf) */1146 ice_add_ieee_ets_common_tlv(&buf[1], etscfg);1147}1148 1149/**1150 * ice_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format1151 * @tlv: Fill ETS Recommended TLV in IEEE format1152 * @dcbcfg: Local store which holds the DCB Config1153 *1154 * Prepare IEEE 802.1Qaz ETS REC TLV1155 */1156static void1157ice_add_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,1158 struct ice_dcbx_cfg *dcbcfg)1159{1160 struct ice_dcb_ets_cfg *etsrec;1161 u8 *buf = tlv->tlvinfo;1162 u32 ouisubtype;1163 u16 typelen;1164 1165 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1166 ICE_IEEE_ETS_TLV_LEN);1167 tlv->typelen = htons(typelen);1168 1169 ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |1170 ICE_IEEE_SUBTYPE_ETS_REC);1171 tlv->ouisubtype = htonl(ouisubtype);1172 1173 etsrec = &dcbcfg->etsrec;1174 1175 /* First Octet is reserved */1176 /* Begin adding at Priority Assignment Table (offset 1 in buf) */1177 ice_add_ieee_ets_common_tlv(&buf[1], etsrec);1178}1179 1180/**1181 * ice_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format1182 * @tlv: Fill PFC TLV in IEEE format1183 * @dcbcfg: Local store which holds the PFC CFG data1184 *1185 * Prepare IEEE 802.1Qaz PFC CFG TLV1186 */1187static void1188ice_add_ieee_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)1189{1190 u8 *buf = tlv->tlvinfo;1191 u32 ouisubtype;1192 u16 typelen;1193 1194 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1195 ICE_IEEE_PFC_TLV_LEN);1196 tlv->typelen = htons(typelen);1197 1198 ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |1199 ICE_IEEE_SUBTYPE_PFC_CFG);1200 tlv->ouisubtype = htonl(ouisubtype);1201 1202 /* ----------------------------------------1203 * |will-|MBC | Re- | PFC | PFC Enable |1204 * |ing | |served| cap | |1205 * -----------------------------------------1206 * |1bit | 1bit|2 bits|4bits| 1 octet |1207 */1208 if (dcbcfg->pfc.willing)1209 buf[0] = BIT(ICE_IEEE_PFC_WILLING_S);1210 1211 if (dcbcfg->pfc.mbc)1212 buf[0] |= BIT(ICE_IEEE_PFC_MBC_S);1213 1214 buf[0] |= dcbcfg->pfc.pfccap & 0xF;1215 buf[1] = dcbcfg->pfc.pfcena;1216}1217 1218/**1219 * ice_add_ieee_app_pri_tlv - Prepare APP TLV in IEEE format1220 * @tlv: Fill APP TLV in IEEE format1221 * @dcbcfg: Local store which holds the APP CFG data1222 *1223 * Prepare IEEE 802.1Qaz APP CFG TLV1224 */1225static void1226ice_add_ieee_app_pri_tlv(struct ice_lldp_org_tlv *tlv,1227 struct ice_dcbx_cfg *dcbcfg)1228{1229 u16 typelen, len, offset = 0;1230 u8 priority, selector, i = 0;1231 u8 *buf = tlv->tlvinfo;1232 u32 ouisubtype;1233 1234 /* No APP TLVs then just return */1235 if (dcbcfg->numapps == 0)1236 return;1237 ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |1238 ICE_IEEE_SUBTYPE_APP_PRI);1239 tlv->ouisubtype = htonl(ouisubtype);1240 1241 /* Move offset to App Priority Table */1242 offset++;1243 /* Application Priority Table (3 octets)1244 * Octets:| 1 | 2 | 3 |1245 * -----------------------------------------1246 * |Priority|Rsrvd| Sel | Protocol ID |1247 * -----------------------------------------1248 * Bits:|23 21|20 19|18 16|15 0|1249 * -----------------------------------------1250 */1251 while (i < dcbcfg->numapps) {1252 priority = dcbcfg->app[i].priority & 0x7;1253 selector = dcbcfg->app[i].selector & 0x7;1254 buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector;1255 buf[offset + 1] = (dcbcfg->app[i].prot_id >> 0x8) & 0xFF;1256 buf[offset + 2] = dcbcfg->app[i].prot_id & 0xFF;1257 /* Move to next app */1258 offset += 3;1259 i++;1260 if (i >= ICE_DCBX_MAX_APPS)1261 break;1262 }1263 /* len includes size of ouisubtype + 1 reserved + 3*numapps */1264 len = sizeof(tlv->ouisubtype) + 1 + (i * 3);1265 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | (len & 0x1FF));1266 tlv->typelen = htons(typelen);1267}1268 1269/**1270 * ice_add_dscp_up_tlv - Prepare DSCP to UP TLV1271 * @tlv: location to build the TLV data1272 * @dcbcfg: location of data to convert to TLV1273 */1274static void1275ice_add_dscp_up_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)1276{1277 u8 *buf = tlv->tlvinfo;1278 u32 ouisubtype;1279 u16 typelen;1280 int i;1281 1282 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1283 ICE_DSCP_UP_TLV_LEN);1284 tlv->typelen = htons(typelen);1285 1286 ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |1287 ICE_DSCP_SUBTYPE_DSCP2UP);1288 tlv->ouisubtype = htonl(ouisubtype);1289 1290 /* bytes 0 - 63 - IPv4 DSCP2UP LUT */1291 for (i = 0; i < ICE_DSCP_NUM_VAL; i++) {1292 /* IPv4 mapping */1293 buf[i] = dcbcfg->dscp_map[i];1294 /* IPv6 mapping */1295 buf[i + ICE_DSCP_IPV6_OFFSET] = dcbcfg->dscp_map[i];1296 }1297 1298 /* byte 64 - IPv4 untagged traffic */1299 buf[i] = 0;1300 1301 /* byte 144 - IPv6 untagged traffic */1302 buf[i + ICE_DSCP_IPV6_OFFSET] = 0;1303}1304 1305#define ICE_BYTES_PER_TC 81306/**1307 * ice_add_dscp_enf_tlv - Prepare DSCP Enforcement TLV1308 * @tlv: location to build the TLV data1309 */1310static void1311ice_add_dscp_enf_tlv(struct ice_lldp_org_tlv *tlv)1312{1313 u8 *buf = tlv->tlvinfo;1314 u32 ouisubtype;1315 u16 typelen;1316 1317 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1318 ICE_DSCP_ENF_TLV_LEN);1319 tlv->typelen = htons(typelen);1320 1321 ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |1322 ICE_DSCP_SUBTYPE_ENFORCE);1323 tlv->ouisubtype = htonl(ouisubtype);1324 1325 /* Allow all DSCP values to be valid for all TC's (IPv4 and IPv6) */1326 memset(buf, 0, 2 * (ICE_MAX_TRAFFIC_CLASS * ICE_BYTES_PER_TC));1327}1328 1329/**1330 * ice_add_dscp_tc_bw_tlv - Prepare DSCP BW for TC TLV1331 * @tlv: location to build the TLV data1332 * @dcbcfg: location of the data to convert to TLV1333 */1334static void1335ice_add_dscp_tc_bw_tlv(struct ice_lldp_org_tlv *tlv,1336 struct ice_dcbx_cfg *dcbcfg)1337{1338 struct ice_dcb_ets_cfg *etscfg;1339 u8 *buf = tlv->tlvinfo;1340 u32 ouisubtype;1341 u8 offset = 0;1342 u16 typelen;1343 int i;1344 1345 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1346 ICE_DSCP_TC_BW_TLV_LEN);1347 tlv->typelen = htons(typelen);1348 1349 ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |1350 ICE_DSCP_SUBTYPE_TCBW);1351 tlv->ouisubtype = htonl(ouisubtype);1352 1353 /* First Octect after subtype1354 * ----------------------------1355 * | RSV | CBS | RSV | Max TCs |1356 * | 1b | 1b | 3b | 3b |1357 * ----------------------------1358 */1359 etscfg = &dcbcfg->etscfg;1360 buf[0] = etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;1361 1362 /* bytes 1 - 4 reserved */1363 offset = 5;1364 1365 /* TC BW table1366 * bytes 0 - 7 for TC 0 - 71367 *1368 * TSA Assignment table1369 * bytes 8 - 15 for TC 0 - 71370 */1371 for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {1372 buf[offset] = etscfg->tcbwtable[i];1373 buf[offset + ICE_MAX_TRAFFIC_CLASS] = etscfg->tsatable[i];1374 offset++;1375 }1376}1377 1378/**1379 * ice_add_dscp_pfc_tlv - Prepare DSCP PFC TLV1380 * @tlv: Fill PFC TLV in IEEE format1381 * @dcbcfg: Local store which holds the PFC CFG data1382 */1383static void1384ice_add_dscp_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)1385{1386 u8 *buf = tlv->tlvinfo;1387 u32 ouisubtype;1388 u16 typelen;1389 1390 typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |1391 ICE_DSCP_PFC_TLV_LEN);1392 tlv->typelen = htons(typelen);1393 1394 ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |1395 ICE_DSCP_SUBTYPE_PFC);1396 tlv->ouisubtype = htonl(ouisubtype);1397 1398 buf[0] = dcbcfg->pfc.pfccap & 0xF;1399 buf[1] = dcbcfg->pfc.pfcena;1400}1401 1402/**1403 * ice_add_dcb_tlv - Add all IEEE or DSCP TLVs1404 * @tlv: Fill TLV data in IEEE format1405 * @dcbcfg: Local store which holds the DCB Config1406 * @tlvid: Type of IEEE TLV1407 *1408 * Add tlv information1409 */1410static void1411ice_add_dcb_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg,1412 u16 tlvid)1413{1414 if (dcbcfg->pfc_mode == ICE_QOS_MODE_VLAN) {1415 switch (tlvid) {1416 case ICE_IEEE_TLV_ID_ETS_CFG:1417 ice_add_ieee_ets_tlv(tlv, dcbcfg);1418 break;1419 case ICE_IEEE_TLV_ID_ETS_REC:1420 ice_add_ieee_etsrec_tlv(tlv, dcbcfg);1421 break;1422 case ICE_IEEE_TLV_ID_PFC_CFG:1423 ice_add_ieee_pfc_tlv(tlv, dcbcfg);1424 break;1425 case ICE_IEEE_TLV_ID_APP_PRI:1426 ice_add_ieee_app_pri_tlv(tlv, dcbcfg);1427 break;1428 default:1429 break;1430 }1431 } else {1432 /* pfc_mode == ICE_QOS_MODE_DSCP */1433 switch (tlvid) {1434 case ICE_TLV_ID_DSCP_UP:1435 ice_add_dscp_up_tlv(tlv, dcbcfg);1436 break;1437 case ICE_TLV_ID_DSCP_ENF:1438 ice_add_dscp_enf_tlv(tlv);1439 break;1440 case ICE_TLV_ID_DSCP_TC_BW:1441 ice_add_dscp_tc_bw_tlv(tlv, dcbcfg);1442 break;1443 case ICE_TLV_ID_DSCP_TO_PFC:1444 ice_add_dscp_pfc_tlv(tlv, dcbcfg);1445 break;1446 default:1447 break;1448 }1449 }1450}1451 1452/**1453 * ice_dcb_cfg_to_lldp - Convert DCB configuration to MIB format1454 * @lldpmib: pointer to the HW struct1455 * @miblen: length of LLDP MIB1456 * @dcbcfg: Local store which holds the DCB Config1457 *1458 * Convert the DCB configuration to MIB format1459 */1460static void1461ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)1462{1463 u16 len, offset = 0, tlvid = ICE_TLV_ID_START;1464 struct ice_lldp_org_tlv *tlv;1465 u16 typelen;1466 1467 tlv = (struct ice_lldp_org_tlv *)lldpmib;1468 while (1) {1469 ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);1470 typelen = ntohs(tlv->typelen);1471 len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);1472 if (len)1473 offset += len + 2;1474 /* END TLV or beyond LLDPDU size */1475 if (tlvid >= ICE_TLV_ID_END_OF_LLDPPDU ||1476 offset > ICE_LLDPDU_SIZE)1477 break;1478 /* Move to next TLV */1479 if (len)1480 tlv = (struct ice_lldp_org_tlv *)1481 ((char *)tlv + sizeof(tlv->typelen) + len);1482 }1483 *miblen = offset;1484}1485 1486/**1487 * ice_set_dcb_cfg - Set the local LLDP MIB to FW1488 * @pi: port information structure1489 *1490 * Set DCB configuration to the Firmware1491 */1492int ice_set_dcb_cfg(struct ice_port_info *pi)1493{1494 u8 mib_type, *lldpmib = NULL;1495 struct ice_dcbx_cfg *dcbcfg;1496 struct ice_hw *hw;1497 u16 miblen;1498 int ret;1499 1500 if (!pi)1501 return -EINVAL;1502 1503 hw = pi->hw;1504 1505 /* update the HW local config */1506 dcbcfg = &pi->qos_cfg.local_dcbx_cfg;1507 /* Allocate the LLDPDU */1508 lldpmib = devm_kzalloc(ice_hw_to_dev(hw), ICE_LLDPDU_SIZE, GFP_KERNEL);1509 if (!lldpmib)1510 return -ENOMEM;1511 1512 mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;1513 if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)1514 mib_type |= SET_LOCAL_MIB_TYPE_CEE_NON_WILLING;1515 1516 ice_dcb_cfg_to_lldp(lldpmib, &miblen, dcbcfg);1517 ret = ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen,1518 NULL);1519 1520 devm_kfree(ice_hw_to_dev(hw), lldpmib);1521 1522 return ret;1523}1524 1525/**1526 * ice_aq_query_port_ets - query port ETS configuration1527 * @pi: port information structure1528 * @buf: pointer to buffer1529 * @buf_size: buffer size in bytes1530 * @cd: pointer to command details structure or NULL1531 *1532 * query current port ETS configuration1533 */1534static int1535ice_aq_query_port_ets(struct ice_port_info *pi,1536 struct ice_aqc_port_ets_elem *buf, u16 buf_size,1537 struct ice_sq_cd *cd)1538{1539 struct ice_aqc_query_port_ets *cmd;1540 struct ice_aq_desc desc;1541 int status;1542 1543 if (!pi)1544 return -EINVAL;1545 cmd = &desc.params.port_ets;1546 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets);1547 cmd->port_teid = pi->root->info.node_teid;1548 1549 status = ice_aq_send_cmd(pi->hw, &desc, buf, buf_size, cd);1550 return status;1551}1552 1553/**1554 * ice_update_port_tc_tree_cfg - update TC tree configuration1555 * @pi: port information structure1556 * @buf: pointer to buffer1557 *1558 * update the SW DB with the new TC changes1559 */1560static int1561ice_update_port_tc_tree_cfg(struct ice_port_info *pi,1562 struct ice_aqc_port_ets_elem *buf)1563{1564 struct ice_sched_node *node, *tc_node;1565 struct ice_aqc_txsched_elem_data elem;1566 u32 teid1, teid2;1567 int status = 0;1568 u8 i, j;1569 1570 if (!pi)1571 return -EINVAL;1572 /* suspend the missing TC nodes */1573 for (i = 0; i < pi->root->num_children; i++) {1574 teid1 = le32_to_cpu(pi->root->children[i]->info.node_teid);1575 ice_for_each_traffic_class(j) {1576 teid2 = le32_to_cpu(buf->tc_node_teid[j]);1577 if (teid1 == teid2)1578 break;1579 }1580 if (j < ICE_MAX_TRAFFIC_CLASS)1581 continue;1582 /* TC is missing */1583 pi->root->children[i]->in_use = false;1584 }1585 /* add the new TC nodes */1586 ice_for_each_traffic_class(j) {1587 teid2 = le32_to_cpu(buf->tc_node_teid[j]);1588 if (teid2 == ICE_INVAL_TEID)1589 continue;1590 /* Is it already present in the tree ? */1591 for (i = 0; i < pi->root->num_children; i++) {1592 tc_node = pi->root->children[i];1593 if (!tc_node)1594 continue;1595 teid1 = le32_to_cpu(tc_node->info.node_teid);1596 if (teid1 == teid2) {1597 tc_node->tc_num = j;1598 tc_node->in_use = true;1599 break;1600 }1601 }1602 if (i < pi->root->num_children)1603 continue;1604 /* new TC */1605 status = ice_sched_query_elem(pi->hw, teid2, &elem);1606 if (!status)1607 status = ice_sched_add_node(pi, 1, &elem, NULL);1608 if (status)1609 break;1610 /* update the TC number */1611 node = ice_sched_find_node_by_teid(pi->root, teid2);1612 if (node)1613 node->tc_num = j;1614 }1615 return status;1616}1617 1618/**1619 * ice_query_port_ets - query port ETS configuration1620 * @pi: port information structure1621 * @buf: pointer to buffer1622 * @buf_size: buffer size in bytes1623 * @cd: pointer to command details structure or NULL1624 *1625 * query current port ETS configuration and update the1626 * SW DB with the TC changes1627 */1628int1629ice_query_port_ets(struct ice_port_info *pi,1630 struct ice_aqc_port_ets_elem *buf, u16 buf_size,1631 struct ice_sq_cd *cd)1632{1633 int status;1634 1635 mutex_lock(&pi->sched_lock);1636 status = ice_aq_query_port_ets(pi, buf, buf_size, cd);1637 if (!status)1638 status = ice_update_port_tc_tree_cfg(pi, buf);1639 mutex_unlock(&pi->sched_lock);1640 return status;1641}1642