193f1cac5SPaul Winder /******************************************************************************
293f1cac5SPaul Winder 
3*df36e06dSRobert Mustacchi   Copyright (c) 2013-2018, Intel Corporation
493f1cac5SPaul Winder   All rights reserved.
593f1cac5SPaul Winder 
693f1cac5SPaul Winder   Redistribution and use in source and binary forms, with or without
793f1cac5SPaul Winder   modification, are permitted provided that the following conditions are met:
893f1cac5SPaul Winder 
993f1cac5SPaul Winder    1. Redistributions of source code must retain the above copyright notice,
1093f1cac5SPaul Winder       this list of conditions and the following disclaimer.
1193f1cac5SPaul Winder 
1293f1cac5SPaul Winder    2. Redistributions in binary form must reproduce the above copyright
1393f1cac5SPaul Winder       notice, this list of conditions and the following disclaimer in the
1493f1cac5SPaul Winder       documentation and/or other materials provided with the distribution.
1593f1cac5SPaul Winder 
1693f1cac5SPaul Winder    3. Neither the name of the Intel Corporation nor the names of its
1793f1cac5SPaul Winder       contributors may be used to endorse or promote products derived from
1893f1cac5SPaul Winder       this software without specific prior written permission.
1993f1cac5SPaul Winder 
2093f1cac5SPaul Winder   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2193f1cac5SPaul Winder   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2293f1cac5SPaul Winder   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2393f1cac5SPaul Winder   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2493f1cac5SPaul Winder   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2593f1cac5SPaul Winder   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2693f1cac5SPaul Winder   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2793f1cac5SPaul Winder   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2893f1cac5SPaul Winder   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2993f1cac5SPaul Winder   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3093f1cac5SPaul Winder   POSSIBILITY OF SUCH DAMAGE.
3193f1cac5SPaul Winder 
3293f1cac5SPaul Winder ******************************************************************************/
3393f1cac5SPaul Winder /*$FreeBSD$*/
3493f1cac5SPaul Winder 
3593f1cac5SPaul Winder #include "i40e_adminq.h"
3693f1cac5SPaul Winder #include "i40e_prototype.h"
3793f1cac5SPaul Winder #include "i40e_dcb.h"
3893f1cac5SPaul Winder 
3993f1cac5SPaul Winder /**
4093f1cac5SPaul Winder  * i40e_get_dcbx_status
4193f1cac5SPaul Winder  * @hw: pointer to the hw struct
4293f1cac5SPaul Winder  * @status: Embedded DCBX Engine Status
4393f1cac5SPaul Winder  *
4493f1cac5SPaul Winder  * Get the DCBX status from the Firmware
4593f1cac5SPaul Winder  **/
i40e_get_dcbx_status(struct i40e_hw * hw,u16 * status)4693f1cac5SPaul Winder enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
4793f1cac5SPaul Winder {
4893f1cac5SPaul Winder 	u32 reg;
4993f1cac5SPaul Winder 
5093f1cac5SPaul Winder 	if (!status)
5193f1cac5SPaul Winder 		return I40E_ERR_PARAM;
5293f1cac5SPaul Winder 
5393f1cac5SPaul Winder 	reg = rd32(hw, I40E_PRTDCB_GENS);
5493f1cac5SPaul Winder 	*status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
5593f1cac5SPaul Winder 			I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
5693f1cac5SPaul Winder 
5793f1cac5SPaul Winder 	return I40E_SUCCESS;
5893f1cac5SPaul Winder }
5993f1cac5SPaul Winder 
6093f1cac5SPaul Winder /**
6193f1cac5SPaul Winder  * i40e_parse_ieee_etscfg_tlv
6293f1cac5SPaul Winder  * @tlv: IEEE 802.1Qaz ETS CFG TLV
6393f1cac5SPaul Winder  * @dcbcfg: Local store to update ETS CFG data
6493f1cac5SPaul Winder  *
6593f1cac5SPaul Winder  * Parses IEEE 802.1Qaz ETS CFG TLV
6693f1cac5SPaul Winder  **/
i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)6793f1cac5SPaul Winder static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
6893f1cac5SPaul Winder 				       struct i40e_dcbx_config *dcbcfg)
6993f1cac5SPaul Winder {
7093f1cac5SPaul Winder 	struct i40e_dcb_ets_config *etscfg;
7193f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
7293f1cac5SPaul Winder 	u16 offset = 0;
7393f1cac5SPaul Winder 	u8 priority;
7493f1cac5SPaul Winder 	int i;
7593f1cac5SPaul Winder 
7693f1cac5SPaul Winder 	/* First Octet post subtype
7793f1cac5SPaul Winder 	 * --------------------------
7893f1cac5SPaul Winder 	 * |will-|CBS  | Re-  | Max |
7993f1cac5SPaul Winder 	 * |ing  |     |served| TCs |
8093f1cac5SPaul Winder 	 * --------------------------
8193f1cac5SPaul Winder 	 * |1bit | 1bit|3 bits|3bits|
8293f1cac5SPaul Winder 	 */
8393f1cac5SPaul Winder 	etscfg = &dcbcfg->etscfg;
8493f1cac5SPaul Winder 	etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
8593f1cac5SPaul Winder 			       I40E_IEEE_ETS_WILLING_SHIFT);
8693f1cac5SPaul Winder 	etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
8793f1cac5SPaul Winder 			   I40E_IEEE_ETS_CBS_SHIFT);
8893f1cac5SPaul Winder 	etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
8993f1cac5SPaul Winder 			      I40E_IEEE_ETS_MAXTC_SHIFT);
9093f1cac5SPaul Winder 
9193f1cac5SPaul Winder 	/* Move offset to Priority Assignment Table */
9293f1cac5SPaul Winder 	offset++;
9393f1cac5SPaul Winder 
9493f1cac5SPaul Winder 	/* Priority Assignment Table (4 octets)
9593f1cac5SPaul Winder 	 * Octets:|    1    |    2    |    3    |    4    |
9693f1cac5SPaul Winder 	 *        -----------------------------------------
9793f1cac5SPaul Winder 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
9893f1cac5SPaul Winder 	 *        -----------------------------------------
9993f1cac5SPaul Winder 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
10093f1cac5SPaul Winder 	 *        -----------------------------------------
10193f1cac5SPaul Winder 	 */
10293f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
10393f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
10493f1cac5SPaul Winder 				I40E_IEEE_ETS_PRIO_1_SHIFT);
10593f1cac5SPaul Winder 		etscfg->prioritytable[i * 2] =  priority;
10693f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
10793f1cac5SPaul Winder 				I40E_IEEE_ETS_PRIO_0_SHIFT);
10893f1cac5SPaul Winder 		etscfg->prioritytable[i * 2 + 1] = priority;
10993f1cac5SPaul Winder 		offset++;
11093f1cac5SPaul Winder 	}
11193f1cac5SPaul Winder 
11293f1cac5SPaul Winder 	/* TC Bandwidth Table (8 octets)
11393f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
11493f1cac5SPaul Winder 	 *        ---------------------------------
11593f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
11693f1cac5SPaul Winder 	 *        ---------------------------------
11793f1cac5SPaul Winder 	 */
11893f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
11993f1cac5SPaul Winder 		etscfg->tcbwtable[i] = buf[offset++];
12093f1cac5SPaul Winder 
12193f1cac5SPaul Winder 	/* TSA Assignment Table (8 octets)
12293f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
12393f1cac5SPaul Winder 	 *        ---------------------------------
12493f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
12593f1cac5SPaul Winder 	 *        ---------------------------------
12693f1cac5SPaul Winder 	 */
12793f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
12893f1cac5SPaul Winder 		etscfg->tsatable[i] = buf[offset++];
12993f1cac5SPaul Winder }
13093f1cac5SPaul Winder 
13193f1cac5SPaul Winder /**
13293f1cac5SPaul Winder  * i40e_parse_ieee_etsrec_tlv
13393f1cac5SPaul Winder  * @tlv: IEEE 802.1Qaz ETS REC TLV
13493f1cac5SPaul Winder  * @dcbcfg: Local store to update ETS REC data
13593f1cac5SPaul Winder  *
13693f1cac5SPaul Winder  * Parses IEEE 802.1Qaz ETS REC TLV
13793f1cac5SPaul Winder  **/
i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)13893f1cac5SPaul Winder static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
13993f1cac5SPaul Winder 				       struct i40e_dcbx_config *dcbcfg)
14093f1cac5SPaul Winder {
14193f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
14293f1cac5SPaul Winder 	u16 offset = 0;
14393f1cac5SPaul Winder 	u8 priority;
14493f1cac5SPaul Winder 	int i;
14593f1cac5SPaul Winder 
14693f1cac5SPaul Winder 	/* Move offset to priority table */
14793f1cac5SPaul Winder 	offset++;
14893f1cac5SPaul Winder 
14993f1cac5SPaul Winder 	/* Priority Assignment Table (4 octets)
15093f1cac5SPaul Winder 	 * Octets:|    1    |    2    |    3    |    4    |
15193f1cac5SPaul Winder 	 *        -----------------------------------------
15293f1cac5SPaul Winder 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
15393f1cac5SPaul Winder 	 *        -----------------------------------------
15493f1cac5SPaul Winder 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
15593f1cac5SPaul Winder 	 *        -----------------------------------------
15693f1cac5SPaul Winder 	 */
15793f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
15893f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
15993f1cac5SPaul Winder 				I40E_IEEE_ETS_PRIO_1_SHIFT);
16093f1cac5SPaul Winder 		dcbcfg->etsrec.prioritytable[i*2] =  priority;
16193f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
16293f1cac5SPaul Winder 				I40E_IEEE_ETS_PRIO_0_SHIFT);
16393f1cac5SPaul Winder 		dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
16493f1cac5SPaul Winder 		offset++;
16593f1cac5SPaul Winder 	}
16693f1cac5SPaul Winder 
16793f1cac5SPaul Winder 	/* TC Bandwidth Table (8 octets)
16893f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
16993f1cac5SPaul Winder 	 *        ---------------------------------
17093f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
17193f1cac5SPaul Winder 	 *        ---------------------------------
17293f1cac5SPaul Winder 	 */
17393f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
17493f1cac5SPaul Winder 		dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
17593f1cac5SPaul Winder 
17693f1cac5SPaul Winder 	/* TSA Assignment Table (8 octets)
17793f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
17893f1cac5SPaul Winder 	 *        ---------------------------------
17993f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
18093f1cac5SPaul Winder 	 *        ---------------------------------
18193f1cac5SPaul Winder 	 */
18293f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
18393f1cac5SPaul Winder 		dcbcfg->etsrec.tsatable[i] = buf[offset++];
18493f1cac5SPaul Winder }
18593f1cac5SPaul Winder 
18693f1cac5SPaul Winder /**
18793f1cac5SPaul Winder  * i40e_parse_ieee_pfccfg_tlv
18893f1cac5SPaul Winder  * @tlv: IEEE 802.1Qaz PFC CFG TLV
18993f1cac5SPaul Winder  * @dcbcfg: Local store to update PFC CFG data
19093f1cac5SPaul Winder  *
19193f1cac5SPaul Winder  * Parses IEEE 802.1Qaz PFC CFG TLV
19293f1cac5SPaul Winder  **/
i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)19393f1cac5SPaul Winder static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
19493f1cac5SPaul Winder 				       struct i40e_dcbx_config *dcbcfg)
19593f1cac5SPaul Winder {
19693f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
19793f1cac5SPaul Winder 
19893f1cac5SPaul Winder 	/* ----------------------------------------
19993f1cac5SPaul Winder 	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
20093f1cac5SPaul Winder 	 * |ing  |     |served| cap |              |
20193f1cac5SPaul Winder 	 * -----------------------------------------
20293f1cac5SPaul Winder 	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
20393f1cac5SPaul Winder 	 */
20493f1cac5SPaul Winder 	dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
20593f1cac5SPaul Winder 				   I40E_IEEE_PFC_WILLING_SHIFT);
20693f1cac5SPaul Winder 	dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
20793f1cac5SPaul Winder 			       I40E_IEEE_PFC_MBC_SHIFT);
20893f1cac5SPaul Winder 	dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
20993f1cac5SPaul Winder 				  I40E_IEEE_PFC_CAP_SHIFT);
21093f1cac5SPaul Winder 	dcbcfg->pfc.pfcenable = buf[1];
21193f1cac5SPaul Winder }
21293f1cac5SPaul Winder 
21393f1cac5SPaul Winder /**
21493f1cac5SPaul Winder  * i40e_parse_ieee_app_tlv
21593f1cac5SPaul Winder  * @tlv: IEEE 802.1Qaz APP TLV
21693f1cac5SPaul Winder  * @dcbcfg: Local store to update APP PRIO data
21793f1cac5SPaul Winder  *
21893f1cac5SPaul Winder  * Parses IEEE 802.1Qaz APP PRIO TLV
21993f1cac5SPaul Winder  **/
i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)22093f1cac5SPaul Winder static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
22193f1cac5SPaul Winder 				    struct i40e_dcbx_config *dcbcfg)
22293f1cac5SPaul Winder {
22393f1cac5SPaul Winder 	u16 typelength;
22493f1cac5SPaul Winder 	u16 offset = 0;
22593f1cac5SPaul Winder 	u16 length;
22693f1cac5SPaul Winder 	int i = 0;
22793f1cac5SPaul Winder 	u8 *buf;
22893f1cac5SPaul Winder 
22993f1cac5SPaul Winder 	typelength = I40E_NTOHS(tlv->typelength);
23093f1cac5SPaul Winder 	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
23193f1cac5SPaul Winder 		       I40E_LLDP_TLV_LEN_SHIFT);
23293f1cac5SPaul Winder 	buf = tlv->tlvinfo;
23393f1cac5SPaul Winder 
23493f1cac5SPaul Winder 	/* The App priority table starts 5 octets after TLV header */
23593f1cac5SPaul Winder 	length -= (sizeof(tlv->ouisubtype) + 1);
23693f1cac5SPaul Winder 
23793f1cac5SPaul Winder 	/* Move offset to App Priority Table */
23893f1cac5SPaul Winder 	offset++;
23993f1cac5SPaul Winder 
24093f1cac5SPaul Winder 	/* Application Priority Table (3 octets)
24193f1cac5SPaul Winder 	 * Octets:|         1          |    2    |    3    |
24293f1cac5SPaul Winder 	 *        -----------------------------------------
24393f1cac5SPaul Winder 	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
24493f1cac5SPaul Winder 	 *        -----------------------------------------
24593f1cac5SPaul Winder 	 *   Bits:|23    21|20 19|18 16|15                0|
24693f1cac5SPaul Winder 	 *        -----------------------------------------
24793f1cac5SPaul Winder 	 */
24893f1cac5SPaul Winder 	while (offset < length) {
24993f1cac5SPaul Winder 		dcbcfg->app[i].priority = (u8)((buf[offset] &
25093f1cac5SPaul Winder 						I40E_IEEE_APP_PRIO_MASK) >>
25193f1cac5SPaul Winder 					       I40E_IEEE_APP_PRIO_SHIFT);
25293f1cac5SPaul Winder 		dcbcfg->app[i].selector = (u8)((buf[offset] &
25393f1cac5SPaul Winder 						I40E_IEEE_APP_SEL_MASK) >>
25493f1cac5SPaul Winder 					       I40E_IEEE_APP_SEL_SHIFT);
25593f1cac5SPaul Winder 		dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
25693f1cac5SPaul Winder 					     buf[offset + 2];
25793f1cac5SPaul Winder 		/* Move to next app */
25893f1cac5SPaul Winder 		offset += 3;
25993f1cac5SPaul Winder 		i++;
26093f1cac5SPaul Winder 		if (i >= I40E_DCBX_MAX_APPS)
26193f1cac5SPaul Winder 			break;
26293f1cac5SPaul Winder 	}
26393f1cac5SPaul Winder 
26493f1cac5SPaul Winder 	dcbcfg->numapps = i;
26593f1cac5SPaul Winder }
26693f1cac5SPaul Winder 
26793f1cac5SPaul Winder /**
26893f1cac5SPaul Winder  * i40e_parse_ieee_etsrec_tlv
26993f1cac5SPaul Winder  * @tlv: IEEE 802.1Qaz TLV
27093f1cac5SPaul Winder  * @dcbcfg: Local store to update ETS REC data
27193f1cac5SPaul Winder  *
27293f1cac5SPaul Winder  * Get the TLV subtype and send it to parsing function
27393f1cac5SPaul Winder  * based on the subtype value
27493f1cac5SPaul Winder  **/
i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)27593f1cac5SPaul Winder static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
27693f1cac5SPaul Winder 				struct i40e_dcbx_config *dcbcfg)
27793f1cac5SPaul Winder {
27893f1cac5SPaul Winder 	u32 ouisubtype;
27993f1cac5SPaul Winder 	u8 subtype;
28093f1cac5SPaul Winder 
28193f1cac5SPaul Winder 	ouisubtype = I40E_NTOHL(tlv->ouisubtype);
28293f1cac5SPaul Winder 	subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
28393f1cac5SPaul Winder 		       I40E_LLDP_TLV_SUBTYPE_SHIFT);
28493f1cac5SPaul Winder 	switch (subtype) {
28593f1cac5SPaul Winder 	case I40E_IEEE_SUBTYPE_ETS_CFG:
28693f1cac5SPaul Winder 		i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
28793f1cac5SPaul Winder 		break;
28893f1cac5SPaul Winder 	case I40E_IEEE_SUBTYPE_ETS_REC:
28993f1cac5SPaul Winder 		i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
29093f1cac5SPaul Winder 		break;
29193f1cac5SPaul Winder 	case I40E_IEEE_SUBTYPE_PFC_CFG:
29293f1cac5SPaul Winder 		i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
29393f1cac5SPaul Winder 		break;
29493f1cac5SPaul Winder 	case I40E_IEEE_SUBTYPE_APP_PRI:
29593f1cac5SPaul Winder 		i40e_parse_ieee_app_tlv(tlv, dcbcfg);
29693f1cac5SPaul Winder 		break;
29793f1cac5SPaul Winder 	default:
29893f1cac5SPaul Winder 		break;
29993f1cac5SPaul Winder 	}
30093f1cac5SPaul Winder }
30193f1cac5SPaul Winder 
30293f1cac5SPaul Winder /**
30393f1cac5SPaul Winder  * i40e_parse_cee_pgcfg_tlv
30493f1cac5SPaul Winder  * @tlv: CEE DCBX PG CFG TLV
30593f1cac5SPaul Winder  * @dcbcfg: Local store to update ETS CFG data
30693f1cac5SPaul Winder  *
30793f1cac5SPaul Winder  * Parses CEE DCBX PG CFG TLV
30893f1cac5SPaul Winder  **/
i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)30993f1cac5SPaul Winder static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
31093f1cac5SPaul Winder 				     struct i40e_dcbx_config *dcbcfg)
31193f1cac5SPaul Winder {
31293f1cac5SPaul Winder 	struct i40e_dcb_ets_config *etscfg;
31393f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
31493f1cac5SPaul Winder 	u16 offset = 0;
31593f1cac5SPaul Winder 	u8 priority;
31693f1cac5SPaul Winder 	int i;
31793f1cac5SPaul Winder 
31893f1cac5SPaul Winder 	etscfg = &dcbcfg->etscfg;
31993f1cac5SPaul Winder 
32093f1cac5SPaul Winder 	if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
32193f1cac5SPaul Winder 		etscfg->willing = 1;
32293f1cac5SPaul Winder 
32393f1cac5SPaul Winder 	etscfg->cbs = 0;
32493f1cac5SPaul Winder 	/* Priority Group Table (4 octets)
32593f1cac5SPaul Winder 	 * Octets:|    1    |    2    |    3    |    4    |
32693f1cac5SPaul Winder 	 *        -----------------------------------------
32793f1cac5SPaul Winder 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
32893f1cac5SPaul Winder 	 *        -----------------------------------------
32993f1cac5SPaul Winder 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
33093f1cac5SPaul Winder 	 *        -----------------------------------------
33193f1cac5SPaul Winder 	 */
33293f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
33393f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
33493f1cac5SPaul Winder 				 I40E_CEE_PGID_PRIO_1_SHIFT);
33593f1cac5SPaul Winder 		etscfg->prioritytable[i * 2] =  priority;
33693f1cac5SPaul Winder 		priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
33793f1cac5SPaul Winder 				 I40E_CEE_PGID_PRIO_0_SHIFT);
33893f1cac5SPaul Winder 		etscfg->prioritytable[i * 2 + 1] = priority;
33993f1cac5SPaul Winder 		offset++;
34093f1cac5SPaul Winder 	}
34193f1cac5SPaul Winder 
34293f1cac5SPaul Winder 	/* PG Percentage Table (8 octets)
34393f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
34493f1cac5SPaul Winder 	 *        ---------------------------------
34593f1cac5SPaul Winder 	 *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
34693f1cac5SPaul Winder 	 *        ---------------------------------
34793f1cac5SPaul Winder 	 */
34893f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
34993f1cac5SPaul Winder 		etscfg->tcbwtable[i] = buf[offset++];
35093f1cac5SPaul Winder 
35193f1cac5SPaul Winder 	/* Number of TCs supported (1 octet) */
35293f1cac5SPaul Winder 	etscfg->maxtcs = buf[offset];
35393f1cac5SPaul Winder }
35493f1cac5SPaul Winder 
35593f1cac5SPaul Winder /**
35693f1cac5SPaul Winder  * i40e_parse_cee_pfccfg_tlv
35793f1cac5SPaul Winder  * @tlv: CEE DCBX PFC CFG TLV
35893f1cac5SPaul Winder  * @dcbcfg: Local store to update PFC CFG data
35993f1cac5SPaul Winder  *
36093f1cac5SPaul Winder  * Parses CEE DCBX PFC CFG TLV
36193f1cac5SPaul Winder  **/
i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)36293f1cac5SPaul Winder static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
36393f1cac5SPaul Winder 				      struct i40e_dcbx_config *dcbcfg)
36493f1cac5SPaul Winder {
36593f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
36693f1cac5SPaul Winder 
36793f1cac5SPaul Winder 	if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
36893f1cac5SPaul Winder 		dcbcfg->pfc.willing = 1;
36993f1cac5SPaul Winder 
37093f1cac5SPaul Winder 	/* ------------------------
37193f1cac5SPaul Winder 	 * | PFC Enable | PFC TCs |
37293f1cac5SPaul Winder 	 * ------------------------
37393f1cac5SPaul Winder 	 * | 1 octet    | 1 octet |
37493f1cac5SPaul Winder 	 */
37593f1cac5SPaul Winder 	dcbcfg->pfc.pfcenable = buf[0];
37693f1cac5SPaul Winder 	dcbcfg->pfc.pfccap = buf[1];
37793f1cac5SPaul Winder }
37893f1cac5SPaul Winder 
37993f1cac5SPaul Winder /**
38093f1cac5SPaul Winder  * i40e_parse_cee_app_tlv
38193f1cac5SPaul Winder  * @tlv: CEE DCBX APP TLV
38293f1cac5SPaul Winder  * @dcbcfg: Local store to update APP PRIO data
38393f1cac5SPaul Winder  *
38493f1cac5SPaul Winder  * Parses CEE DCBX APP PRIO TLV
38593f1cac5SPaul Winder  **/
i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)38693f1cac5SPaul Winder static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
38793f1cac5SPaul Winder 				   struct i40e_dcbx_config *dcbcfg)
38893f1cac5SPaul Winder {
38993f1cac5SPaul Winder 	u16 length, typelength, offset = 0;
39093f1cac5SPaul Winder 	struct i40e_cee_app_prio *app;
39193f1cac5SPaul Winder 	u8 i;
39293f1cac5SPaul Winder 
39393f1cac5SPaul Winder 	typelength = I40E_NTOHS(tlv->hdr.typelen);
39493f1cac5SPaul Winder 	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
39593f1cac5SPaul Winder 		       I40E_LLDP_TLV_LEN_SHIFT);
39693f1cac5SPaul Winder 
39793f1cac5SPaul Winder 	dcbcfg->numapps = length / sizeof(*app);
39893f1cac5SPaul Winder 	if (!dcbcfg->numapps)
39993f1cac5SPaul Winder 		return;
40093f1cac5SPaul Winder 	if (dcbcfg->numapps > I40E_DCBX_MAX_APPS)
40193f1cac5SPaul Winder 		dcbcfg->numapps = I40E_DCBX_MAX_APPS;
40293f1cac5SPaul Winder 
40393f1cac5SPaul Winder 	for (i = 0; i < dcbcfg->numapps; i++) {
40493f1cac5SPaul Winder 		u8 up, selector;
40593f1cac5SPaul Winder 
40693f1cac5SPaul Winder 		app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
40793f1cac5SPaul Winder 		for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
40893f1cac5SPaul Winder 			if (app->prio_map & BIT(up))
40993f1cac5SPaul Winder 				break;
41093f1cac5SPaul Winder 		}
41193f1cac5SPaul Winder 		dcbcfg->app[i].priority = up;
41293f1cac5SPaul Winder 
41393f1cac5SPaul Winder 		/* Get Selector from lower 2 bits, and convert to IEEE */
41493f1cac5SPaul Winder 		selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
41593f1cac5SPaul Winder 		switch (selector) {
41693f1cac5SPaul Winder 		case I40E_CEE_APP_SEL_ETHTYPE:
41793f1cac5SPaul Winder 			dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
41893f1cac5SPaul Winder 			break;
41993f1cac5SPaul Winder 		case I40E_CEE_APP_SEL_TCPIP:
42093f1cac5SPaul Winder 			dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
42193f1cac5SPaul Winder 			break;
42293f1cac5SPaul Winder 		default:
42393f1cac5SPaul Winder 			/* Keep selector as it is for unknown types */
42493f1cac5SPaul Winder 			dcbcfg->app[i].selector = selector;
42593f1cac5SPaul Winder 		}
42693f1cac5SPaul Winder 
42793f1cac5SPaul Winder 		dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
42893f1cac5SPaul Winder 		/* Move to next app */
42993f1cac5SPaul Winder 		offset += sizeof(*app);
43093f1cac5SPaul Winder 	}
43193f1cac5SPaul Winder }
43293f1cac5SPaul Winder 
43393f1cac5SPaul Winder /**
43493f1cac5SPaul Winder  * i40e_parse_cee_tlv
43593f1cac5SPaul Winder  * @tlv: CEE DCBX TLV
43693f1cac5SPaul Winder  * @dcbcfg: Local store to update DCBX config data
43793f1cac5SPaul Winder  *
43893f1cac5SPaul Winder  * Get the TLV subtype and send it to parsing function
43993f1cac5SPaul Winder  * based on the subtype value
44093f1cac5SPaul Winder  **/
i40e_parse_cee_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)44193f1cac5SPaul Winder static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
44293f1cac5SPaul Winder 			       struct i40e_dcbx_config *dcbcfg)
44393f1cac5SPaul Winder {
44493f1cac5SPaul Winder 	u16 len, tlvlen, sublen, typelength;
44593f1cac5SPaul Winder 	struct i40e_cee_feat_tlv *sub_tlv;
44693f1cac5SPaul Winder 	u8 subtype, feat_tlv_count = 0;
44793f1cac5SPaul Winder 	u32 ouisubtype;
44893f1cac5SPaul Winder 
44993f1cac5SPaul Winder 	ouisubtype = I40E_NTOHL(tlv->ouisubtype);
45093f1cac5SPaul Winder 	subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
45193f1cac5SPaul Winder 		       I40E_LLDP_TLV_SUBTYPE_SHIFT);
45293f1cac5SPaul Winder 	/* Return if not CEE DCBX */
45393f1cac5SPaul Winder 	if (subtype != I40E_CEE_DCBX_TYPE)
45493f1cac5SPaul Winder 		return;
45593f1cac5SPaul Winder 
45693f1cac5SPaul Winder 	typelength = I40E_NTOHS(tlv->typelength);
45793f1cac5SPaul Winder 	tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
45893f1cac5SPaul Winder 			I40E_LLDP_TLV_LEN_SHIFT);
45993f1cac5SPaul Winder 	len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
46093f1cac5SPaul Winder 	      sizeof(struct i40e_cee_ctrl_tlv);
46193f1cac5SPaul Winder 	/* Return if no CEE DCBX Feature TLVs */
46293f1cac5SPaul Winder 	if (tlvlen <= len)
46393f1cac5SPaul Winder 		return;
46493f1cac5SPaul Winder 
46593f1cac5SPaul Winder 	sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
46693f1cac5SPaul Winder 	while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
46793f1cac5SPaul Winder 		typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
46893f1cac5SPaul Winder 		sublen = (u16)((typelength &
46993f1cac5SPaul Winder 				I40E_LLDP_TLV_LEN_MASK) >>
47093f1cac5SPaul Winder 				I40E_LLDP_TLV_LEN_SHIFT);
47193f1cac5SPaul Winder 		subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
47293f1cac5SPaul Winder 				I40E_LLDP_TLV_TYPE_SHIFT);
47393f1cac5SPaul Winder 		switch (subtype) {
47493f1cac5SPaul Winder 		case I40E_CEE_SUBTYPE_PG_CFG:
47593f1cac5SPaul Winder 			i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
47693f1cac5SPaul Winder 			break;
47793f1cac5SPaul Winder 		case I40E_CEE_SUBTYPE_PFC_CFG:
47893f1cac5SPaul Winder 			i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
47993f1cac5SPaul Winder 			break;
48093f1cac5SPaul Winder 		case I40E_CEE_SUBTYPE_APP_PRI:
48193f1cac5SPaul Winder 			i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
48293f1cac5SPaul Winder 			break;
48393f1cac5SPaul Winder 		default:
48493f1cac5SPaul Winder 			return; /* Invalid Sub-type return */
48593f1cac5SPaul Winder 		}
48693f1cac5SPaul Winder 		feat_tlv_count++;
48793f1cac5SPaul Winder 		/* Move to next sub TLV */
48893f1cac5SPaul Winder 		sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
48993f1cac5SPaul Winder 						sizeof(sub_tlv->hdr.typelen) +
49093f1cac5SPaul Winder 						sublen);
49193f1cac5SPaul Winder 	}
49293f1cac5SPaul Winder }
49393f1cac5SPaul Winder 
49493f1cac5SPaul Winder /**
49593f1cac5SPaul Winder  * i40e_parse_org_tlv
49693f1cac5SPaul Winder  * @tlv: Organization specific TLV
49793f1cac5SPaul Winder  * @dcbcfg: Local store to update ETS REC data
49893f1cac5SPaul Winder  *
49993f1cac5SPaul Winder  * Currently only IEEE 802.1Qaz TLV is supported, all others
50093f1cac5SPaul Winder  * will be returned
50193f1cac5SPaul Winder  **/
i40e_parse_org_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)50293f1cac5SPaul Winder static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
50393f1cac5SPaul Winder 			       struct i40e_dcbx_config *dcbcfg)
50493f1cac5SPaul Winder {
50593f1cac5SPaul Winder 	u32 ouisubtype;
50693f1cac5SPaul Winder 	u32 oui;
50793f1cac5SPaul Winder 
50893f1cac5SPaul Winder 	ouisubtype = I40E_NTOHL(tlv->ouisubtype);
50993f1cac5SPaul Winder 	oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
51093f1cac5SPaul Winder 		    I40E_LLDP_TLV_OUI_SHIFT);
51193f1cac5SPaul Winder 	switch (oui) {
51293f1cac5SPaul Winder 	case I40E_IEEE_8021QAZ_OUI:
51393f1cac5SPaul Winder 		i40e_parse_ieee_tlv(tlv, dcbcfg);
51493f1cac5SPaul Winder 		break;
51593f1cac5SPaul Winder 	case I40E_CEE_DCBX_OUI:
51693f1cac5SPaul Winder 		i40e_parse_cee_tlv(tlv, dcbcfg);
51793f1cac5SPaul Winder 		break;
51893f1cac5SPaul Winder 	default:
51993f1cac5SPaul Winder 		break;
52093f1cac5SPaul Winder 	}
52193f1cac5SPaul Winder }
52293f1cac5SPaul Winder 
52393f1cac5SPaul Winder /**
52493f1cac5SPaul Winder  * i40e_lldp_to_dcb_config
52593f1cac5SPaul Winder  * @lldpmib: LLDPDU to be parsed
52693f1cac5SPaul Winder  * @dcbcfg: store for LLDPDU data
52793f1cac5SPaul Winder  *
52893f1cac5SPaul Winder  * Parse DCB configuration from the LLDPDU
52993f1cac5SPaul Winder  **/
i40e_lldp_to_dcb_config(u8 * lldpmib,struct i40e_dcbx_config * dcbcfg)53093f1cac5SPaul Winder enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
53193f1cac5SPaul Winder 				    struct i40e_dcbx_config *dcbcfg)
53293f1cac5SPaul Winder {
53393f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
53493f1cac5SPaul Winder 	struct i40e_lldp_org_tlv *tlv;
53593f1cac5SPaul Winder 	u16 type;
53693f1cac5SPaul Winder 	u16 length;
53793f1cac5SPaul Winder 	u16 typelength;
53893f1cac5SPaul Winder 	u16 offset = 0;
53993f1cac5SPaul Winder 
54093f1cac5SPaul Winder 	if (!lldpmib || !dcbcfg)
54193f1cac5SPaul Winder 		return I40E_ERR_PARAM;
54293f1cac5SPaul Winder 
54393f1cac5SPaul Winder 	/* set to the start of LLDPDU */
54493f1cac5SPaul Winder 	lldpmib += I40E_LLDP_MIB_HLEN;
54593f1cac5SPaul Winder 	tlv = (struct i40e_lldp_org_tlv *)lldpmib;
54693f1cac5SPaul Winder 	while (1) {
54793f1cac5SPaul Winder 		typelength = I40E_NTOHS(tlv->typelength);
54893f1cac5SPaul Winder 		type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
54993f1cac5SPaul Winder 			     I40E_LLDP_TLV_TYPE_SHIFT);
55093f1cac5SPaul Winder 		length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
55193f1cac5SPaul Winder 			       I40E_LLDP_TLV_LEN_SHIFT);
55293f1cac5SPaul Winder 		offset += sizeof(typelength) + length;
55393f1cac5SPaul Winder 
55493f1cac5SPaul Winder 		/* END TLV or beyond LLDPDU size */
55593f1cac5SPaul Winder 		if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
55693f1cac5SPaul Winder 			break;
55793f1cac5SPaul Winder 
55893f1cac5SPaul Winder 		switch (type) {
55993f1cac5SPaul Winder 		case I40E_TLV_TYPE_ORG:
56093f1cac5SPaul Winder 			i40e_parse_org_tlv(tlv, dcbcfg);
56193f1cac5SPaul Winder 			break;
56293f1cac5SPaul Winder 		default:
56393f1cac5SPaul Winder 			break;
56493f1cac5SPaul Winder 		}
56593f1cac5SPaul Winder 
56693f1cac5SPaul Winder 		/* Move to next TLV */
56793f1cac5SPaul Winder 		tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
56893f1cac5SPaul Winder 						    sizeof(tlv->typelength) +
56993f1cac5SPaul Winder 						    length);
57093f1cac5SPaul Winder 	}
57193f1cac5SPaul Winder 
57293f1cac5SPaul Winder 	return ret;
57393f1cac5SPaul Winder }
57493f1cac5SPaul Winder 
57593f1cac5SPaul Winder /**
57693f1cac5SPaul Winder  * i40e_aq_get_dcb_config
57793f1cac5SPaul Winder  * @hw: pointer to the hw struct
57893f1cac5SPaul Winder  * @mib_type: mib type for the query
57993f1cac5SPaul Winder  * @bridgetype: bridge type for the query (remote)
58093f1cac5SPaul Winder  * @dcbcfg: store for LLDPDU data
58193f1cac5SPaul Winder  *
58293f1cac5SPaul Winder  * Query DCB configuration from the Firmware
58393f1cac5SPaul Winder  **/
i40e_aq_get_dcb_config(struct i40e_hw * hw,u8 mib_type,u8 bridgetype,struct i40e_dcbx_config * dcbcfg)58493f1cac5SPaul Winder enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
58593f1cac5SPaul Winder 				   u8 bridgetype,
58693f1cac5SPaul Winder 				   struct i40e_dcbx_config *dcbcfg)
58793f1cac5SPaul Winder {
58893f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
58993f1cac5SPaul Winder 	struct i40e_virt_mem mem;
59093f1cac5SPaul Winder 	u8 *lldpmib;
59193f1cac5SPaul Winder 
59293f1cac5SPaul Winder 	/* Allocate the LLDPDU */
59393f1cac5SPaul Winder 	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
59493f1cac5SPaul Winder 	if (ret)
59593f1cac5SPaul Winder 		return ret;
59693f1cac5SPaul Winder 
59793f1cac5SPaul Winder 	lldpmib = (u8 *)mem.va;
59893f1cac5SPaul Winder 	ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
59993f1cac5SPaul Winder 				   (void *)lldpmib, I40E_LLDPDU_SIZE,
60093f1cac5SPaul Winder 				   NULL, NULL, NULL);
60193f1cac5SPaul Winder 	if (ret)
60293f1cac5SPaul Winder 		goto free_mem;
60393f1cac5SPaul Winder 
60493f1cac5SPaul Winder 	/* Parse LLDP MIB to get dcb configuration */
60593f1cac5SPaul Winder 	ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
60693f1cac5SPaul Winder 
60793f1cac5SPaul Winder free_mem:
60893f1cac5SPaul Winder 	i40e_free_virt_mem(hw, &mem);
60993f1cac5SPaul Winder 	return ret;
61093f1cac5SPaul Winder }
61193f1cac5SPaul Winder 
61293f1cac5SPaul Winder /**
61393f1cac5SPaul Winder  * i40e_cee_to_dcb_v1_config
61493f1cac5SPaul Winder  * @cee_cfg: pointer to CEE v1 response configuration struct
61593f1cac5SPaul Winder  * @dcbcfg: DCB configuration struct
61693f1cac5SPaul Winder  *
61793f1cac5SPaul Winder  * Convert CEE v1 configuration from firmware to DCB configuration
61893f1cac5SPaul Winder  **/
i40e_cee_to_dcb_v1_config(struct i40e_aqc_get_cee_dcb_cfg_v1_resp * cee_cfg,struct i40e_dcbx_config * dcbcfg)61993f1cac5SPaul Winder static void i40e_cee_to_dcb_v1_config(
62093f1cac5SPaul Winder 			struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
62193f1cac5SPaul Winder 			struct i40e_dcbx_config *dcbcfg)
62293f1cac5SPaul Winder {
62393f1cac5SPaul Winder 	u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
62493f1cac5SPaul Winder 	u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
62593f1cac5SPaul Winder 	u8 i, tc, err;
62693f1cac5SPaul Winder 
62793f1cac5SPaul Winder 	/* CEE PG data to ETS config */
62893f1cac5SPaul Winder 	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
62993f1cac5SPaul Winder 
63093f1cac5SPaul Winder 	/* Note that the FW creates the oper_prio_tc nibbles reversed
63193f1cac5SPaul Winder 	 * from those in the CEE Priority Group sub-TLV.
63293f1cac5SPaul Winder 	 */
63393f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
63493f1cac5SPaul Winder 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
63593f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_0_MASK) >>
63693f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_0_SHIFT);
63793f1cac5SPaul Winder 		dcbcfg->etscfg.prioritytable[i*2] =  tc;
63893f1cac5SPaul Winder 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
63993f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_1_MASK) >>
64093f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_1_SHIFT);
64193f1cac5SPaul Winder 		dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
64293f1cac5SPaul Winder 	}
64393f1cac5SPaul Winder 
64493f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
64593f1cac5SPaul Winder 		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
64693f1cac5SPaul Winder 
64793f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
64893f1cac5SPaul Winder 		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
64993f1cac5SPaul Winder 			/* Map it to next empty TC */
65093f1cac5SPaul Winder 			dcbcfg->etscfg.prioritytable[i] =
65193f1cac5SPaul Winder 						cee_cfg->oper_num_tc - 1;
65293f1cac5SPaul Winder 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
65393f1cac5SPaul Winder 		} else {
65493f1cac5SPaul Winder 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
65593f1cac5SPaul Winder 		}
65693f1cac5SPaul Winder 	}
65793f1cac5SPaul Winder 
65893f1cac5SPaul Winder 	/* CEE PFC data to ETS config */
65993f1cac5SPaul Winder 	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
66093f1cac5SPaul Winder 	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
66193f1cac5SPaul Winder 
66293f1cac5SPaul Winder 	status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
66393f1cac5SPaul Winder 		  I40E_AQC_CEE_APP_STATUS_SHIFT;
66493f1cac5SPaul Winder 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
66593f1cac5SPaul Winder 	/* Add APPs if Error is False */
66693f1cac5SPaul Winder 	if (!err) {
66793f1cac5SPaul Winder 		/* CEE operating configuration supports FCoE/iSCSI/FIP only */
66893f1cac5SPaul Winder 		dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
66993f1cac5SPaul Winder 
67093f1cac5SPaul Winder 		/* FCoE APP */
67193f1cac5SPaul Winder 		dcbcfg->app[0].priority =
67293f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
67393f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_FCOE_SHIFT;
67493f1cac5SPaul Winder 		dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
67593f1cac5SPaul Winder 		dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
67693f1cac5SPaul Winder 
67793f1cac5SPaul Winder 		/* iSCSI APP */
67893f1cac5SPaul Winder 		dcbcfg->app[1].priority =
67993f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
68093f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
68193f1cac5SPaul Winder 		dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
68293f1cac5SPaul Winder 		dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
68393f1cac5SPaul Winder 
68493f1cac5SPaul Winder 		/* FIP APP */
68593f1cac5SPaul Winder 		dcbcfg->app[2].priority =
68693f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
68793f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_FIP_SHIFT;
68893f1cac5SPaul Winder 		dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
68993f1cac5SPaul Winder 		dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
69093f1cac5SPaul Winder 	}
69193f1cac5SPaul Winder }
69293f1cac5SPaul Winder 
69393f1cac5SPaul Winder /**
69493f1cac5SPaul Winder  * i40e_cee_to_dcb_config
69593f1cac5SPaul Winder  * @cee_cfg: pointer to CEE configuration struct
69693f1cac5SPaul Winder  * @dcbcfg: DCB configuration struct
69793f1cac5SPaul Winder  *
69893f1cac5SPaul Winder  * Convert CEE configuration from firmware to DCB configuration
69993f1cac5SPaul Winder  **/
i40e_cee_to_dcb_config(struct i40e_aqc_get_cee_dcb_cfg_resp * cee_cfg,struct i40e_dcbx_config * dcbcfg)70093f1cac5SPaul Winder static void i40e_cee_to_dcb_config(
70193f1cac5SPaul Winder 				struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
70293f1cac5SPaul Winder 				struct i40e_dcbx_config *dcbcfg)
70393f1cac5SPaul Winder {
70493f1cac5SPaul Winder 	u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
70593f1cac5SPaul Winder 	u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
70693f1cac5SPaul Winder 	u8 i, tc, err, sync, oper;
70793f1cac5SPaul Winder 
70893f1cac5SPaul Winder 	/* CEE PG data to ETS config */
70993f1cac5SPaul Winder 	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
71093f1cac5SPaul Winder 
71193f1cac5SPaul Winder 	/* Note that the FW creates the oper_prio_tc nibbles reversed
71293f1cac5SPaul Winder 	 * from those in the CEE Priority Group sub-TLV.
71393f1cac5SPaul Winder 	 */
71493f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
71593f1cac5SPaul Winder 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
71693f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_0_MASK) >>
71793f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_0_SHIFT);
71893f1cac5SPaul Winder 		dcbcfg->etscfg.prioritytable[i*2] =  tc;
71993f1cac5SPaul Winder 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
72093f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_1_MASK) >>
72193f1cac5SPaul Winder 			 I40E_CEE_PGID_PRIO_1_SHIFT);
72293f1cac5SPaul Winder 		dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
72393f1cac5SPaul Winder 	}
72493f1cac5SPaul Winder 
72593f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
72693f1cac5SPaul Winder 		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
72793f1cac5SPaul Winder 
72893f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
72993f1cac5SPaul Winder 		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
73093f1cac5SPaul Winder 			/* Map it to next empty TC */
73193f1cac5SPaul Winder 			dcbcfg->etscfg.prioritytable[i] =
73293f1cac5SPaul Winder 						cee_cfg->oper_num_tc - 1;
73393f1cac5SPaul Winder 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
73493f1cac5SPaul Winder 		} else {
73593f1cac5SPaul Winder 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
73693f1cac5SPaul Winder 		}
73793f1cac5SPaul Winder 	}
73893f1cac5SPaul Winder 
73993f1cac5SPaul Winder 	/* CEE PFC data to ETS config */
74093f1cac5SPaul Winder 	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
74193f1cac5SPaul Winder 	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
74293f1cac5SPaul Winder 
74393f1cac5SPaul Winder 	i = 0;
74493f1cac5SPaul Winder 	status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
74593f1cac5SPaul Winder 		  I40E_AQC_CEE_FCOE_STATUS_SHIFT;
74693f1cac5SPaul Winder 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
74793f1cac5SPaul Winder 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
74893f1cac5SPaul Winder 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
74993f1cac5SPaul Winder 	/* Add FCoE APP if Error is False and Oper/Sync is True */
75093f1cac5SPaul Winder 	if (!err && sync && oper) {
75193f1cac5SPaul Winder 		/* FCoE APP */
75293f1cac5SPaul Winder 		dcbcfg->app[i].priority =
75393f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
75493f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_FCOE_SHIFT;
75593f1cac5SPaul Winder 		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
75693f1cac5SPaul Winder 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
75793f1cac5SPaul Winder 		i++;
75893f1cac5SPaul Winder 	}
75993f1cac5SPaul Winder 
76093f1cac5SPaul Winder 	status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
76193f1cac5SPaul Winder 		  I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
76293f1cac5SPaul Winder 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
76393f1cac5SPaul Winder 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
76493f1cac5SPaul Winder 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
76593f1cac5SPaul Winder 	/* Add iSCSI APP if Error is False and Oper/Sync is True */
76693f1cac5SPaul Winder 	if (!err && sync && oper) {
76793f1cac5SPaul Winder 		/* iSCSI APP */
76893f1cac5SPaul Winder 		dcbcfg->app[i].priority =
76993f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
77093f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
77193f1cac5SPaul Winder 		dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
77293f1cac5SPaul Winder 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
77393f1cac5SPaul Winder 		i++;
77493f1cac5SPaul Winder 	}
77593f1cac5SPaul Winder 
77693f1cac5SPaul Winder 	status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
77793f1cac5SPaul Winder 		  I40E_AQC_CEE_FIP_STATUS_SHIFT;
77893f1cac5SPaul Winder 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
77993f1cac5SPaul Winder 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
78093f1cac5SPaul Winder 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
78193f1cac5SPaul Winder 	/* Add FIP APP if Error is False and Oper/Sync is True */
78293f1cac5SPaul Winder 	if (!err && sync && oper) {
78393f1cac5SPaul Winder 		/* FIP APP */
78493f1cac5SPaul Winder 		dcbcfg->app[i].priority =
78593f1cac5SPaul Winder 			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
78693f1cac5SPaul Winder 			 I40E_AQC_CEE_APP_FIP_SHIFT;
78793f1cac5SPaul Winder 		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
78893f1cac5SPaul Winder 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
78993f1cac5SPaul Winder 		i++;
79093f1cac5SPaul Winder 	}
79193f1cac5SPaul Winder 	dcbcfg->numapps = i;
79293f1cac5SPaul Winder }
79393f1cac5SPaul Winder 
79493f1cac5SPaul Winder /**
79593f1cac5SPaul Winder  * i40e_get_ieee_dcb_config
79693f1cac5SPaul Winder  * @hw: pointer to the hw struct
79793f1cac5SPaul Winder  *
79893f1cac5SPaul Winder  * Get IEEE mode DCB configuration from the Firmware
79993f1cac5SPaul Winder  **/
i40e_get_ieee_dcb_config(struct i40e_hw * hw)80093f1cac5SPaul Winder static enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw)
80193f1cac5SPaul Winder {
80293f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
80393f1cac5SPaul Winder 
80493f1cac5SPaul Winder 	/* IEEE mode */
80593f1cac5SPaul Winder 	hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
80693f1cac5SPaul Winder 	/* Get Local DCB Config */
80793f1cac5SPaul Winder 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
80893f1cac5SPaul Winder 				     &hw->local_dcbx_config);
80993f1cac5SPaul Winder 	if (ret)
81093f1cac5SPaul Winder 		goto out;
81193f1cac5SPaul Winder 
81293f1cac5SPaul Winder 	/* Get Remote DCB Config */
81393f1cac5SPaul Winder 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
81493f1cac5SPaul Winder 				     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
81593f1cac5SPaul Winder 				     &hw->remote_dcbx_config);
81693f1cac5SPaul Winder 	/* Don't treat ENOENT as an error for Remote MIBs */
81793f1cac5SPaul Winder 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
81893f1cac5SPaul Winder 		ret = I40E_SUCCESS;
81993f1cac5SPaul Winder 
82093f1cac5SPaul Winder out:
82193f1cac5SPaul Winder 	return ret;
82293f1cac5SPaul Winder }
82393f1cac5SPaul Winder 
82493f1cac5SPaul Winder /**
82593f1cac5SPaul Winder  * i40e_get_dcb_config
82693f1cac5SPaul Winder  * @hw: pointer to the hw struct
82793f1cac5SPaul Winder  *
82893f1cac5SPaul Winder  * Get DCB configuration from the Firmware
82993f1cac5SPaul Winder  **/
i40e_get_dcb_config(struct i40e_hw * hw)83093f1cac5SPaul Winder enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
83193f1cac5SPaul Winder {
83293f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
83393f1cac5SPaul Winder 	struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
83493f1cac5SPaul Winder 	struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
83593f1cac5SPaul Winder 
83693f1cac5SPaul Winder 	/* If Firmware version < v4.33 on X710/XL710, IEEE only */
83793f1cac5SPaul Winder 	if ((hw->mac.type == I40E_MAC_XL710) &&
83893f1cac5SPaul Winder 	    (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
83993f1cac5SPaul Winder 	      (hw->aq.fw_maj_ver < 4)))
84093f1cac5SPaul Winder 		return i40e_get_ieee_dcb_config(hw);
84193f1cac5SPaul Winder 
84293f1cac5SPaul Winder 	/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
84393f1cac5SPaul Winder 	if ((hw->mac.type == I40E_MAC_XL710) &&
84493f1cac5SPaul Winder 	    ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
84593f1cac5SPaul Winder 		ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
84693f1cac5SPaul Winder 						 sizeof(cee_v1_cfg), NULL);
84793f1cac5SPaul Winder 		if (ret == I40E_SUCCESS) {
84893f1cac5SPaul Winder 			/* CEE mode */
84993f1cac5SPaul Winder 			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
85093f1cac5SPaul Winder 			hw->local_dcbx_config.tlv_status =
85193f1cac5SPaul Winder 					LE16_TO_CPU(cee_v1_cfg.tlv_status);
85293f1cac5SPaul Winder 			i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
85393f1cac5SPaul Winder 						  &hw->local_dcbx_config);
85493f1cac5SPaul Winder 		}
85593f1cac5SPaul Winder 	} else {
85693f1cac5SPaul Winder 		ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
85793f1cac5SPaul Winder 						 sizeof(cee_cfg), NULL);
85893f1cac5SPaul Winder 		if (ret == I40E_SUCCESS) {
85993f1cac5SPaul Winder 			/* CEE mode */
86093f1cac5SPaul Winder 			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
86193f1cac5SPaul Winder 			hw->local_dcbx_config.tlv_status =
86293f1cac5SPaul Winder 					LE32_TO_CPU(cee_cfg.tlv_status);
86393f1cac5SPaul Winder 			i40e_cee_to_dcb_config(&cee_cfg,
86493f1cac5SPaul Winder 					       &hw->local_dcbx_config);
86593f1cac5SPaul Winder 		}
86693f1cac5SPaul Winder 	}
86793f1cac5SPaul Winder 
86893f1cac5SPaul Winder 	/* CEE mode not enabled try querying IEEE data */
86993f1cac5SPaul Winder 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
87093f1cac5SPaul Winder 		return i40e_get_ieee_dcb_config(hw);
87193f1cac5SPaul Winder 
87293f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
87393f1cac5SPaul Winder 		goto out;
87493f1cac5SPaul Winder 
87593f1cac5SPaul Winder 	/* Get CEE DCB Desired Config */
87693f1cac5SPaul Winder 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
87793f1cac5SPaul Winder 				     &hw->desired_dcbx_config);
87893f1cac5SPaul Winder 	if (ret)
87993f1cac5SPaul Winder 		goto out;
88093f1cac5SPaul Winder 
88193f1cac5SPaul Winder 	/* Get Remote DCB Config */
88293f1cac5SPaul Winder 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
88393f1cac5SPaul Winder 			     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
88493f1cac5SPaul Winder 			     &hw->remote_dcbx_config);
88593f1cac5SPaul Winder 	/* Don't treat ENOENT as an error for Remote MIBs */
88693f1cac5SPaul Winder 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
88793f1cac5SPaul Winder 		ret = I40E_SUCCESS;
88893f1cac5SPaul Winder 
88993f1cac5SPaul Winder out:
89093f1cac5SPaul Winder 	return ret;
89193f1cac5SPaul Winder }
89293f1cac5SPaul Winder 
89393f1cac5SPaul Winder /**
89493f1cac5SPaul Winder  * i40e_init_dcb
89593f1cac5SPaul Winder  * @hw: pointer to the hw struct
896*df36e06dSRobert Mustacchi  * @enable_mib_change: enable mib change event
89793f1cac5SPaul Winder  *
89893f1cac5SPaul Winder  * Update DCB configuration from the Firmware
89993f1cac5SPaul Winder  **/
i40e_init_dcb(struct i40e_hw * hw,bool enable_mib_change)900*df36e06dSRobert Mustacchi enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
90193f1cac5SPaul Winder {
90293f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
90393f1cac5SPaul Winder 	struct i40e_lldp_variables lldp_cfg;
90493f1cac5SPaul Winder 	u8 adminstatus = 0;
90593f1cac5SPaul Winder 
90693f1cac5SPaul Winder 	if (!hw->func_caps.dcb)
907*df36e06dSRobert Mustacchi 		return I40E_NOT_SUPPORTED;
90893f1cac5SPaul Winder 
90993f1cac5SPaul Winder 	/* Read LLDP NVM area */
910*df36e06dSRobert Mustacchi 	if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) {
911*df36e06dSRobert Mustacchi 		u8 offset = 0;
912*df36e06dSRobert Mustacchi 
913*df36e06dSRobert Mustacchi 		if (hw->mac.type == I40E_MAC_XL710)
914*df36e06dSRobert Mustacchi 			offset = I40E_LLDP_CURRENT_STATUS_XL710_OFFSET;
915*df36e06dSRobert Mustacchi 		else if (hw->mac.type == I40E_MAC_X722)
916*df36e06dSRobert Mustacchi 			offset = I40E_LLDP_CURRENT_STATUS_X722_OFFSET;
917*df36e06dSRobert Mustacchi 		else
918*df36e06dSRobert Mustacchi 			return I40E_NOT_SUPPORTED;
919*df36e06dSRobert Mustacchi 
920*df36e06dSRobert Mustacchi 		ret = i40e_read_nvm_module_data(hw,
921*df36e06dSRobert Mustacchi 						I40E_SR_EMP_SR_SETTINGS_PTR,
922*df36e06dSRobert Mustacchi 						offset,
923*df36e06dSRobert Mustacchi 						I40E_LLDP_CURRENT_STATUS_OFFSET,
924*df36e06dSRobert Mustacchi 						I40E_LLDP_CURRENT_STATUS_SIZE,
925*df36e06dSRobert Mustacchi 						&lldp_cfg.adminstatus);
926*df36e06dSRobert Mustacchi 	} else {
927*df36e06dSRobert Mustacchi 		ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
928*df36e06dSRobert Mustacchi 	}
92993f1cac5SPaul Winder 	if (ret)
930*df36e06dSRobert Mustacchi 		return I40E_ERR_NOT_READY;
93193f1cac5SPaul Winder 
93293f1cac5SPaul Winder 	/* Get the LLDP AdminStatus for the current port */
93393f1cac5SPaul Winder 	adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
93493f1cac5SPaul Winder 	adminstatus &= 0xF;
93593f1cac5SPaul Winder 
93693f1cac5SPaul Winder 	/* LLDP agent disabled */
93793f1cac5SPaul Winder 	if (!adminstatus) {
93893f1cac5SPaul Winder 		hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
939*df36e06dSRobert Mustacchi 		return I40E_ERR_NOT_READY;
94093f1cac5SPaul Winder 	}
94193f1cac5SPaul Winder 
94293f1cac5SPaul Winder 	/* Get DCBX status */
94393f1cac5SPaul Winder 	ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
94493f1cac5SPaul Winder 	if (ret)
94593f1cac5SPaul Winder 		return ret;
94693f1cac5SPaul Winder 
94793f1cac5SPaul Winder 	/* Check the DCBX Status */
948*df36e06dSRobert Mustacchi 	if (hw->dcbx_status == I40E_DCBX_STATUS_DONE ||
949*df36e06dSRobert Mustacchi 	    hw->dcbx_status == I40E_DCBX_STATUS_IN_PROGRESS) {
95093f1cac5SPaul Winder 		/* Get current DCBX configuration */
95193f1cac5SPaul Winder 		ret = i40e_get_dcb_config(hw);
95293f1cac5SPaul Winder 		if (ret)
95393f1cac5SPaul Winder 			return ret;
954*df36e06dSRobert Mustacchi 	} else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
955*df36e06dSRobert Mustacchi 		return I40E_ERR_NOT_READY;
95693f1cac5SPaul Winder 	}
95793f1cac5SPaul Winder 
95893f1cac5SPaul Winder 	/* Configure the LLDP MIB change event */
959*df36e06dSRobert Mustacchi 	if (enable_mib_change)
960*df36e06dSRobert Mustacchi 		ret = i40e_aq_cfg_lldp_mib_change_event(hw, TRUE, NULL);
961*df36e06dSRobert Mustacchi 
962*df36e06dSRobert Mustacchi 	return ret;
963*df36e06dSRobert Mustacchi }
964*df36e06dSRobert Mustacchi 
965*df36e06dSRobert Mustacchi /**
966*df36e06dSRobert Mustacchi  * i40e_get_fw_lldp_status
967*df36e06dSRobert Mustacchi  * @hw: pointer to the hw struct
968*df36e06dSRobert Mustacchi  * @lldp_status: pointer to the status enum
969*df36e06dSRobert Mustacchi  *
970*df36e06dSRobert Mustacchi  * Get status of FW Link Layer Discovery Protocol (LLDP) Agent.
971*df36e06dSRobert Mustacchi  * Status of agent is reported via @lldp_status parameter.
972*df36e06dSRobert Mustacchi  **/
973*df36e06dSRobert Mustacchi enum i40e_status_code
i40e_get_fw_lldp_status(struct i40e_hw * hw,enum i40e_get_fw_lldp_status_resp * lldp_status)974*df36e06dSRobert Mustacchi i40e_get_fw_lldp_status(struct i40e_hw *hw,
975*df36e06dSRobert Mustacchi 			enum i40e_get_fw_lldp_status_resp *lldp_status)
976*df36e06dSRobert Mustacchi {
977*df36e06dSRobert Mustacchi 	enum i40e_status_code ret;
978*df36e06dSRobert Mustacchi 	struct i40e_virt_mem mem;
979*df36e06dSRobert Mustacchi 	u8 *lldpmib;
980*df36e06dSRobert Mustacchi 
981*df36e06dSRobert Mustacchi 	if (!lldp_status)
982*df36e06dSRobert Mustacchi 		return I40E_ERR_PARAM;
983*df36e06dSRobert Mustacchi 
984*df36e06dSRobert Mustacchi 	/* Allocate buffer for the LLDPDU */
985*df36e06dSRobert Mustacchi 	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
98693f1cac5SPaul Winder 	if (ret)
98793f1cac5SPaul Winder 		return ret;
98893f1cac5SPaul Winder 
989*df36e06dSRobert Mustacchi 	lldpmib = (u8 *)mem.va;
990*df36e06dSRobert Mustacchi 	ret = i40e_aq_get_lldp_mib(hw, 0, 0, (void *)lldpmib,
991*df36e06dSRobert Mustacchi 				   I40E_LLDPDU_SIZE, NULL, NULL, NULL);
992*df36e06dSRobert Mustacchi 
993*df36e06dSRobert Mustacchi 	if (ret == I40E_SUCCESS) {
994*df36e06dSRobert Mustacchi 		*lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
995*df36e06dSRobert Mustacchi 	} else if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) {
996*df36e06dSRobert Mustacchi 		/* MIB is not available yet but the agent is running */
997*df36e06dSRobert Mustacchi 		*lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
998*df36e06dSRobert Mustacchi 		ret = I40E_SUCCESS;
999*df36e06dSRobert Mustacchi 	} else if (hw->aq.asq_last_status == I40E_AQ_RC_EPERM) {
1000*df36e06dSRobert Mustacchi 		*lldp_status = I40E_GET_FW_LLDP_STATUS_DISABLED;
1001*df36e06dSRobert Mustacchi 		ret = I40E_SUCCESS;
1002*df36e06dSRobert Mustacchi 	}
1003*df36e06dSRobert Mustacchi 
1004*df36e06dSRobert Mustacchi 	i40e_free_virt_mem(hw, &mem);
100593f1cac5SPaul Winder 	return ret;
100693f1cac5SPaul Winder }
100793f1cac5SPaul Winder 
1008*df36e06dSRobert Mustacchi 
100993f1cac5SPaul Winder /**
101093f1cac5SPaul Winder  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
101193f1cac5SPaul Winder  * @tlv: Fill the ETS config data in IEEE format
101293f1cac5SPaul Winder  * @dcbcfg: Local store which holds the DCB Config
101393f1cac5SPaul Winder  *
101493f1cac5SPaul Winder  * Prepare IEEE 802.1Qaz ETS CFG TLV
101593f1cac5SPaul Winder  **/
i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)101693f1cac5SPaul Winder static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
101793f1cac5SPaul Winder 				  struct i40e_dcbx_config *dcbcfg)
101893f1cac5SPaul Winder {
101993f1cac5SPaul Winder 	u8 priority0, priority1, maxtcwilling = 0;
102093f1cac5SPaul Winder 	struct i40e_dcb_ets_config *etscfg;
102193f1cac5SPaul Winder 	u16 offset = 0, typelength, i;
102293f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
102393f1cac5SPaul Winder 	u32 ouisubtype;
102493f1cac5SPaul Winder 
102593f1cac5SPaul Winder 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
102693f1cac5SPaul Winder 			I40E_IEEE_ETS_TLV_LENGTH);
102793f1cac5SPaul Winder 	tlv->typelength = I40E_HTONS(typelength);
102893f1cac5SPaul Winder 
102993f1cac5SPaul Winder 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
103093f1cac5SPaul Winder 			I40E_IEEE_SUBTYPE_ETS_CFG);
103193f1cac5SPaul Winder 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
103293f1cac5SPaul Winder 
103393f1cac5SPaul Winder 	/* First Octet post subtype
103493f1cac5SPaul Winder 	 * --------------------------
103593f1cac5SPaul Winder 	 * |will-|CBS  | Re-  | Max |
103693f1cac5SPaul Winder 	 * |ing  |     |served| TCs |
103793f1cac5SPaul Winder 	 * --------------------------
103893f1cac5SPaul Winder 	 * |1bit | 1bit|3 bits|3bits|
103993f1cac5SPaul Winder 	 */
104093f1cac5SPaul Winder 	etscfg = &dcbcfg->etscfg;
104193f1cac5SPaul Winder 	if (etscfg->willing)
104293f1cac5SPaul Winder 		maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
104393f1cac5SPaul Winder 	maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
104493f1cac5SPaul Winder 	buf[offset] = maxtcwilling;
104593f1cac5SPaul Winder 
104693f1cac5SPaul Winder 	/* Move offset to Priority Assignment Table */
104793f1cac5SPaul Winder 	offset++;
104893f1cac5SPaul Winder 
104993f1cac5SPaul Winder 	/* Priority Assignment Table (4 octets)
105093f1cac5SPaul Winder 	 * Octets:|    1    |    2    |    3    |    4    |
105193f1cac5SPaul Winder 	 *        -----------------------------------------
105293f1cac5SPaul Winder 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
105393f1cac5SPaul Winder 	 *        -----------------------------------------
105493f1cac5SPaul Winder 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
105593f1cac5SPaul Winder 	 *        -----------------------------------------
105693f1cac5SPaul Winder 	 */
105793f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
105893f1cac5SPaul Winder 		priority0 = etscfg->prioritytable[i * 2] & 0xF;
105993f1cac5SPaul Winder 		priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
106093f1cac5SPaul Winder 		buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
106193f1cac5SPaul Winder 				priority1;
106293f1cac5SPaul Winder 		offset++;
106393f1cac5SPaul Winder 	}
106493f1cac5SPaul Winder 
106593f1cac5SPaul Winder 	/* TC Bandwidth Table (8 octets)
106693f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
106793f1cac5SPaul Winder 	 *        ---------------------------------
106893f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
106993f1cac5SPaul Winder 	 *        ---------------------------------
107093f1cac5SPaul Winder 	 */
107193f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
107293f1cac5SPaul Winder 		buf[offset++] = etscfg->tcbwtable[i];
107393f1cac5SPaul Winder 
107493f1cac5SPaul Winder 	/* TSA Assignment Table (8 octets)
107593f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
107693f1cac5SPaul Winder 	 *        ---------------------------------
107793f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
107893f1cac5SPaul Winder 	 *        ---------------------------------
107993f1cac5SPaul Winder 	 */
108093f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
108193f1cac5SPaul Winder 		buf[offset++] = etscfg->tsatable[i];
108293f1cac5SPaul Winder }
108393f1cac5SPaul Winder 
108493f1cac5SPaul Winder /**
108593f1cac5SPaul Winder  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
108693f1cac5SPaul Winder  * @tlv: Fill ETS Recommended TLV in IEEE format
108793f1cac5SPaul Winder  * @dcbcfg: Local store which holds the DCB Config
108893f1cac5SPaul Winder  *
108993f1cac5SPaul Winder  * Prepare IEEE 802.1Qaz ETS REC TLV
109093f1cac5SPaul Winder  **/
i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)109193f1cac5SPaul Winder static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
109293f1cac5SPaul Winder 				     struct i40e_dcbx_config *dcbcfg)
109393f1cac5SPaul Winder {
109493f1cac5SPaul Winder 	struct i40e_dcb_ets_config *etsrec;
109593f1cac5SPaul Winder 	u16 offset = 0, typelength, i;
109693f1cac5SPaul Winder 	u8 priority0, priority1;
109793f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
109893f1cac5SPaul Winder 	u32 ouisubtype;
109993f1cac5SPaul Winder 
110093f1cac5SPaul Winder 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
110193f1cac5SPaul Winder 			I40E_IEEE_ETS_TLV_LENGTH);
110293f1cac5SPaul Winder 	tlv->typelength = I40E_HTONS(typelength);
110393f1cac5SPaul Winder 
110493f1cac5SPaul Winder 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
110593f1cac5SPaul Winder 			I40E_IEEE_SUBTYPE_ETS_REC);
110693f1cac5SPaul Winder 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
110793f1cac5SPaul Winder 
110893f1cac5SPaul Winder 	etsrec = &dcbcfg->etsrec;
110993f1cac5SPaul Winder 	/* First Octet is reserved */
111093f1cac5SPaul Winder 	/* Move offset to Priority Assignment Table */
111193f1cac5SPaul Winder 	offset++;
111293f1cac5SPaul Winder 
111393f1cac5SPaul Winder 	/* Priority Assignment Table (4 octets)
111493f1cac5SPaul Winder 	 * Octets:|    1    |    2    |    3    |    4    |
111593f1cac5SPaul Winder 	 *        -----------------------------------------
111693f1cac5SPaul Winder 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
111793f1cac5SPaul Winder 	 *        -----------------------------------------
111893f1cac5SPaul Winder 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
111993f1cac5SPaul Winder 	 *        -----------------------------------------
112093f1cac5SPaul Winder 	 */
112193f1cac5SPaul Winder 	for (i = 0; i < 4; i++) {
112293f1cac5SPaul Winder 		priority0 = etsrec->prioritytable[i * 2] & 0xF;
112393f1cac5SPaul Winder 		priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
112493f1cac5SPaul Winder 		buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
112593f1cac5SPaul Winder 				priority1;
112693f1cac5SPaul Winder 		offset++;
112793f1cac5SPaul Winder 	}
112893f1cac5SPaul Winder 
112993f1cac5SPaul Winder 	/* TC Bandwidth Table (8 octets)
113093f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
113193f1cac5SPaul Winder 	 *        ---------------------------------
113293f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
113393f1cac5SPaul Winder 	 *        ---------------------------------
113493f1cac5SPaul Winder 	 */
113593f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
113693f1cac5SPaul Winder 		buf[offset++] = etsrec->tcbwtable[i];
113793f1cac5SPaul Winder 
113893f1cac5SPaul Winder 	/* TSA Assignment Table (8 octets)
113993f1cac5SPaul Winder 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
114093f1cac5SPaul Winder 	 *        ---------------------------------
114193f1cac5SPaul Winder 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
114293f1cac5SPaul Winder 	 *        ---------------------------------
114393f1cac5SPaul Winder 	 */
114493f1cac5SPaul Winder 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
114593f1cac5SPaul Winder 		buf[offset++] = etsrec->tsatable[i];
114693f1cac5SPaul Winder }
114793f1cac5SPaul Winder 
114893f1cac5SPaul Winder  /**
114993f1cac5SPaul Winder  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
115093f1cac5SPaul Winder  * @tlv: Fill PFC TLV in IEEE format
115193f1cac5SPaul Winder  * @dcbcfg: Local store to get PFC CFG data
115293f1cac5SPaul Winder  *
115393f1cac5SPaul Winder  * Prepare IEEE 802.1Qaz PFC CFG TLV
115493f1cac5SPaul Winder  **/
i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)115593f1cac5SPaul Winder static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
115693f1cac5SPaul Winder 				  struct i40e_dcbx_config *dcbcfg)
115793f1cac5SPaul Winder {
115893f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
115993f1cac5SPaul Winder 	u32 ouisubtype;
116093f1cac5SPaul Winder 	u16 typelength;
116193f1cac5SPaul Winder 
116293f1cac5SPaul Winder 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
116393f1cac5SPaul Winder 			I40E_IEEE_PFC_TLV_LENGTH);
116493f1cac5SPaul Winder 	tlv->typelength = I40E_HTONS(typelength);
116593f1cac5SPaul Winder 
116693f1cac5SPaul Winder 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
116793f1cac5SPaul Winder 			I40E_IEEE_SUBTYPE_PFC_CFG);
116893f1cac5SPaul Winder 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
116993f1cac5SPaul Winder 
117093f1cac5SPaul Winder 	/* ----------------------------------------
117193f1cac5SPaul Winder 	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
117293f1cac5SPaul Winder 	 * |ing  |     |served| cap |              |
117393f1cac5SPaul Winder 	 * -----------------------------------------
117493f1cac5SPaul Winder 	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
117593f1cac5SPaul Winder 	 */
117693f1cac5SPaul Winder 	if (dcbcfg->pfc.willing)
117793f1cac5SPaul Winder 		buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
117893f1cac5SPaul Winder 
117993f1cac5SPaul Winder 	if (dcbcfg->pfc.mbc)
118093f1cac5SPaul Winder 		buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
118193f1cac5SPaul Winder 
118293f1cac5SPaul Winder 	buf[0] |= dcbcfg->pfc.pfccap & 0xF;
118393f1cac5SPaul Winder 	buf[1] = dcbcfg->pfc.pfcenable;
118493f1cac5SPaul Winder }
118593f1cac5SPaul Winder 
118693f1cac5SPaul Winder /**
118793f1cac5SPaul Winder  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
118893f1cac5SPaul Winder  * @tlv: Fill APP TLV in IEEE format
118993f1cac5SPaul Winder  * @dcbcfg: Local store to get APP CFG data
119093f1cac5SPaul Winder  *
119193f1cac5SPaul Winder  * Prepare IEEE 802.1Qaz APP CFG TLV
119293f1cac5SPaul Winder  **/
i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)119393f1cac5SPaul Winder static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
119493f1cac5SPaul Winder 				      struct i40e_dcbx_config *dcbcfg)
119593f1cac5SPaul Winder {
119693f1cac5SPaul Winder 	u16 typelength, length, offset = 0;
119793f1cac5SPaul Winder 	u8 priority, selector, i = 0;
119893f1cac5SPaul Winder 	u8 *buf = tlv->tlvinfo;
119993f1cac5SPaul Winder 	u32 ouisubtype;
120093f1cac5SPaul Winder 
120193f1cac5SPaul Winder 	/* No APP TLVs then just return */
120293f1cac5SPaul Winder 	if (dcbcfg->numapps == 0)
120393f1cac5SPaul Winder 		return;
120493f1cac5SPaul Winder 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
120593f1cac5SPaul Winder 			I40E_IEEE_SUBTYPE_APP_PRI);
120693f1cac5SPaul Winder 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
120793f1cac5SPaul Winder 
120893f1cac5SPaul Winder 	/* Move offset to App Priority Table */
120993f1cac5SPaul Winder 	offset++;
121093f1cac5SPaul Winder 	/* Application Priority Table (3 octets)
121193f1cac5SPaul Winder 	 * Octets:|         1          |    2    |    3    |
121293f1cac5SPaul Winder 	 *        -----------------------------------------
121393f1cac5SPaul Winder 	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
121493f1cac5SPaul Winder 	 *        -----------------------------------------
121593f1cac5SPaul Winder 	 *   Bits:|23    21|20 19|18 16|15                0|
121693f1cac5SPaul Winder 	 *        -----------------------------------------
121793f1cac5SPaul Winder 	 */
121893f1cac5SPaul Winder 	while (i < dcbcfg->numapps) {
121993f1cac5SPaul Winder 		priority = dcbcfg->app[i].priority & 0x7;
122093f1cac5SPaul Winder 		selector = dcbcfg->app[i].selector & 0x7;
122193f1cac5SPaul Winder 		buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
122293f1cac5SPaul Winder 		buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
122393f1cac5SPaul Winder 		buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
122493f1cac5SPaul Winder 		/* Move to next app */
122593f1cac5SPaul Winder 		offset += 3;
122693f1cac5SPaul Winder 		i++;
122793f1cac5SPaul Winder 		if (i >= I40E_DCBX_MAX_APPS)
122893f1cac5SPaul Winder 			break;
122993f1cac5SPaul Winder 	}
123093f1cac5SPaul Winder 	/* length includes size of ouisubtype + 1 reserved + 3*numapps */
123193f1cac5SPaul Winder 	length = sizeof(tlv->ouisubtype) + 1 + (i*3);
123293f1cac5SPaul Winder 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
123393f1cac5SPaul Winder 		(length & 0x1FF));
123493f1cac5SPaul Winder 	tlv->typelength = I40E_HTONS(typelength);
123593f1cac5SPaul Winder }
123693f1cac5SPaul Winder 
123793f1cac5SPaul Winder  /**
123893f1cac5SPaul Winder  * i40e_add_dcb_tlv - Add all IEEE TLVs
123993f1cac5SPaul Winder  * @tlv: pointer to org tlv
124093f1cac5SPaul Winder  *
124193f1cac5SPaul Winder  * add tlv information
124293f1cac5SPaul Winder  **/
i40e_add_dcb_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg,u16 tlvid)124393f1cac5SPaul Winder static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
124493f1cac5SPaul Winder 			     struct i40e_dcbx_config *dcbcfg,
124593f1cac5SPaul Winder 			     u16 tlvid)
124693f1cac5SPaul Winder {
124793f1cac5SPaul Winder 	switch (tlvid) {
124893f1cac5SPaul Winder 	case I40E_IEEE_TLV_ID_ETS_CFG:
124993f1cac5SPaul Winder 		i40e_add_ieee_ets_tlv(tlv, dcbcfg);
125093f1cac5SPaul Winder 		break;
125193f1cac5SPaul Winder 	case I40E_IEEE_TLV_ID_ETS_REC:
125293f1cac5SPaul Winder 		i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
125393f1cac5SPaul Winder 		break;
125493f1cac5SPaul Winder 	case I40E_IEEE_TLV_ID_PFC_CFG:
125593f1cac5SPaul Winder 		i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
125693f1cac5SPaul Winder 		break;
125793f1cac5SPaul Winder 	case I40E_IEEE_TLV_ID_APP_PRI:
125893f1cac5SPaul Winder 		i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
125993f1cac5SPaul Winder 		break;
126093f1cac5SPaul Winder 	default:
126193f1cac5SPaul Winder 		break;
126293f1cac5SPaul Winder 	}
126393f1cac5SPaul Winder }
126493f1cac5SPaul Winder 
126593f1cac5SPaul Winder  /**
126693f1cac5SPaul Winder  * i40e_set_dcb_config - Set the local LLDP MIB to FW
126793f1cac5SPaul Winder  * @hw: pointer to the hw struct
126893f1cac5SPaul Winder  *
126993f1cac5SPaul Winder  * Set DCB configuration to the Firmware
127093f1cac5SPaul Winder  **/
i40e_set_dcb_config(struct i40e_hw * hw)127193f1cac5SPaul Winder enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
127293f1cac5SPaul Winder {
127393f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
127493f1cac5SPaul Winder 	struct i40e_dcbx_config *dcbcfg;
127593f1cac5SPaul Winder 	struct i40e_virt_mem mem;
127693f1cac5SPaul Winder 	u8 mib_type, *lldpmib;
127793f1cac5SPaul Winder 	u16 miblen;
127893f1cac5SPaul Winder 
127993f1cac5SPaul Winder 	/* update the hw local config */
128093f1cac5SPaul Winder 	dcbcfg = &hw->local_dcbx_config;
128193f1cac5SPaul Winder 	/* Allocate the LLDPDU */
128293f1cac5SPaul Winder 	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
128393f1cac5SPaul Winder 	if (ret)
128493f1cac5SPaul Winder 		return ret;
128593f1cac5SPaul Winder 
128693f1cac5SPaul Winder 	mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
128793f1cac5SPaul Winder 	if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
128893f1cac5SPaul Winder 		mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
128993f1cac5SPaul Winder 			    SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
129093f1cac5SPaul Winder 	}
129193f1cac5SPaul Winder 	lldpmib = (u8 *)mem.va;
129293f1cac5SPaul Winder 	ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
129393f1cac5SPaul Winder 	ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
129493f1cac5SPaul Winder 
129593f1cac5SPaul Winder 	i40e_free_virt_mem(hw, &mem);
129693f1cac5SPaul Winder 	return ret;
129793f1cac5SPaul Winder }
129893f1cac5SPaul Winder 
129993f1cac5SPaul Winder /**
130093f1cac5SPaul Winder  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1301*df36e06dSRobert Mustacchi  * @lldpmib: pointer to mib to be output
1302*df36e06dSRobert Mustacchi  * @miblen: pointer to u16 for length of lldpmib
130393f1cac5SPaul Winder  * @dcbcfg: store for LLDPDU data
130493f1cac5SPaul Winder  *
130593f1cac5SPaul Winder  * send DCB configuration to FW
130693f1cac5SPaul Winder  **/
i40e_dcb_config_to_lldp(u8 * lldpmib,u16 * miblen,struct i40e_dcbx_config * dcbcfg)130793f1cac5SPaul Winder enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
130893f1cac5SPaul Winder 					      struct i40e_dcbx_config *dcbcfg)
130993f1cac5SPaul Winder {
131093f1cac5SPaul Winder 	u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
131193f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
131293f1cac5SPaul Winder 	struct i40e_lldp_org_tlv *tlv;
131393f1cac5SPaul Winder 	u16 typelength;
131493f1cac5SPaul Winder 
131593f1cac5SPaul Winder 	tlv = (struct i40e_lldp_org_tlv *)lldpmib;
131693f1cac5SPaul Winder 	while (1) {
131793f1cac5SPaul Winder 		i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
131893f1cac5SPaul Winder 		typelength = I40E_NTOHS(tlv->typelength);
131993f1cac5SPaul Winder 		length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
132093f1cac5SPaul Winder 				I40E_LLDP_TLV_LEN_SHIFT);
132193f1cac5SPaul Winder 		if (length)
132293f1cac5SPaul Winder 			offset += length + 2;
132393f1cac5SPaul Winder 		/* END TLV or beyond LLDPDU size */
132493f1cac5SPaul Winder 		if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
132593f1cac5SPaul Winder 		    (offset > I40E_LLDPDU_SIZE))
132693f1cac5SPaul Winder 			break;
132793f1cac5SPaul Winder 		/* Move to next TLV */
132893f1cac5SPaul Winder 		if (length)
132993f1cac5SPaul Winder 			tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
133093f1cac5SPaul Winder 			      sizeof(tlv->typelength) + length);
133193f1cac5SPaul Winder 	}
133293f1cac5SPaul Winder 	*miblen = offset;
133393f1cac5SPaul Winder 	return ret;
133493f1cac5SPaul Winder }
133593f1cac5SPaul Winder 
133693f1cac5SPaul Winder 
133793f1cac5SPaul Winder /**
133893f1cac5SPaul Winder  * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM
133993f1cac5SPaul Winder  * @hw: pointer to the HW structure
134093f1cac5SPaul Winder  * @lldp_cfg: pointer to hold lldp configuration variables
134193f1cac5SPaul Winder  * @module: address of the module pointer
134293f1cac5SPaul Winder  * @word_offset: offset of LLDP configuration
134393f1cac5SPaul Winder  *
134493f1cac5SPaul Winder  * Reads the LLDP configuration data from NVM using passed addresses
134593f1cac5SPaul Winder  **/
_i40e_read_lldp_cfg(struct i40e_hw * hw,struct i40e_lldp_variables * lldp_cfg,u8 module,u32 word_offset)134693f1cac5SPaul Winder static enum i40e_status_code _i40e_read_lldp_cfg(struct i40e_hw *hw,
134793f1cac5SPaul Winder 					  struct i40e_lldp_variables *lldp_cfg,
134893f1cac5SPaul Winder 					  u8 module, u32 word_offset)
134993f1cac5SPaul Winder {
135093f1cac5SPaul Winder 	u32 address, offset = (2 * word_offset);
135193f1cac5SPaul Winder 	enum i40e_status_code ret;
135293f1cac5SPaul Winder 	__le16 raw_mem;
135393f1cac5SPaul Winder 	u16 mem;
135493f1cac5SPaul Winder 
135593f1cac5SPaul Winder 	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
135693f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
135793f1cac5SPaul Winder 		return ret;
135893f1cac5SPaul Winder 
135993f1cac5SPaul Winder 	ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem,
136093f1cac5SPaul Winder 			       TRUE, NULL);
136193f1cac5SPaul Winder 	i40e_release_nvm(hw);
136293f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
136393f1cac5SPaul Winder 		return ret;
136493f1cac5SPaul Winder 
136593f1cac5SPaul Winder 	mem = LE16_TO_CPU(raw_mem);
136693f1cac5SPaul Winder 	/* Check if this pointer needs to be read in word size or 4K sector
136793f1cac5SPaul Winder 	 * units.
136893f1cac5SPaul Winder 	 */
136993f1cac5SPaul Winder 	if (mem & I40E_PTR_TYPE)
137093f1cac5SPaul Winder 		address = (0x7FFF & mem) * 4096;
137193f1cac5SPaul Winder 	else
137293f1cac5SPaul Winder 		address = (0x7FFF & mem) * 2;
137393f1cac5SPaul Winder 
137493f1cac5SPaul Winder 	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
137593f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
137693f1cac5SPaul Winder 		goto err_lldp_cfg;
137793f1cac5SPaul Winder 
137893f1cac5SPaul Winder 	ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem,
137993f1cac5SPaul Winder 			       TRUE, NULL);
138093f1cac5SPaul Winder 	i40e_release_nvm(hw);
138193f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
138293f1cac5SPaul Winder 		return ret;
138393f1cac5SPaul Winder 
138493f1cac5SPaul Winder 	mem = LE16_TO_CPU(raw_mem);
138593f1cac5SPaul Winder 	offset = mem + word_offset;
138693f1cac5SPaul Winder 	offset *= 2;
138793f1cac5SPaul Winder 
138893f1cac5SPaul Winder 	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
138993f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
139093f1cac5SPaul Winder 		goto err_lldp_cfg;
139193f1cac5SPaul Winder 
139293f1cac5SPaul Winder 	ret = i40e_aq_read_nvm(hw, 0, address + offset,
139393f1cac5SPaul Winder 			       sizeof(struct i40e_lldp_variables), lldp_cfg,
139493f1cac5SPaul Winder 			       TRUE, NULL);
139593f1cac5SPaul Winder 	i40e_release_nvm(hw);
139693f1cac5SPaul Winder 
139793f1cac5SPaul Winder err_lldp_cfg:
139893f1cac5SPaul Winder 	return ret;
139993f1cac5SPaul Winder }
140093f1cac5SPaul Winder 
140193f1cac5SPaul Winder /**
140293f1cac5SPaul Winder  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
140393f1cac5SPaul Winder  * @hw: pointer to the HW structure
140493f1cac5SPaul Winder  * @lldp_cfg: pointer to hold lldp configuration variables
140593f1cac5SPaul Winder  *
140693f1cac5SPaul Winder  * Reads the LLDP configuration data from NVM
140793f1cac5SPaul Winder  **/
i40e_read_lldp_cfg(struct i40e_hw * hw,struct i40e_lldp_variables * lldp_cfg)140893f1cac5SPaul Winder enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
140993f1cac5SPaul Winder 					 struct i40e_lldp_variables *lldp_cfg)
141093f1cac5SPaul Winder {
141193f1cac5SPaul Winder 	enum i40e_status_code ret = I40E_SUCCESS;
141293f1cac5SPaul Winder 	u32 mem;
141393f1cac5SPaul Winder 
141493f1cac5SPaul Winder 	if (!lldp_cfg)
141593f1cac5SPaul Winder 		return I40E_ERR_PARAM;
141693f1cac5SPaul Winder 
141793f1cac5SPaul Winder 	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
141893f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
141993f1cac5SPaul Winder 		return ret;
142093f1cac5SPaul Winder 
142193f1cac5SPaul Winder 	ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem),
142293f1cac5SPaul Winder 			       &mem, TRUE, NULL);
142393f1cac5SPaul Winder 	i40e_release_nvm(hw);
142493f1cac5SPaul Winder 	if (ret != I40E_SUCCESS)
142593f1cac5SPaul Winder 		return ret;
142693f1cac5SPaul Winder 
142793f1cac5SPaul Winder 	/* Read a bit that holds information whether we are running flat or
142893f1cac5SPaul Winder 	 * structured NVM image. Flat image has LLDP configuration in shadow
142993f1cac5SPaul Winder 	 * ram, so there is a need to pass different addresses for both cases.
143093f1cac5SPaul Winder 	 */
143193f1cac5SPaul Winder 	if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) {
143293f1cac5SPaul Winder 		/* Flat NVM case */
143393f1cac5SPaul Winder 		ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR,
143493f1cac5SPaul Winder 					  I40E_SR_LLDP_CFG_PTR);
143593f1cac5SPaul Winder 	} else {
143693f1cac5SPaul Winder 		/* Good old structured NVM image */
143793f1cac5SPaul Winder 		ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR,
143893f1cac5SPaul Winder 					  I40E_NVM_LLDP_CFG_PTR);
143993f1cac5SPaul Winder 	}
144093f1cac5SPaul Winder 
144193f1cac5SPaul Winder 	return ret;
144293f1cac5SPaul Winder }
1443