dpdk/drivers/net/ice/base/ice_dcb.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2001-2021 Intel Corporation
   3 */
   4
   5#include "ice_common.h"
   6#include "ice_sched.h"
   7#include "ice_dcb.h"
   8
   9/**
  10 * ice_aq_get_lldp_mib
  11 * @hw: pointer to the HW struct
  12 * @bridge_type: type of bridge requested
  13 * @mib_type: Local, Remote or both Local and Remote MIBs
  14 * @buf: pointer to the caller-supplied buffer to store the MIB block
  15 * @buf_size: size of the buffer (in bytes)
  16 * @local_len: length of the returned Local LLDP MIB
  17 * @remote_len: length of the returned Remote LLDP MIB
  18 * @cd: pointer to command details structure or NULL
  19 *
  20 * Requests the complete LLDP MIB (entire packet). (0x0A00)
  21 */
  22enum ice_status
  23ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,
  24                    u16 buf_size, u16 *local_len, u16 *remote_len,
  25                    struct ice_sq_cd *cd)
  26{
  27        struct ice_aqc_lldp_get_mib *cmd;
  28        struct ice_aq_desc desc;
  29        enum ice_status status;
  30
  31        cmd = &desc.params.lldp_get_mib;
  32
  33        if (buf_size == 0 || !buf)
  34                return ICE_ERR_PARAM;
  35
  36        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);
  37
  38        cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;
  39        cmd->type |= (bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
  40                ICE_AQ_LLDP_BRID_TYPE_M;
  41
  42        desc.datalen = CPU_TO_LE16(buf_size);
  43
  44        status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
  45        if (!status) {
  46                if (local_len)
  47                        *local_len = LE16_TO_CPU(cmd->local_len);
  48                if (remote_len)
  49                        *remote_len = LE16_TO_CPU(cmd->remote_len);
  50        }
  51
  52        return status;
  53}
  54
  55/**
  56 * ice_aq_cfg_lldp_mib_change
  57 * @hw: pointer to the HW struct
  58 * @ena_update: Enable or Disable event posting
  59 * @cd: pointer to command details structure or NULL
  60 *
  61 * Enable or Disable posting of an event on ARQ when LLDP MIB
  62 * associated with the interface changes (0x0A01)
  63 */
  64enum ice_status
  65ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
  66                           struct ice_sq_cd *cd)
  67{
  68        struct ice_aqc_lldp_set_mib_change *cmd;
  69        struct ice_aq_desc desc;
  70
  71        cmd = &desc.params.lldp_set_event;
  72
  73        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change);
  74
  75        if (!ena_update)
  76                cmd->command |= ICE_AQ_LLDP_MIB_UPDATE_DIS;
  77
  78        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
  79}
  80
  81/**
  82 * ice_aq_stop_lldp
  83 * @hw: pointer to the HW struct
  84 * @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown
  85 *                       False if LLDP Agent needs to be Stopped
  86 * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across
  87 *           reboots
  88 * @cd: pointer to command details structure or NULL
  89 *
  90 * Stop or Shutdown the embedded LLDP Agent (0x0A05)
  91 */
  92enum ice_status
  93ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
  94                 struct ice_sq_cd *cd)
  95{
  96        struct ice_aqc_lldp_stop *cmd;
  97        struct ice_aq_desc desc;
  98
  99        cmd = &desc.params.lldp_stop;
 100
 101        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop);
 102
 103        if (shutdown_lldp_agent)
 104                cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;
 105
 106        if (persist)
 107                cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;
 108
 109        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 110}
 111
 112/**
 113 * ice_aq_start_lldp
 114 * @hw: pointer to the HW struct
 115 * @persist: True if Start of LLDP Agent needs to be persistent across reboots
 116 * @cd: pointer to command details structure or NULL
 117 *
 118 * Start the embedded LLDP Agent on all ports. (0x0A06)
 119 */
 120enum ice_status
 121ice_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_status
 140 * @hw: pointer to the HW struct
 141 *
 142 * Get the DCBX status from the Firmware
 143 */
 144u8 ice_get_dcbx_status(struct ice_hw *hw)
 145{
 146        u32 reg;
 147
 148        reg = rd32(hw, PRTDCB_GENS);
 149        return (u8)((reg & PRTDCB_GENS_DCBX_STATUS_M) >>
 150                    PRTDCB_GENS_DCBX_STATUS_S);
 151}
 152
 153/**
 154 * ice_parse_ieee_ets_common_tlv
 155 * @buf: Data buffer to be parsed for ETS CFG/REC data
 156 * @ets_cfg: Container to store parsed data
 157 *
 158 * Parses the common data of IEEE 802.1Qaz ETS CFG/REC TLV
 159 */
 160static void
 161ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
 162{
 163        u8 offset = 0;
 164        int i;
 165
 166        /* Priority Assignment Table (4 octets)
 167         * Octets:|    1    |    2    |    3    |    4    |
 168         *        -----------------------------------------
 169         *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
 170         *        -----------------------------------------
 171         *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
 172         *        -----------------------------------------
 173         */
 174        for (i = 0; i < 4; i++) {
 175                ets_cfg->prio_table[i * 2] =
 176                        ((buf[offset] & ICE_IEEE_ETS_PRIO_1_M) >>
 177                         ICE_IEEE_ETS_PRIO_1_S);
 178                ets_cfg->prio_table[i * 2 + 1] =
 179                        ((buf[offset] & ICE_IEEE_ETS_PRIO_0_M) >>
 180                         ICE_IEEE_ETS_PRIO_0_S);
 181                offset++;
 182        }
 183
 184        /* TC Bandwidth Table (8 octets)
 185         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 186         *        ---------------------------------
 187         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 188         *        ---------------------------------
 189         *
 190         * TSA Assignment Table (8 octets)
 191         * Octets:| 9 | 10| 11| 12| 13| 14| 15| 16|
 192         *        ---------------------------------
 193         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 194         *        ---------------------------------
 195         */
 196        ice_for_each_traffic_class(i) {
 197                ets_cfg->tcbwtable[i] = buf[offset];
 198                ets_cfg->tsatable[i] = buf[ICE_MAX_TRAFFIC_CLASS + offset++];
 199        }
 200}
 201
 202/**
 203 * ice_parse_ieee_etscfg_tlv
 204 * @tlv: IEEE 802.1Qaz ETS CFG TLV
 205 * @dcbcfg: Local store to update ETS CFG data
 206 *
 207 * Parses IEEE 802.1Qaz ETS CFG TLV
 208 */
 209static void
 210ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,
 211                          struct ice_dcbx_cfg *dcbcfg)
 212{
 213        struct ice_dcb_ets_cfg *etscfg;
 214        u8 *buf = tlv->tlvinfo;
 215
 216        /* First Octet post subtype
 217         * --------------------------
 218         * |will-|CBS  | Re-  | Max |
 219         * |ing  |     |served| TCs |
 220         * --------------------------
 221         * |1bit | 1bit|3 bits|3bits|
 222         */
 223        etscfg = &dcbcfg->etscfg;
 224        etscfg->willing = ((buf[0] & ICE_IEEE_ETS_WILLING_M) >>
 225                           ICE_IEEE_ETS_WILLING_S);
 226        etscfg->cbs = ((buf[0] & ICE_IEEE_ETS_CBS_M) >> ICE_IEEE_ETS_CBS_S);
 227        etscfg->maxtcs = ((buf[0] & ICE_IEEE_ETS_MAXTC_M) >>
 228                          ICE_IEEE_ETS_MAXTC_S);
 229
 230        /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
 231        ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);
 232}
 233
 234/**
 235 * ice_parse_ieee_etsrec_tlv
 236 * @tlv: IEEE 802.1Qaz ETS REC TLV
 237 * @dcbcfg: Local store to update ETS REC data
 238 *
 239 * Parses IEEE 802.1Qaz ETS REC TLV
 240 */
 241static void
 242ice_parse_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
 243                          struct ice_dcbx_cfg *dcbcfg)
 244{
 245        u8 *buf = tlv->tlvinfo;
 246
 247        /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
 248        ice_parse_ieee_ets_common_tlv(&buf[1], &dcbcfg->etsrec);
 249}
 250
 251/**
 252 * ice_parse_ieee_pfccfg_tlv
 253 * @tlv: IEEE 802.1Qaz PFC CFG TLV
 254 * @dcbcfg: Local store to update PFC CFG data
 255 *
 256 * Parses IEEE 802.1Qaz PFC CFG TLV
 257 */
 258static void
 259ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,
 260                          struct ice_dcbx_cfg *dcbcfg)
 261{
 262        u8 *buf = tlv->tlvinfo;
 263
 264        /* ----------------------------------------
 265         * |will-|MBC  | Re-  | PFC |  PFC Enable  |
 266         * |ing  |     |served| cap |              |
 267         * -----------------------------------------
 268         * |1bit | 1bit|2 bits|4bits| 1 octet      |
 269         */
 270        dcbcfg->pfc.willing = ((buf[0] & ICE_IEEE_PFC_WILLING_M) >>
 271                               ICE_IEEE_PFC_WILLING_S);
 272        dcbcfg->pfc.mbc = ((buf[0] & ICE_IEEE_PFC_MBC_M) >> ICE_IEEE_PFC_MBC_S);
 273        dcbcfg->pfc.pfccap = ((buf[0] & ICE_IEEE_PFC_CAP_M) >>
 274                              ICE_IEEE_PFC_CAP_S);
 275        dcbcfg->pfc.pfcena = buf[1];
 276}
 277
 278/**
 279 * ice_parse_ieee_app_tlv
 280 * @tlv: IEEE 802.1Qaz APP TLV
 281 * @dcbcfg: Local store to update APP PRIO data
 282 *
 283 * Parses IEEE 802.1Qaz APP PRIO TLV
 284 */
 285static void
 286ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
 287                       struct ice_dcbx_cfg *dcbcfg)
 288{
 289        u16 offset = 0;
 290        u16 typelen;
 291        int i = 0;
 292        u16 len;
 293        u8 *buf;
 294
 295        typelen = NTOHS(tlv->typelen);
 296        len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
 297        buf = tlv->tlvinfo;
 298
 299        /* Removing sizeof(ouisubtype) and reserved byte from len.
 300         * Remaining len div 3 is number of APP TLVs.
 301         */
 302        len -= (sizeof(tlv->ouisubtype) + 1);
 303
 304        /* Move offset to App Priority Table */
 305        offset++;
 306
 307        /* Application Priority Table (3 octets)
 308         * Octets:|         1          |    2    |    3    |
 309         *        -----------------------------------------
 310         *        |Priority|Rsrvd| Sel |    Protocol ID    |
 311         *        -----------------------------------------
 312         *   Bits:|23    21|20 19|18 16|15                0|
 313         *        -----------------------------------------
 314         */
 315        while (offset < len) {
 316                dcbcfg->app[i].priority = ((buf[offset] &
 317                                            ICE_IEEE_APP_PRIO_M) >>
 318                                           ICE_IEEE_APP_PRIO_S);
 319                dcbcfg->app[i].selector = ((buf[offset] &
 320                                            ICE_IEEE_APP_SEL_M) >>
 321                                           ICE_IEEE_APP_SEL_S);
 322                dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |
 323                        buf[offset + 2];
 324                /* Move to next app */
 325                offset += 3;
 326                i++;
 327                if (i >= ICE_DCBX_MAX_APPS)
 328                        break;
 329        }
 330
 331        dcbcfg->numapps = i;
 332}
 333
 334/**
 335 * ice_parse_ieee_tlv
 336 * @tlv: IEEE 802.1Qaz TLV
 337 * @dcbcfg: Local store to update ETS REC data
 338 *
 339 * Get the TLV subtype and send it to parsing function
 340 * based on the subtype value
 341 */
 342static void
 343ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
 344{
 345        u32 ouisubtype;
 346        u8 subtype;
 347
 348        ouisubtype = NTOHL(tlv->ouisubtype);
 349        subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
 350                       ICE_LLDP_TLV_SUBTYPE_S);
 351        switch (subtype) {
 352        case ICE_IEEE_SUBTYPE_ETS_CFG:
 353                ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);
 354                break;
 355        case ICE_IEEE_SUBTYPE_ETS_REC:
 356                ice_parse_ieee_etsrec_tlv(tlv, dcbcfg);
 357                break;
 358        case ICE_IEEE_SUBTYPE_PFC_CFG:
 359                ice_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
 360                break;
 361        case ICE_IEEE_SUBTYPE_APP_PRI:
 362                ice_parse_ieee_app_tlv(tlv, dcbcfg);
 363                break;
 364        default:
 365                break;
 366        }
 367}
 368
 369/**
 370 * ice_parse_cee_pgcfg_tlv
 371 * @tlv: CEE DCBX PG CFG TLV
 372 * @dcbcfg: Local store to update ETS CFG data
 373 *
 374 * Parses CEE DCBX PG CFG TLV
 375 */
 376static void
 377ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,
 378                        struct ice_dcbx_cfg *dcbcfg)
 379{
 380        struct ice_dcb_ets_cfg *etscfg;
 381        u8 *buf = tlv->tlvinfo;
 382        u16 offset = 0;
 383        int i;
 384
 385        etscfg = &dcbcfg->etscfg;
 386
 387        if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
 388                etscfg->willing = 1;
 389
 390        etscfg->cbs = 0;
 391        /* Priority Group Table (4 octets)
 392         * Octets:|    1    |    2    |    3    |    4    |
 393         *        -----------------------------------------
 394         *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
 395         *        -----------------------------------------
 396         *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
 397         *        -----------------------------------------
 398         */
 399        for (i = 0; i < 4; i++) {
 400                etscfg->prio_table[i * 2] =
 401                        ((buf[offset] & ICE_CEE_PGID_PRIO_1_M) >>
 402                         ICE_CEE_PGID_PRIO_1_S);
 403                etscfg->prio_table[i * 2 + 1] =
 404                        ((buf[offset] & ICE_CEE_PGID_PRIO_0_M) >>
 405                         ICE_CEE_PGID_PRIO_0_S);
 406                offset++;
 407        }
 408
 409        /* PG Percentage Table (8 octets)
 410         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 411         *        ---------------------------------
 412         *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
 413         *        ---------------------------------
 414         */
 415        ice_for_each_traffic_class(i) {
 416                etscfg->tcbwtable[i] = buf[offset++];
 417
 418                if (etscfg->prio_table[i] == ICE_CEE_PGID_STRICT)
 419                        dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
 420                else
 421                        dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
 422        }
 423
 424        /* Number of TCs supported (1 octet) */
 425        etscfg->maxtcs = buf[offset];
 426}
 427
 428/**
 429 * ice_parse_cee_pfccfg_tlv
 430 * @tlv: CEE DCBX PFC CFG TLV
 431 * @dcbcfg: Local store to update PFC CFG data
 432 *
 433 * Parses CEE DCBX PFC CFG TLV
 434 */
 435static void
 436ice_parse_cee_pfccfg_tlv(struct ice_cee_feat_tlv *tlv,
 437                         struct ice_dcbx_cfg *dcbcfg)
 438{
 439        u8 *buf = tlv->tlvinfo;
 440
 441        if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
 442                dcbcfg->pfc.willing = 1;
 443
 444        /* ------------------------
 445         * | PFC Enable | PFC TCs |
 446         * ------------------------
 447         * | 1 octet    | 1 octet |
 448         */
 449        dcbcfg->pfc.pfcena = buf[0];
 450        dcbcfg->pfc.pfccap = buf[1];
 451}
 452
 453/**
 454 * ice_parse_cee_app_tlv
 455 * @tlv: CEE DCBX APP TLV
 456 * @dcbcfg: Local store to update APP PRIO data
 457 *
 458 * Parses CEE DCBX APP PRIO TLV
 459 */
 460static void
 461ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
 462{
 463        u16 len, typelen, offset = 0;
 464        struct ice_cee_app_prio *app;
 465        u8 i;
 466
 467        typelen = NTOHS(tlv->hdr.typelen);
 468        len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
 469
 470        dcbcfg->numapps = len / sizeof(*app);
 471        if (!dcbcfg->numapps)
 472                return;
 473        if (dcbcfg->numapps > ICE_DCBX_MAX_APPS)
 474                dcbcfg->numapps = ICE_DCBX_MAX_APPS;
 475
 476        for (i = 0; i < dcbcfg->numapps; i++) {
 477                u8 up, selector;
 478
 479                app = (struct ice_cee_app_prio *)(tlv->tlvinfo + offset);
 480                for (up = 0; up < ICE_MAX_USER_PRIORITY; up++)
 481                        if (app->prio_map & BIT(up))
 482                                break;
 483
 484                dcbcfg->app[i].priority = up;
 485
 486                /* Get Selector from lower 2 bits, and convert to IEEE */
 487                selector = (app->upper_oui_sel & ICE_CEE_APP_SELECTOR_M);
 488                switch (selector) {
 489                case ICE_CEE_APP_SEL_ETHTYPE:
 490                        dcbcfg->app[i].selector = ICE_APP_SEL_ETHTYPE;
 491                        break;
 492                case ICE_CEE_APP_SEL_TCPIP:
 493                        dcbcfg->app[i].selector = ICE_APP_SEL_TCPIP;
 494                        break;
 495                default:
 496                        /* Keep selector as it is for unknown types */
 497                        dcbcfg->app[i].selector = selector;
 498                }
 499
 500                dcbcfg->app[i].prot_id = NTOHS(app->protocol);
 501                /* Move to next app */
 502                offset += sizeof(*app);
 503        }
 504}
 505
 506/**
 507 * ice_parse_cee_tlv
 508 * @tlv: CEE DCBX TLV
 509 * @dcbcfg: Local store to update DCBX config data
 510 *
 511 * Get the TLV subtype and send it to parsing function
 512 * based on the subtype value
 513 */
 514static void
 515ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
 516{
 517        struct ice_cee_feat_tlv *sub_tlv;
 518        u8 subtype, feat_tlv_count = 0;
 519        u16 len, tlvlen, typelen;
 520        u32 ouisubtype;
 521
 522        ouisubtype = NTOHL(tlv->ouisubtype);
 523        subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
 524                       ICE_LLDP_TLV_SUBTYPE_S);
 525        /* Return if not CEE DCBX */
 526        if (subtype != ICE_CEE_DCBX_TYPE)
 527                return;
 528
 529        typelen = NTOHS(tlv->typelen);
 530        tlvlen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
 531        len = sizeof(tlv->typelen) + sizeof(ouisubtype) +
 532                sizeof(struct ice_cee_ctrl_tlv);
 533        /* Return if no CEE DCBX Feature TLVs */
 534        if (tlvlen <= len)
 535                return;
 536
 537        sub_tlv = (struct ice_cee_feat_tlv *)((char *)tlv + len);
 538        while (feat_tlv_count < ICE_CEE_MAX_FEAT_TYPE) {
 539                u16 sublen;
 540
 541                typelen = NTOHS(sub_tlv->hdr.typelen);
 542                sublen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
 543                subtype = (u8)((typelen & ICE_LLDP_TLV_TYPE_M) >>
 544                               ICE_LLDP_TLV_TYPE_S);
 545                switch (subtype) {
 546                case ICE_CEE_SUBTYPE_PG_CFG:
 547                        ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
 548                        break;
 549                case ICE_CEE_SUBTYPE_PFC_CFG:
 550                        ice_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
 551                        break;
 552                case ICE_CEE_SUBTYPE_APP_PRI:
 553                        ice_parse_cee_app_tlv(sub_tlv, dcbcfg);
 554                        break;
 555                default:
 556                        return; /* Invalid Sub-type return */
 557                }
 558                feat_tlv_count++;
 559                /* Move to next sub TLV */
 560                sub_tlv = (struct ice_cee_feat_tlv *)
 561                          ((char *)sub_tlv + sizeof(sub_tlv->hdr.typelen) +
 562                           sublen);
 563        }
 564}
 565
 566/**
 567 * ice_parse_org_tlv
 568 * @tlv: Organization specific TLV
 569 * @dcbcfg: Local store to update ETS REC data
 570 *
 571 * Currently only IEEE 802.1Qaz TLV is supported, all others
 572 * will be returned
 573 */
 574static void
 575ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
 576{
 577        u32 ouisubtype;
 578        u32 oui;
 579
 580        ouisubtype = NTOHL(tlv->ouisubtype);
 581        oui = ((ouisubtype & ICE_LLDP_TLV_OUI_M) >> ICE_LLDP_TLV_OUI_S);
 582        switch (oui) {
 583        case ICE_IEEE_8021QAZ_OUI:
 584                ice_parse_ieee_tlv(tlv, dcbcfg);
 585                break;
 586        case ICE_CEE_DCBX_OUI:
 587                ice_parse_cee_tlv(tlv, dcbcfg);
 588                break;
 589        default:
 590                break;
 591        }
 592}
 593
 594/**
 595 * ice_lldp_to_dcb_cfg
 596 * @lldpmib: LLDPDU to be parsed
 597 * @dcbcfg: store for LLDPDU data
 598 *
 599 * Parse DCB configuration from the LLDPDU
 600 */
 601enum ice_status ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
 602{
 603        struct ice_lldp_org_tlv *tlv;
 604        enum ice_status ret = ICE_SUCCESS;
 605        u16 offset = 0;
 606        u16 typelen;
 607        u16 type;
 608        u16 len;
 609
 610        if (!lldpmib || !dcbcfg)
 611                return ICE_ERR_PARAM;
 612
 613        /* set to the start of LLDPDU */
 614        lldpmib += ETH_HEADER_LEN;
 615        tlv = (struct ice_lldp_org_tlv *)lldpmib;
 616        while (1) {
 617                typelen = NTOHS(tlv->typelen);
 618                type = ((typelen & ICE_LLDP_TLV_TYPE_M) >> ICE_LLDP_TLV_TYPE_S);
 619                len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
 620                offset += sizeof(typelen) + len;
 621
 622                /* END TLV or beyond LLDPDU size */
 623                if (type == ICE_TLV_TYPE_END || offset > ICE_LLDPDU_SIZE)
 624                        break;
 625
 626                switch (type) {
 627                case ICE_TLV_TYPE_ORG:
 628                        ice_parse_org_tlv(tlv, dcbcfg);
 629                        break;
 630                default:
 631                        break;
 632                }
 633
 634                /* Move to next TLV */
 635                tlv = (struct ice_lldp_org_tlv *)
 636                      ((char *)tlv + sizeof(tlv->typelen) + len);
 637        }
 638
 639        return ret;
 640}
 641
 642/**
 643 * ice_aq_get_dcb_cfg
 644 * @hw: pointer to the HW struct
 645 * @mib_type: MIB type for the query
 646 * @bridgetype: bridge type for the query (remote)
 647 * @dcbcfg: store for LLDPDU data
 648 *
 649 * Query DCB configuration from the firmware
 650 */
 651enum ice_status
 652ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
 653                   struct ice_dcbx_cfg *dcbcfg)
 654{
 655        enum ice_status ret;
 656        u8 *lldpmib;
 657
 658        /* Allocate the LLDPDU */
 659        lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
 660        if (!lldpmib)
 661                return ICE_ERR_NO_MEMORY;
 662
 663        ret = ice_aq_get_lldp_mib(hw, bridgetype, mib_type, (void *)lldpmib,
 664                                  ICE_LLDPDU_SIZE, NULL, NULL, NULL);
 665
 666        if (ret == ICE_SUCCESS)
 667                /* Parse LLDP MIB to get DCB configuration */
 668                ret = ice_lldp_to_dcb_cfg(lldpmib, dcbcfg);
 669
 670        ice_free(hw, lldpmib);
 671
 672        return ret;
 673}
 674
 675/**
 676 * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW
 677 * @hw: pointer to the HW struct
 678 * @start_dcbx_agent: True if DCBX Agent needs to be started
 679 *                    False if DCBX Agent needs to be stopped
 680 * @dcbx_agent_status: FW indicates back the DCBX agent status
 681 *                     True if DCBX Agent is active
 682 *                     False if DCBX Agent is stopped
 683 * @cd: pointer to command details structure or NULL
 684 *
 685 * Start/Stop the embedded dcbx Agent. In case that this wrapper function
 686 * returns ICE_SUCCESS, caller will need to check if FW returns back the same
 687 * value as stated in dcbx_agent_status, and react accordingly. (0x0A09)
 688 */
 689enum ice_status
 690ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,
 691                       bool *dcbx_agent_status, struct ice_sq_cd *cd)
 692{
 693        struct ice_aqc_lldp_stop_start_specific_agent *cmd;
 694        enum ice_status status;
 695        struct ice_aq_desc desc;
 696        u16 opcode;
 697
 698        cmd = &desc.params.lldp_agent_ctrl;
 699
 700        opcode = ice_aqc_opc_lldp_stop_start_specific_agent;
 701
 702        ice_fill_dflt_direct_cmd_desc(&desc, opcode);
 703
 704        if (start_dcbx_agent)
 705                cmd->command = ICE_AQC_START_STOP_AGENT_START_DCBX;
 706
 707        status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 708
 709        *dcbx_agent_status = false;
 710
 711        if (status == ICE_SUCCESS &&
 712            cmd->command == ICE_AQC_START_STOP_AGENT_START_DCBX)
 713                *dcbx_agent_status = true;
 714
 715        return status;
 716}
 717
 718/**
 719 * ice_aq_get_cee_dcb_cfg
 720 * @hw: pointer to the HW struct
 721 * @buff: response buffer that stores CEE operational configuration
 722 * @cd: pointer to command details structure or NULL
 723 *
 724 * Get CEE DCBX mode operational configuration from firmware (0x0A07)
 725 */
 726enum ice_status
 727ice_aq_get_cee_dcb_cfg(struct ice_hw *hw,
 728                       struct ice_aqc_get_cee_dcb_cfg_resp *buff,
 729                       struct ice_sq_cd *cd)
 730{
 731        struct ice_aq_desc desc;
 732
 733        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg);
 734
 735        return ice_aq_send_cmd(hw, &desc, (void *)buff, sizeof(*buff), cd);
 736}
 737
 738/**
 739 * ice_aq_set_pfc_mode - Set PFC mode
 740 * @hw: pointer to the HW struct
 741 * @pfc_mode: value of PFC mode to set
 742 * @cd: pointer to command details structure or NULL
 743 *
 744 * This AQ call configures the PFC mdoe to DSCP-based PFC mode or VLAN
 745 * -based PFC (0x0303)
 746 */
 747enum ice_status
 748ice_aq_set_pfc_mode(struct ice_hw *hw, u8 pfc_mode, struct ice_sq_cd *cd)
 749{
 750        struct ice_aqc_set_query_pfc_mode *cmd;
 751        struct ice_aq_desc desc;
 752        enum ice_status status;
 753
 754        if (pfc_mode > ICE_AQC_PFC_DSCP_BASED_PFC)
 755                return ICE_ERR_PARAM;
 756
 757        cmd = &desc.params.set_query_pfc_mode;
 758
 759        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_pfc_mode);
 760
 761        cmd->pfc_mode = pfc_mode;
 762
 763        status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 764        if (status)
 765                return status;
 766
 767        /* The spec isn't clear about whether the FW will return an error code
 768         * if the PFC mode requested by the driver was not set. The spec just
 769         * says that the FW will write the PFC mode set back into cmd->pfc_mode,
 770         * so after the AQ has been executed, check if cmd->pfc_mode is what was
 771         * requested.
 772         */
 773        if (cmd->pfc_mode != pfc_mode)
 774                return ICE_ERR_NOT_SUPPORTED;
 775
 776        return ICE_SUCCESS;
 777}
 778
 779/**
 780 * ice_cee_to_dcb_cfg
 781 * @cee_cfg: pointer to CEE configuration struct
 782 * @pi: port information structure
 783 *
 784 * Convert CEE configuration from firmware to DCB configuration
 785 */
 786static void
 787ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,
 788                   struct ice_port_info *pi)
 789{
 790        u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
 791        u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift;
 792        u8 i, j, err, sync, oper, app_index, ice_app_sel_type;
 793        u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
 794        u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift;
 795        struct ice_dcbx_cfg *cmp_dcbcfg, *dcbcfg;
 796        u16 ice_app_prot_id_type;
 797
 798        dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
 799        dcbcfg->dcbx_mode = ICE_DCBX_MODE_CEE;
 800        dcbcfg->tlv_status = tlv_status;
 801
 802        /* CEE PG data */
 803        dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
 804
 805        /* Note that the FW creates the oper_prio_tc nibbles reversed
 806         * from those in the CEE Priority Group sub-TLV.
 807         */
 808        for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
 809                dcbcfg->etscfg.prio_table[i * 2] =
 810                        ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_0_M) >>
 811                         ICE_CEE_PGID_PRIO_0_S);
 812                dcbcfg->etscfg.prio_table[i * 2 + 1] =
 813                        ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_1_M) >>
 814                         ICE_CEE_PGID_PRIO_1_S);
 815        }
 816
 817        ice_for_each_traffic_class(i) {
 818                dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
 819
 820                if (dcbcfg->etscfg.prio_table[i] == ICE_CEE_PGID_STRICT) {
 821                        /* Map it to next empty TC */
 822                        dcbcfg->etscfg.prio_table[i] = cee_cfg->oper_num_tc - 1;
 823                        dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
 824                } else {
 825                        dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
 826                }
 827        }
 828
 829        /* CEE PFC data */
 830        dcbcfg->pfc.pfcena = cee_cfg->oper_pfc_en;
 831        dcbcfg->pfc.pfccap = ICE_MAX_TRAFFIC_CLASS;
 832
 833        /* CEE APP TLV data */
 834        if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
 835                cmp_dcbcfg = &pi->qos_cfg.desired_dcbx_cfg;
 836        else
 837                cmp_dcbcfg = &pi->qos_cfg.remote_dcbx_cfg;
 838
 839        app_index = 0;
 840        for (i = 0; i < 3; i++) {
 841                if (i == 0) {
 842                        /* FCoE APP */
 843                        ice_aqc_cee_status_mask = ICE_AQC_CEE_FCOE_STATUS_M;
 844                        ice_aqc_cee_status_shift = ICE_AQC_CEE_FCOE_STATUS_S;
 845                        ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FCOE_M;
 846                        ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FCOE_S;
 847                        ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
 848                        ice_app_prot_id_type = ICE_APP_PROT_ID_FCOE;
 849                } else if (i == 1) {
 850                        /* iSCSI APP */
 851                        ice_aqc_cee_status_mask = ICE_AQC_CEE_ISCSI_STATUS_M;
 852                        ice_aqc_cee_status_shift = ICE_AQC_CEE_ISCSI_STATUS_S;
 853                        ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_ISCSI_M;
 854                        ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_ISCSI_S;
 855                        ice_app_sel_type = ICE_APP_SEL_TCPIP;
 856                        ice_app_prot_id_type = ICE_APP_PROT_ID_ISCSI;
 857
 858                        for (j = 0; j < cmp_dcbcfg->numapps; j++) {
 859                                u16 prot_id = cmp_dcbcfg->app[j].prot_id;
 860                                u8 sel = cmp_dcbcfg->app[j].selector;
 861
 862                                if  (sel == ICE_APP_SEL_TCPIP &&
 863                                     (prot_id == ICE_APP_PROT_ID_ISCSI ||
 864                                      prot_id == ICE_APP_PROT_ID_ISCSI_860)) {
 865                                        ice_app_prot_id_type = prot_id;
 866                                        break;
 867                                }
 868                        }
 869                } else {
 870                        /* FIP APP */
 871                        ice_aqc_cee_status_mask = ICE_AQC_CEE_FIP_STATUS_M;
 872                        ice_aqc_cee_status_shift = ICE_AQC_CEE_FIP_STATUS_S;
 873                        ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FIP_M;
 874                        ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FIP_S;
 875                        ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
 876                        ice_app_prot_id_type = ICE_APP_PROT_ID_FIP;
 877                }
 878
 879                status = (tlv_status & ice_aqc_cee_status_mask) >>
 880                         ice_aqc_cee_status_shift;
 881                err = (status & ICE_TLV_STATUS_ERR) ? 1 : 0;
 882                sync = (status & ICE_TLV_STATUS_SYNC) ? 1 : 0;
 883                oper = (status & ICE_TLV_STATUS_OPER) ? 1 : 0;
 884                /* Add FCoE/iSCSI/FIP APP if Error is False and
 885                 * Oper/Sync is True
 886                 */
 887                if (!err && sync && oper) {
 888                        dcbcfg->app[app_index].priority =
 889                                (app_prio & ice_aqc_cee_app_mask) >>
 890                                ice_aqc_cee_app_shift;
 891                        dcbcfg->app[app_index].selector = ice_app_sel_type;
 892                        dcbcfg->app[app_index].prot_id = ice_app_prot_id_type;
 893                        app_index++;
 894                }
 895        }
 896
 897        dcbcfg->numapps = app_index;
 898}
 899
 900/**
 901 * ice_get_ieee_or_cee_dcb_cfg
 902 * @pi: port information structure
 903 * @dcbx_mode: mode of DCBX (IEEE or CEE)
 904 *
 905 * Get IEEE or CEE mode DCB configuration from the Firmware
 906 */
 907STATIC enum ice_status
 908ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode)
 909{
 910        struct ice_dcbx_cfg *dcbx_cfg = NULL;
 911        enum ice_status ret;
 912
 913        if (!pi)
 914                return ICE_ERR_PARAM;
 915
 916        if (dcbx_mode == ICE_DCBX_MODE_IEEE)
 917                dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
 918        else if (dcbx_mode == ICE_DCBX_MODE_CEE)
 919                dcbx_cfg = &pi->qos_cfg.desired_dcbx_cfg;
 920
 921        /* Get Local DCB Config in case of ICE_DCBX_MODE_IEEE
 922         * or get CEE DCB Desired Config in case of ICE_DCBX_MODE_CEE
 923         */
 924        ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_LOCAL,
 925                                 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
 926        if (ret)
 927                goto out;
 928
 929        /* Get Remote DCB Config */
 930        dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;
 931        ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,
 932                                 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
 933        /* Don't treat ENOENT as an error for Remote MIBs */
 934        if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
 935                ret = ICE_SUCCESS;
 936
 937out:
 938        return ret;
 939}
 940
 941/**
 942 * ice_get_dcb_cfg
 943 * @pi: port information structure
 944 *
 945 * Get DCB configuration from the Firmware
 946 */
 947enum ice_status ice_get_dcb_cfg(struct ice_port_info *pi)
 948{
 949        struct ice_aqc_get_cee_dcb_cfg_resp cee_cfg;
 950        struct ice_dcbx_cfg *dcbx_cfg;
 951        enum ice_status ret;
 952
 953        if (!pi)
 954                return ICE_ERR_PARAM;
 955
 956        ret = ice_aq_get_cee_dcb_cfg(pi->hw, &cee_cfg, NULL);
 957        if (ret == ICE_SUCCESS) {
 958                /* CEE mode */
 959                ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE);
 960                ice_cee_to_dcb_cfg(&cee_cfg, pi);
 961        } else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) {
 962                /* CEE mode not enabled try querying IEEE data */
 963                dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
 964                dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;
 965                ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_IEEE);
 966        }
 967
 968        return ret;
 969}
 970
 971/**
 972 * ice_init_dcb
 973 * @hw: pointer to the HW struct
 974 * @enable_mib_change: enable MIB change event
 975 *
 976 * Update DCB configuration from the Firmware
 977 */
 978enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
 979{
 980        struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
 981        enum ice_status ret = ICE_SUCCESS;
 982
 983        if (!hw->func_caps.common_cap.dcb)
 984                return ICE_ERR_NOT_SUPPORTED;
 985
 986        qos_cfg->is_sw_lldp = true;
 987
 988        /* Get DCBX status */
 989        qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
 990
 991        if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DONE ||
 992            qos_cfg->dcbx_status == ICE_DCBX_STATUS_IN_PROGRESS ||
 993            qos_cfg->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
 994                /* Get current DCBX configuration */
 995                ret = ice_get_dcb_cfg(hw->port_info);
 996                if (ret)
 997                        return ret;
 998                qos_cfg->is_sw_lldp = false;
 999        } else if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS) {
1000                return ICE_ERR_NOT_READY;
1001        }
1002
1003        /* Configure the LLDP MIB change event */
1004        if (enable_mib_change) {
1005                ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);
1006                if (ret)
1007                        qos_cfg->is_sw_lldp = true;
1008        }
1009
1010        return ret;
1011}
1012
1013/**
1014 * ice_cfg_lldp_mib_change
1015 * @hw: pointer to the HW struct
1016 * @ena_mib: enable/disable MIB change event
1017 *
1018 * Configure (disable/enable) MIB
1019 */
1020enum ice_status ice_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_mib)
1021{
1022        struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
1023        enum ice_status ret;
1024
1025        if (!hw->func_caps.common_cap.dcb)
1026                return ICE_ERR_NOT_SUPPORTED;
1027
1028        /* Get DCBX status */
1029        qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
1030
1031        if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS)
1032                return ICE_ERR_NOT_READY;
1033
1034        ret = ice_aq_cfg_lldp_mib_change(hw, ena_mib, NULL);
1035        if (!ret)
1036                qos_cfg->is_sw_lldp = !ena_mib;
1037
1038        return ret;
1039}
1040
1041/**
1042 * ice_add_ieee_ets_common_tlv
1043 * @buf: Data buffer to be populated with ice_dcb_ets_cfg data
1044 * @ets_cfg: Container for ice_dcb_ets_cfg data
1045 *
1046 * Populate the TLV buffer with ice_dcb_ets_cfg data
1047 */
1048static void
1049ice_add_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
1050{
1051        u8 priority0, priority1;
1052        u8 offset = 0;
1053        int i;
1054
1055        /* Priority Assignment Table (4 octets)
1056         * Octets:|    1    |    2    |    3    |    4    |
1057         *        -----------------------------------------
1058         *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1059         *        -----------------------------------------
1060         *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1061         *        -----------------------------------------
1062         */
1063        for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
1064                priority0 = ets_cfg->prio_table[i * 2] & 0xF;
1065                priority1 = ets_cfg->prio_table[i * 2 + 1] & 0xF;
1066                buf[offset] = (priority0 << ICE_IEEE_ETS_PRIO_1_S) | priority1;
1067                offset++;
1068        }
1069
1070        /* TC Bandwidth Table (8 octets)
1071         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1072         *        ---------------------------------
1073         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1074         *        ---------------------------------
1075         *
1076         * TSA Assignment Table (8 octets)
1077         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1078         *        ---------------------------------
1079         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1080         *        ---------------------------------
1081         */
1082        ice_for_each_traffic_class(i) {
1083                buf[offset] = ets_cfg->tcbwtable[i];
1084                buf[ICE_MAX_TRAFFIC_CLASS + offset] = ets_cfg->tsatable[i];
1085                offset++;
1086        }
1087}
1088
1089/**
1090 * ice_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
1091 * @tlv: Fill the ETS config data in IEEE format
1092 * @dcbcfg: Local store which holds the DCB Config
1093 *
1094 * Prepare IEEE 802.1Qaz ETS CFG TLV
1095 */
1096static void
1097ice_add_ieee_ets_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1098{
1099        struct ice_dcb_ets_cfg *etscfg;
1100        u8 *buf = tlv->tlvinfo;
1101        u8 maxtcwilling = 0;
1102        u32 ouisubtype;
1103        u16 typelen;
1104
1105        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1106                   ICE_IEEE_ETS_TLV_LEN);
1107        tlv->typelen = HTONS(typelen);
1108
1109        ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1110                      ICE_IEEE_SUBTYPE_ETS_CFG);
1111        tlv->ouisubtype = HTONL(ouisubtype);
1112
1113        /* First Octet post subtype
1114         * --------------------------
1115         * |will-|CBS  | Re-  | Max |
1116         * |ing  |     |served| TCs |
1117         * --------------------------
1118         * |1bit | 1bit|3 bits|3bits|
1119         */
1120        etscfg = &dcbcfg->etscfg;
1121        if (etscfg->willing)
1122                maxtcwilling = BIT(ICE_IEEE_ETS_WILLING_S);
1123        maxtcwilling |= etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1124        buf[0] = maxtcwilling;
1125
1126        /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1127        ice_add_ieee_ets_common_tlv(&buf[1], etscfg);
1128}
1129
1130/**
1131 * ice_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1132 * @tlv: Fill ETS Recommended TLV in IEEE format
1133 * @dcbcfg: Local store which holds the DCB Config
1134 *
1135 * Prepare IEEE 802.1Qaz ETS REC TLV
1136 */
1137static void
1138ice_add_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
1139                        struct ice_dcbx_cfg *dcbcfg)
1140{
1141        struct ice_dcb_ets_cfg *etsrec;
1142        u8 *buf = tlv->tlvinfo;
1143        u32 ouisubtype;
1144        u16 typelen;
1145
1146        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1147                   ICE_IEEE_ETS_TLV_LEN);
1148        tlv->typelen = HTONS(typelen);
1149
1150        ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1151                      ICE_IEEE_SUBTYPE_ETS_REC);
1152        tlv->ouisubtype = HTONL(ouisubtype);
1153
1154        etsrec = &dcbcfg->etsrec;
1155
1156        /* First Octet is reserved */
1157        /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1158        ice_add_ieee_ets_common_tlv(&buf[1], etsrec);
1159}
1160
1161/**
1162 * ice_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1163 * @tlv: Fill PFC TLV in IEEE format
1164 * @dcbcfg: Local store which holds the PFC CFG data
1165 *
1166 * Prepare IEEE 802.1Qaz PFC CFG TLV
1167 */
1168static void
1169ice_add_ieee_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1170{
1171        u8 *buf = tlv->tlvinfo;
1172        u32 ouisubtype;
1173        u16 typelen;
1174
1175        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1176                   ICE_IEEE_PFC_TLV_LEN);
1177        tlv->typelen = HTONS(typelen);
1178
1179        ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1180                      ICE_IEEE_SUBTYPE_PFC_CFG);
1181        tlv->ouisubtype = HTONL(ouisubtype);
1182
1183        /* ----------------------------------------
1184         * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1185         * |ing  |     |served| cap |              |
1186         * -----------------------------------------
1187         * |1bit | 1bit|2 bits|4bits| 1 octet      |
1188         */
1189        if (dcbcfg->pfc.willing)
1190                buf[0] = BIT(ICE_IEEE_PFC_WILLING_S);
1191
1192        if (dcbcfg->pfc.mbc)
1193                buf[0] |= BIT(ICE_IEEE_PFC_MBC_S);
1194
1195        buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1196        buf[1] = dcbcfg->pfc.pfcena;
1197}
1198
1199/**
1200 * ice_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1201 * @tlv: Fill APP TLV in IEEE format
1202 * @dcbcfg: Local store which holds the APP CFG data
1203 *
1204 * Prepare IEEE 802.1Qaz APP CFG TLV
1205 */
1206static void
1207ice_add_ieee_app_pri_tlv(struct ice_lldp_org_tlv *tlv,
1208                         struct ice_dcbx_cfg *dcbcfg)
1209{
1210        u16 typelen, len, offset = 0;
1211        u8 priority, selector, i = 0;
1212        u8 *buf = tlv->tlvinfo;
1213        u32 ouisubtype;
1214
1215        /* No APP TLVs then just return */
1216        if (dcbcfg->numapps == 0)
1217                return;
1218        ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1219                      ICE_IEEE_SUBTYPE_APP_PRI);
1220        tlv->ouisubtype = HTONL(ouisubtype);
1221
1222        /* Move offset to App Priority Table */
1223        offset++;
1224        /* Application Priority Table (3 octets)
1225         * Octets:|         1          |    2    |    3    |
1226         *        -----------------------------------------
1227         *        |Priority|Rsrvd| Sel |    Protocol ID    |
1228         *        -----------------------------------------
1229         *   Bits:|23    21|20 19|18 16|15                0|
1230         *        -----------------------------------------
1231         */
1232        while (i < dcbcfg->numapps) {
1233                priority = dcbcfg->app[i].priority & 0x7;
1234                selector = dcbcfg->app[i].selector & 0x7;
1235                buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector;
1236                buf[offset + 1] = (dcbcfg->app[i].prot_id >> 0x8) & 0xFF;
1237                buf[offset + 2] = dcbcfg->app[i].prot_id & 0xFF;
1238                /* Move to next app */
1239                offset += 3;
1240                i++;
1241                if (i >= ICE_DCBX_MAX_APPS)
1242                        break;
1243        }
1244        /* len includes size of ouisubtype + 1 reserved + 3*numapps */
1245        len = sizeof(tlv->ouisubtype) + 1 + (i * 3);
1246        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | (len & 0x1FF));
1247        tlv->typelen = HTONS(typelen);
1248}
1249
1250/**
1251 * ice_add_dscp_up_tlv - Prepare DSCP to UP TLV
1252 * @tlv: location to build the TLV data
1253 * @dcbcfg: location of data to convert to TLV
1254 */
1255static void
1256ice_add_dscp_up_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1257{
1258        u8 *buf = tlv->tlvinfo;
1259        u32 ouisubtype;
1260        u16 typelen;
1261        int i;
1262
1263        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1264                   ICE_DSCP_UP_TLV_LEN);
1265        tlv->typelen = HTONS(typelen);
1266
1267        ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1268                           ICE_DSCP_SUBTYPE_DSCP2UP);
1269        tlv->ouisubtype = HTONL(ouisubtype);
1270
1271        /* bytes 0 - 63 - IPv4 DSCP2UP LUT */
1272        for (i = 0; i < ICE_DSCP_NUM_VAL; i++) {
1273                /* IPv4 mapping */
1274                buf[i] = dcbcfg->dscp_map[i];
1275                /* IPv6 mapping */
1276                buf[i + ICE_DSCP_IPV6_OFFSET] = dcbcfg->dscp_map[i];
1277        }
1278
1279        /* byte 64 - IPv4 untagged traffic */
1280        buf[i] = 0;
1281
1282        /* byte 144 - IPv6 untagged traffic */
1283        buf[i + ICE_DSCP_IPV6_OFFSET] = 0;
1284}
1285
1286#define ICE_BYTES_PER_TC        8
1287/**
1288 * ice_add_dscp_enf_tlv - Prepare DSCP Enforcement TLV
1289 * @tlv: location to build the TLV data
1290 */
1291static void
1292ice_add_dscp_enf_tlv(struct ice_lldp_org_tlv *tlv)
1293{
1294        u8 *buf = tlv->tlvinfo;
1295        u32 ouisubtype;
1296        u16 typelen;
1297
1298        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1299                   ICE_DSCP_ENF_TLV_LEN);
1300        tlv->typelen = HTONS(typelen);
1301
1302        ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1303                           ICE_DSCP_SUBTYPE_ENFORCE);
1304        tlv->ouisubtype = HTONL(ouisubtype);
1305
1306        /* Allow all DSCP values to be valid for all TC's (IPv4 and IPv6) */
1307        memset(buf, 0, 2 * (ICE_MAX_TRAFFIC_CLASS * ICE_BYTES_PER_TC));
1308}
1309
1310/**
1311 * ice_add_dscp_tc_bw_tlv - Prepare DSCP BW for TC TLV
1312 * @tlv: location to build the TLV data
1313 * @dcbcfg: location of the data to convert to TLV
1314 */
1315static void
1316ice_add_dscp_tc_bw_tlv(struct ice_lldp_org_tlv *tlv,
1317                       struct ice_dcbx_cfg *dcbcfg)
1318{
1319        struct ice_dcb_ets_cfg *etscfg;
1320        u8 *buf = tlv->tlvinfo;
1321        u32 ouisubtype;
1322        u8 offset = 0;
1323        u16 typelen;
1324        int i;
1325
1326        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1327                   ICE_DSCP_TC_BW_TLV_LEN);
1328        tlv->typelen = HTONS(typelen);
1329
1330        ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1331                           ICE_DSCP_SUBTYPE_TCBW);
1332        tlv->ouisubtype = HTONL(ouisubtype);
1333
1334        /* First Octet after subtype
1335         * ----------------------------
1336         * | RSV | CBS | RSV | Max TCs |
1337         * | 1b  | 1b  | 3b  | 3b      |
1338         * ----------------------------
1339         */
1340        etscfg = &dcbcfg->etscfg;
1341        buf[0] = etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1342
1343        /* bytes 1 - 4 reserved */
1344        offset = 5;
1345
1346        /* TC BW table
1347         * bytes 0 - 7 for TC 0 - 7
1348         *
1349         * TSA Assignment table
1350         * bytes 8 - 15 for TC 0 - 7
1351         */
1352        for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
1353                buf[offset] = etscfg->tcbwtable[i];
1354                buf[offset + ICE_MAX_TRAFFIC_CLASS] = etscfg->tsatable[i];
1355                offset++;
1356        }
1357}
1358
1359/**
1360 * ice_add_dscp_pfc_tlv - Prepare DSCP PFC TLV
1361 * @tlv: Fill PFC TLV in IEEE format
1362 * @dcbcfg: Local store which holds the PFC CFG data
1363 */
1364static void
1365ice_add_dscp_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1366{
1367        u8 *buf = tlv->tlvinfo;
1368        u32 ouisubtype;
1369        u16 typelen;
1370
1371        typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1372                   ICE_DSCP_PFC_TLV_LEN);
1373        tlv->typelen = HTONS(typelen);
1374
1375        ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1376                           ICE_DSCP_SUBTYPE_PFC);
1377        tlv->ouisubtype = HTONL(ouisubtype);
1378
1379        buf[0] = dcbcfg->pfc.pfccap & 0xF;
1380        buf[1] = dcbcfg->pfc.pfcena & 0xF;
1381}
1382
1383/**
1384 * ice_add_dcb_tlv - Add all IEEE or DSCP TLVs
1385 * @tlv: Fill TLV data in IEEE format
1386 * @dcbcfg: Local store which holds the DCB Config
1387 * @tlvid: Type of IEEE TLV
1388 *
1389 * Add tlv information
1390 */
1391static void
1392ice_add_dcb_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg,
1393                u16 tlvid)
1394{
1395        if (dcbcfg->pfc_mode == ICE_QOS_MODE_VLAN) {
1396                switch (tlvid) {
1397                case ICE_IEEE_TLV_ID_ETS_CFG:
1398                        ice_add_ieee_ets_tlv(tlv, dcbcfg);
1399                        break;
1400                case ICE_IEEE_TLV_ID_ETS_REC:
1401                        ice_add_ieee_etsrec_tlv(tlv, dcbcfg);
1402                        break;
1403                case ICE_IEEE_TLV_ID_PFC_CFG:
1404                        ice_add_ieee_pfc_tlv(tlv, dcbcfg);
1405                        break;
1406                case ICE_IEEE_TLV_ID_APP_PRI:
1407                        ice_add_ieee_app_pri_tlv(tlv, dcbcfg);
1408                        break;
1409                default:
1410                        break;
1411                }
1412        } else {
1413                /* pfc_mode == ICE_QOS_MODE_DSCP */
1414                switch (tlvid) {
1415                case ICE_TLV_ID_DSCP_UP:
1416                        ice_add_dscp_up_tlv(tlv, dcbcfg);
1417                        break;
1418                case ICE_TLV_ID_DSCP_ENF:
1419                        ice_add_dscp_enf_tlv(tlv);
1420                        break;
1421                case ICE_TLV_ID_DSCP_TC_BW:
1422                        ice_add_dscp_tc_bw_tlv(tlv, dcbcfg);
1423                        break;
1424                case ICE_TLV_ID_DSCP_TO_PFC:
1425                        ice_add_dscp_pfc_tlv(tlv, dcbcfg);
1426                        break;
1427                default:
1428                        break;
1429                }
1430        }
1431}
1432
1433/**
1434 * ice_dcb_cfg_to_lldp - Convert DCB configuration to MIB format
1435 * @lldpmib: pointer to the HW struct
1436 * @miblen: length of LLDP MIB
1437 * @dcbcfg: Local store which holds the DCB Config
1438 *
1439 * Convert the DCB configuration to MIB format
1440 */
1441void ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)
1442{
1443        u16 len, offset = 0, tlvid = ICE_TLV_ID_START;
1444        struct ice_lldp_org_tlv *tlv;
1445        u16 typelen;
1446
1447        tlv = (struct ice_lldp_org_tlv *)lldpmib;
1448        while (1) {
1449                ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1450                typelen = NTOHS(tlv->typelen);
1451                len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
1452                if (len)
1453                        offset += len + 2;
1454                /* END TLV or beyond LLDPDU size */
1455                if (tlvid >= ICE_TLV_ID_END_OF_LLDPPDU ||
1456                    offset > ICE_LLDPDU_SIZE)
1457                        break;
1458                /* Move to next TLV */
1459                if (len)
1460                        tlv = (struct ice_lldp_org_tlv *)
1461                                ((char *)tlv + sizeof(tlv->typelen) + len);
1462        }
1463        *miblen = offset;
1464}
1465
1466/**
1467 * ice_set_dcb_cfg - Set the local LLDP MIB to FW
1468 * @pi: port information structure
1469 *
1470 * Set DCB configuration to the Firmware
1471 */
1472enum ice_status ice_set_dcb_cfg(struct ice_port_info *pi)
1473{
1474        u8 mib_type, *lldpmib = NULL;
1475        struct ice_dcbx_cfg *dcbcfg;
1476        enum ice_status ret;
1477        struct ice_hw *hw;
1478        u16 miblen;
1479
1480        if (!pi)
1481                return ICE_ERR_PARAM;
1482
1483        hw = pi->hw;
1484
1485        /* update the HW local config */
1486        dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
1487        /* Allocate the LLDPDU */
1488        lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
1489        if (!lldpmib)
1490                return ICE_ERR_NO_MEMORY;
1491
1492        mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
1493        if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
1494                mib_type |= SET_LOCAL_MIB_TYPE_CEE_NON_WILLING;
1495
1496        ice_dcb_cfg_to_lldp(lldpmib, &miblen, dcbcfg);
1497        ret = ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen,
1498                                  NULL);
1499
1500        ice_free(hw, lldpmib);
1501
1502        return ret;
1503}
1504
1505/**
1506 * ice_aq_query_port_ets - query port ETS configuration
1507 * @pi: port information structure
1508 * @buf: pointer to buffer
1509 * @buf_size: buffer size in bytes
1510 * @cd: pointer to command details structure or NULL
1511 *
1512 * query current port ETS configuration
1513 */
1514enum ice_status
1515ice_aq_query_port_ets(struct ice_port_info *pi,
1516                      struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1517                      struct ice_sq_cd *cd)
1518{
1519        struct ice_aqc_query_port_ets *cmd;
1520        struct ice_aq_desc desc;
1521        enum ice_status status;
1522
1523        if (!pi)
1524                return ICE_ERR_PARAM;
1525        cmd = &desc.params.port_ets;
1526        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets);
1527        if (pi->root)
1528                cmd->port_teid = pi->root->info.node_teid;
1529
1530        status = ice_aq_send_cmd(pi->hw, &desc, buf, buf_size, cd);
1531        return status;
1532}
1533
1534/**
1535 * ice_update_port_tc_tree_cfg - update TC tree configuration
1536 * @pi: port information structure
1537 * @buf: pointer to buffer
1538 *
1539 * update the SW DB with the new TC changes
1540 */
1541enum ice_status
1542ice_update_port_tc_tree_cfg(struct ice_port_info *pi,
1543                            struct ice_aqc_port_ets_elem *buf)
1544{
1545        struct ice_sched_node *node, *tc_node;
1546        struct ice_aqc_txsched_elem_data elem;
1547        enum ice_status status = ICE_SUCCESS;
1548        u32 teid1, teid2;
1549        u8 i, j;
1550
1551        if (!pi)
1552                return ICE_ERR_PARAM;
1553        /* suspend the missing TC nodes */
1554        for (i = 0; i < pi->root->num_children; i++) {
1555                teid1 = LE32_TO_CPU(pi->root->children[i]->info.node_teid);
1556                ice_for_each_traffic_class(j) {
1557                        teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1558                        if (teid1 == teid2)
1559                                break;
1560                }
1561                if (j < ICE_MAX_TRAFFIC_CLASS)
1562                        continue;
1563                /* TC is missing */
1564                pi->root->children[i]->in_use = false;
1565        }
1566        /* add the new TC nodes */
1567        ice_for_each_traffic_class(j) {
1568                teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1569                if (teid2 == ICE_INVAL_TEID)
1570                        continue;
1571                /* Is it already present in the tree ? */
1572                for (i = 0; i < pi->root->num_children; i++) {
1573                        tc_node = pi->root->children[i];
1574                        if (!tc_node)
1575                                continue;
1576                        teid1 = LE32_TO_CPU(tc_node->info.node_teid);
1577                        if (teid1 == teid2) {
1578                                tc_node->tc_num = j;
1579                                tc_node->in_use = true;
1580                                break;
1581                        }
1582                }
1583                if (i < pi->root->num_children)
1584                        continue;
1585                /* new TC */
1586                status = ice_sched_query_elem(pi->hw, teid2, &elem);
1587                if (!status)
1588                        status = ice_sched_add_node(pi, 1, &elem);
1589                if (status)
1590                        break;
1591                /* update the TC number */
1592                node = ice_sched_find_node_by_teid(pi->root, teid2);
1593                if (node)
1594                        node->tc_num = j;
1595        }
1596        return status;
1597}
1598
1599/**
1600 * ice_query_port_ets - query port ETS configuration
1601 * @pi: port information structure
1602 * @buf: pointer to buffer
1603 * @buf_size: buffer size in bytes
1604 * @cd: pointer to command details structure or NULL
1605 *
1606 * query current port ETS configuration and update the
1607 * SW DB with the TC changes
1608 */
1609enum ice_status
1610ice_query_port_ets(struct ice_port_info *pi,
1611                   struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1612                   struct ice_sq_cd *cd)
1613{
1614        enum ice_status status;
1615
1616        ice_acquire_lock(&pi->sched_lock);
1617        status = ice_aq_query_port_ets(pi, buf, buf_size, cd);
1618        if (!status)
1619                status = ice_update_port_tc_tree_cfg(pi, buf);
1620        ice_release_lock(&pi->sched_lock);
1621        return status;
1622}
1623