i40e/base: add parsing for CEE DCBX TLVs
[dpdk.git] / drivers / net / i40e / base / i40e_dcb.c
index 033e52d..9c8e044 100644 (file)
@@ -298,6 +298,188 @@ static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
        }
 }
 
+/**
+ * i40e_parse_cee_pgcfg_tlv
+ * @tlv: CEE DCBX PG CFG TLV
+ * @dcbcfg: Local store to update ETS CFG data
+ *
+ * Parses CEE DCBX PG CFG TLV
+ **/
+static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
+                                    struct i40e_dcbx_config *dcbcfg)
+{
+       struct i40e_dcb_ets_config *etscfg;
+       u8 *buf = tlv->tlvinfo;
+       u16 offset = 0;
+       u8 priority;
+       int i;
+
+       etscfg = &dcbcfg->etscfg;
+
+       if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
+               etscfg->willing = 1;
+
+       etscfg->cbs = 0;
+       /* Priority Group Table (4 octets)
+        * Octets:|    1    |    2    |    3    |    4    |
+        *        -----------------------------------------
+        *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
+        *        -----------------------------------------
+        *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
+        *        -----------------------------------------
+        */
+       for (i = 0; i < 4; i++) {
+               priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
+                                I40E_CEE_PGID_PRIO_1_SHIFT);
+               etscfg->prioritytable[i * 2] =  priority;
+               priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
+                                I40E_CEE_PGID_PRIO_0_SHIFT);
+               etscfg->prioritytable[i * 2 + 1] = priority;
+               offset++;
+       }
+
+       /* PG Percentage Table (8 octets)
+        * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+        *        ---------------------------------
+        *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
+        *        ---------------------------------
+        */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               etscfg->tcbwtable[i] = buf[offset++];
+
+       /* Number of TCs supported (1 octet) */
+       etscfg->maxtcs = buf[offset];
+}
+
+/**
+ * i40e_parse_cee_pfccfg_tlv
+ * @tlv: CEE DCBX PFC CFG TLV
+ * @dcbcfg: Local store to update PFC CFG data
+ *
+ * Parses CEE DCBX PFC CFG TLV
+ **/
+static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
+                                     struct i40e_dcbx_config *dcbcfg)
+{
+       u8 *buf = tlv->tlvinfo;
+
+       if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
+               dcbcfg->pfc.willing = 1;
+
+       /* ------------------------
+        * | PFC Enable | PFC TCs |
+        * ------------------------
+        * | 1 octet    | 1 octet |
+        */
+       dcbcfg->pfc.pfcenable = buf[0];
+       dcbcfg->pfc.pfccap = buf[1];
+}
+
+/**
+ * i40e_parse_cee_app_tlv
+ * @tlv: CEE DCBX APP TLV
+ * @dcbcfg: Local store to update APP PRIO data
+ *
+ * Parses CEE DCBX APP PRIO TLV
+ **/
+static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
+                                  struct i40e_dcbx_config *dcbcfg)
+{
+       u16 length, typelength, offset = 0;
+       struct i40e_cee_app_prio *app;
+       u8 i, up, selector;
+
+       typelength = I40E_NTOHS(tlv->hdr.typelen);
+       length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
+                      I40E_LLDP_TLV_LEN_SHIFT);
+
+       dcbcfg->numapps = length/sizeof(*app);
+       if (!dcbcfg->numapps)
+               return;
+
+       for (i = 0; i < dcbcfg->numapps; i++) {
+               app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
+               for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
+                       if (app->prio_map & BIT(up))
+                               break;
+               }
+               dcbcfg->app[i].priority = up;
+               /* Get Selector from lower 2 bits, and convert to IEEE */
+               selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
+               if (selector == I40E_CEE_APP_SEL_ETHTYPE)
+                       dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
+               else if (selector == I40E_CEE_APP_SEL_TCPIP)
+                       dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
+               else
+                       /* Keep selector as it is for unknown types */
+                       dcbcfg->app[i].selector = selector;
+               dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
+               /* Move to next app */
+               offset += sizeof(*app);
+       }
+}
+
+/**
+ * i40e_parse_cee_tlv
+ * @tlv: CEE DCBX TLV
+ * @dcbcfg: Local store to update DCBX config data
+ *
+ * Get the TLV subtype and send it to parsing function
+ * based on the subtype value
+ **/
+static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
+                              struct i40e_dcbx_config *dcbcfg)
+{
+       u16 len, tlvlen, sublen, typelength;
+       struct i40e_cee_feat_tlv *sub_tlv;
+       u8 subtype, feat_tlv_count = 0;
+       u32 ouisubtype;
+
+       ouisubtype = I40E_NTOHL(tlv->ouisubtype);
+       subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
+                      I40E_LLDP_TLV_SUBTYPE_SHIFT);
+       /* Return if not CEE DCBX */
+       if (subtype != I40E_CEE_DCBX_TYPE)
+               return;
+
+       typelength = I40E_NTOHS(tlv->typelength);
+       tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
+                       I40E_LLDP_TLV_LEN_SHIFT);
+       len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
+             sizeof(struct i40e_cee_ctrl_tlv);
+       /* Return if no CEE DCBX Feature TLVs */
+       if (tlvlen <= len)
+               return;
+
+       sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
+       while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
+               typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
+               sublen = (u16)((typelength &
+                               I40E_LLDP_TLV_LEN_MASK) >>
+                               I40E_LLDP_TLV_LEN_SHIFT);
+               subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
+                               I40E_LLDP_TLV_TYPE_SHIFT);
+               switch (subtype) {
+               case I40E_CEE_SUBTYPE_PG_CFG:
+                       i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
+                       break;
+               case I40E_CEE_SUBTYPE_PFC_CFG:
+                       i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
+                       break;
+               case I40E_CEE_SUBTYPE_APP_PRI:
+                       i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
+                       break;
+               default:
+                       return; /* Invalid Sub-type return */
+               }
+               feat_tlv_count++;
+               /* Move to next sub TLV */
+               sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
+                                               sizeof(sub_tlv->hdr.typelen) +
+                                               sublen);
+       }
+}
+
 /**
  * i40e_parse_org_tlv
  * @tlv: Organization specific TLV
@@ -319,6 +501,9 @@ static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
        case I40E_IEEE_8021QAZ_OUI:
                i40e_parse_ieee_tlv(tlv, dcbcfg);
                break;
+       case I40E_CEE_DCBX_OUI:
+               i40e_parse_cee_tlv(tlv, dcbcfg);
+               break;
        default:
                break;
        }
@@ -426,7 +611,7 @@ static void i40e_cee_to_dcb_v1_config(
 {
        u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
        u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
-       u8 i, tc, err, sync, oper;
+       u8 i, tc, err;
 
        /* CEE PG data to ETS config */
        dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
@@ -466,9 +651,7 @@ static void i40e_cee_to_dcb_v1_config(
        status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
                  I40E_AQC_CEE_APP_STATUS_SHIFT;
        err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
-       sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
-       oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
-       /* Add APPs if Error is False and Oper/Sync is True */
+       /* Add APPs if Error is False */
        if (!err) {
                /* CEE operating configuration supports FCoE/iSCSI/FIP only */
                dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;