linux/drivers/net/ethernet/intel/i40e/i40e_dcb.c
<<
>>
Prefs
   1/*******************************************************************************
   2 *
   3 * Intel Ethernet Controller XL710 Family Linux Driver
   4 * Copyright(c) 2013 - 2014 Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along
  16 * with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 *
  18 * The full GNU General Public License is included in this distribution in
  19 * the file called "COPYING".
  20 *
  21 * Contact Information:
  22 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  24 *
  25 ******************************************************************************/
  26
  27#include "i40e_adminq.h"
  28#include "i40e_prototype.h"
  29#include "i40e_dcb.h"
  30
  31/**
  32 * i40e_get_dcbx_status
  33 * @hw: pointer to the hw struct
  34 * @status: Embedded DCBX Engine Status
  35 *
  36 * Get the DCBX status from the Firmware
  37 **/
  38i40e_status i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
  39{
  40        u32 reg;
  41
  42        if (!status)
  43                return I40E_ERR_PARAM;
  44
  45        reg = rd32(hw, I40E_PRTDCB_GENS);
  46        *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
  47                        I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
  48
  49        return 0;
  50}
  51
  52/**
  53 * i40e_parse_ieee_etscfg_tlv
  54 * @tlv: IEEE 802.1Qaz ETS CFG TLV
  55 * @dcbcfg: Local store to update ETS CFG data
  56 *
  57 * Parses IEEE 802.1Qaz ETS CFG TLV
  58 **/
  59static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
  60                                       struct i40e_dcbx_config *dcbcfg)
  61{
  62        struct i40e_dcb_ets_config *etscfg;
  63        u8 *buf = tlv->tlvinfo;
  64        u16 offset = 0;
  65        u8 priority;
  66        int i;
  67
  68        /* First Octet post subtype
  69         * --------------------------
  70         * |will-|CBS  | Re-  | Max |
  71         * |ing  |     |served| TCs |
  72         * --------------------------
  73         * |1bit | 1bit|3 bits|3bits|
  74         */
  75        etscfg = &dcbcfg->etscfg;
  76        etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
  77                               I40E_IEEE_ETS_WILLING_SHIFT);
  78        etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
  79                           I40E_IEEE_ETS_CBS_SHIFT);
  80        etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
  81                              I40E_IEEE_ETS_MAXTC_SHIFT);
  82
  83        /* Move offset to Priority Assignment Table */
  84        offset++;
  85
  86        /* Priority Assignment Table (4 octets)
  87         * Octets:|    1    |    2    |    3    |    4    |
  88         *        -----------------------------------------
  89         *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
  90         *        -----------------------------------------
  91         *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
  92         *        -----------------------------------------
  93         */
  94        for (i = 0; i < 4; i++) {
  95                priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
  96                                I40E_IEEE_ETS_PRIO_1_SHIFT);
  97                etscfg->prioritytable[i * 2] =  priority;
  98                priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
  99                                I40E_IEEE_ETS_PRIO_0_SHIFT);
 100                etscfg->prioritytable[i * 2 + 1] = priority;
 101                offset++;
 102        }
 103
 104        /* TC Bandwidth Table (8 octets)
 105         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 106         *        ---------------------------------
 107         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 108         *        ---------------------------------
 109         */
 110        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 111                etscfg->tcbwtable[i] = buf[offset++];
 112
 113        /* TSA Assignment Table (8 octets)
 114         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 115         *        ---------------------------------
 116         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 117         *        ---------------------------------
 118         */
 119        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 120                etscfg->tsatable[i] = buf[offset++];
 121}
 122
 123/**
 124 * i40e_parse_ieee_etsrec_tlv
 125 * @tlv: IEEE 802.1Qaz ETS REC TLV
 126 * @dcbcfg: Local store to update ETS REC data
 127 *
 128 * Parses IEEE 802.1Qaz ETS REC TLV
 129 **/
 130static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
 131                                       struct i40e_dcbx_config *dcbcfg)
 132{
 133        u8 *buf = tlv->tlvinfo;
 134        u16 offset = 0;
 135        u8 priority;
 136        int i;
 137
 138        /* Move offset to priority table */
 139        offset++;
 140
 141        /* Priority Assignment Table (4 octets)
 142         * Octets:|    1    |    2    |    3    |    4    |
 143         *        -----------------------------------------
 144         *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
 145         *        -----------------------------------------
 146         *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
 147         *        -----------------------------------------
 148         */
 149        for (i = 0; i < 4; i++) {
 150                priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
 151                                I40E_IEEE_ETS_PRIO_1_SHIFT);
 152                dcbcfg->etsrec.prioritytable[i*2] =  priority;
 153                priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
 154                                I40E_IEEE_ETS_PRIO_0_SHIFT);
 155                dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
 156                offset++;
 157        }
 158
 159        /* TC Bandwidth Table (8 octets)
 160         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 161         *        ---------------------------------
 162         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 163         *        ---------------------------------
 164         */
 165        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 166                dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
 167
 168        /* TSA Assignment Table (8 octets)
 169         * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
 170         *        ---------------------------------
 171         *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
 172         *        ---------------------------------
 173         */
 174        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 175                dcbcfg->etsrec.tsatable[i] = buf[offset++];
 176}
 177
 178/**
 179 * i40e_parse_ieee_pfccfg_tlv
 180 * @tlv: IEEE 802.1Qaz PFC CFG TLV
 181 * @dcbcfg: Local store to update PFC CFG data
 182 *
 183 * Parses IEEE 802.1Qaz PFC CFG TLV
 184 **/
 185static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
 186                                       struct i40e_dcbx_config *dcbcfg)
 187{
 188        u8 *buf = tlv->tlvinfo;
 189
 190        /* ----------------------------------------
 191         * |will-|MBC  | Re-  | PFC |  PFC Enable  |
 192         * |ing  |     |served| cap |              |
 193         * -----------------------------------------
 194         * |1bit | 1bit|2 bits|4bits| 1 octet      |
 195         */
 196        dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
 197                                   I40E_IEEE_PFC_WILLING_SHIFT);
 198        dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
 199                               I40E_IEEE_PFC_MBC_SHIFT);
 200        dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
 201                                  I40E_IEEE_PFC_CAP_SHIFT);
 202        dcbcfg->pfc.pfcenable = buf[1];
 203}
 204
 205/**
 206 * i40e_parse_ieee_app_tlv
 207 * @tlv: IEEE 802.1Qaz APP TLV
 208 * @dcbcfg: Local store to update APP PRIO data
 209 *
 210 * Parses IEEE 802.1Qaz APP PRIO TLV
 211 **/
 212static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
 213                                    struct i40e_dcbx_config *dcbcfg)
 214{
 215        u16 typelength;
 216        u16 offset = 0;
 217        u16 length;
 218        int i = 0;
 219        u8 *buf;
 220
 221        typelength = ntohs(tlv->typelength);
 222        length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
 223                       I40E_LLDP_TLV_LEN_SHIFT);
 224        buf = tlv->tlvinfo;
 225
 226        /* The App priority table starts 5 octets after TLV header */
 227        length -= (sizeof(tlv->ouisubtype) + 1);
 228
 229        /* Move offset to App Priority Table */
 230        offset++;
 231
 232        /* Application Priority Table (3 octets)
 233         * Octets:|         1          |    2    |    3    |
 234         *        -----------------------------------------
 235         *        |Priority|Rsrvd| Sel |    Protocol ID    |
 236         *        -----------------------------------------
 237         *   Bits:|23    21|20 19|18 16|15                0|
 238         *        -----------------------------------------
 239         */
 240        while (offset < length) {
 241                dcbcfg->app[i].priority = (u8)((buf[offset] &
 242                                                I40E_IEEE_APP_PRIO_MASK) >>
 243                                               I40E_IEEE_APP_PRIO_SHIFT);
 244                dcbcfg->app[i].selector = (u8)((buf[offset] &
 245                                                I40E_IEEE_APP_SEL_MASK) >>
 246                                               I40E_IEEE_APP_SEL_SHIFT);
 247                dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
 248                                             buf[offset + 2];
 249                /* Move to next app */
 250                offset += 3;
 251                i++;
 252                if (i >= I40E_DCBX_MAX_APPS)
 253                        break;
 254        }
 255
 256        dcbcfg->numapps = i;
 257}
 258
 259/**
 260 * i40e_parse_ieee_etsrec_tlv
 261 * @tlv: IEEE 802.1Qaz TLV
 262 * @dcbcfg: Local store to update ETS REC data
 263 *
 264 * Get the TLV subtype and send it to parsing function
 265 * based on the subtype value
 266 **/
 267static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
 268                                struct i40e_dcbx_config *dcbcfg)
 269{
 270        u32 ouisubtype;
 271        u8 subtype;
 272
 273        ouisubtype = ntohl(tlv->ouisubtype);
 274        subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
 275                       I40E_LLDP_TLV_SUBTYPE_SHIFT);
 276        switch (subtype) {
 277        case I40E_IEEE_SUBTYPE_ETS_CFG:
 278                i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
 279                break;
 280        case I40E_IEEE_SUBTYPE_ETS_REC:
 281                i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
 282                break;
 283        case I40E_IEEE_SUBTYPE_PFC_CFG:
 284                i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
 285                break;
 286        case I40E_IEEE_SUBTYPE_APP_PRI:
 287                i40e_parse_ieee_app_tlv(tlv, dcbcfg);
 288                break;
 289        default:
 290                break;
 291        }
 292}
 293
 294/**
 295 * i40e_parse_org_tlv
 296 * @tlv: Organization specific TLV
 297 * @dcbcfg: Local store to update ETS REC data
 298 *
 299 * Currently only IEEE 802.1Qaz TLV is supported, all others
 300 * will be returned
 301 **/
 302static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
 303                               struct i40e_dcbx_config *dcbcfg)
 304{
 305        u32 ouisubtype;
 306        u32 oui;
 307
 308        ouisubtype = ntohl(tlv->ouisubtype);
 309        oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
 310                    I40E_LLDP_TLV_OUI_SHIFT);
 311        switch (oui) {
 312        case I40E_IEEE_8021QAZ_OUI:
 313                i40e_parse_ieee_tlv(tlv, dcbcfg);
 314                break;
 315        default:
 316                break;
 317        }
 318}
 319
 320/**
 321 * i40e_lldp_to_dcb_config
 322 * @lldpmib: LLDPDU to be parsed
 323 * @dcbcfg: store for LLDPDU data
 324 *
 325 * Parse DCB configuration from the LLDPDU
 326 **/
 327i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
 328                                    struct i40e_dcbx_config *dcbcfg)
 329{
 330        i40e_status ret = 0;
 331        struct i40e_lldp_org_tlv *tlv;
 332        u16 type;
 333        u16 length;
 334        u16 typelength;
 335        u16 offset = 0;
 336
 337        if (!lldpmib || !dcbcfg)
 338                return I40E_ERR_PARAM;
 339
 340        /* set to the start of LLDPDU */
 341        lldpmib += ETH_HLEN;
 342        tlv = (struct i40e_lldp_org_tlv *)lldpmib;
 343        while (1) {
 344                typelength = ntohs(tlv->typelength);
 345                type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
 346                             I40E_LLDP_TLV_TYPE_SHIFT);
 347                length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
 348                               I40E_LLDP_TLV_LEN_SHIFT);
 349                offset += sizeof(typelength) + length;
 350
 351                /* END TLV or beyond LLDPDU size */
 352                if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
 353                        break;
 354
 355                switch (type) {
 356                case I40E_TLV_TYPE_ORG:
 357                        i40e_parse_org_tlv(tlv, dcbcfg);
 358                        break;
 359                default:
 360                        break;
 361                }
 362
 363                /* Move to next TLV */
 364                tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
 365                                                    sizeof(tlv->typelength) +
 366                                                    length);
 367        }
 368
 369        return ret;
 370}
 371
 372/**
 373 * i40e_aq_get_dcb_config
 374 * @hw: pointer to the hw struct
 375 * @mib_type: mib type for the query
 376 * @bridgetype: bridge type for the query (remote)
 377 * @dcbcfg: store for LLDPDU data
 378 *
 379 * Query DCB configuration from the Firmware
 380 **/
 381i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
 382                                   u8 bridgetype,
 383                                   struct i40e_dcbx_config *dcbcfg)
 384{
 385        i40e_status ret = 0;
 386        struct i40e_virt_mem mem;
 387        u8 *lldpmib;
 388
 389        /* Allocate the LLDPDU */
 390        ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
 391        if (ret)
 392                return ret;
 393
 394        lldpmib = (u8 *)mem.va;
 395        ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
 396                                   (void *)lldpmib, I40E_LLDPDU_SIZE,
 397                                   NULL, NULL, NULL);
 398        if (ret)
 399                goto free_mem;
 400
 401        /* Parse LLDP MIB to get dcb configuration */
 402        ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
 403
 404free_mem:
 405        i40e_free_virt_mem(hw, &mem);
 406        return ret;
 407}
 408
 409/**
 410 * i40e_cee_to_dcb_v1_config
 411 * @cee_cfg: pointer to CEE v1 response configuration struct
 412 * @dcbcfg: DCB configuration struct
 413 *
 414 * Convert CEE v1 configuration from firmware to DCB configuration
 415 **/
 416static void i40e_cee_to_dcb_v1_config(
 417                        struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
 418                        struct i40e_dcbx_config *dcbcfg)
 419{
 420        u16 status, tlv_status = le16_to_cpu(cee_cfg->tlv_status);
 421        u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
 422        u8 i, tc, err;
 423
 424        /* CEE PG data to ETS config */
 425        dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
 426
 427        for (i = 0; i < 4; i++) {
 428                tc = (u8)((cee_cfg->oper_prio_tc[i] &
 429                         I40E_CEE_PGID_PRIO_1_MASK) >>
 430                         I40E_CEE_PGID_PRIO_1_SHIFT);
 431                dcbcfg->etscfg.prioritytable[i*2] =  tc;
 432                tc = (u8)((cee_cfg->oper_prio_tc[i] &
 433                         I40E_CEE_PGID_PRIO_0_MASK) >>
 434                         I40E_CEE_PGID_PRIO_0_SHIFT);
 435                dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
 436        }
 437
 438        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 439                dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
 440
 441        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
 442                if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
 443                        /* Map it to next empty TC */
 444                        dcbcfg->etscfg.prioritytable[i] =
 445                                                cee_cfg->oper_num_tc - 1;
 446                        dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
 447                } else {
 448                        dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
 449                }
 450        }
 451
 452        /* CEE PFC data to ETS config */
 453        dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
 454        dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
 455
 456        status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
 457                  I40E_AQC_CEE_APP_STATUS_SHIFT;
 458        err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
 459        /* Add APPs if Error is False */
 460        if (!err) {
 461                /* CEE operating configuration supports FCoE/iSCSI/FIP only */
 462                dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
 463
 464                /* FCoE APP */
 465                dcbcfg->app[0].priority =
 466                        (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
 467                         I40E_AQC_CEE_APP_FCOE_SHIFT;
 468                dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
 469                dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
 470
 471                /* iSCSI APP */
 472                dcbcfg->app[1].priority =
 473                        (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
 474                         I40E_AQC_CEE_APP_ISCSI_SHIFT;
 475                dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
 476                dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
 477
 478                /* FIP APP */
 479                dcbcfg->app[2].priority =
 480                        (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
 481                         I40E_AQC_CEE_APP_FIP_SHIFT;
 482                dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
 483                dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
 484        }
 485}
 486
 487/**
 488 * i40e_cee_to_dcb_config
 489 * @cee_cfg: pointer to CEE configuration struct
 490 * @dcbcfg: DCB configuration struct
 491 *
 492 * Convert CEE configuration from firmware to DCB configuration
 493 **/
 494static void i40e_cee_to_dcb_config(
 495                                struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
 496                                struct i40e_dcbx_config *dcbcfg)
 497{
 498        u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);
 499        u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
 500        u8 i, tc, err, sync, oper;
 501
 502        /* CEE PG data to ETS config */
 503        dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
 504
 505        for (i = 0; i < 4; i++) {
 506                tc = (u8)((cee_cfg->oper_prio_tc[i] &
 507                         I40E_CEE_PGID_PRIO_1_MASK) >>
 508                         I40E_CEE_PGID_PRIO_1_SHIFT);
 509                dcbcfg->etscfg.prioritytable[i*2] =  tc;
 510                tc = (u8)((cee_cfg->oper_prio_tc[i] &
 511                         I40E_CEE_PGID_PRIO_0_MASK) >>
 512                         I40E_CEE_PGID_PRIO_0_SHIFT);
 513                dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
 514        }
 515
 516        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
 517                dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
 518
 519        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
 520                if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
 521                        /* Map it to next empty TC */
 522                        dcbcfg->etscfg.prioritytable[i] =
 523                                                cee_cfg->oper_num_tc - 1;
 524                        dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
 525                } else {
 526                        dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
 527                }
 528        }
 529
 530        /* CEE PFC data to ETS config */
 531        dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
 532        dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
 533
 534        status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
 535                  I40E_AQC_CEE_APP_STATUS_SHIFT;
 536        err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
 537        sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
 538        oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
 539        /* Add APPs if Error is False and Oper/Sync is True */
 540        if (!err && sync && oper) {
 541                /* CEE operating configuration supports FCoE/iSCSI/FIP only */
 542                dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
 543
 544                /* FCoE APP */
 545                dcbcfg->app[0].priority =
 546                        (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
 547                         I40E_AQC_CEE_APP_FCOE_SHIFT;
 548                dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
 549                dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
 550
 551                /* iSCSI APP */
 552                dcbcfg->app[1].priority =
 553                        (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
 554                         I40E_AQC_CEE_APP_ISCSI_SHIFT;
 555                dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
 556                dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
 557
 558                /* FIP APP */
 559                dcbcfg->app[2].priority =
 560                        (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
 561                         I40E_AQC_CEE_APP_FIP_SHIFT;
 562                dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
 563                dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
 564        }
 565}
 566
 567/**
 568 * i40e_get_dcb_config
 569 * @hw: pointer to the hw struct
 570 *
 571 * Get DCB configuration from the Firmware
 572 **/
 573i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
 574{
 575        i40e_status ret = 0;
 576        struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
 577        struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
 578
 579        /* If Firmware version < v4.33 IEEE only */
 580        if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
 581            (hw->aq.fw_maj_ver < 4))
 582                goto ieee;
 583
 584        /* If Firmware version == v4.33 use old CEE struct */
 585        if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
 586                ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
 587                                                 sizeof(cee_v1_cfg), NULL);
 588                if (!ret) {
 589                        /* CEE mode */
 590                        hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
 591                        hw->local_dcbx_config.tlv_status =
 592                                        le16_to_cpu(cee_v1_cfg.tlv_status);
 593                        i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
 594                                                  &hw->local_dcbx_config);
 595                }
 596        } else {
 597                ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
 598                                                 sizeof(cee_cfg), NULL);
 599                if (!ret) {
 600                        /* CEE mode */
 601                        hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
 602                        hw->local_dcbx_config.tlv_status =
 603                                        le32_to_cpu(cee_cfg.tlv_status);
 604                        i40e_cee_to_dcb_config(&cee_cfg,
 605                                               &hw->local_dcbx_config);
 606                }
 607        }
 608
 609        /* CEE mode not enabled try querying IEEE data */
 610        if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
 611                goto ieee;
 612        else
 613                goto out;
 614
 615ieee:
 616        /* IEEE mode */
 617        hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
 618        /* Get Local DCB Config */
 619        ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
 620                                     &hw->local_dcbx_config);
 621        if (ret)
 622                goto out;
 623
 624        /* Get Remote DCB Config */
 625        ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
 626                                     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
 627                                     &hw->remote_dcbx_config);
 628        /* Don't treat ENOENT as an error for Remote MIBs */
 629        if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
 630                ret = 0;
 631
 632out:
 633        return ret;
 634}
 635
 636/**
 637 * i40e_init_dcb
 638 * @hw: pointer to the hw struct
 639 *
 640 * Update DCB configuration from the Firmware
 641 **/
 642i40e_status i40e_init_dcb(struct i40e_hw *hw)
 643{
 644        i40e_status ret = 0;
 645        struct i40e_lldp_variables lldp_cfg;
 646        u8 adminstatus = 0;
 647
 648        if (!hw->func_caps.dcb)
 649                return ret;
 650
 651        /* Read LLDP NVM area */
 652        ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
 653        if (ret)
 654                return ret;
 655
 656        /* Get the LLDP AdminStatus for the current port */
 657        adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
 658        adminstatus &= 0xF;
 659
 660        /* LLDP agent disabled */
 661        if (!adminstatus) {
 662                hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
 663                return ret;
 664        }
 665
 666        /* Get DCBX status */
 667        ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
 668        if (ret)
 669                return ret;
 670
 671        /* Check the DCBX Status */
 672        switch (hw->dcbx_status) {
 673        case I40E_DCBX_STATUS_DONE:
 674        case I40E_DCBX_STATUS_IN_PROGRESS:
 675                /* Get current DCBX configuration */
 676                ret = i40e_get_dcb_config(hw);
 677                if (ret)
 678                        return ret;
 679                break;
 680        case I40E_DCBX_STATUS_DISABLED:
 681                return ret;
 682        case I40E_DCBX_STATUS_NOT_STARTED:
 683        case I40E_DCBX_STATUS_MULTIPLE_PEERS:
 684        default:
 685                break;
 686        }
 687
 688        /* Configure the LLDP MIB change event */
 689        ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
 690        if (ret)
 691                return ret;
 692
 693        return ret;
 694}
 695
 696/**
 697 * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
 698 * @hw: pointer to the HW structure
 699 * @lldp_cfg: pointer to hold lldp configuration variables
 700 *
 701 * Reads the LLDP configuration data from NVM
 702 **/
 703i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
 704                               struct i40e_lldp_variables *lldp_cfg)
 705{
 706        i40e_status ret = 0;
 707        u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
 708
 709        if (!lldp_cfg)
 710                return I40E_ERR_PARAM;
 711
 712        ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
 713        if (ret)
 714                goto err_lldp_cfg;
 715
 716        ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
 717                               sizeof(struct i40e_lldp_variables),
 718                               (u8 *)lldp_cfg,
 719                               true, NULL);
 720        i40e_release_nvm(hw);
 721
 722err_lldp_cfg:
 723        return ret;
 724}
 725