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