i40e/base: prepare local LLDP MIB in TLV
authorJingjing Wu <jingjing.wu@intel.com>
Sun, 6 Sep 2015 07:11:33 +0000 (15:11 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Thu, 1 Oct 2015 23:35:22 +0000 (01:35 +0200)
This patch prepares the LLDP MIB in IEEE TLV format based on
the local dcb config.

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Helin Zhang <helin.zhang@intel.com>
Tested-by: Huilong Xu <huilongx.xu@intel.com>
drivers/net/i40e/base/i40e_adminq_cmd.h
drivers/net/i40e/base/i40e_dcb.c
drivers/net/i40e/base/i40e_dcb.h
drivers/net/i40e/base/i40e_type.h

index 6365e55..4bbc368 100644 (file)
@@ -2125,7 +2125,13 @@ I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_cee_dcb_cfg_resp);
  */
 struct i40e_aqc_lldp_set_local_mib {
 #define SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT       0
-#define SET_LOCAL_MIB_AC_TYPE_DCBX_MASK                (1 << SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT)
+#define SET_LOCAL_MIB_AC_TYPE_DCBX_MASK        (1 << \
+                                       SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT)
+#define SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB        0x0
+#define SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT   (1)
+#define SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_MASK    (1 << \
+                               SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT)
+#define SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS         0x1
        u8      type;
        u8      reserved0;
        __le16  length;
index 9c8e044..ab4decd 100644 (file)
@@ -884,6 +884,333 @@ enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
        return ret;
 }
 
+/**
+ * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
+ * @tlv: Fill the ETS config data in IEEE format
+ * @dcbcfg: Local store which holds the DCB Config
+ *
+ * Prepare IEEE 802.1Qaz ETS CFG TLV
+ **/
+static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
+                                 struct i40e_dcbx_config *dcbcfg)
+{
+       u8 priority0, priority1, maxtcwilling = 0;
+       struct i40e_dcb_ets_config *etscfg;
+       u16 offset = 0, typelength, i;
+       u8 *buf = tlv->tlvinfo;
+       u32 ouisubtype;
+
+       typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
+                       I40E_IEEE_ETS_TLV_LENGTH);
+       tlv->typelength = I40E_HTONS(typelength);
+
+       ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
+                       I40E_IEEE_SUBTYPE_ETS_CFG);
+       tlv->ouisubtype = I40E_HTONL(ouisubtype);
+
+       /* First Octet post subtype
+        * --------------------------
+        * |will-|CBS  | Re-  | Max |
+        * |ing  |     |served| TCs |
+        * --------------------------
+        * |1bit | 1bit|3 bits|3bits|
+        */
+       etscfg = &dcbcfg->etscfg;
+       if (etscfg->willing)
+               maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
+       maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
+       buf[offset] = maxtcwilling;
+
+       /* Move offset to Priority Assignment Table */
+       offset++;
+
+       /* Priority Assignment 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++) {
+               priority0 = etscfg->prioritytable[i * 2] & 0xF;
+               priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
+               buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
+                               priority1;
+               offset++;
+       }
+
+       /* TC Bandwidth Table (8 octets)
+        * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+        *        ---------------------------------
+        *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
+        *        ---------------------------------
+        */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               buf[offset++] = etscfg->tcbwtable[i];
+
+       /* TSA Assignment Table (8 octets)
+        * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+        *        ---------------------------------
+        *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
+        *        ---------------------------------
+        */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               buf[offset++] = etscfg->tsatable[i];
+}
+
+/**
+ * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
+ * @tlv: Fill ETS Recommended TLV in IEEE format
+ * @dcbcfg: Local store which holds the DCB Config
+ *
+ * Prepare IEEE 802.1Qaz ETS REC TLV
+ **/
+static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
+                                    struct i40e_dcbx_config *dcbcfg)
+{
+       struct i40e_dcb_ets_config *etsrec;
+       u16 offset = 0, typelength, i;
+       u8 priority0, priority1;
+       u8 *buf = tlv->tlvinfo;
+       u32 ouisubtype;
+
+       typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
+                       I40E_IEEE_ETS_TLV_LENGTH);
+       tlv->typelength = I40E_HTONS(typelength);
+
+       ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
+                       I40E_IEEE_SUBTYPE_ETS_REC);
+       tlv->ouisubtype = I40E_HTONL(ouisubtype);
+
+       etsrec = &dcbcfg->etsrec;
+       /* First Octet is reserved */
+       /* Move offset to Priority Assignment Table */
+       offset++;
+
+       /* Priority Assignment 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++) {
+               priority0 = etsrec->prioritytable[i * 2] & 0xF;
+               priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
+               buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
+                               priority1;
+               offset++;
+       }
+
+       /* TC Bandwidth Table (8 octets)
+        * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+        *        ---------------------------------
+        *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
+        *        ---------------------------------
+        */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               buf[offset++] = etsrec->tcbwtable[i];
+
+       /* TSA Assignment Table (8 octets)
+        * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+        *        ---------------------------------
+        *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
+        *        ---------------------------------
+        */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               buf[offset++] = etsrec->tsatable[i];
+}
+
+ /**
+ * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
+ * @tlv: Fill PFC TLV in IEEE format
+ * @dcbcfg: Local store to get PFC CFG data
+ *
+ * Prepare IEEE 802.1Qaz PFC CFG TLV
+ **/
+static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
+                                 struct i40e_dcbx_config *dcbcfg)
+{
+       u8 *buf = tlv->tlvinfo;
+       u32 ouisubtype;
+       u16 typelength;
+
+       typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
+                       I40E_IEEE_PFC_TLV_LENGTH);
+       tlv->typelength = I40E_HTONS(typelength);
+
+       ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
+                       I40E_IEEE_SUBTYPE_PFC_CFG);
+       tlv->ouisubtype = I40E_HTONL(ouisubtype);
+
+       /* ----------------------------------------
+        * |will-|MBC  | Re-  | PFC |  PFC Enable  |
+        * |ing  |     |served| cap |              |
+        * -----------------------------------------
+        * |1bit | 1bit|2 bits|4bits| 1 octet      |
+        */
+       if (dcbcfg->pfc.willing)
+               buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
+
+       if (dcbcfg->pfc.mbc)
+               buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
+
+       buf[0] |= dcbcfg->pfc.pfccap & 0xF;
+       buf[1] = dcbcfg->pfc.pfcenable;
+}
+
+/**
+ * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
+ * @tlv: Fill APP TLV in IEEE format
+ * @dcbcfg: Local store to get APP CFG data
+ *
+ * Prepare IEEE 802.1Qaz APP CFG TLV
+ **/
+static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
+                                     struct i40e_dcbx_config *dcbcfg)
+{
+       u16 typelength, length, offset = 0;
+       u8 priority, selector, i = 0;
+       u8 *buf = tlv->tlvinfo;
+       u32 ouisubtype;
+
+       /* No APP TLVs then just return */
+       if (dcbcfg->numapps == 0)
+               return;
+       ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
+                       I40E_IEEE_SUBTYPE_APP_PRI);
+       tlv->ouisubtype = I40E_HTONL(ouisubtype);
+
+       /* Move offset to App Priority Table */
+       offset++;
+       /* Application Priority Table (3 octets)
+        * Octets:|         1          |    2    |    3    |
+        *        -----------------------------------------
+        *        |Priority|Rsrvd| Sel |    Protocol ID    |
+        *        -----------------------------------------
+        *   Bits:|23    21|20 19|18 16|15                0|
+        *        -----------------------------------------
+        */
+       while (i < dcbcfg->numapps) {
+               priority = dcbcfg->app[i].priority & 0x7;
+               selector = dcbcfg->app[i].selector & 0x7;
+               buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
+               buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
+               buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
+               /* Move to next app */
+               offset += 3;
+               i++;
+               if (i >= I40E_DCBX_MAX_APPS)
+                       break;
+       }
+       /* length includes size of ouisubtype + 1 reserved + 3*numapps */
+       length = sizeof(tlv->ouisubtype) + 1 + (i*3);
+       typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
+               (length & 0x1FF));
+       tlv->typelength = I40E_HTONS(typelength);
+}
+
+ /**
+ * i40e_add_dcb_tlv - Add all IEEE TLVs
+ * @tlv: pointer to org tlv
+ *
+ * add tlv information
+ **/
+static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
+                            struct i40e_dcbx_config *dcbcfg,
+                            u16 tlvid)
+{
+       switch (tlvid) {
+       case I40E_IEEE_TLV_ID_ETS_CFG:
+               i40e_add_ieee_ets_tlv(tlv, dcbcfg);
+               break;
+       case I40E_IEEE_TLV_ID_ETS_REC:
+               i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
+               break;
+       case I40E_IEEE_TLV_ID_PFC_CFG:
+               i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
+               break;
+       case I40E_IEEE_TLV_ID_APP_PRI:
+               i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
+               break;
+       default:
+               break;
+       }
+}
+
+ /**
+ * i40e_set_dcb_config - Set the local LLDP MIB to FW
+ * @hw: pointer to the hw struct
+ *
+ * Set DCB configuration to the Firmware
+ **/
+enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
+{
+       enum i40e_status_code ret = I40E_SUCCESS;
+       struct i40e_dcbx_config *dcbcfg;
+       struct i40e_virt_mem mem;
+       u8 mib_type, *lldpmib;
+       u16 miblen;
+
+       /* update the hw local config */
+       dcbcfg = &hw->local_dcbx_config;
+       /* Allocate the LLDPDU */
+       ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
+       if (ret)
+               return ret;
+
+       mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
+       if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
+               mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
+                           SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
+       }
+       lldpmib = (u8 *)mem.va;
+       ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
+       ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
+
+       i40e_free_virt_mem(hw, &mem);
+       return ret;
+}
+
+/**
+ * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
+ * @hw: pointer to the hw struct
+ * @dcbcfg: store for LLDPDU data
+ *
+ * send DCB configuration to FW
+ **/
+enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
+                                             struct i40e_dcbx_config *dcbcfg)
+{
+       u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
+       enum i40e_status_code ret = I40E_SUCCESS;
+       struct i40e_lldp_org_tlv *tlv;
+       u16 type, typelength;
+
+       tlv = (struct i40e_lldp_org_tlv *)lldpmib;
+       while (1) {
+               i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
+               typelength = I40E_NTOHS(tlv->typelength);
+               type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
+                               I40E_LLDP_TLV_TYPE_SHIFT);
+               length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
+                               I40E_LLDP_TLV_LEN_SHIFT);
+               if (length)
+                       offset += length + 2;
+               /* END TLV or beyond LLDPDU size */
+               if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
+                   (offset > I40E_LLDPDU_SIZE))
+                       break;
+               /* Move to next TLV */
+               if (length)
+                       tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
+                             sizeof(tlv->typelength) + length);
+       }
+       *miblen = offset;
+       return ret;
+}
 
 
 /**
index 3aa228b..3b709ef 100644 (file)
@@ -216,5 +216,8 @@ enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
                                             struct i40e_dcbx_config *dcbcfg);
 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw);
 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw);
+enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw);
+enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
+                                             struct i40e_dcbx_config *dcbcfg);
 
 #endif /* _I40E_DCB_H_ */
index e109b4c..e5b05f9 100644 (file)
@@ -522,6 +522,8 @@ struct i40e_dcbx_config {
        u8  dcbx_mode;
 #define I40E_DCBX_MODE_CEE     0x1
 #define I40E_DCBX_MODE_IEEE    0x2
+       u8  app_mode;
+#define I40E_DCBX_APPS_NON_WILLING     0x1
        u32 numapps;
        struct i40e_dcb_ets_config etscfg;
        struct i40e_dcb_ets_config etsrec;