Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2019, Intel Corporation. */
0003 
0004 #include "ice_common.h"
0005 #include "ice_sched.h"
0006 #include "ice_dcb.h"
0007 
0008 /**
0009  * ice_aq_get_lldp_mib
0010  * @hw: pointer to the HW struct
0011  * @bridge_type: type of bridge requested
0012  * @mib_type: Local, Remote or both Local and Remote MIBs
0013  * @buf: pointer to the caller-supplied buffer to store the MIB block
0014  * @buf_size: size of the buffer (in bytes)
0015  * @local_len: length of the returned Local LLDP MIB
0016  * @remote_len: length of the returned Remote LLDP MIB
0017  * @cd: pointer to command details structure or NULL
0018  *
0019  * Requests the complete LLDP MIB (entire packet). (0x0A00)
0020  */
0021 static int
0022 ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,
0023             u16 buf_size, u16 *local_len, u16 *remote_len,
0024             struct ice_sq_cd *cd)
0025 {
0026     struct ice_aqc_lldp_get_mib *cmd;
0027     struct ice_aq_desc desc;
0028     int status;
0029 
0030     cmd = &desc.params.lldp_get_mib;
0031 
0032     if (buf_size == 0 || !buf)
0033         return -EINVAL;
0034 
0035     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);
0036 
0037     cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;
0038     cmd->type |= (bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
0039         ICE_AQ_LLDP_BRID_TYPE_M;
0040 
0041     desc.datalen = cpu_to_le16(buf_size);
0042 
0043     status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
0044     if (!status) {
0045         if (local_len)
0046             *local_len = le16_to_cpu(cmd->local_len);
0047         if (remote_len)
0048             *remote_len = le16_to_cpu(cmd->remote_len);
0049     }
0050 
0051     return status;
0052 }
0053 
0054 /**
0055  * ice_aq_cfg_lldp_mib_change
0056  * @hw: pointer to the HW struct
0057  * @ena_update: Enable or Disable event posting
0058  * @cd: pointer to command details structure or NULL
0059  *
0060  * Enable or Disable posting of an event on ARQ when LLDP MIB
0061  * associated with the interface changes (0x0A01)
0062  */
0063 static int
0064 ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
0065                struct ice_sq_cd *cd)
0066 {
0067     struct ice_aqc_lldp_set_mib_change *cmd;
0068     struct ice_aq_desc desc;
0069 
0070     cmd = &desc.params.lldp_set_event;
0071 
0072     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change);
0073 
0074     if (!ena_update)
0075         cmd->command |= ICE_AQ_LLDP_MIB_UPDATE_DIS;
0076 
0077     return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
0078 }
0079 
0080 /**
0081  * ice_aq_stop_lldp
0082  * @hw: pointer to the HW struct
0083  * @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown
0084  *           False if LLDP Agent needs to be Stopped
0085  * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across
0086  *       reboots
0087  * @cd: pointer to command details structure or NULL
0088  *
0089  * Stop or Shutdown the embedded LLDP Agent (0x0A05)
0090  */
0091 int
0092 ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
0093          struct ice_sq_cd *cd)
0094 {
0095     struct ice_aqc_lldp_stop *cmd;
0096     struct ice_aq_desc desc;
0097 
0098     cmd = &desc.params.lldp_stop;
0099 
0100     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop);
0101 
0102     if (shutdown_lldp_agent)
0103         cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;
0104 
0105     if (persist)
0106         cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;
0107 
0108     return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
0109 }
0110 
0111 /**
0112  * ice_aq_start_lldp
0113  * @hw: pointer to the HW struct
0114  * @persist: True if Start of LLDP Agent needs to be persistent across reboots
0115  * @cd: pointer to command details structure or NULL
0116  *
0117  * Start the embedded LLDP Agent on all ports. (0x0A06)
0118  */
0119 int ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd)
0120 {
0121     struct ice_aqc_lldp_start *cmd;
0122     struct ice_aq_desc desc;
0123 
0124     cmd = &desc.params.lldp_start;
0125 
0126     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_start);
0127 
0128     cmd->command = ICE_AQ_LLDP_AGENT_START;
0129 
0130     if (persist)
0131         cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_ENA;
0132 
0133     return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
0134 }
0135 
0136 /**
0137  * ice_get_dcbx_status
0138  * @hw: pointer to the HW struct
0139  *
0140  * Get the DCBX status from the Firmware
0141  */
0142 static u8 ice_get_dcbx_status(struct ice_hw *hw)
0143 {
0144     u32 reg;
0145 
0146     reg = rd32(hw, PRTDCB_GENS);
0147     return (u8)((reg & PRTDCB_GENS_DCBX_STATUS_M) >>
0148             PRTDCB_GENS_DCBX_STATUS_S);
0149 }
0150 
0151 /**
0152  * ice_parse_ieee_ets_common_tlv
0153  * @buf: Data buffer to be parsed for ETS CFG/REC data
0154  * @ets_cfg: Container to store parsed data
0155  *
0156  * Parses the common data of IEEE 802.1Qaz ETS CFG/REC TLV
0157  */
0158 static void
0159 ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
0160 {
0161     u8 offset = 0;
0162     int i;
0163 
0164     /* Priority Assignment Table (4 octets)
0165      * Octets:|    1    |    2    |    3    |    4    |
0166      *        -----------------------------------------
0167      *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
0168      *        -----------------------------------------
0169      *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
0170      *        -----------------------------------------
0171      */
0172     for (i = 0; i < 4; i++) {
0173         ets_cfg->prio_table[i * 2] =
0174             ((buf[offset] & ICE_IEEE_ETS_PRIO_1_M) >>
0175              ICE_IEEE_ETS_PRIO_1_S);
0176         ets_cfg->prio_table[i * 2 + 1] =
0177             ((buf[offset] & ICE_IEEE_ETS_PRIO_0_M) >>
0178              ICE_IEEE_ETS_PRIO_0_S);
0179         offset++;
0180     }
0181 
0182     /* TC Bandwidth Table (8 octets)
0183      * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
0184      *        ---------------------------------
0185      *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
0186      *        ---------------------------------
0187      *
0188      * TSA Assignment Table (8 octets)
0189      * Octets:| 9 | 10| 11| 12| 13| 14| 15| 16|
0190      *        ---------------------------------
0191      *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
0192      *        ---------------------------------
0193      */
0194     ice_for_each_traffic_class(i) {
0195         ets_cfg->tcbwtable[i] = buf[offset];
0196         ets_cfg->tsatable[i] = buf[ICE_MAX_TRAFFIC_CLASS + offset++];
0197     }
0198 }
0199 
0200 /**
0201  * ice_parse_ieee_etscfg_tlv
0202  * @tlv: IEEE 802.1Qaz ETS CFG TLV
0203  * @dcbcfg: Local store to update ETS CFG data
0204  *
0205  * Parses IEEE 802.1Qaz ETS CFG TLV
0206  */
0207 static void
0208 ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,
0209               struct ice_dcbx_cfg *dcbcfg)
0210 {
0211     struct ice_dcb_ets_cfg *etscfg;
0212     u8 *buf = tlv->tlvinfo;
0213 
0214     /* First Octet post subtype
0215      * --------------------------
0216      * |will-|CBS  | Re-  | Max |
0217      * |ing  |     |served| TCs |
0218      * --------------------------
0219      * |1bit | 1bit|3 bits|3bits|
0220      */
0221     etscfg = &dcbcfg->etscfg;
0222     etscfg->willing = ((buf[0] & ICE_IEEE_ETS_WILLING_M) >>
0223                ICE_IEEE_ETS_WILLING_S);
0224     etscfg->cbs = ((buf[0] & ICE_IEEE_ETS_CBS_M) >> ICE_IEEE_ETS_CBS_S);
0225     etscfg->maxtcs = ((buf[0] & ICE_IEEE_ETS_MAXTC_M) >>
0226               ICE_IEEE_ETS_MAXTC_S);
0227 
0228     /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
0229     ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);
0230 }
0231 
0232 /**
0233  * ice_parse_ieee_etsrec_tlv
0234  * @tlv: IEEE 802.1Qaz ETS REC TLV
0235  * @dcbcfg: Local store to update ETS REC data
0236  *
0237  * Parses IEEE 802.1Qaz ETS REC TLV
0238  */
0239 static void
0240 ice_parse_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
0241               struct ice_dcbx_cfg *dcbcfg)
0242 {
0243     u8 *buf = tlv->tlvinfo;
0244 
0245     /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
0246     ice_parse_ieee_ets_common_tlv(&buf[1], &dcbcfg->etsrec);
0247 }
0248 
0249 /**
0250  * ice_parse_ieee_pfccfg_tlv
0251  * @tlv: IEEE 802.1Qaz PFC CFG TLV
0252  * @dcbcfg: Local store to update PFC CFG data
0253  *
0254  * Parses IEEE 802.1Qaz PFC CFG TLV
0255  */
0256 static void
0257 ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,
0258               struct ice_dcbx_cfg *dcbcfg)
0259 {
0260     u8 *buf = tlv->tlvinfo;
0261 
0262     /* ----------------------------------------
0263      * |will-|MBC  | Re-  | PFC |  PFC Enable  |
0264      * |ing  |     |served| cap |              |
0265      * -----------------------------------------
0266      * |1bit | 1bit|2 bits|4bits| 1 octet      |
0267      */
0268     dcbcfg->pfc.willing = ((buf[0] & ICE_IEEE_PFC_WILLING_M) >>
0269                    ICE_IEEE_PFC_WILLING_S);
0270     dcbcfg->pfc.mbc = ((buf[0] & ICE_IEEE_PFC_MBC_M) >> ICE_IEEE_PFC_MBC_S);
0271     dcbcfg->pfc.pfccap = ((buf[0] & ICE_IEEE_PFC_CAP_M) >>
0272                   ICE_IEEE_PFC_CAP_S);
0273     dcbcfg->pfc.pfcena = buf[1];
0274 }
0275 
0276 /**
0277  * ice_parse_ieee_app_tlv
0278  * @tlv: IEEE 802.1Qaz APP TLV
0279  * @dcbcfg: Local store to update APP PRIO data
0280  *
0281  * Parses IEEE 802.1Qaz APP PRIO TLV
0282  */
0283 static void
0284 ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
0285                struct ice_dcbx_cfg *dcbcfg)
0286 {
0287     u16 offset = 0;
0288     u16 typelen;
0289     int i = 0;
0290     u16 len;
0291     u8 *buf;
0292 
0293     typelen = ntohs(tlv->typelen);
0294     len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
0295     buf = tlv->tlvinfo;
0296 
0297     /* Removing sizeof(ouisubtype) and reserved byte from len.
0298      * Remaining len div 3 is number of APP TLVs.
0299      */
0300     len -= (sizeof(tlv->ouisubtype) + 1);
0301 
0302     /* Move offset to App Priority Table */
0303     offset++;
0304 
0305     /* Application Priority Table (3 octets)
0306      * Octets:|         1          |    2    |    3    |
0307      *        -----------------------------------------
0308      *        |Priority|Rsrvd| Sel |    Protocol ID    |
0309      *        -----------------------------------------
0310      *   Bits:|23    21|20 19|18 16|15                0|
0311      *        -----------------------------------------
0312      */
0313     while (offset < len) {
0314         dcbcfg->app[i].priority = ((buf[offset] &
0315                         ICE_IEEE_APP_PRIO_M) >>
0316                        ICE_IEEE_APP_PRIO_S);
0317         dcbcfg->app[i].selector = ((buf[offset] &
0318                         ICE_IEEE_APP_SEL_M) >>
0319                        ICE_IEEE_APP_SEL_S);
0320         dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |
0321             buf[offset + 2];
0322         /* Move to next app */
0323         offset += 3;
0324         i++;
0325         if (i >= ICE_DCBX_MAX_APPS)
0326             break;
0327     }
0328 
0329     dcbcfg->numapps = i;
0330 }
0331 
0332 /**
0333  * ice_parse_ieee_tlv
0334  * @tlv: IEEE 802.1Qaz TLV
0335  * @dcbcfg: Local store to update ETS REC data
0336  *
0337  * Get the TLV subtype and send it to parsing function
0338  * based on the subtype value
0339  */
0340 static void
0341 ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
0342 {
0343     u32 ouisubtype;
0344     u8 subtype;
0345 
0346     ouisubtype = ntohl(tlv->ouisubtype);
0347     subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
0348                ICE_LLDP_TLV_SUBTYPE_S);
0349     switch (subtype) {
0350     case ICE_IEEE_SUBTYPE_ETS_CFG:
0351         ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);
0352         break;
0353     case ICE_IEEE_SUBTYPE_ETS_REC:
0354         ice_parse_ieee_etsrec_tlv(tlv, dcbcfg);
0355         break;
0356     case ICE_IEEE_SUBTYPE_PFC_CFG:
0357         ice_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
0358         break;
0359     case ICE_IEEE_SUBTYPE_APP_PRI:
0360         ice_parse_ieee_app_tlv(tlv, dcbcfg);
0361         break;
0362     default:
0363         break;
0364     }
0365 }
0366 
0367 /**
0368  * ice_parse_cee_pgcfg_tlv
0369  * @tlv: CEE DCBX PG CFG TLV
0370  * @dcbcfg: Local store to update ETS CFG data
0371  *
0372  * Parses CEE DCBX PG CFG TLV
0373  */
0374 static void
0375 ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,
0376             struct ice_dcbx_cfg *dcbcfg)
0377 {
0378     struct ice_dcb_ets_cfg *etscfg;
0379     u8 *buf = tlv->tlvinfo;
0380     u16 offset = 0;
0381     int i;
0382 
0383     etscfg = &dcbcfg->etscfg;
0384 
0385     if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
0386         etscfg->willing = 1;
0387 
0388     etscfg->cbs = 0;
0389     /* Priority Group Table (4 octets)
0390      * Octets:|    1    |    2    |    3    |    4    |
0391      *        -----------------------------------------
0392      *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
0393      *        -----------------------------------------
0394      *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
0395      *        -----------------------------------------
0396      */
0397     for (i = 0; i < 4; i++) {
0398         etscfg->prio_table[i * 2] =
0399             ((buf[offset] & ICE_CEE_PGID_PRIO_1_M) >>
0400              ICE_CEE_PGID_PRIO_1_S);
0401         etscfg->prio_table[i * 2 + 1] =
0402             ((buf[offset] & ICE_CEE_PGID_PRIO_0_M) >>
0403              ICE_CEE_PGID_PRIO_0_S);
0404         offset++;
0405     }
0406 
0407     /* PG Percentage Table (8 octets)
0408      * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
0409      *        ---------------------------------
0410      *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
0411      *        ---------------------------------
0412      */
0413     ice_for_each_traffic_class(i) {
0414         etscfg->tcbwtable[i] = buf[offset++];
0415 
0416         if (etscfg->prio_table[i] == ICE_CEE_PGID_STRICT)
0417             dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
0418         else
0419             dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
0420     }
0421 
0422     /* Number of TCs supported (1 octet) */
0423     etscfg->maxtcs = buf[offset];
0424 }
0425 
0426 /**
0427  * ice_parse_cee_pfccfg_tlv
0428  * @tlv: CEE DCBX PFC CFG TLV
0429  * @dcbcfg: Local store to update PFC CFG data
0430  *
0431  * Parses CEE DCBX PFC CFG TLV
0432  */
0433 static void
0434 ice_parse_cee_pfccfg_tlv(struct ice_cee_feat_tlv *tlv,
0435              struct ice_dcbx_cfg *dcbcfg)
0436 {
0437     u8 *buf = tlv->tlvinfo;
0438 
0439     if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
0440         dcbcfg->pfc.willing = 1;
0441 
0442     /* ------------------------
0443      * | PFC Enable | PFC TCs |
0444      * ------------------------
0445      * | 1 octet    | 1 octet |
0446      */
0447     dcbcfg->pfc.pfcena = buf[0];
0448     dcbcfg->pfc.pfccap = buf[1];
0449 }
0450 
0451 /**
0452  * ice_parse_cee_app_tlv
0453  * @tlv: CEE DCBX APP TLV
0454  * @dcbcfg: Local store to update APP PRIO data
0455  *
0456  * Parses CEE DCBX APP PRIO TLV
0457  */
0458 static void
0459 ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
0460 {
0461     u16 len, typelen, offset = 0;
0462     struct ice_cee_app_prio *app;
0463     u8 i;
0464 
0465     typelen = ntohs(tlv->hdr.typelen);
0466     len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
0467 
0468     dcbcfg->numapps = len / sizeof(*app);
0469     if (!dcbcfg->numapps)
0470         return;
0471     if (dcbcfg->numapps > ICE_DCBX_MAX_APPS)
0472         dcbcfg->numapps = ICE_DCBX_MAX_APPS;
0473 
0474     for (i = 0; i < dcbcfg->numapps; i++) {
0475         u8 up, selector;
0476 
0477         app = (struct ice_cee_app_prio *)(tlv->tlvinfo + offset);
0478         for (up = 0; up < ICE_MAX_USER_PRIORITY; up++)
0479             if (app->prio_map & BIT(up))
0480                 break;
0481 
0482         dcbcfg->app[i].priority = up;
0483 
0484         /* Get Selector from lower 2 bits, and convert to IEEE */
0485         selector = (app->upper_oui_sel & ICE_CEE_APP_SELECTOR_M);
0486         switch (selector) {
0487         case ICE_CEE_APP_SEL_ETHTYPE:
0488             dcbcfg->app[i].selector = ICE_APP_SEL_ETHTYPE;
0489             break;
0490         case ICE_CEE_APP_SEL_TCPIP:
0491             dcbcfg->app[i].selector = ICE_APP_SEL_TCPIP;
0492             break;
0493         default:
0494             /* Keep selector as it is for unknown types */
0495             dcbcfg->app[i].selector = selector;
0496         }
0497 
0498         dcbcfg->app[i].prot_id = ntohs(app->protocol);
0499         /* Move to next app */
0500         offset += sizeof(*app);
0501     }
0502 }
0503 
0504 /**
0505  * ice_parse_cee_tlv
0506  * @tlv: CEE DCBX TLV
0507  * @dcbcfg: Local store to update DCBX config data
0508  *
0509  * Get the TLV subtype and send it to parsing function
0510  * based on the subtype value
0511  */
0512 static void
0513 ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
0514 {
0515     struct ice_cee_feat_tlv *sub_tlv;
0516     u8 subtype, feat_tlv_count = 0;
0517     u16 len, tlvlen, typelen;
0518     u32 ouisubtype;
0519 
0520     ouisubtype = ntohl(tlv->ouisubtype);
0521     subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
0522                ICE_LLDP_TLV_SUBTYPE_S);
0523     /* Return if not CEE DCBX */
0524     if (subtype != ICE_CEE_DCBX_TYPE)
0525         return;
0526 
0527     typelen = ntohs(tlv->typelen);
0528     tlvlen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
0529     len = sizeof(tlv->typelen) + sizeof(ouisubtype) +
0530         sizeof(struct ice_cee_ctrl_tlv);
0531     /* Return if no CEE DCBX Feature TLVs */
0532     if (tlvlen <= len)
0533         return;
0534 
0535     sub_tlv = (struct ice_cee_feat_tlv *)((char *)tlv + len);
0536     while (feat_tlv_count < ICE_CEE_MAX_FEAT_TYPE) {
0537         u16 sublen;
0538 
0539         typelen = ntohs(sub_tlv->hdr.typelen);
0540         sublen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
0541         subtype = (u8)((typelen & ICE_LLDP_TLV_TYPE_M) >>
0542                    ICE_LLDP_TLV_TYPE_S);
0543         switch (subtype) {
0544         case ICE_CEE_SUBTYPE_PG_CFG:
0545             ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
0546             break;
0547         case ICE_CEE_SUBTYPE_PFC_CFG:
0548             ice_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
0549             break;
0550         case ICE_CEE_SUBTYPE_APP_PRI:
0551             ice_parse_cee_app_tlv(sub_tlv, dcbcfg);
0552             break;
0553         default:
0554             return; /* Invalid Sub-type return */
0555         }
0556         feat_tlv_count++;
0557         /* Move to next sub TLV */
0558         sub_tlv = (struct ice_cee_feat_tlv *)
0559               ((char *)sub_tlv + sizeof(sub_tlv->hdr.typelen) +
0560                sublen);
0561     }
0562 }
0563 
0564 /**
0565  * ice_parse_org_tlv
0566  * @tlv: Organization specific TLV
0567  * @dcbcfg: Local store to update ETS REC data
0568  *
0569  * Currently only IEEE 802.1Qaz TLV is supported, all others
0570  * will be returned
0571  */
0572 static void
0573 ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
0574 {
0575     u32 ouisubtype;
0576     u32 oui;
0577 
0578     ouisubtype = ntohl(tlv->ouisubtype);
0579     oui = ((ouisubtype & ICE_LLDP_TLV_OUI_M) >> ICE_LLDP_TLV_OUI_S);
0580     switch (oui) {
0581     case ICE_IEEE_8021QAZ_OUI:
0582         ice_parse_ieee_tlv(tlv, dcbcfg);
0583         break;
0584     case ICE_CEE_DCBX_OUI:
0585         ice_parse_cee_tlv(tlv, dcbcfg);
0586         break;
0587     default:
0588         break;
0589     }
0590 }
0591 
0592 /**
0593  * ice_lldp_to_dcb_cfg
0594  * @lldpmib: LLDPDU to be parsed
0595  * @dcbcfg: store for LLDPDU data
0596  *
0597  * Parse DCB configuration from the LLDPDU
0598  */
0599 static int ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
0600 {
0601     struct ice_lldp_org_tlv *tlv;
0602     u16 offset = 0;
0603     int ret = 0;
0604     u16 typelen;
0605     u16 type;
0606     u16 len;
0607 
0608     if (!lldpmib || !dcbcfg)
0609         return -EINVAL;
0610 
0611     /* set to the start of LLDPDU */
0612     lldpmib += ETH_HLEN;
0613     tlv = (struct ice_lldp_org_tlv *)lldpmib;
0614     while (1) {
0615         typelen = ntohs(tlv->typelen);
0616         type = ((typelen & ICE_LLDP_TLV_TYPE_M) >> ICE_LLDP_TLV_TYPE_S);
0617         len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
0618         offset += sizeof(typelen) + len;
0619 
0620         /* END TLV or beyond LLDPDU size */
0621         if (type == ICE_TLV_TYPE_END || offset > ICE_LLDPDU_SIZE)
0622             break;
0623 
0624         switch (type) {
0625         case ICE_TLV_TYPE_ORG:
0626             ice_parse_org_tlv(tlv, dcbcfg);
0627             break;
0628         default:
0629             break;
0630         }
0631 
0632         /* Move to next TLV */
0633         tlv = (struct ice_lldp_org_tlv *)
0634               ((char *)tlv + sizeof(tlv->typelen) + len);
0635     }
0636 
0637     return ret;
0638 }
0639 
0640 /**
0641  * ice_aq_get_dcb_cfg
0642  * @hw: pointer to the HW struct
0643  * @mib_type: MIB type for the query
0644  * @bridgetype: bridge type for the query (remote)
0645  * @dcbcfg: store for LLDPDU data
0646  *
0647  * Query DCB configuration from the firmware
0648  */
0649 int
0650 ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
0651            struct ice_dcbx_cfg *dcbcfg)
0652 {
0653     u8 *lldpmib;
0654     int ret;
0655 
0656     /* Allocate the LLDPDU */
0657     lldpmib = devm_kzalloc(ice_hw_to_dev(hw), ICE_LLDPDU_SIZE, GFP_KERNEL);
0658     if (!lldpmib)
0659         return -ENOMEM;
0660 
0661     ret = ice_aq_get_lldp_mib(hw, bridgetype, mib_type, (void *)lldpmib,
0662                   ICE_LLDPDU_SIZE, NULL, NULL, NULL);
0663 
0664     if (!ret)
0665         /* Parse LLDP MIB to get DCB configuration */
0666         ret = ice_lldp_to_dcb_cfg(lldpmib, dcbcfg);
0667 
0668     devm_kfree(ice_hw_to_dev(hw), lldpmib);
0669 
0670     return ret;
0671 }
0672 
0673 /**
0674  * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW
0675  * @hw: pointer to the HW struct
0676  * @start_dcbx_agent: True if DCBX Agent needs to be started
0677  *            False if DCBX Agent needs to be stopped
0678  * @dcbx_agent_status: FW indicates back the DCBX agent status
0679  *             True if DCBX Agent is active
0680  *             False if DCBX Agent is stopped
0681  * @cd: pointer to command details structure or NULL
0682  *
0683  * Start/Stop the embedded dcbx Agent. In case that this wrapper function
0684  * returns 0, caller will need to check if FW returns back the same
0685  * value as stated in dcbx_agent_status, and react accordingly. (0x0A09)
0686  */
0687 int
0688 ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,
0689                bool *dcbx_agent_status, struct ice_sq_cd *cd)
0690 {
0691     struct ice_aqc_lldp_stop_start_specific_agent *cmd;
0692     struct ice_aq_desc desc;
0693     u16 opcode;
0694     int status;
0695 
0696     cmd = &desc.params.lldp_agent_ctrl;
0697 
0698     opcode = ice_aqc_opc_lldp_stop_start_specific_agent;
0699 
0700     ice_fill_dflt_direct_cmd_desc(&desc, opcode);
0701 
0702     if (start_dcbx_agent)
0703         cmd->command = ICE_AQC_START_STOP_AGENT_START_DCBX;
0704 
0705     status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
0706 
0707     *dcbx_agent_status = false;
0708 
0709     if (!status &&
0710         cmd->command == ICE_AQC_START_STOP_AGENT_START_DCBX)
0711         *dcbx_agent_status = true;
0712 
0713     return status;
0714 }
0715 
0716 /**
0717  * ice_aq_get_cee_dcb_cfg
0718  * @hw: pointer to the HW struct
0719  * @buff: response buffer that stores CEE operational configuration
0720  * @cd: pointer to command details structure or NULL
0721  *
0722  * Get CEE DCBX mode operational configuration from firmware (0x0A07)
0723  */
0724 static int
0725 ice_aq_get_cee_dcb_cfg(struct ice_hw *hw,
0726                struct ice_aqc_get_cee_dcb_cfg_resp *buff,
0727                struct ice_sq_cd *cd)
0728 {
0729     struct ice_aq_desc desc;
0730 
0731     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg);
0732 
0733     return ice_aq_send_cmd(hw, &desc, (void *)buff, sizeof(*buff), cd);
0734 }
0735 
0736 /**
0737  * ice_aq_set_pfc_mode - Set PFC mode
0738  * @hw: pointer to the HW struct
0739  * @pfc_mode: value of PFC mode to set
0740  * @cd: pointer to command details structure or NULL
0741  *
0742  * This AQ call configures the PFC mode to DSCP-based PFC mode or
0743  * VLAN-based PFC (0x0303)
0744  */
0745 int ice_aq_set_pfc_mode(struct ice_hw *hw, u8 pfc_mode, struct ice_sq_cd *cd)
0746 {
0747     struct ice_aqc_set_query_pfc_mode *cmd;
0748     struct ice_aq_desc desc;
0749     int status;
0750 
0751     if (pfc_mode > ICE_AQC_PFC_DSCP_BASED_PFC)
0752         return -EINVAL;
0753 
0754     cmd = &desc.params.set_query_pfc_mode;
0755 
0756     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_pfc_mode);
0757 
0758     cmd->pfc_mode = pfc_mode;
0759 
0760     status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
0761     if (status)
0762         return status;
0763 
0764     /* FW will write the PFC mode set back into cmd->pfc_mode, but if DCB is
0765      * disabled, FW will write back 0 to cmd->pfc_mode. After the AQ has
0766      * been executed, check if cmd->pfc_mode is what was requested. If not,
0767      * return an error.
0768      */
0769     if (cmd->pfc_mode != pfc_mode)
0770         return -EOPNOTSUPP;
0771 
0772     return 0;
0773 }
0774 
0775 /**
0776  * ice_cee_to_dcb_cfg
0777  * @cee_cfg: pointer to CEE configuration struct
0778  * @pi: port information structure
0779  *
0780  * Convert CEE configuration from firmware to DCB configuration
0781  */
0782 static void
0783 ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,
0784            struct ice_port_info *pi)
0785 {
0786     u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);
0787     u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift, j;
0788     u8 i, err, sync, oper, app_index, ice_app_sel_type;
0789     u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
0790     u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift;
0791     struct ice_dcbx_cfg *cmp_dcbcfg, *dcbcfg;
0792     u16 ice_app_prot_id_type;
0793 
0794     dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
0795     dcbcfg->dcbx_mode = ICE_DCBX_MODE_CEE;
0796     dcbcfg->tlv_status = tlv_status;
0797 
0798     /* CEE PG data */
0799     dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
0800 
0801     /* Note that the FW creates the oper_prio_tc nibbles reversed
0802      * from those in the CEE Priority Group sub-TLV.
0803      */
0804     for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
0805         dcbcfg->etscfg.prio_table[i * 2] =
0806             ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_0_M) >>
0807              ICE_CEE_PGID_PRIO_0_S);
0808         dcbcfg->etscfg.prio_table[i * 2 + 1] =
0809             ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_1_M) >>
0810              ICE_CEE_PGID_PRIO_1_S);
0811     }
0812 
0813     ice_for_each_traffic_class(i) {
0814         dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
0815 
0816         if (dcbcfg->etscfg.prio_table[i] == ICE_CEE_PGID_STRICT) {
0817             /* Map it to next empty TC */
0818             dcbcfg->etscfg.prio_table[i] = cee_cfg->oper_num_tc - 1;
0819             dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
0820         } else {
0821             dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
0822         }
0823     }
0824 
0825     /* CEE PFC data */
0826     dcbcfg->pfc.pfcena = cee_cfg->oper_pfc_en;
0827     dcbcfg->pfc.pfccap = ICE_MAX_TRAFFIC_CLASS;
0828 
0829     /* CEE APP TLV data */
0830     if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
0831         cmp_dcbcfg = &pi->qos_cfg.desired_dcbx_cfg;
0832     else
0833         cmp_dcbcfg = &pi->qos_cfg.remote_dcbx_cfg;
0834 
0835     app_index = 0;
0836     for (i = 0; i < 3; i++) {
0837         if (i == 0) {
0838             /* FCoE APP */
0839             ice_aqc_cee_status_mask = ICE_AQC_CEE_FCOE_STATUS_M;
0840             ice_aqc_cee_status_shift = ICE_AQC_CEE_FCOE_STATUS_S;
0841             ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FCOE_M;
0842             ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FCOE_S;
0843             ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
0844             ice_app_prot_id_type = ETH_P_FCOE;
0845         } else if (i == 1) {
0846             /* iSCSI APP */
0847             ice_aqc_cee_status_mask = ICE_AQC_CEE_ISCSI_STATUS_M;
0848             ice_aqc_cee_status_shift = ICE_AQC_CEE_ISCSI_STATUS_S;
0849             ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_ISCSI_M;
0850             ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_ISCSI_S;
0851             ice_app_sel_type = ICE_APP_SEL_TCPIP;
0852             ice_app_prot_id_type = ISCSI_LISTEN_PORT;
0853 
0854             for (j = 0; j < cmp_dcbcfg->numapps; j++) {
0855                 u16 prot_id = cmp_dcbcfg->app[j].prot_id;
0856                 u8 sel = cmp_dcbcfg->app[j].selector;
0857 
0858                 if  (sel == ICE_APP_SEL_TCPIP &&
0859                      (prot_id == ISCSI_LISTEN_PORT ||
0860                       prot_id == ICE_APP_PROT_ID_ISCSI_860)) {
0861                     ice_app_prot_id_type = prot_id;
0862                     break;
0863                 }
0864             }
0865         } else {
0866             /* FIP APP */
0867             ice_aqc_cee_status_mask = ICE_AQC_CEE_FIP_STATUS_M;
0868             ice_aqc_cee_status_shift = ICE_AQC_CEE_FIP_STATUS_S;
0869             ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FIP_M;
0870             ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FIP_S;
0871             ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
0872             ice_app_prot_id_type = ETH_P_FIP;
0873         }
0874 
0875         status = (tlv_status & ice_aqc_cee_status_mask) >>
0876              ice_aqc_cee_status_shift;
0877         err = (status & ICE_TLV_STATUS_ERR) ? 1 : 0;
0878         sync = (status & ICE_TLV_STATUS_SYNC) ? 1 : 0;
0879         oper = (status & ICE_TLV_STATUS_OPER) ? 1 : 0;
0880         /* Add FCoE/iSCSI/FIP APP if Error is False and
0881          * Oper/Sync is True
0882          */
0883         if (!err && sync && oper) {
0884             dcbcfg->app[app_index].priority =
0885                 (app_prio & ice_aqc_cee_app_mask) >>
0886                 ice_aqc_cee_app_shift;
0887             dcbcfg->app[app_index].selector = ice_app_sel_type;
0888             dcbcfg->app[app_index].prot_id = ice_app_prot_id_type;
0889             app_index++;
0890         }
0891     }
0892 
0893     dcbcfg->numapps = app_index;
0894 }
0895 
0896 /**
0897  * ice_get_ieee_or_cee_dcb_cfg
0898  * @pi: port information structure
0899  * @dcbx_mode: mode of DCBX (IEEE or CEE)
0900  *
0901  * Get IEEE or CEE mode DCB configuration from the Firmware
0902  */
0903 static int ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode)
0904 {
0905     struct ice_dcbx_cfg *dcbx_cfg = NULL;
0906     int ret;
0907 
0908     if (!pi)
0909         return -EINVAL;
0910 
0911     if (dcbx_mode == ICE_DCBX_MODE_IEEE)
0912         dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
0913     else if (dcbx_mode == ICE_DCBX_MODE_CEE)
0914         dcbx_cfg = &pi->qos_cfg.desired_dcbx_cfg;
0915 
0916     /* Get Local DCB Config in case of ICE_DCBX_MODE_IEEE
0917      * or get CEE DCB Desired Config in case of ICE_DCBX_MODE_CEE
0918      */
0919     ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_LOCAL,
0920                  ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
0921     if (ret)
0922         goto out;
0923 
0924     /* Get Remote DCB Config */
0925     dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;
0926     ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,
0927                  ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
0928     /* Don't treat ENOENT as an error for Remote MIBs */
0929     if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
0930         ret = 0;
0931 
0932 out:
0933     return ret;
0934 }
0935 
0936 /**
0937  * ice_get_dcb_cfg
0938  * @pi: port information structure
0939  *
0940  * Get DCB configuration from the Firmware
0941  */
0942 int ice_get_dcb_cfg(struct ice_port_info *pi)
0943 {
0944     struct ice_aqc_get_cee_dcb_cfg_resp cee_cfg;
0945     struct ice_dcbx_cfg *dcbx_cfg;
0946     int ret;
0947 
0948     if (!pi)
0949         return -EINVAL;
0950 
0951     ret = ice_aq_get_cee_dcb_cfg(pi->hw, &cee_cfg, NULL);
0952     if (!ret) {
0953         /* CEE mode */
0954         ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE);
0955         ice_cee_to_dcb_cfg(&cee_cfg, pi);
0956     } else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) {
0957         /* CEE mode not enabled try querying IEEE data */
0958         dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
0959         dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;
0960         ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_IEEE);
0961     }
0962 
0963     return ret;
0964 }
0965 
0966 /**
0967  * ice_init_dcb
0968  * @hw: pointer to the HW struct
0969  * @enable_mib_change: enable MIB change event
0970  *
0971  * Update DCB configuration from the Firmware
0972  */
0973 int ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
0974 {
0975     struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
0976     int ret = 0;
0977 
0978     if (!hw->func_caps.common_cap.dcb)
0979         return -EOPNOTSUPP;
0980 
0981     qos_cfg->is_sw_lldp = true;
0982 
0983     /* Get DCBX status */
0984     qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
0985 
0986     if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DONE ||
0987         qos_cfg->dcbx_status == ICE_DCBX_STATUS_IN_PROGRESS ||
0988         qos_cfg->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
0989         /* Get current DCBX configuration */
0990         ret = ice_get_dcb_cfg(hw->port_info);
0991         if (ret)
0992             return ret;
0993         qos_cfg->is_sw_lldp = false;
0994     } else if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS) {
0995         return -EBUSY;
0996     }
0997 
0998     /* Configure the LLDP MIB change event */
0999     if (enable_mib_change) {
1000         ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);
1001         if (ret)
1002             qos_cfg->is_sw_lldp = true;
1003     }
1004 
1005     return ret;
1006 }
1007 
1008 /**
1009  * ice_cfg_lldp_mib_change
1010  * @hw: pointer to the HW struct
1011  * @ena_mib: enable/disable MIB change event
1012  *
1013  * Configure (disable/enable) MIB
1014  */
1015 int ice_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_mib)
1016 {
1017     struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
1018     int ret;
1019 
1020     if (!hw->func_caps.common_cap.dcb)
1021         return -EOPNOTSUPP;
1022 
1023     /* Get DCBX status */
1024     qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
1025 
1026     if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS)
1027         return -EBUSY;
1028 
1029     ret = ice_aq_cfg_lldp_mib_change(hw, ena_mib, NULL);
1030     if (!ret)
1031         qos_cfg->is_sw_lldp = !ena_mib;
1032 
1033     return ret;
1034 }
1035 
1036 /**
1037  * ice_add_ieee_ets_common_tlv
1038  * @buf: Data buffer to be populated with ice_dcb_ets_cfg data
1039  * @ets_cfg: Container for ice_dcb_ets_cfg data
1040  *
1041  * Populate the TLV buffer with ice_dcb_ets_cfg data
1042  */
1043 static void
1044 ice_add_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
1045 {
1046     u8 priority0, priority1;
1047     u8 offset = 0;
1048     int i;
1049 
1050     /* Priority Assignment Table (4 octets)
1051      * Octets:|    1    |    2    |    3    |    4    |
1052      *        -----------------------------------------
1053      *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1054      *        -----------------------------------------
1055      *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1056      *        -----------------------------------------
1057      */
1058     for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
1059         priority0 = ets_cfg->prio_table[i * 2] & 0xF;
1060         priority1 = ets_cfg->prio_table[i * 2 + 1] & 0xF;
1061         buf[offset] = (priority0 << ICE_IEEE_ETS_PRIO_1_S) | priority1;
1062         offset++;
1063     }
1064 
1065     /* TC Bandwidth Table (8 octets)
1066      * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1067      *        ---------------------------------
1068      *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1069      *        ---------------------------------
1070      *
1071      * TSA Assignment Table (8 octets)
1072      * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1073      *        ---------------------------------
1074      *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1075      *        ---------------------------------
1076      */
1077     ice_for_each_traffic_class(i) {
1078         buf[offset] = ets_cfg->tcbwtable[i];
1079         buf[ICE_MAX_TRAFFIC_CLASS + offset] = ets_cfg->tsatable[i];
1080         offset++;
1081     }
1082 }
1083 
1084 /**
1085  * ice_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
1086  * @tlv: Fill the ETS config data in IEEE format
1087  * @dcbcfg: Local store which holds the DCB Config
1088  *
1089  * Prepare IEEE 802.1Qaz ETS CFG TLV
1090  */
1091 static void
1092 ice_add_ieee_ets_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1093 {
1094     struct ice_dcb_ets_cfg *etscfg;
1095     u8 *buf = tlv->tlvinfo;
1096     u8 maxtcwilling = 0;
1097     u32 ouisubtype;
1098     u16 typelen;
1099 
1100     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1101            ICE_IEEE_ETS_TLV_LEN);
1102     tlv->typelen = htons(typelen);
1103 
1104     ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1105               ICE_IEEE_SUBTYPE_ETS_CFG);
1106     tlv->ouisubtype = htonl(ouisubtype);
1107 
1108     /* First Octet post subtype
1109      * --------------------------
1110      * |will-|CBS  | Re-  | Max |
1111      * |ing  |     |served| TCs |
1112      * --------------------------
1113      * |1bit | 1bit|3 bits|3bits|
1114      */
1115     etscfg = &dcbcfg->etscfg;
1116     if (etscfg->willing)
1117         maxtcwilling = BIT(ICE_IEEE_ETS_WILLING_S);
1118     maxtcwilling |= etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1119     buf[0] = maxtcwilling;
1120 
1121     /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1122     ice_add_ieee_ets_common_tlv(&buf[1], etscfg);
1123 }
1124 
1125 /**
1126  * ice_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1127  * @tlv: Fill ETS Recommended TLV in IEEE format
1128  * @dcbcfg: Local store which holds the DCB Config
1129  *
1130  * Prepare IEEE 802.1Qaz ETS REC TLV
1131  */
1132 static void
1133 ice_add_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
1134             struct ice_dcbx_cfg *dcbcfg)
1135 {
1136     struct ice_dcb_ets_cfg *etsrec;
1137     u8 *buf = tlv->tlvinfo;
1138     u32 ouisubtype;
1139     u16 typelen;
1140 
1141     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1142            ICE_IEEE_ETS_TLV_LEN);
1143     tlv->typelen = htons(typelen);
1144 
1145     ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1146               ICE_IEEE_SUBTYPE_ETS_REC);
1147     tlv->ouisubtype = htonl(ouisubtype);
1148 
1149     etsrec = &dcbcfg->etsrec;
1150 
1151     /* First Octet is reserved */
1152     /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1153     ice_add_ieee_ets_common_tlv(&buf[1], etsrec);
1154 }
1155 
1156 /**
1157  * ice_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1158  * @tlv: Fill PFC TLV in IEEE format
1159  * @dcbcfg: Local store which holds the PFC CFG data
1160  *
1161  * Prepare IEEE 802.1Qaz PFC CFG TLV
1162  */
1163 static void
1164 ice_add_ieee_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1165 {
1166     u8 *buf = tlv->tlvinfo;
1167     u32 ouisubtype;
1168     u16 typelen;
1169 
1170     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1171            ICE_IEEE_PFC_TLV_LEN);
1172     tlv->typelen = htons(typelen);
1173 
1174     ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1175               ICE_IEEE_SUBTYPE_PFC_CFG);
1176     tlv->ouisubtype = htonl(ouisubtype);
1177 
1178     /* ----------------------------------------
1179      * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1180      * |ing  |     |served| cap |              |
1181      * -----------------------------------------
1182      * |1bit | 1bit|2 bits|4bits| 1 octet      |
1183      */
1184     if (dcbcfg->pfc.willing)
1185         buf[0] = BIT(ICE_IEEE_PFC_WILLING_S);
1186 
1187     if (dcbcfg->pfc.mbc)
1188         buf[0] |= BIT(ICE_IEEE_PFC_MBC_S);
1189 
1190     buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1191     buf[1] = dcbcfg->pfc.pfcena;
1192 }
1193 
1194 /**
1195  * ice_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1196  * @tlv: Fill APP TLV in IEEE format
1197  * @dcbcfg: Local store which holds the APP CFG data
1198  *
1199  * Prepare IEEE 802.1Qaz APP CFG TLV
1200  */
1201 static void
1202 ice_add_ieee_app_pri_tlv(struct ice_lldp_org_tlv *tlv,
1203              struct ice_dcbx_cfg *dcbcfg)
1204 {
1205     u16 typelen, len, offset = 0;
1206     u8 priority, selector, i = 0;
1207     u8 *buf = tlv->tlvinfo;
1208     u32 ouisubtype;
1209 
1210     /* No APP TLVs then just return */
1211     if (dcbcfg->numapps == 0)
1212         return;
1213     ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1214               ICE_IEEE_SUBTYPE_APP_PRI);
1215     tlv->ouisubtype = htonl(ouisubtype);
1216 
1217     /* Move offset to App Priority Table */
1218     offset++;
1219     /* Application Priority Table (3 octets)
1220      * Octets:|         1          |    2    |    3    |
1221      *        -----------------------------------------
1222      *        |Priority|Rsrvd| Sel |    Protocol ID    |
1223      *        -----------------------------------------
1224      *   Bits:|23    21|20 19|18 16|15                0|
1225      *        -----------------------------------------
1226      */
1227     while (i < dcbcfg->numapps) {
1228         priority = dcbcfg->app[i].priority & 0x7;
1229         selector = dcbcfg->app[i].selector & 0x7;
1230         buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector;
1231         buf[offset + 1] = (dcbcfg->app[i].prot_id >> 0x8) & 0xFF;
1232         buf[offset + 2] = dcbcfg->app[i].prot_id & 0xFF;
1233         /* Move to next app */
1234         offset += 3;
1235         i++;
1236         if (i >= ICE_DCBX_MAX_APPS)
1237             break;
1238     }
1239     /* len includes size of ouisubtype + 1 reserved + 3*numapps */
1240     len = sizeof(tlv->ouisubtype) + 1 + (i * 3);
1241     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | (len & 0x1FF));
1242     tlv->typelen = htons(typelen);
1243 }
1244 
1245 /**
1246  * ice_add_dscp_up_tlv - Prepare DSCP to UP TLV
1247  * @tlv: location to build the TLV data
1248  * @dcbcfg: location of data to convert to TLV
1249  */
1250 static void
1251 ice_add_dscp_up_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1252 {
1253     u8 *buf = tlv->tlvinfo;
1254     u32 ouisubtype;
1255     u16 typelen;
1256     int i;
1257 
1258     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1259            ICE_DSCP_UP_TLV_LEN);
1260     tlv->typelen = htons(typelen);
1261 
1262     ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1263                ICE_DSCP_SUBTYPE_DSCP2UP);
1264     tlv->ouisubtype = htonl(ouisubtype);
1265 
1266     /* bytes 0 - 63 - IPv4 DSCP2UP LUT */
1267     for (i = 0; i < ICE_DSCP_NUM_VAL; i++) {
1268         /* IPv4 mapping */
1269         buf[i] = dcbcfg->dscp_map[i];
1270         /* IPv6 mapping */
1271         buf[i + ICE_DSCP_IPV6_OFFSET] = dcbcfg->dscp_map[i];
1272     }
1273 
1274     /* byte 64 - IPv4 untagged traffic */
1275     buf[i] = 0;
1276 
1277     /* byte 144 - IPv6 untagged traffic */
1278     buf[i + ICE_DSCP_IPV6_OFFSET] = 0;
1279 }
1280 
1281 #define ICE_BYTES_PER_TC    8
1282 /**
1283  * ice_add_dscp_enf_tlv - Prepare DSCP Enforcement TLV
1284  * @tlv: location to build the TLV data
1285  */
1286 static void
1287 ice_add_dscp_enf_tlv(struct ice_lldp_org_tlv *tlv)
1288 {
1289     u8 *buf = tlv->tlvinfo;
1290     u32 ouisubtype;
1291     u16 typelen;
1292 
1293     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1294            ICE_DSCP_ENF_TLV_LEN);
1295     tlv->typelen = htons(typelen);
1296 
1297     ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1298                ICE_DSCP_SUBTYPE_ENFORCE);
1299     tlv->ouisubtype = htonl(ouisubtype);
1300 
1301     /* Allow all DSCP values to be valid for all TC's (IPv4 and IPv6) */
1302     memset(buf, 0, 2 * (ICE_MAX_TRAFFIC_CLASS * ICE_BYTES_PER_TC));
1303 }
1304 
1305 /**
1306  * ice_add_dscp_tc_bw_tlv - Prepare DSCP BW for TC TLV
1307  * @tlv: location to build the TLV data
1308  * @dcbcfg: location of the data to convert to TLV
1309  */
1310 static void
1311 ice_add_dscp_tc_bw_tlv(struct ice_lldp_org_tlv *tlv,
1312                struct ice_dcbx_cfg *dcbcfg)
1313 {
1314     struct ice_dcb_ets_cfg *etscfg;
1315     u8 *buf = tlv->tlvinfo;
1316     u32 ouisubtype;
1317     u8 offset = 0;
1318     u16 typelen;
1319     int i;
1320 
1321     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1322            ICE_DSCP_TC_BW_TLV_LEN);
1323     tlv->typelen = htons(typelen);
1324 
1325     ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1326                ICE_DSCP_SUBTYPE_TCBW);
1327     tlv->ouisubtype = htonl(ouisubtype);
1328 
1329     /* First Octect after subtype
1330      * ----------------------------
1331      * | RSV | CBS | RSV | Max TCs |
1332      * | 1b  | 1b  | 3b  | 3b      |
1333      * ----------------------------
1334      */
1335     etscfg = &dcbcfg->etscfg;
1336     buf[0] = etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1337 
1338     /* bytes 1 - 4 reserved */
1339     offset = 5;
1340 
1341     /* TC BW table
1342      * bytes 0 - 7 for TC 0 - 7
1343      *
1344      * TSA Assignment table
1345      * bytes 8 - 15 for TC 0 - 7
1346      */
1347     for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
1348         buf[offset] = etscfg->tcbwtable[i];
1349         buf[offset + ICE_MAX_TRAFFIC_CLASS] = etscfg->tsatable[i];
1350         offset++;
1351     }
1352 }
1353 
1354 /**
1355  * ice_add_dscp_pfc_tlv - Prepare DSCP PFC TLV
1356  * @tlv: Fill PFC TLV in IEEE format
1357  * @dcbcfg: Local store which holds the PFC CFG data
1358  */
1359 static void
1360 ice_add_dscp_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1361 {
1362     u8 *buf = tlv->tlvinfo;
1363     u32 ouisubtype;
1364     u16 typelen;
1365 
1366     typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1367            ICE_DSCP_PFC_TLV_LEN);
1368     tlv->typelen = htons(typelen);
1369 
1370     ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1371                ICE_DSCP_SUBTYPE_PFC);
1372     tlv->ouisubtype = htonl(ouisubtype);
1373 
1374     buf[0] = dcbcfg->pfc.pfccap & 0xF;
1375     buf[1] = dcbcfg->pfc.pfcena & 0xF;
1376 }
1377 
1378 /**
1379  * ice_add_dcb_tlv - Add all IEEE or DSCP TLVs
1380  * @tlv: Fill TLV data in IEEE format
1381  * @dcbcfg: Local store which holds the DCB Config
1382  * @tlvid: Type of IEEE TLV
1383  *
1384  * Add tlv information
1385  */
1386 static void
1387 ice_add_dcb_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg,
1388         u16 tlvid)
1389 {
1390     if (dcbcfg->pfc_mode == ICE_QOS_MODE_VLAN) {
1391         switch (tlvid) {
1392         case ICE_IEEE_TLV_ID_ETS_CFG:
1393             ice_add_ieee_ets_tlv(tlv, dcbcfg);
1394             break;
1395         case ICE_IEEE_TLV_ID_ETS_REC:
1396             ice_add_ieee_etsrec_tlv(tlv, dcbcfg);
1397             break;
1398         case ICE_IEEE_TLV_ID_PFC_CFG:
1399             ice_add_ieee_pfc_tlv(tlv, dcbcfg);
1400             break;
1401         case ICE_IEEE_TLV_ID_APP_PRI:
1402             ice_add_ieee_app_pri_tlv(tlv, dcbcfg);
1403             break;
1404         default:
1405             break;
1406         }
1407     } else {
1408         /* pfc_mode == ICE_QOS_MODE_DSCP */
1409         switch (tlvid) {
1410         case ICE_TLV_ID_DSCP_UP:
1411             ice_add_dscp_up_tlv(tlv, dcbcfg);
1412             break;
1413         case ICE_TLV_ID_DSCP_ENF:
1414             ice_add_dscp_enf_tlv(tlv);
1415             break;
1416         case ICE_TLV_ID_DSCP_TC_BW:
1417             ice_add_dscp_tc_bw_tlv(tlv, dcbcfg);
1418             break;
1419         case ICE_TLV_ID_DSCP_TO_PFC:
1420             ice_add_dscp_pfc_tlv(tlv, dcbcfg);
1421             break;
1422         default:
1423             break;
1424         }
1425     }
1426 }
1427 
1428 /**
1429  * ice_dcb_cfg_to_lldp - Convert DCB configuration to MIB format
1430  * @lldpmib: pointer to the HW struct
1431  * @miblen: length of LLDP MIB
1432  * @dcbcfg: Local store which holds the DCB Config
1433  *
1434  * Convert the DCB configuration to MIB format
1435  */
1436 static void
1437 ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)
1438 {
1439     u16 len, offset = 0, tlvid = ICE_TLV_ID_START;
1440     struct ice_lldp_org_tlv *tlv;
1441     u16 typelen;
1442 
1443     tlv = (struct ice_lldp_org_tlv *)lldpmib;
1444     while (1) {
1445         ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1446         typelen = ntohs(tlv->typelen);
1447         len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
1448         if (len)
1449             offset += len + 2;
1450         /* END TLV or beyond LLDPDU size */
1451         if (tlvid >= ICE_TLV_ID_END_OF_LLDPPDU ||
1452             offset > ICE_LLDPDU_SIZE)
1453             break;
1454         /* Move to next TLV */
1455         if (len)
1456             tlv = (struct ice_lldp_org_tlv *)
1457                 ((char *)tlv + sizeof(tlv->typelen) + len);
1458     }
1459     *miblen = offset;
1460 }
1461 
1462 /**
1463  * ice_set_dcb_cfg - Set the local LLDP MIB to FW
1464  * @pi: port information structure
1465  *
1466  * Set DCB configuration to the Firmware
1467  */
1468 int ice_set_dcb_cfg(struct ice_port_info *pi)
1469 {
1470     u8 mib_type, *lldpmib = NULL;
1471     struct ice_dcbx_cfg *dcbcfg;
1472     struct ice_hw *hw;
1473     u16 miblen;
1474     int ret;
1475 
1476     if (!pi)
1477         return -EINVAL;
1478 
1479     hw = pi->hw;
1480 
1481     /* update the HW local config */
1482     dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
1483     /* Allocate the LLDPDU */
1484     lldpmib = devm_kzalloc(ice_hw_to_dev(hw), ICE_LLDPDU_SIZE, GFP_KERNEL);
1485     if (!lldpmib)
1486         return -ENOMEM;
1487 
1488     mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
1489     if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
1490         mib_type |= SET_LOCAL_MIB_TYPE_CEE_NON_WILLING;
1491 
1492     ice_dcb_cfg_to_lldp(lldpmib, &miblen, dcbcfg);
1493     ret = ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen,
1494                   NULL);
1495 
1496     devm_kfree(ice_hw_to_dev(hw), lldpmib);
1497 
1498     return ret;
1499 }
1500 
1501 /**
1502  * ice_aq_query_port_ets - query port ETS configuration
1503  * @pi: port information structure
1504  * @buf: pointer to buffer
1505  * @buf_size: buffer size in bytes
1506  * @cd: pointer to command details structure or NULL
1507  *
1508  * query current port ETS configuration
1509  */
1510 static int
1511 ice_aq_query_port_ets(struct ice_port_info *pi,
1512               struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1513               struct ice_sq_cd *cd)
1514 {
1515     struct ice_aqc_query_port_ets *cmd;
1516     struct ice_aq_desc desc;
1517     int status;
1518 
1519     if (!pi)
1520         return -EINVAL;
1521     cmd = &desc.params.port_ets;
1522     ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets);
1523     cmd->port_teid = pi->root->info.node_teid;
1524 
1525     status = ice_aq_send_cmd(pi->hw, &desc, buf, buf_size, cd);
1526     return status;
1527 }
1528 
1529 /**
1530  * ice_update_port_tc_tree_cfg - update TC tree configuration
1531  * @pi: port information structure
1532  * @buf: pointer to buffer
1533  *
1534  * update the SW DB with the new TC changes
1535  */
1536 static int
1537 ice_update_port_tc_tree_cfg(struct ice_port_info *pi,
1538                 struct ice_aqc_port_ets_elem *buf)
1539 {
1540     struct ice_sched_node *node, *tc_node;
1541     struct ice_aqc_txsched_elem_data elem;
1542     u32 teid1, teid2;
1543     int status = 0;
1544     u8 i, j;
1545 
1546     if (!pi)
1547         return -EINVAL;
1548     /* suspend the missing TC nodes */
1549     for (i = 0; i < pi->root->num_children; i++) {
1550         teid1 = le32_to_cpu(pi->root->children[i]->info.node_teid);
1551         ice_for_each_traffic_class(j) {
1552             teid2 = le32_to_cpu(buf->tc_node_teid[j]);
1553             if (teid1 == teid2)
1554                 break;
1555         }
1556         if (j < ICE_MAX_TRAFFIC_CLASS)
1557             continue;
1558         /* TC is missing */
1559         pi->root->children[i]->in_use = false;
1560     }
1561     /* add the new TC nodes */
1562     ice_for_each_traffic_class(j) {
1563         teid2 = le32_to_cpu(buf->tc_node_teid[j]);
1564         if (teid2 == ICE_INVAL_TEID)
1565             continue;
1566         /* Is it already present in the tree ? */
1567         for (i = 0; i < pi->root->num_children; i++) {
1568             tc_node = pi->root->children[i];
1569             if (!tc_node)
1570                 continue;
1571             teid1 = le32_to_cpu(tc_node->info.node_teid);
1572             if (teid1 == teid2) {
1573                 tc_node->tc_num = j;
1574                 tc_node->in_use = true;
1575                 break;
1576             }
1577         }
1578         if (i < pi->root->num_children)
1579             continue;
1580         /* new TC */
1581         status = ice_sched_query_elem(pi->hw, teid2, &elem);
1582         if (!status)
1583             status = ice_sched_add_node(pi, 1, &elem);
1584         if (status)
1585             break;
1586         /* update the TC number */
1587         node = ice_sched_find_node_by_teid(pi->root, teid2);
1588         if (node)
1589             node->tc_num = j;
1590     }
1591     return status;
1592 }
1593 
1594 /**
1595  * ice_query_port_ets - query port ETS configuration
1596  * @pi: port information structure
1597  * @buf: pointer to buffer
1598  * @buf_size: buffer size in bytes
1599  * @cd: pointer to command details structure or NULL
1600  *
1601  * query current port ETS configuration and update the
1602  * SW DB with the TC changes
1603  */
1604 int
1605 ice_query_port_ets(struct ice_port_info *pi,
1606            struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1607            struct ice_sq_cd *cd)
1608 {
1609     int status;
1610 
1611     mutex_lock(&pi->sched_lock);
1612     status = ice_aq_query_port_ets(pi, buf, buf_size, cd);
1613     if (!status)
1614         status = ice_update_port_tc_tree_cfg(pi, buf);
1615     mutex_unlock(&pi->sched_lock);
1616     return status;
1617 }