162306a36Sopenharmony_ci/* bnx2x_dcb.c: QLogic Everest network driver. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright 2009-2013 Broadcom Corporation 462306a36Sopenharmony_ci * Copyright 2014 QLogic Corporation 562306a36Sopenharmony_ci * All rights reserved 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Unless you and QLogic execute a separate written software license 862306a36Sopenharmony_ci * agreement governing use of this software, this software is licensed to you 962306a36Sopenharmony_ci * under the terms of the GNU General Public License version 2, available 1062306a36Sopenharmony_ci * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Notwithstanding the above, under no circumstances may you combine this 1362306a36Sopenharmony_ci * software in any way with any other QLogic software provided under a 1462306a36Sopenharmony_ci * license other than the GPL, without QLogic's express prior written 1562306a36Sopenharmony_ci * consent. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com> 1862306a36Sopenharmony_ci * Written by: Dmitry Kravkov 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/netdevice.h> 2562306a36Sopenharmony_ci#include <linux/types.h> 2662306a36Sopenharmony_ci#include <linux/errno.h> 2762306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2862306a36Sopenharmony_ci#include <net/dcbnl.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "bnx2x.h" 3162306a36Sopenharmony_ci#include "bnx2x_cmn.h" 3262306a36Sopenharmony_ci#include "bnx2x_dcb.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* forward declarations of dcbx related functions */ 3562306a36Sopenharmony_cistatic void bnx2x_pfc_set_pfc(struct bnx2x *bp); 3662306a36Sopenharmony_cistatic void bnx2x_dcbx_update_ets_params(struct bnx2x *bp); 3762306a36Sopenharmony_cistatic void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, 3862306a36Sopenharmony_ci u32 *set_configuration_ets_pg, 3962306a36Sopenharmony_ci u32 *pri_pg_tbl); 4062306a36Sopenharmony_cistatic void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, 4162306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 4262306a36Sopenharmony_ci struct pg_help_data *help_data); 4362306a36Sopenharmony_cistatic void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, 4462306a36Sopenharmony_ci struct pg_help_data *help_data, 4562306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 4662306a36Sopenharmony_ci u32 *pg_pri_orginal_spread); 4762306a36Sopenharmony_cistatic void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, 4862306a36Sopenharmony_ci struct cos_help_data *cos_data, 4962306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 5062306a36Sopenharmony_ci struct dcbx_ets_feature *ets); 5162306a36Sopenharmony_cistatic void bnx2x_dcbx_fw_struct(struct bnx2x *bp, 5262306a36Sopenharmony_ci struct bnx2x_func_tx_start_params*); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */ 5562306a36Sopenharmony_cistatic void bnx2x_read_data(struct bnx2x *bp, u32 *buff, 5662306a36Sopenharmony_ci u32 addr, u32 len) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci int i; 5962306a36Sopenharmony_ci for (i = 0; i < len; i += 4, buff++) 6062306a36Sopenharmony_ci *buff = REG_RD(bp, addr + i); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void bnx2x_write_data(struct bnx2x *bp, u32 *buff, 6462306a36Sopenharmony_ci u32 addr, u32 len) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci int i; 6762306a36Sopenharmony_ci for (i = 0; i < len; i += 4, buff++) 6862306a36Sopenharmony_ci REG_WR(bp, addr + i, *buff); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void bnx2x_pfc_set(struct bnx2x *bp) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct bnx2x_nig_brb_pfc_port_params pfc_params = {0}; 7462306a36Sopenharmony_ci u32 pri_bit, val = 0; 7562306a36Sopenharmony_ci int i; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci pfc_params.num_of_rx_cos_priority_mask = 7862306a36Sopenharmony_ci bp->dcbx_port_params.ets.num_of_cos; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Tx COS configuration */ 8162306a36Sopenharmony_ci for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++) 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * We configure only the pauseable bits (non pauseable aren't 8462306a36Sopenharmony_ci * configured at all) it's done to avoid false pauses from 8562306a36Sopenharmony_ci * network 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci pfc_params.rx_cos_priority_mask[i] = 8862306a36Sopenharmony_ci bp->dcbx_port_params.ets.cos_params[i].pri_bitmask 8962306a36Sopenharmony_ci & DCBX_PFC_PRI_PAUSE_MASK(bp); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Rx COS configuration 9362306a36Sopenharmony_ci * Changing PFC RX configuration . 9462306a36Sopenharmony_ci * In RX COS0 will always be configured to lossless and COS1 to lossy 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) { 9762306a36Sopenharmony_ci pri_bit = 1 << i; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!(pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp))) 10062306a36Sopenharmony_ci val |= 1 << (i * 4); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci pfc_params.pkt_priority_to_cos = val; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* RX COS0 */ 10662306a36Sopenharmony_ci pfc_params.llfc_low_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp); 10762306a36Sopenharmony_ci /* RX COS1 */ 10862306a36Sopenharmony_ci pfc_params.llfc_high_priority_classes = 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 11162306a36Sopenharmony_ci bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED; 11262306a36Sopenharmony_ci bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params); 11362306a36Sopenharmony_ci bnx2x_release_phy_lock(bp); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void bnx2x_pfc_clear(struct bnx2x *bp) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct bnx2x_nig_brb_pfc_port_params nig_params = {0}; 11962306a36Sopenharmony_ci nig_params.pause_enable = 1; 12062306a36Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 12162306a36Sopenharmony_ci bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED; 12262306a36Sopenharmony_ci bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params); 12362306a36Sopenharmony_ci bnx2x_release_phy_lock(bp); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp, 12762306a36Sopenharmony_ci struct dcbx_features *features, 12862306a36Sopenharmony_ci u32 error) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci u8 i = 0; 13162306a36Sopenharmony_ci DP(NETIF_MSG_LINK, "local_mib.error %x\n", error); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* PG */ 13462306a36Sopenharmony_ci DP(NETIF_MSG_LINK, 13562306a36Sopenharmony_ci "local_mib.features.ets.enabled %x\n", features->ets.enabled); 13662306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) 13762306a36Sopenharmony_ci DP(NETIF_MSG_LINK, 13862306a36Sopenharmony_ci "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i, 13962306a36Sopenharmony_ci DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i)); 14062306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) 14162306a36Sopenharmony_ci DP(NETIF_MSG_LINK, 14262306a36Sopenharmony_ci "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i, 14362306a36Sopenharmony_ci DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* pfc */ 14662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pri_en_bitmap %x\n", 14762306a36Sopenharmony_ci features->pfc.pri_en_bitmap); 14862306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.pfc.pfc_caps %x\n", 14962306a36Sopenharmony_ci features->pfc.pfc_caps); 15062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.pfc.enabled %x\n", 15162306a36Sopenharmony_ci features->pfc.enabled); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.app.default_pri %x\n", 15462306a36Sopenharmony_ci features->app.default_pri); 15562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.app.tc_supported %x\n", 15662306a36Sopenharmony_ci features->app.tc_supported); 15762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_features.app.enabled %x\n", 15862306a36Sopenharmony_ci features->app.enabled); 15962306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { 16062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 16162306a36Sopenharmony_ci "dcbx_features.app.app_pri_tbl[%x].app_id %x\n", 16262306a36Sopenharmony_ci i, features->app.app_pri_tbl[i].app_id); 16362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 16462306a36Sopenharmony_ci "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n", 16562306a36Sopenharmony_ci i, features->app.app_pri_tbl[i].pri_bitmap); 16662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 16762306a36Sopenharmony_ci "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n", 16862306a36Sopenharmony_ci i, features->app.app_pri_tbl[i].appBitfield); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp, 17362306a36Sopenharmony_ci u8 pri_bitmap, 17462306a36Sopenharmony_ci u8 llfc_traf_type) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci u32 pri = MAX_PFC_PRIORITIES; 17762306a36Sopenharmony_ci u32 index = MAX_PFC_PRIORITIES - 1; 17862306a36Sopenharmony_ci u32 pri_mask; 17962306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Choose the highest priority */ 18262306a36Sopenharmony_ci while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) { 18362306a36Sopenharmony_ci pri_mask = 1 << index; 18462306a36Sopenharmony_ci if (GET_FLAGS(pri_bitmap, pri_mask)) 18562306a36Sopenharmony_ci pri = index ; 18662306a36Sopenharmony_ci index--; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (pri < MAX_PFC_PRIORITIES) 19062306a36Sopenharmony_ci ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp, 19462306a36Sopenharmony_ci struct dcbx_app_priority_feature *app, 19562306a36Sopenharmony_ci u32 error) { 19662306a36Sopenharmony_ci u8 index; 19762306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 19862306a36Sopenharmony_ci u8 iscsi_pri_found = 0, fcoe_pri_found = 0; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) 20162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_ERROR\n"); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_LOCAL_APP_MISMATCH)) 20462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_MISMATCH\n"); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_REMOTE_APP_TLV_NOT_FOUND)) 20762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_REMOTE_APP_TLV_NOT_FOUND\n"); 20862306a36Sopenharmony_ci if (app->enabled && 20962306a36Sopenharmony_ci !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR | DCBX_LOCAL_APP_MISMATCH | 21062306a36Sopenharmony_ci DCBX_REMOTE_APP_TLV_NOT_FOUND)) { 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci bp->dcbx_port_params.app.enabled = true; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Use 0 as the default application priority for all. */ 21562306a36Sopenharmony_ci for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) 21662306a36Sopenharmony_ci ttp[index] = 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) { 21962306a36Sopenharmony_ci struct dcbx_app_priority_entry *entry = 22062306a36Sopenharmony_ci app->app_pri_tbl; 22162306a36Sopenharmony_ci enum traffic_type type = MAX_TRAFFIC_TYPE; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (GET_FLAGS(entry[index].appBitfield, 22462306a36Sopenharmony_ci DCBX_APP_SF_DEFAULT) && 22562306a36Sopenharmony_ci GET_FLAGS(entry[index].appBitfield, 22662306a36Sopenharmony_ci DCBX_APP_SF_ETH_TYPE)) { 22762306a36Sopenharmony_ci type = LLFC_TRAFFIC_TYPE_NW; 22862306a36Sopenharmony_ci } else if (GET_FLAGS(entry[index].appBitfield, 22962306a36Sopenharmony_ci DCBX_APP_SF_PORT) && 23062306a36Sopenharmony_ci TCP_PORT_ISCSI == entry[index].app_id) { 23162306a36Sopenharmony_ci type = LLFC_TRAFFIC_TYPE_ISCSI; 23262306a36Sopenharmony_ci iscsi_pri_found = 1; 23362306a36Sopenharmony_ci } else if (GET_FLAGS(entry[index].appBitfield, 23462306a36Sopenharmony_ci DCBX_APP_SF_ETH_TYPE) && 23562306a36Sopenharmony_ci ETH_TYPE_FCOE == entry[index].app_id) { 23662306a36Sopenharmony_ci type = LLFC_TRAFFIC_TYPE_FCOE; 23762306a36Sopenharmony_ci fcoe_pri_found = 1; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (type == MAX_TRAFFIC_TYPE) 24162306a36Sopenharmony_ci continue; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci bnx2x_dcbx_get_ap_priority(bp, 24462306a36Sopenharmony_ci entry[index].pri_bitmap, 24562306a36Sopenharmony_ci type); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* If we have received a non-zero default application 24962306a36Sopenharmony_ci * priority, then use that for applications which are 25062306a36Sopenharmony_ci * not configured with any priority. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci if (ttp[LLFC_TRAFFIC_TYPE_NW] != 0) { 25362306a36Sopenharmony_ci if (!iscsi_pri_found) { 25462306a36Sopenharmony_ci ttp[LLFC_TRAFFIC_TYPE_ISCSI] = 25562306a36Sopenharmony_ci ttp[LLFC_TRAFFIC_TYPE_NW]; 25662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 25762306a36Sopenharmony_ci "ISCSI is using default priority.\n"); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci if (!fcoe_pri_found) { 26062306a36Sopenharmony_ci ttp[LLFC_TRAFFIC_TYPE_FCOE] = 26162306a36Sopenharmony_ci ttp[LLFC_TRAFFIC_TYPE_NW]; 26262306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 26362306a36Sopenharmony_ci "FCoE is using default priority.\n"); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_DISABLED\n"); 26862306a36Sopenharmony_ci bp->dcbx_port_params.app.enabled = false; 26962306a36Sopenharmony_ci for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) 27062306a36Sopenharmony_ci ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp, 27562306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 27662306a36Sopenharmony_ci u32 error) { 27762306a36Sopenharmony_ci int i = 0; 27862306a36Sopenharmony_ci u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0}; 27962306a36Sopenharmony_ci struct pg_help_data pg_help_data; 28062306a36Sopenharmony_ci struct bnx2x_dcbx_cos_params *cos_params = 28162306a36Sopenharmony_ci bp->dcbx_port_params.ets.cos_params; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci memset(&pg_help_data, 0, sizeof(struct pg_help_data)); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR)) 28662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ERROR\n"); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_REMOTE_ETS_TLV_NOT_FOUND)) 28962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_REMOTE_ETS_TLV_NOT_FOUND\n"); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Clean up old settings of ets on COS */ 29262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) { 29362306a36Sopenharmony_ci cos_params[i].pauseable = false; 29462306a36Sopenharmony_ci cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID; 29562306a36Sopenharmony_ci cos_params[i].bw_tbl = DCBX_INVALID_COS_BW; 29662306a36Sopenharmony_ci cos_params[i].pri_bitmask = 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (bp->dcbx_port_params.app.enabled && ets->enabled && 30062306a36Sopenharmony_ci !GET_FLAGS(error, 30162306a36Sopenharmony_ci DCBX_LOCAL_ETS_ERROR | DCBX_REMOTE_ETS_TLV_NOT_FOUND)) { 30262306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ENABLE\n"); 30362306a36Sopenharmony_ci bp->dcbx_port_params.ets.enabled = true; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci bnx2x_dcbx_get_ets_pri_pg_tbl(bp, 30662306a36Sopenharmony_ci pg_pri_orginal_spread, 30762306a36Sopenharmony_ci ets->pri_pg_tbl); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci bnx2x_dcbx_get_num_pg_traf_type(bp, 31062306a36Sopenharmony_ci pg_pri_orginal_spread, 31162306a36Sopenharmony_ci &pg_help_data); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci bnx2x_dcbx_fill_cos_params(bp, &pg_help_data, 31462306a36Sopenharmony_ci ets, pg_pri_orginal_spread); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci } else { 31762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_DISABLED\n"); 31862306a36Sopenharmony_ci bp->dcbx_port_params.ets.enabled = false; 31962306a36Sopenharmony_ci ets->pri_pg_tbl[0] = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++) 32262306a36Sopenharmony_ci DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp, 32762306a36Sopenharmony_ci struct dcbx_pfc_feature *pfc, u32 error) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR)) 33062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_ERROR\n"); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (GET_FLAGS(error, DCBX_REMOTE_PFC_TLV_NOT_FOUND)) 33362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_REMOTE_PFC_TLV_NOT_FOUND\n"); 33462306a36Sopenharmony_ci if (bp->dcbx_port_params.app.enabled && pfc->enabled && 33562306a36Sopenharmony_ci !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR | DCBX_LOCAL_PFC_MISMATCH | 33662306a36Sopenharmony_ci DCBX_REMOTE_PFC_TLV_NOT_FOUND)) { 33762306a36Sopenharmony_ci bp->dcbx_port_params.pfc.enabled = true; 33862306a36Sopenharmony_ci bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 33962306a36Sopenharmony_ci ~(pfc->pri_en_bitmap); 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_DISABLED\n"); 34262306a36Sopenharmony_ci bp->dcbx_port_params.pfc.enabled = false; 34362306a36Sopenharmony_ci bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* maps unmapped priorities to to the same COS as L2 */ 34862306a36Sopenharmony_cistatic void bnx2x_dcbx_map_nw(struct bnx2x *bp) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int i; 35162306a36Sopenharmony_ci u32 unmapped = (1 << MAX_PFC_PRIORITIES) - 1; /* all ones */ 35262306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 35362306a36Sopenharmony_ci u32 nw_prio = 1 << ttp[LLFC_TRAFFIC_TYPE_NW]; 35462306a36Sopenharmony_ci struct bnx2x_dcbx_cos_params *cos_params = 35562306a36Sopenharmony_ci bp->dcbx_port_params.ets.cos_params; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* get unmapped priorities by clearing mapped bits */ 35862306a36Sopenharmony_ci for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) 35962306a36Sopenharmony_ci unmapped &= ~(1 << ttp[i]); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* find cos for nw prio and extend it with unmapped */ 36262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params); i++) { 36362306a36Sopenharmony_ci if (cos_params[i].pri_bitmask & nw_prio) { 36462306a36Sopenharmony_ci /* extend the bitmask with unmapped */ 36562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 36662306a36Sopenharmony_ci "cos %d extended with 0x%08x\n", i, unmapped); 36762306a36Sopenharmony_ci cos_params[i].pri_bitmask |= unmapped; 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void bnx2x_get_dcbx_drv_param(struct bnx2x *bp, 37462306a36Sopenharmony_ci struct dcbx_features *features, 37562306a36Sopenharmony_ci u32 error) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci bnx2x_dcbx_get_ap_feature(bp, &features->app, error); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci bnx2x_dcbx_get_ets_feature(bp, &features->ets, error); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci bnx2x_dcbx_map_nw(bp); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci#define DCBX_LOCAL_MIB_MAX_TRY_READ (100) 38762306a36Sopenharmony_cistatic int bnx2x_dcbx_read_mib(struct bnx2x *bp, 38862306a36Sopenharmony_ci u32 *base_mib_addr, 38962306a36Sopenharmony_ci u32 offset, 39062306a36Sopenharmony_ci int read_mib_type) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int max_try_read = 0; 39362306a36Sopenharmony_ci u32 mib_size, prefix_seq_num, suffix_seq_num; 39462306a36Sopenharmony_ci struct lldp_remote_mib *remote_mib ; 39562306a36Sopenharmony_ci struct lldp_local_mib *local_mib; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci switch (read_mib_type) { 39862306a36Sopenharmony_ci case DCBX_READ_LOCAL_MIB: 39962306a36Sopenharmony_ci mib_size = sizeof(struct lldp_local_mib); 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci case DCBX_READ_REMOTE_MIB: 40262306a36Sopenharmony_ci mib_size = sizeof(struct lldp_remote_mib); 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci default: 40562306a36Sopenharmony_ci return 1; /*error*/ 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci offset += BP_PORT(bp) * mib_size; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci do { 41162306a36Sopenharmony_ci bnx2x_read_data(bp, base_mib_addr, offset, mib_size); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci max_try_read++; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci switch (read_mib_type) { 41662306a36Sopenharmony_ci case DCBX_READ_LOCAL_MIB: 41762306a36Sopenharmony_ci local_mib = (struct lldp_local_mib *) base_mib_addr; 41862306a36Sopenharmony_ci prefix_seq_num = local_mib->prefix_seq_num; 41962306a36Sopenharmony_ci suffix_seq_num = local_mib->suffix_seq_num; 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case DCBX_READ_REMOTE_MIB: 42262306a36Sopenharmony_ci remote_mib = (struct lldp_remote_mib *) base_mib_addr; 42362306a36Sopenharmony_ci prefix_seq_num = remote_mib->prefix_seq_num; 42462306a36Sopenharmony_ci suffix_seq_num = remote_mib->suffix_seq_num; 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci return 1; /*error*/ 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } while ((prefix_seq_num != suffix_seq_num) && 43062306a36Sopenharmony_ci (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ)); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) { 43362306a36Sopenharmony_ci BNX2X_ERR("MIB could not be read\n"); 43462306a36Sopenharmony_ci return 1; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void bnx2x_pfc_set_pfc(struct bnx2x *bp) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int mfw_configured = SHMEM2_HAS(bp, drv_flags) && 44362306a36Sopenharmony_ci GET_FLAGS(SHMEM2_RD(bp, drv_flags), 44462306a36Sopenharmony_ci 1 << DRV_FLAGS_DCB_MFW_CONFIGURED); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (bp->dcbx_port_params.pfc.enabled && 44762306a36Sopenharmony_ci (!(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) || mfw_configured)) 44862306a36Sopenharmony_ci /* 44962306a36Sopenharmony_ci * 1. Fills up common PFC structures if required 45062306a36Sopenharmony_ci * 2. Configure NIG, MAC and BRB via the elink 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci bnx2x_pfc_set(bp); 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci bnx2x_pfc_clear(bp); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciint bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct bnx2x_func_state_params func_params = {NULL}; 46062306a36Sopenharmony_ci int rc; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci func_params.f_obj = &bp->func_obj; 46362306a36Sopenharmony_ci func_params.cmd = BNX2X_F_CMD_TX_STOP; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); 46662306a36Sopenharmony_ci __set_bit(RAMROD_RETRY, &func_params.ramrod_flags); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n"); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci rc = bnx2x_func_state_change(bp, &func_params); 47162306a36Sopenharmony_ci if (rc) { 47262306a36Sopenharmony_ci BNX2X_ERR("Unable to hold traffic for HW configuration\n"); 47362306a36Sopenharmony_ci bnx2x_panic(); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return rc; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciint bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct bnx2x_func_state_params func_params = {NULL}; 48262306a36Sopenharmony_ci struct bnx2x_func_tx_start_params *tx_params = 48362306a36Sopenharmony_ci &func_params.params.tx_start; 48462306a36Sopenharmony_ci int rc; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci func_params.f_obj = &bp->func_obj; 48762306a36Sopenharmony_ci func_params.cmd = BNX2X_F_CMD_TX_START; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); 49062306a36Sopenharmony_ci __set_bit(RAMROD_RETRY, &func_params.ramrod_flags); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci bnx2x_dcbx_fw_struct(bp, tx_params); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "START TRAFFIC\n"); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rc = bnx2x_func_state_change(bp, &func_params); 49762306a36Sopenharmony_ci if (rc) { 49862306a36Sopenharmony_ci BNX2X_ERR("Unable to resume traffic after HW configuration\n"); 49962306a36Sopenharmony_ci bnx2x_panic(); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci return rc; 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); 50862306a36Sopenharmony_ci int rc = 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) { 51162306a36Sopenharmony_ci BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos); 51262306a36Sopenharmony_ci return; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* valid COS entries */ 51662306a36Sopenharmony_ci if (ets->num_of_cos == 1) /* no ETS */ 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* sanity */ 52062306a36Sopenharmony_ci if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) && 52162306a36Sopenharmony_ci (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) || 52262306a36Sopenharmony_ci ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) && 52362306a36Sopenharmony_ci (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) { 52462306a36Sopenharmony_ci BNX2X_ERR("all COS should have at least bw_limit or strict" 52562306a36Sopenharmony_ci "ets->cos_params[0].strict= %x" 52662306a36Sopenharmony_ci "ets->cos_params[0].bw_tbl= %x" 52762306a36Sopenharmony_ci "ets->cos_params[1].strict= %x" 52862306a36Sopenharmony_ci "ets->cos_params[1].bw_tbl= %x", 52962306a36Sopenharmony_ci ets->cos_params[0].strict, 53062306a36Sopenharmony_ci ets->cos_params[0].bw_tbl, 53162306a36Sopenharmony_ci ets->cos_params[1].strict, 53262306a36Sopenharmony_ci ets->cos_params[1].bw_tbl); 53362306a36Sopenharmony_ci return; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci /* If we join a group and there is bw_tbl and strict then bw rules */ 53662306a36Sopenharmony_ci if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) && 53762306a36Sopenharmony_ci (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) { 53862306a36Sopenharmony_ci u32 bw_tbl_0 = ets->cos_params[0].bw_tbl; 53962306a36Sopenharmony_ci u32 bw_tbl_1 = ets->cos_params[1].bw_tbl; 54062306a36Sopenharmony_ci /* Do not allow 0-100 configuration 54162306a36Sopenharmony_ci * since PBF does not support it 54262306a36Sopenharmony_ci * force 1-99 instead 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci if (bw_tbl_0 == 0) { 54562306a36Sopenharmony_ci bw_tbl_0 = 1; 54662306a36Sopenharmony_ci bw_tbl_1 = 99; 54762306a36Sopenharmony_ci } else if (bw_tbl_1 == 0) { 54862306a36Sopenharmony_ci bw_tbl_1 = 1; 54962306a36Sopenharmony_ci bw_tbl_0 = 99; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1); 55362306a36Sopenharmony_ci } else { 55462306a36Sopenharmony_ci if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST) 55562306a36Sopenharmony_ci rc = bnx2x_ets_strict(&bp->link_params, 0); 55662306a36Sopenharmony_ci else if (ets->cos_params[1].strict 55762306a36Sopenharmony_ci == BNX2X_DCBX_STRICT_COS_HIGHEST) 55862306a36Sopenharmony_ci rc = bnx2x_ets_strict(&bp->link_params, 1); 55962306a36Sopenharmony_ci if (rc) 56062306a36Sopenharmony_ci BNX2X_ERR("update_ets_params failed\n"); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * In E3B0 the configuration may have more than 2 COS. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_cistatic void bnx2x_dcbx_update_ets_config(struct bnx2x *bp) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); 57062306a36Sopenharmony_ci struct bnx2x_ets_params ets_params = { 0 }; 57162306a36Sopenharmony_ci u8 i; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ets_params.num_of_cos = ets->num_of_cos; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for (i = 0; i < ets->num_of_cos; i++) { 57662306a36Sopenharmony_ci /* COS is SP */ 57762306a36Sopenharmony_ci if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) { 57862306a36Sopenharmony_ci if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) { 57962306a36Sopenharmony_ci BNX2X_ERR("COS can't be not BW and not SP\n"); 58062306a36Sopenharmony_ci return; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ets_params.cos[i].state = bnx2x_cos_state_strict; 58462306a36Sopenharmony_ci ets_params.cos[i].params.sp_params.pri = 58562306a36Sopenharmony_ci ets->cos_params[i].strict; 58662306a36Sopenharmony_ci } else { /* COS is BW */ 58762306a36Sopenharmony_ci if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) { 58862306a36Sopenharmony_ci BNX2X_ERR("COS can't be not BW and not SP\n"); 58962306a36Sopenharmony_ci return; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci ets_params.cos[i].state = bnx2x_cos_state_bw; 59262306a36Sopenharmony_ci ets_params.cos[i].params.bw_params.bw = 59362306a36Sopenharmony_ci (u8)ets->cos_params[i].bw_tbl; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Configure the ETS in HW */ 59862306a36Sopenharmony_ci if (bnx2x_ets_e3b0_config(&bp->link_params, &bp->link_vars, 59962306a36Sopenharmony_ci &ets_params)) { 60062306a36Sopenharmony_ci BNX2X_ERR("bnx2x_ets_e3b0_config failed\n"); 60162306a36Sopenharmony_ci bnx2x_ets_disabled(&bp->link_params, &bp->link_vars); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci int mfw_configured = SHMEM2_HAS(bp, drv_flags) && 60862306a36Sopenharmony_ci GET_FLAGS(SHMEM2_RD(bp, drv_flags), 60962306a36Sopenharmony_ci 1 << DRV_FLAGS_DCB_MFW_CONFIGURED); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci bnx2x_ets_disabled(&bp->link_params, &bp->link_vars); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (!bp->dcbx_port_params.ets.enabled || 61462306a36Sopenharmony_ci ((bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) && !mfw_configured)) 61562306a36Sopenharmony_ci return; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (CHIP_IS_E3B0(bp)) 61862306a36Sopenharmony_ci bnx2x_dcbx_update_ets_config(bp); 61962306a36Sopenharmony_ci else 62062306a36Sopenharmony_ci bnx2x_dcbx_2cos_limit_update_ets_config(bp); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci#ifdef BCM_DCBNL 62462306a36Sopenharmony_cistatic int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct lldp_remote_mib remote_mib = {0}; 62762306a36Sopenharmony_ci u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset); 62862306a36Sopenharmony_ci int rc; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_remote_mib_offset 0x%x\n", 63162306a36Sopenharmony_ci dcbx_remote_mib_offset); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) { 63462306a36Sopenharmony_ci BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n"); 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset, 63962306a36Sopenharmony_ci DCBX_READ_REMOTE_MIB); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (rc) { 64262306a36Sopenharmony_ci BNX2X_ERR("Failed to read remote mib from FW\n"); 64362306a36Sopenharmony_ci return rc; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* save features and flags */ 64762306a36Sopenharmony_ci bp->dcbx_remote_feat = remote_mib.features; 64862306a36Sopenharmony_ci bp->dcbx_remote_flags = remote_mib.flags; 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci#endif 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct lldp_local_mib local_mib = {0}; 65662306a36Sopenharmony_ci u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset); 65762306a36Sopenharmony_ci int rc; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) { 66262306a36Sopenharmony_ci BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n"); 66362306a36Sopenharmony_ci return -EINVAL; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset, 66762306a36Sopenharmony_ci DCBX_READ_LOCAL_MIB); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (rc) { 67062306a36Sopenharmony_ci BNX2X_ERR("Failed to read local mib from FW\n"); 67162306a36Sopenharmony_ci return rc; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* save features and error */ 67562306a36Sopenharmony_ci bp->dcbx_local_feat = local_mib.features; 67662306a36Sopenharmony_ci bp->dcbx_error = local_mib.error; 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci#ifdef BCM_DCBNL 68162306a36Sopenharmony_cistatic inline 68262306a36Sopenharmony_ciu8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci u8 pri; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Choose the highest priority */ 68762306a36Sopenharmony_ci for (pri = MAX_PFC_PRIORITIES - 1; pri > 0; pri--) 68862306a36Sopenharmony_ci if (ent->pri_bitmap & (1 << pri)) 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci return pri; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic inline 69462306a36Sopenharmony_ciu8 bnx2x_dcbx_dcbnl_app_idtype(struct dcbx_app_priority_entry *ent) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci return ((ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) == 69762306a36Sopenharmony_ci DCBX_APP_SF_PORT) ? DCB_APP_IDTYPE_PORTNUM : 69862306a36Sopenharmony_ci DCB_APP_IDTYPE_ETHTYPE; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ciint bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci int i, err = 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_APP_PROTOCOL && err == 0; i++) { 70662306a36Sopenharmony_ci struct dcbx_app_priority_entry *ent = 70762306a36Sopenharmony_ci &bp->dcbx_local_feat.app.app_pri_tbl[i]; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { 71062306a36Sopenharmony_ci u8 up = bnx2x_dcbx_dcbnl_app_up(ent); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* avoid invalid user-priority */ 71362306a36Sopenharmony_ci if (up) { 71462306a36Sopenharmony_ci struct dcb_app app; 71562306a36Sopenharmony_ci app.selector = bnx2x_dcbx_dcbnl_app_idtype(ent); 71662306a36Sopenharmony_ci app.protocol = ent->app_id; 71762306a36Sopenharmony_ci app.priority = delall ? 0 : up; 71862306a36Sopenharmony_ci err = dcb_setapp(bp->dev, &app); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci return err; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci#endif 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci u8 prio, cos; 72962306a36Sopenharmony_ci for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) { 73062306a36Sopenharmony_ci for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { 73162306a36Sopenharmony_ci if (bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask 73262306a36Sopenharmony_ci & (1 << prio)) { 73362306a36Sopenharmony_ci bp->prio_to_cos[prio] = cos; 73462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 73562306a36Sopenharmony_ci "tx_mapping %d --> %d\n", prio, cos); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* setup tc must be called under rtnl lock, but we can't take it here 74162306a36Sopenharmony_ci * as we are handling an attention on a work queue which must be 74262306a36Sopenharmony_ci * flushed at some rtnl-locked contexts (e.g. if down) 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_SETUP_TC, 0); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_civoid bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci switch (state) { 75062306a36Sopenharmony_ci case BNX2X_DCBX_STATE_NEG_RECEIVED: 75162306a36Sopenharmony_ci { 75262306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); 75362306a36Sopenharmony_ci#ifdef BCM_DCBNL 75462306a36Sopenharmony_ci /** 75562306a36Sopenharmony_ci * Delete app tlvs from dcbnl before reading new 75662306a36Sopenharmony_ci * negotiation results 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci bnx2x_dcbnl_update_applist(bp, true); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Read remote mib if dcbx is in the FW */ 76162306a36Sopenharmony_ci if (bnx2x_dcbx_read_shmem_remote_mib(bp)) 76262306a36Sopenharmony_ci return; 76362306a36Sopenharmony_ci#endif 76462306a36Sopenharmony_ci /* Read neg results if dcbx is in the FW */ 76562306a36Sopenharmony_ci if (bnx2x_dcbx_read_shmem_neg_results(bp)) 76662306a36Sopenharmony_ci return; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat, 76962306a36Sopenharmony_ci bp->dcbx_error); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat, 77262306a36Sopenharmony_ci bp->dcbx_error); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* mark DCBX result for PMF migration */ 77562306a36Sopenharmony_ci bnx2x_update_drv_flags(bp, 77662306a36Sopenharmony_ci 1 << DRV_FLAGS_DCB_CONFIGURED, 77762306a36Sopenharmony_ci 1); 77862306a36Sopenharmony_ci#ifdef BCM_DCBNL 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * Add new app tlvs to dcbnl 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci bnx2x_dcbnl_update_applist(bp, false); 78362306a36Sopenharmony_ci#endif 78462306a36Sopenharmony_ci /* 78562306a36Sopenharmony_ci * reconfigure the netdevice with the results of the new 78662306a36Sopenharmony_ci * dcbx negotiation. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci bnx2x_dcbx_update_tc_mapping(bp); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* 79162306a36Sopenharmony_ci * allow other functions to update their netdevices 79262306a36Sopenharmony_ci * accordingly 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci if (IS_MF(bp)) 79562306a36Sopenharmony_ci bnx2x_link_sync_notify(bp); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_STOP, 0); 79862306a36Sopenharmony_ci return; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci case BNX2X_DCBX_STATE_TX_PAUSED: 80162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_PAUSED\n"); 80262306a36Sopenharmony_ci bnx2x_pfc_set_pfc(bp); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci bnx2x_dcbx_update_ets_params(bp); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* ets may affect cmng configuration: reinit it in hw */ 80762306a36Sopenharmony_ci bnx2x_set_local_cmng(bp); 80862306a36Sopenharmony_ci return; 80962306a36Sopenharmony_ci case BNX2X_DCBX_STATE_TX_RELEASED: 81062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_RELEASED\n"); 81162306a36Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0); 81262306a36Sopenharmony_ci#ifdef BCM_DCBNL 81362306a36Sopenharmony_ci /* 81462306a36Sopenharmony_ci * Send a notification for the new negotiated parameters 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0); 81762306a36Sopenharmony_ci#endif 81862306a36Sopenharmony_ci return; 81962306a36Sopenharmony_ci default: 82062306a36Sopenharmony_ci BNX2X_ERR("Unknown DCBX_STATE\n"); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci#define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \ 82562306a36Sopenharmony_ci BP_PORT(bp)*sizeof(struct lldp_admin_mib)) 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp, 82862306a36Sopenharmony_ci u32 dcbx_lldp_params_offset) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct lldp_admin_mib admin_mib; 83162306a36Sopenharmony_ci u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0; 83262306a36Sopenharmony_ci u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /*shortcuts*/ 83562306a36Sopenharmony_ci struct dcbx_features *af = &admin_mib.features; 83662306a36Sopenharmony_ci struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci memset(&admin_mib, 0, sizeof(struct lldp_admin_mib)); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Read the data first */ 84162306a36Sopenharmony_ci bnx2x_read_data(bp, (u32 *)&admin_mib, offset, 84262306a36Sopenharmony_ci sizeof(struct lldp_admin_mib)); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON) 84562306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); 84662306a36Sopenharmony_ci else 84762306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (dp->overwrite_settings == BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE) { 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK); 85262306a36Sopenharmony_ci admin_mib.ver_cfg_flags |= 85362306a36Sopenharmony_ci (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) & 85462306a36Sopenharmony_ci DCBX_CEE_VERSION_MASK; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci af->ets.enabled = (u8)dp->admin_ets_enable; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci af->pfc.enabled = (u8)dp->admin_pfc_enable; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* FOR IEEE dp->admin_tc_supported_tx_enable */ 86162306a36Sopenharmony_ci if (dp->admin_ets_configuration_tx_enable) 86262306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, 86362306a36Sopenharmony_ci DCBX_ETS_CONFIG_TX_ENABLED); 86462306a36Sopenharmony_ci else 86562306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, 86662306a36Sopenharmony_ci DCBX_ETS_CONFIG_TX_ENABLED); 86762306a36Sopenharmony_ci /* For IEEE admin_ets_recommendation_tx_enable */ 86862306a36Sopenharmony_ci if (dp->admin_pfc_tx_enable) 86962306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, 87062306a36Sopenharmony_ci DCBX_PFC_CONFIG_TX_ENABLED); 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, 87362306a36Sopenharmony_ci DCBX_PFC_CONFIG_TX_ENABLED); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (dp->admin_application_priority_tx_enable) 87662306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, 87762306a36Sopenharmony_ci DCBX_APP_CONFIG_TX_ENABLED); 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, 88062306a36Sopenharmony_ci DCBX_APP_CONFIG_TX_ENABLED); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (dp->admin_ets_willing) 88362306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); 88462306a36Sopenharmony_ci else 88562306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); 88662306a36Sopenharmony_ci /* For IEEE admin_ets_reco_valid */ 88762306a36Sopenharmony_ci if (dp->admin_pfc_willing) 88862306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); 88962306a36Sopenharmony_ci else 89062306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (dp->admin_app_priority_willing) 89362306a36Sopenharmony_ci SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); 89462306a36Sopenharmony_ci else 89562306a36Sopenharmony_ci RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) { 89862306a36Sopenharmony_ci DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i, 89962306a36Sopenharmony_ci (u8)dp->admin_configuration_bw_precentage[i]); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "pg_bw_tbl[%d] = %02x\n", 90262306a36Sopenharmony_ci i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i)); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { 90662306a36Sopenharmony_ci DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i, 90762306a36Sopenharmony_ci (u8)dp->admin_configuration_ets_pg[i]); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "pri_pg_tbl[%d] = %02x\n", 91062306a36Sopenharmony_ci i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i)); 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /*For IEEE admin_recommendation_bw_percentage 91462306a36Sopenharmony_ci *For IEEE admin_recommendation_ets_pg */ 91562306a36Sopenharmony_ci af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap; 91662306a36Sopenharmony_ci for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) { 91762306a36Sopenharmony_ci if (dp->admin_priority_app_table[i].valid) { 91862306a36Sopenharmony_ci struct bnx2x_admin_priority_app_table *table = 91962306a36Sopenharmony_ci dp->admin_priority_app_table; 92062306a36Sopenharmony_ci if ((ETH_TYPE_FCOE == table[i].app_id) && 92162306a36Sopenharmony_ci (TRAFFIC_TYPE_ETH == table[i].traffic_type)) 92262306a36Sopenharmony_ci traf_type = FCOE_APP_IDX; 92362306a36Sopenharmony_ci else if ((TCP_PORT_ISCSI == table[i].app_id) && 92462306a36Sopenharmony_ci (TRAFFIC_TYPE_PORT == table[i].traffic_type)) 92562306a36Sopenharmony_ci traf_type = ISCSI_APP_IDX; 92662306a36Sopenharmony_ci else 92762306a36Sopenharmony_ci traf_type = other_traf_type++; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci af->app.app_pri_tbl[traf_type].app_id = 93062306a36Sopenharmony_ci table[i].app_id; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci af->app.app_pri_tbl[traf_type].pri_bitmap = 93362306a36Sopenharmony_ci (u8)(1 << table[i].priority); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci af->app.app_pri_tbl[traf_type].appBitfield = 93662306a36Sopenharmony_ci (DCBX_APP_ENTRY_VALID); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci af->app.app_pri_tbl[traf_type].appBitfield |= 93962306a36Sopenharmony_ci (TRAFFIC_TYPE_ETH == table[i].traffic_type) ? 94062306a36Sopenharmony_ci DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci af->app.default_pri = (u8)dp->admin_default_priority; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Write the data. */ 94862306a36Sopenharmony_ci bnx2x_write_data(bp, (u32 *)&admin_mib, offset, 94962306a36Sopenharmony_ci sizeof(struct lldp_admin_mib)); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_civoid bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci if (!CHIP_IS_E1x(bp)) { 95562306a36Sopenharmony_ci bp->dcb_state = dcb_on; 95662306a36Sopenharmony_ci bp->dcbx_enabled = dcbx_enabled; 95762306a36Sopenharmony_ci } else { 95862306a36Sopenharmony_ci bp->dcb_state = false; 95962306a36Sopenharmony_ci bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCB state [%s:%s]\n", 96262306a36Sopenharmony_ci dcb_on ? "ON" : "OFF", 96362306a36Sopenharmony_ci dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" : 96462306a36Sopenharmony_ci dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" : 96562306a36Sopenharmony_ci dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ? 96662306a36Sopenharmony_ci "on-chip with negotiation" : "invalid"); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_civoid bnx2x_dcbx_init_params(struct bnx2x *bp) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */ 97262306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_willing = 1; 97362306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_willing = 1; 97462306a36Sopenharmony_ci bp->dcbx_config_params.overwrite_settings = 1; 97562306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_enable = 1; 97662306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_enable = 1; 97762306a36Sopenharmony_ci bp->dcbx_config_params.admin_tc_supported_tx_enable = 1; 97862306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; 97962306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_tx_enable = 1; 98062306a36Sopenharmony_ci bp->dcbx_config_params.admin_application_priority_tx_enable = 1; 98162306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_reco_valid = 1; 98262306a36Sopenharmony_ci bp->dcbx_config_params.admin_app_priority_willing = 1; 98362306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 100; 98462306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 0; 98562306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 0; 98662306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0; 98762306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0; 98862306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0; 98962306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0; 99062306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0; 99162306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[0] = 0; 99262306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0; 99362306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0; 99462306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[3] = 0; 99562306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0; 99662306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0; 99762306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0; 99862306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0; 99962306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 100; 100062306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 0; 100162306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 0; 100262306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0; 100362306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 0; 100462306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 0; 100562306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 0; 100662306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 0; 100762306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0; 100862306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1; 100962306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2; 101062306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3; 101162306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4; 101262306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5; 101362306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6; 101462306a36Sopenharmony_ci bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7; 101562306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_bitmap = 0x0; 101662306a36Sopenharmony_ci bp->dcbx_config_params.admin_priority_app_table[0].valid = 0; 101762306a36Sopenharmony_ci bp->dcbx_config_params.admin_priority_app_table[1].valid = 0; 101862306a36Sopenharmony_ci bp->dcbx_config_params.admin_priority_app_table[2].valid = 0; 101962306a36Sopenharmony_ci bp->dcbx_config_params.admin_priority_app_table[3].valid = 0; 102062306a36Sopenharmony_ci bp->dcbx_config_params.admin_default_priority = 0; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_civoid bnx2x_dcbx_init(struct bnx2x *bp, bool update_shmem) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* only PMF can send ADMIN msg to MFW in old MFW versions */ 102862306a36Sopenharmony_ci if ((!bp->port.pmf) && (!(bp->flags & BC_SUPPORTS_DCBX_MSG_NON_PMF))) 102962306a36Sopenharmony_ci return; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (bp->dcbx_enabled <= 0) 103262306a36Sopenharmony_ci return; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* validate: 103562306a36Sopenharmony_ci * chip of good for dcbx version, 103662306a36Sopenharmony_ci * dcb is wanted 103762306a36Sopenharmony_ci * shmem2 contains DCBX support fields 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcb_state %d bp->port.pmf %d\n", 104062306a36Sopenharmony_ci bp->dcb_state, bp->port.pmf); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (bp->dcb_state == BNX2X_DCB_STATE_ON && 104362306a36Sopenharmony_ci SHMEM2_HAS(bp, dcbx_lldp_params_offset)) { 104462306a36Sopenharmony_ci dcbx_lldp_params_offset = 104562306a36Sopenharmony_ci SHMEM2_RD(bp, dcbx_lldp_params_offset); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbx_lldp_params_offset 0x%x\n", 104862306a36Sopenharmony_ci dcbx_lldp_params_offset); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) { 105362306a36Sopenharmony_ci /* need HW lock to avoid scenario of two drivers 105462306a36Sopenharmony_ci * writing in parallel to shmem 105562306a36Sopenharmony_ci */ 105662306a36Sopenharmony_ci bnx2x_acquire_hw_lock(bp, 105762306a36Sopenharmony_ci HW_LOCK_RESOURCE_DCBX_ADMIN_MIB); 105862306a36Sopenharmony_ci if (update_shmem) 105962306a36Sopenharmony_ci bnx2x_dcbx_admin_mib_updated_params(bp, 106062306a36Sopenharmony_ci dcbx_lldp_params_offset); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* Let HW start negotiation */ 106362306a36Sopenharmony_ci bnx2x_fw_command(bp, 106462306a36Sopenharmony_ci DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0); 106562306a36Sopenharmony_ci /* release HW lock only after MFW acks that it finished 106662306a36Sopenharmony_ci * reading values from shmem 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_ci bnx2x_release_hw_lock(bp, 106962306a36Sopenharmony_ci HW_LOCK_RESOURCE_DCBX_ADMIN_MIB); 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_cistatic void 107462306a36Sopenharmony_cibnx2x_dcbx_print_cos_params(struct bnx2x *bp, 107562306a36Sopenharmony_ci struct bnx2x_func_tx_start_params *pfc_fw_cfg) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci u8 pri = 0; 107862306a36Sopenharmony_ci u8 cos = 0; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 108162306a36Sopenharmony_ci "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version); 108262306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 108362306a36Sopenharmony_ci "pdev->params.dcbx_port_params.pfc.priority_non_pauseable_mask %x\n", 108462306a36Sopenharmony_ci bp->dcbx_port_params.pfc.priority_non_pauseable_mask); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) { 108762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 108862306a36Sopenharmony_ci "pdev->params.dcbx_port_params.ets.cos_params[%d].pri_bitmask %x\n", 108962306a36Sopenharmony_ci cos, bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 109262306a36Sopenharmony_ci "pdev->params.dcbx_port_params.ets.cos_params[%d].bw_tbl %x\n", 109362306a36Sopenharmony_ci cos, bp->dcbx_port_params.ets.cos_params[cos].bw_tbl); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 109662306a36Sopenharmony_ci "pdev->params.dcbx_port_params.ets.cos_params[%d].strict %x\n", 109762306a36Sopenharmony_ci cos, bp->dcbx_port_params.ets.cos_params[cos].strict); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 110062306a36Sopenharmony_ci "pdev->params.dcbx_port_params.ets.cos_params[%d].pauseable %x\n", 110162306a36Sopenharmony_ci cos, bp->dcbx_port_params.ets.cos_params[cos].pauseable); 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { 110562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 110662306a36Sopenharmony_ci "pfc_fw_cfg->traffic_type_to_priority_cos[%d].priority %x\n", 110762306a36Sopenharmony_ci pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 111062306a36Sopenharmony_ci "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n", 111162306a36Sopenharmony_ci pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci/* fills help_data according to pg_info */ 111662306a36Sopenharmony_cistatic void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, 111762306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 111862306a36Sopenharmony_ci struct pg_help_data *help_data) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci bool pg_found = false; 112162306a36Sopenharmony_ci u32 i, traf_type, add_traf_type, add_pg; 112262306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 112362306a36Sopenharmony_ci struct pg_entry_help_data *data = help_data->data; /*shortcut*/ 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* Set to invalid */ 112662306a36Sopenharmony_ci for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) 112762306a36Sopenharmony_ci data[i].pg = DCBX_ILLEGAL_PG; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci for (add_traf_type = 0; 113062306a36Sopenharmony_ci add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) { 113162306a36Sopenharmony_ci pg_found = false; 113262306a36Sopenharmony_ci if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) { 113362306a36Sopenharmony_ci add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]]; 113462306a36Sopenharmony_ci for (traf_type = 0; 113562306a36Sopenharmony_ci traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; 113662306a36Sopenharmony_ci traf_type++) { 113762306a36Sopenharmony_ci if (data[traf_type].pg == add_pg) { 113862306a36Sopenharmony_ci if (!(data[traf_type].pg_priority & 113962306a36Sopenharmony_ci (1 << ttp[add_traf_type]))) 114062306a36Sopenharmony_ci data[traf_type]. 114162306a36Sopenharmony_ci num_of_dif_pri++; 114262306a36Sopenharmony_ci data[traf_type].pg_priority |= 114362306a36Sopenharmony_ci (1 << ttp[add_traf_type]); 114462306a36Sopenharmony_ci pg_found = true; 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci if (!pg_found) { 114962306a36Sopenharmony_ci data[help_data->num_of_pg].pg = add_pg; 115062306a36Sopenharmony_ci data[help_data->num_of_pg].pg_priority = 115162306a36Sopenharmony_ci (1 << ttp[add_traf_type]); 115262306a36Sopenharmony_ci data[help_data->num_of_pg].num_of_dif_pri = 1; 115362306a36Sopenharmony_ci help_data->num_of_pg++; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 115762306a36Sopenharmony_ci "add_traf_type %d pg_found %s num_of_pg %d\n", 115862306a36Sopenharmony_ci add_traf_type, !pg_found ? "NO" : "YES", 115962306a36Sopenharmony_ci help_data->num_of_pg); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, 116462306a36Sopenharmony_ci struct cos_help_data *cos_data, 116562306a36Sopenharmony_ci u32 pri_join_mask) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci /* Only one priority than only one COS */ 116862306a36Sopenharmony_ci cos_data->data[0].pausable = 116962306a36Sopenharmony_ci IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); 117062306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = pri_join_mask; 117162306a36Sopenharmony_ci cos_data->data[0].cos_bw = 100; 117262306a36Sopenharmony_ci cos_data->num_of_cos = 1; 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_cistatic inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, 117662306a36Sopenharmony_ci struct cos_entry_help_data *data, 117762306a36Sopenharmony_ci u8 pg_bw) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci if (data->cos_bw == DCBX_INVALID_COS_BW) 118062306a36Sopenharmony_ci data->cos_bw = pg_bw; 118162306a36Sopenharmony_ci else 118262306a36Sopenharmony_ci data->cos_bw += pg_bw; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, 118662306a36Sopenharmony_ci struct cos_help_data *cos_data, 118762306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 118862306a36Sopenharmony_ci struct dcbx_ets_feature *ets) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci u32 pri_tested = 0; 119162306a36Sopenharmony_ci u8 i = 0; 119262306a36Sopenharmony_ci u8 entry = 0; 119362306a36Sopenharmony_ci u8 pg_entry = 0; 119462306a36Sopenharmony_ci u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci cos_data->data[0].pausable = true; 119762306a36Sopenharmony_ci cos_data->data[1].pausable = false; 119862306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci for (i = 0 ; i < num_of_pri ; i++) { 120162306a36Sopenharmony_ci pri_tested = 1 << bp->dcbx_port_params. 120262306a36Sopenharmony_ci app.traffic_type_priority[i]; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) { 120562306a36Sopenharmony_ci cos_data->data[1].pri_join_mask |= pri_tested; 120662306a36Sopenharmony_ci entry = 1; 120762306a36Sopenharmony_ci } else { 120862306a36Sopenharmony_ci cos_data->data[0].pri_join_mask |= pri_tested; 120962306a36Sopenharmony_ci entry = 0; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params. 121262306a36Sopenharmony_ci app.traffic_type_priority[i]]; 121362306a36Sopenharmony_ci /* There can be only one strict pg */ 121462306a36Sopenharmony_ci if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) 121562306a36Sopenharmony_ci bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry], 121662306a36Sopenharmony_ci DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry)); 121762306a36Sopenharmony_ci else 121862306a36Sopenharmony_ci /* If we join a group and one is strict 121962306a36Sopenharmony_ci * than the bw rules 122062306a36Sopenharmony_ci */ 122162306a36Sopenharmony_ci cos_data->data[entry].strict = 122262306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci if ((0 == cos_data->data[0].pri_join_mask) && 122562306a36Sopenharmony_ci (0 == cos_data->data[1].pri_join_mask)) 122662306a36Sopenharmony_ci BNX2X_ERR("dcbx error: Both groups must have priorities\n"); 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci#ifndef POWER_OF_2 123062306a36Sopenharmony_ci#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1)))) 123162306a36Sopenharmony_ci#endif 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_cistatic void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp, 123462306a36Sopenharmony_ci struct pg_help_data *pg_help_data, 123562306a36Sopenharmony_ci struct cos_help_data *cos_data, 123662306a36Sopenharmony_ci u32 pri_join_mask, 123762306a36Sopenharmony_ci u8 num_of_dif_pri) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci u8 i = 0; 124062306a36Sopenharmony_ci u32 pri_tested = 0; 124162306a36Sopenharmony_ci u32 pri_mask_without_pri = 0; 124262306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 124362306a36Sopenharmony_ci /*debug*/ 124462306a36Sopenharmony_ci if (num_of_dif_pri == 1) { 124562306a36Sopenharmony_ci bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask); 124662306a36Sopenharmony_ci return; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci /* single priority group */ 124962306a36Sopenharmony_ci if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) { 125062306a36Sopenharmony_ci /* If there are both pauseable and non-pauseable priorities, 125162306a36Sopenharmony_ci * the pauseable priorities go to the first queue and 125262306a36Sopenharmony_ci * the non-pauseable priorities go to the second queue. 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { 125562306a36Sopenharmony_ci /* Pauseable */ 125662306a36Sopenharmony_ci cos_data->data[0].pausable = true; 125762306a36Sopenharmony_ci /* Non pauseable.*/ 125862306a36Sopenharmony_ci cos_data->data[1].pausable = false; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci if (2 == num_of_dif_pri) { 126162306a36Sopenharmony_ci cos_data->data[0].cos_bw = 50; 126262306a36Sopenharmony_ci cos_data->data[1].cos_bw = 50; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (3 == num_of_dif_pri) { 126662306a36Sopenharmony_ci if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp, 126762306a36Sopenharmony_ci pri_join_mask))) { 126862306a36Sopenharmony_ci cos_data->data[0].cos_bw = 33; 126962306a36Sopenharmony_ci cos_data->data[1].cos_bw = 67; 127062306a36Sopenharmony_ci } else { 127162306a36Sopenharmony_ci cos_data->data[0].cos_bw = 67; 127262306a36Sopenharmony_ci cos_data->data[1].cos_bw = 33; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) { 127762306a36Sopenharmony_ci /* If there are only pauseable priorities, 127862306a36Sopenharmony_ci * then one/two priorities go to the first queue 127962306a36Sopenharmony_ci * and one priority goes to the second queue. 128062306a36Sopenharmony_ci */ 128162306a36Sopenharmony_ci if (2 == num_of_dif_pri) { 128262306a36Sopenharmony_ci cos_data->data[0].cos_bw = 50; 128362306a36Sopenharmony_ci cos_data->data[1].cos_bw = 50; 128462306a36Sopenharmony_ci } else { 128562306a36Sopenharmony_ci cos_data->data[0].cos_bw = 67; 128662306a36Sopenharmony_ci cos_data->data[1].cos_bw = 33; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci cos_data->data[1].pausable = true; 128962306a36Sopenharmony_ci cos_data->data[0].pausable = true; 129062306a36Sopenharmony_ci /* All priorities except FCOE */ 129162306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = (pri_join_mask & 129262306a36Sopenharmony_ci ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]))); 129362306a36Sopenharmony_ci /* Only FCOE priority.*/ 129462306a36Sopenharmony_ci cos_data->data[1].pri_join_mask = 129562306a36Sopenharmony_ci (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]); 129662306a36Sopenharmony_ci } else 129762306a36Sopenharmony_ci /* If there are only non-pauseable priorities, 129862306a36Sopenharmony_ci * they will all go to the same queue. 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci bnx2x_dcbx_ets_disabled_entry_data(bp, 130162306a36Sopenharmony_ci cos_data, pri_join_mask); 130262306a36Sopenharmony_ci } else { 130362306a36Sopenharmony_ci /* priority group which is not BW limited (PG#15):*/ 130462306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { 130562306a36Sopenharmony_ci /* If there are both pauseable and non-pauseable 130662306a36Sopenharmony_ci * priorities, the pauseable priorities go to the first 130762306a36Sopenharmony_ci * queue and the non-pauseable priorities 130862306a36Sopenharmony_ci * go to the second queue. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_ci if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) > 131162306a36Sopenharmony_ci DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) { 131262306a36Sopenharmony_ci cos_data->data[0].strict = 131362306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 131462306a36Sopenharmony_ci cos_data->data[1].strict = 131562306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( 131662306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST); 131762306a36Sopenharmony_ci } else { 131862306a36Sopenharmony_ci cos_data->data[0].strict = 131962306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( 132062306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST); 132162306a36Sopenharmony_ci cos_data->data[1].strict = 132262306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci /* Pauseable */ 132562306a36Sopenharmony_ci cos_data->data[0].pausable = true; 132662306a36Sopenharmony_ci /* Non pause-able.*/ 132762306a36Sopenharmony_ci cos_data->data[1].pausable = false; 132862306a36Sopenharmony_ci } else { 132962306a36Sopenharmony_ci /* If there are only pauseable priorities or 133062306a36Sopenharmony_ci * only non-pauseable,* the lower priorities go 133162306a36Sopenharmony_ci * to the first queue and the higher priorities go 133262306a36Sopenharmony_ci * to the second queue. 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci cos_data->data[0].pausable = 133562306a36Sopenharmony_ci cos_data->data[1].pausable = 133662306a36Sopenharmony_ci IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) { 133962306a36Sopenharmony_ci pri_tested = 1 << bp->dcbx_port_params. 134062306a36Sopenharmony_ci app.traffic_type_priority[i]; 134162306a36Sopenharmony_ci /* Remove priority tested */ 134262306a36Sopenharmony_ci pri_mask_without_pri = 134362306a36Sopenharmony_ci (pri_join_mask & ((u8)(~pri_tested))); 134462306a36Sopenharmony_ci if (pri_mask_without_pri < pri_tested) 134562306a36Sopenharmony_ci break; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX) 134962306a36Sopenharmony_ci BNX2X_ERR("Invalid value for pri_join_mask - could not find a priority\n"); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = pri_mask_without_pri; 135262306a36Sopenharmony_ci cos_data->data[1].pri_join_mask = pri_tested; 135362306a36Sopenharmony_ci /* Both queues are strict priority, 135462306a36Sopenharmony_ci * and that with the highest priority 135562306a36Sopenharmony_ci * gets the highest strict priority in the arbiter. 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci cos_data->data[0].strict = 135862306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( 135962306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST); 136062306a36Sopenharmony_ci cos_data->data[1].strict = 136162306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params( 136762306a36Sopenharmony_ci struct bnx2x *bp, 136862306a36Sopenharmony_ci struct pg_help_data *pg_help_data, 136962306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 137062306a36Sopenharmony_ci struct cos_help_data *cos_data, 137162306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 137262306a36Sopenharmony_ci u32 pri_join_mask, 137362306a36Sopenharmony_ci u8 num_of_dif_pri) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci u8 i = 0; 137662306a36Sopenharmony_ci u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 }; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* If there are both pauseable and non-pauseable priorities, 137962306a36Sopenharmony_ci * the pauseable priorities go to the first queue and 138062306a36Sopenharmony_ci * the non-pauseable priorities go to the second queue. 138162306a36Sopenharmony_ci */ 138262306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { 138362306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, 138462306a36Sopenharmony_ci pg_help_data->data[0].pg_priority) || 138562306a36Sopenharmony_ci IS_DCBX_PFC_PRI_MIX_PAUSE(bp, 138662306a36Sopenharmony_ci pg_help_data->data[1].pg_priority)) { 138762306a36Sopenharmony_ci /* If one PG contains both pauseable and 138862306a36Sopenharmony_ci * non-pauseable priorities then ETS is disabled. 138962306a36Sopenharmony_ci */ 139062306a36Sopenharmony_ci bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data, 139162306a36Sopenharmony_ci pg_pri_orginal_spread, ets); 139262306a36Sopenharmony_ci bp->dcbx_port_params.ets.enabled = false; 139362306a36Sopenharmony_ci return; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* Pauseable */ 139762306a36Sopenharmony_ci cos_data->data[0].pausable = true; 139862306a36Sopenharmony_ci /* Non pauseable. */ 139962306a36Sopenharmony_ci cos_data->data[1].pausable = false; 140062306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, 140162306a36Sopenharmony_ci pg_help_data->data[0].pg_priority)) { 140262306a36Sopenharmony_ci /* 0 is pauseable */ 140362306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = 140462306a36Sopenharmony_ci pg_help_data->data[0].pg_priority; 140562306a36Sopenharmony_ci pg[0] = pg_help_data->data[0].pg; 140662306a36Sopenharmony_ci cos_data->data[1].pri_join_mask = 140762306a36Sopenharmony_ci pg_help_data->data[1].pg_priority; 140862306a36Sopenharmony_ci pg[1] = pg_help_data->data[1].pg; 140962306a36Sopenharmony_ci } else {/* 1 is pauseable */ 141062306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = 141162306a36Sopenharmony_ci pg_help_data->data[1].pg_priority; 141262306a36Sopenharmony_ci pg[0] = pg_help_data->data[1].pg; 141362306a36Sopenharmony_ci cos_data->data[1].pri_join_mask = 141462306a36Sopenharmony_ci pg_help_data->data[0].pg_priority; 141562306a36Sopenharmony_ci pg[1] = pg_help_data->data[0].pg; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci } else { 141862306a36Sopenharmony_ci /* If there are only pauseable priorities or 141962306a36Sopenharmony_ci * only non-pauseable, each PG goes to a queue. 142062306a36Sopenharmony_ci */ 142162306a36Sopenharmony_ci cos_data->data[0].pausable = cos_data->data[1].pausable = 142262306a36Sopenharmony_ci IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); 142362306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = 142462306a36Sopenharmony_ci pg_help_data->data[0].pg_priority; 142562306a36Sopenharmony_ci pg[0] = pg_help_data->data[0].pg; 142662306a36Sopenharmony_ci cos_data->data[1].pri_join_mask = 142762306a36Sopenharmony_ci pg_help_data->data[1].pg_priority; 142862306a36Sopenharmony_ci pg[1] = pg_help_data->data[1].pg; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci /* There can be only one strict pg */ 143262306a36Sopenharmony_ci for (i = 0 ; i < ARRAY_SIZE(pg); i++) { 143362306a36Sopenharmony_ci if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES) 143462306a36Sopenharmony_ci cos_data->data[i].cos_bw = 143562306a36Sopenharmony_ci DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]); 143662306a36Sopenharmony_ci else 143762306a36Sopenharmony_ci cos_data->data[i].strict = 143862306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int bnx2x_dcbx_join_pgs( 144362306a36Sopenharmony_ci struct bnx2x *bp, 144462306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 144562306a36Sopenharmony_ci struct pg_help_data *pg_help_data, 144662306a36Sopenharmony_ci u8 required_num_of_pg) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci u8 entry_joined = pg_help_data->num_of_pg - 1; 144962306a36Sopenharmony_ci u8 entry_removed = entry_joined + 1; 145062306a36Sopenharmony_ci u8 pg_joined = 0; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data) 145362306a36Sopenharmony_ci <= pg_help_data->num_of_pg) { 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci BNX2X_ERR("required_num_of_pg can't be zero\n"); 145662306a36Sopenharmony_ci return -EINVAL; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci while (required_num_of_pg < pg_help_data->num_of_pg) { 146062306a36Sopenharmony_ci entry_joined = pg_help_data->num_of_pg - 2; 146162306a36Sopenharmony_ci entry_removed = entry_joined + 1; 146262306a36Sopenharmony_ci /* protect index */ 146362306a36Sopenharmony_ci entry_removed %= ARRAY_SIZE(pg_help_data->data); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci pg_help_data->data[entry_joined].pg_priority |= 146662306a36Sopenharmony_ci pg_help_data->data[entry_removed].pg_priority; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci pg_help_data->data[entry_joined].num_of_dif_pri += 146962306a36Sopenharmony_ci pg_help_data->data[entry_removed].num_of_dif_pri; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG || 147262306a36Sopenharmony_ci pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG) 147362306a36Sopenharmony_ci /* Entries joined strict priority rules */ 147462306a36Sopenharmony_ci pg_help_data->data[entry_joined].pg = 147562306a36Sopenharmony_ci DCBX_STRICT_PRI_PG; 147662306a36Sopenharmony_ci else { 147762306a36Sopenharmony_ci /* Entries can be joined join BW */ 147862306a36Sopenharmony_ci pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl, 147962306a36Sopenharmony_ci pg_help_data->data[entry_joined].pg) + 148062306a36Sopenharmony_ci DCBX_PG_BW_GET(ets->pg_bw_tbl, 148162306a36Sopenharmony_ci pg_help_data->data[entry_removed].pg); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci DCBX_PG_BW_SET(ets->pg_bw_tbl, 148462306a36Sopenharmony_ci pg_help_data->data[entry_joined].pg, pg_joined); 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci /* Joined the entries */ 148762306a36Sopenharmony_ci pg_help_data->num_of_pg--; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci return 0; 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params( 149462306a36Sopenharmony_ci struct bnx2x *bp, 149562306a36Sopenharmony_ci struct pg_help_data *pg_help_data, 149662306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 149762306a36Sopenharmony_ci struct cos_help_data *cos_data, 149862306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 149962306a36Sopenharmony_ci u32 pri_join_mask, 150062306a36Sopenharmony_ci u8 num_of_dif_pri) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci u8 i = 0; 150362306a36Sopenharmony_ci u32 pri_tested = 0; 150462306a36Sopenharmony_ci u8 entry = 0; 150562306a36Sopenharmony_ci u8 pg_entry = 0; 150662306a36Sopenharmony_ci bool b_found_strict = false; 150762306a36Sopenharmony_ci u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; 151062306a36Sopenharmony_ci /* If there are both pauseable and non-pauseable priorities, 151162306a36Sopenharmony_ci * the pauseable priorities go to the first queue and the 151262306a36Sopenharmony_ci * non-pauseable priorities go to the second queue. 151362306a36Sopenharmony_ci */ 151462306a36Sopenharmony_ci if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) 151562306a36Sopenharmony_ci bnx2x_dcbx_separate_pauseable_from_non(bp, 151662306a36Sopenharmony_ci cos_data, pg_pri_orginal_spread, ets); 151762306a36Sopenharmony_ci else { 151862306a36Sopenharmony_ci /* If two BW-limited PG-s were combined to one queue, 151962306a36Sopenharmony_ci * the BW is their sum. 152062306a36Sopenharmony_ci * 152162306a36Sopenharmony_ci * If there are only pauseable priorities or only non-pauseable, 152262306a36Sopenharmony_ci * and there are both BW-limited and non-BW-limited PG-s, 152362306a36Sopenharmony_ci * the BW-limited PG/s go to one queue and the non-BW-limited 152462306a36Sopenharmony_ci * PG/s go to the second queue. 152562306a36Sopenharmony_ci * 152662306a36Sopenharmony_ci * If there are only pauseable priorities or only non-pauseable 152762306a36Sopenharmony_ci * and all are BW limited, then two priorities go to the first 152862306a36Sopenharmony_ci * queue and one priority goes to the second queue. 152962306a36Sopenharmony_ci * 153062306a36Sopenharmony_ci * We will join this two cases: 153162306a36Sopenharmony_ci * if one is BW limited it will go to the second queue 153262306a36Sopenharmony_ci * otherwise the last priority will get it 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci cos_data->data[0].pausable = cos_data->data[1].pausable = 153662306a36Sopenharmony_ci IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci for (i = 0 ; i < num_of_pri; i++) { 153962306a36Sopenharmony_ci pri_tested = 1 << bp->dcbx_port_params. 154062306a36Sopenharmony_ci app.traffic_type_priority[i]; 154162306a36Sopenharmony_ci pg_entry = (u8)pg_pri_orginal_spread[bp-> 154262306a36Sopenharmony_ci dcbx_port_params.app.traffic_type_priority[i]]; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) { 154562306a36Sopenharmony_ci entry = 0; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci if (i == (num_of_pri-1) && !b_found_strict) 154862306a36Sopenharmony_ci /* last entry will be handled separately 154962306a36Sopenharmony_ci * If no priority is strict than last 155062306a36Sopenharmony_ci * entry goes to last queue. 155162306a36Sopenharmony_ci */ 155262306a36Sopenharmony_ci entry = 1; 155362306a36Sopenharmony_ci cos_data->data[entry].pri_join_mask |= 155462306a36Sopenharmony_ci pri_tested; 155562306a36Sopenharmony_ci bnx2x_dcbx_add_to_cos_bw(bp, 155662306a36Sopenharmony_ci &cos_data->data[entry], 155762306a36Sopenharmony_ci DCBX_PG_BW_GET(ets->pg_bw_tbl, 155862306a36Sopenharmony_ci pg_entry)); 155962306a36Sopenharmony_ci } else { 156062306a36Sopenharmony_ci b_found_strict = true; 156162306a36Sopenharmony_ci cos_data->data[1].pri_join_mask |= pri_tested; 156262306a36Sopenharmony_ci /* If we join a group and one is strict 156362306a36Sopenharmony_ci * than the bw rules 156462306a36Sopenharmony_ci */ 156562306a36Sopenharmony_ci cos_data->data[1].strict = 156662306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_HIGHEST; 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp, 157362306a36Sopenharmony_ci struct pg_help_data *help_data, 157462306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 157562306a36Sopenharmony_ci struct cos_help_data *cos_data, 157662306a36Sopenharmony_ci u32 *pg_pri_orginal_spread, 157762306a36Sopenharmony_ci u32 pri_join_mask, 157862306a36Sopenharmony_ci u8 num_of_dif_pri) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci /* default E2 settings */ 158162306a36Sopenharmony_ci cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci switch (help_data->num_of_pg) { 158462306a36Sopenharmony_ci case 1: 158562306a36Sopenharmony_ci bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params( 158662306a36Sopenharmony_ci bp, 158762306a36Sopenharmony_ci help_data, 158862306a36Sopenharmony_ci cos_data, 158962306a36Sopenharmony_ci pri_join_mask, 159062306a36Sopenharmony_ci num_of_dif_pri); 159162306a36Sopenharmony_ci break; 159262306a36Sopenharmony_ci case 2: 159362306a36Sopenharmony_ci bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params( 159462306a36Sopenharmony_ci bp, 159562306a36Sopenharmony_ci help_data, 159662306a36Sopenharmony_ci ets, 159762306a36Sopenharmony_ci cos_data, 159862306a36Sopenharmony_ci pg_pri_orginal_spread, 159962306a36Sopenharmony_ci pri_join_mask, 160062306a36Sopenharmony_ci num_of_dif_pri); 160162306a36Sopenharmony_ci break; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci case 3: 160462306a36Sopenharmony_ci bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params( 160562306a36Sopenharmony_ci bp, 160662306a36Sopenharmony_ci help_data, 160762306a36Sopenharmony_ci ets, 160862306a36Sopenharmony_ci cos_data, 160962306a36Sopenharmony_ci pg_pri_orginal_spread, 161062306a36Sopenharmony_ci pri_join_mask, 161162306a36Sopenharmony_ci num_of_dif_pri); 161262306a36Sopenharmony_ci break; 161362306a36Sopenharmony_ci default: 161462306a36Sopenharmony_ci BNX2X_ERR("Wrong pg_help_data.num_of_pg\n"); 161562306a36Sopenharmony_ci bnx2x_dcbx_ets_disabled_entry_data(bp, 161662306a36Sopenharmony_ci cos_data, pri_join_mask); 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp, 162162306a36Sopenharmony_ci struct cos_help_data *cos_data, 162262306a36Sopenharmony_ci u8 entry, 162362306a36Sopenharmony_ci u8 num_spread_of_entries, 162462306a36Sopenharmony_ci u8 strict_app_pris) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST; 162762306a36Sopenharmony_ci u8 num_of_app_pri = MAX_PFC_PRIORITIES; 162862306a36Sopenharmony_ci u8 app_pri_bit = 0; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci while (num_spread_of_entries && num_of_app_pri > 0) { 163162306a36Sopenharmony_ci app_pri_bit = 1 << (num_of_app_pri - 1); 163262306a36Sopenharmony_ci if (app_pri_bit & strict_app_pris) { 163362306a36Sopenharmony_ci struct cos_entry_help_data *data = &cos_data-> 163462306a36Sopenharmony_ci data[entry]; 163562306a36Sopenharmony_ci num_spread_of_entries--; 163662306a36Sopenharmony_ci if (num_spread_of_entries == 0) { 163762306a36Sopenharmony_ci /* last entry needed put all the entries left */ 163862306a36Sopenharmony_ci data->cos_bw = DCBX_INVALID_COS_BW; 163962306a36Sopenharmony_ci data->strict = strict_pri; 164062306a36Sopenharmony_ci data->pri_join_mask = strict_app_pris; 164162306a36Sopenharmony_ci data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, 164262306a36Sopenharmony_ci data->pri_join_mask); 164362306a36Sopenharmony_ci } else { 164462306a36Sopenharmony_ci strict_app_pris &= ~app_pri_bit; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci data->cos_bw = DCBX_INVALID_COS_BW; 164762306a36Sopenharmony_ci data->strict = strict_pri; 164862306a36Sopenharmony_ci data->pri_join_mask = app_pri_bit; 164962306a36Sopenharmony_ci data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, 165062306a36Sopenharmony_ci data->pri_join_mask); 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci strict_pri = 165462306a36Sopenharmony_ci BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(strict_pri); 165562306a36Sopenharmony_ci entry++; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci num_of_app_pri--; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (num_spread_of_entries) { 166262306a36Sopenharmony_ci BNX2X_ERR("Didn't succeed to spread strict priorities\n"); 166362306a36Sopenharmony_ci return -EINVAL; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci return 0; 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp, 167062306a36Sopenharmony_ci struct cos_help_data *cos_data, 167162306a36Sopenharmony_ci u8 entry, 167262306a36Sopenharmony_ci u8 num_spread_of_entries, 167362306a36Sopenharmony_ci u8 strict_app_pris) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry, 167662306a36Sopenharmony_ci num_spread_of_entries, 167762306a36Sopenharmony_ci strict_app_pris)) { 167862306a36Sopenharmony_ci struct cos_entry_help_data *data = &cos_data-> 167962306a36Sopenharmony_ci data[entry]; 168062306a36Sopenharmony_ci /* Fill BW entry */ 168162306a36Sopenharmony_ci data->cos_bw = DCBX_INVALID_COS_BW; 168262306a36Sopenharmony_ci data->strict = BNX2X_DCBX_STRICT_COS_HIGHEST; 168362306a36Sopenharmony_ci data->pri_join_mask = strict_app_pris; 168462306a36Sopenharmony_ci data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, 168562306a36Sopenharmony_ci data->pri_join_mask); 168662306a36Sopenharmony_ci return 1; 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci return num_spread_of_entries; 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_cistatic void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp, 169362306a36Sopenharmony_ci struct pg_help_data *help_data, 169462306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 169562306a36Sopenharmony_ci struct cos_help_data *cos_data, 169662306a36Sopenharmony_ci u32 pri_join_mask) 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci u8 need_num_of_entries = 0; 170062306a36Sopenharmony_ci u8 i = 0; 170162306a36Sopenharmony_ci u8 entry = 0; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci /* 170462306a36Sopenharmony_ci * if the number of requested PG-s in CEE is greater than 3 170562306a36Sopenharmony_ci * then the results are not determined since this is a violation 170662306a36Sopenharmony_ci * of the standard. 170762306a36Sopenharmony_ci */ 170862306a36Sopenharmony_ci if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) { 170962306a36Sopenharmony_ci if (bnx2x_dcbx_join_pgs(bp, ets, help_data, 171062306a36Sopenharmony_ci DCBX_COS_MAX_NUM_E3B0)) { 171162306a36Sopenharmony_ci BNX2X_ERR("Unable to reduce the number of PGs - we will disables ETS\n"); 171262306a36Sopenharmony_ci bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, 171362306a36Sopenharmony_ci pri_join_mask); 171462306a36Sopenharmony_ci return; 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci for (i = 0 ; i < help_data->num_of_pg; i++) { 171962306a36Sopenharmony_ci struct pg_entry_help_data *pg = &help_data->data[i]; 172062306a36Sopenharmony_ci if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) { 172162306a36Sopenharmony_ci struct cos_entry_help_data *data = &cos_data-> 172262306a36Sopenharmony_ci data[entry]; 172362306a36Sopenharmony_ci /* Fill BW entry */ 172462306a36Sopenharmony_ci data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg); 172562306a36Sopenharmony_ci data->strict = BNX2X_DCBX_STRICT_INVALID; 172662306a36Sopenharmony_ci data->pri_join_mask = pg->pg_priority; 172762306a36Sopenharmony_ci data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, 172862306a36Sopenharmony_ci data->pri_join_mask); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci entry++; 173162306a36Sopenharmony_ci } else { 173262306a36Sopenharmony_ci need_num_of_entries = min_t(u8, 173362306a36Sopenharmony_ci (u8)pg->num_of_dif_pri, 173462306a36Sopenharmony_ci (u8)DCBX_COS_MAX_NUM_E3B0 - 173562306a36Sopenharmony_ci help_data->num_of_pg + 1); 173662306a36Sopenharmony_ci /* 173762306a36Sopenharmony_ci * If there are still VOQ-s which have no associated PG, 173862306a36Sopenharmony_ci * then associate these VOQ-s to PG15. These PG-s will 173962306a36Sopenharmony_ci * be used for SP between priorities on PG15. 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_ci entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data, 174262306a36Sopenharmony_ci entry, need_num_of_entries, pg->pg_priority); 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci /* the entry will represent the number of COSes used */ 174762306a36Sopenharmony_ci cos_data->num_of_cos = entry; 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_cistatic void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, 175062306a36Sopenharmony_ci struct pg_help_data *help_data, 175162306a36Sopenharmony_ci struct dcbx_ets_feature *ets, 175262306a36Sopenharmony_ci u32 *pg_pri_orginal_spread) 175362306a36Sopenharmony_ci{ 175462306a36Sopenharmony_ci struct cos_help_data cos_data; 175562306a36Sopenharmony_ci u8 i = 0; 175662306a36Sopenharmony_ci u32 pri_join_mask = 0; 175762306a36Sopenharmony_ci u8 num_of_dif_pri = 0; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci memset(&cos_data, 0, sizeof(cos_data)); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* Validate the pg value */ 176262306a36Sopenharmony_ci for (i = 0; i < help_data->num_of_pg ; i++) { 176362306a36Sopenharmony_ci if (DCBX_STRICT_PRIORITY != help_data->data[i].pg && 176462306a36Sopenharmony_ci DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg) 176562306a36Sopenharmony_ci BNX2X_ERR("Invalid pg[%d] data %x\n", i, 176662306a36Sopenharmony_ci help_data->data[i].pg); 176762306a36Sopenharmony_ci pri_join_mask |= help_data->data[i].pg_priority; 176862306a36Sopenharmony_ci num_of_dif_pri += help_data->data[i].num_of_dif_pri; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* defaults */ 177262306a36Sopenharmony_ci cos_data.num_of_cos = 1; 177362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) { 177462306a36Sopenharmony_ci cos_data.data[i].pri_join_mask = 0; 177562306a36Sopenharmony_ci cos_data.data[i].pausable = false; 177662306a36Sopenharmony_ci cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID; 177762306a36Sopenharmony_ci cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (CHIP_IS_E3B0(bp)) 178162306a36Sopenharmony_ci bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets, 178262306a36Sopenharmony_ci &cos_data, pri_join_mask); 178362306a36Sopenharmony_ci else /* E2 + E3A0 */ 178462306a36Sopenharmony_ci bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp, 178562306a36Sopenharmony_ci help_data, ets, 178662306a36Sopenharmony_ci &cos_data, 178762306a36Sopenharmony_ci pg_pri_orginal_spread, 178862306a36Sopenharmony_ci pri_join_mask, 178962306a36Sopenharmony_ci num_of_dif_pri); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci for (i = 0; i < cos_data.num_of_cos ; i++) { 179262306a36Sopenharmony_ci struct bnx2x_dcbx_cos_params *p = 179362306a36Sopenharmony_ci &bp->dcbx_port_params.ets.cos_params[i]; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci p->strict = cos_data.data[i].strict; 179662306a36Sopenharmony_ci p->bw_tbl = cos_data.data[i].cos_bw; 179762306a36Sopenharmony_ci p->pri_bitmask = cos_data.data[i].pri_join_mask; 179862306a36Sopenharmony_ci p->pauseable = cos_data.data[i].pausable; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* sanity */ 180162306a36Sopenharmony_ci if (p->bw_tbl != DCBX_INVALID_COS_BW || 180262306a36Sopenharmony_ci p->strict != BNX2X_DCBX_STRICT_INVALID) { 180362306a36Sopenharmony_ci if (p->pri_bitmask == 0) 180462306a36Sopenharmony_ci BNX2X_ERR("Invalid pri_bitmask for %d\n", i); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) { 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (p->pauseable && 180962306a36Sopenharmony_ci DCBX_PFC_PRI_GET_NON_PAUSE(bp, 181062306a36Sopenharmony_ci p->pri_bitmask) != 0) 181162306a36Sopenharmony_ci BNX2X_ERR("Inconsistent config for pausable COS %d\n", 181262306a36Sopenharmony_ci i); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (!p->pauseable && 181562306a36Sopenharmony_ci DCBX_PFC_PRI_GET_PAUSE(bp, 181662306a36Sopenharmony_ci p->pri_bitmask) != 0) 181762306a36Sopenharmony_ci BNX2X_ERR("Inconsistent config for nonpausable COS %d\n", 181862306a36Sopenharmony_ci i); 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci if (p->pauseable) 182362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "COS %d PAUSABLE prijoinmask 0x%x\n", 182462306a36Sopenharmony_ci i, cos_data.data[i].pri_join_mask); 182562306a36Sopenharmony_ci else 182662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, 182762306a36Sopenharmony_ci "COS %d NONPAUSABLE prijoinmask 0x%x\n", 182862306a36Sopenharmony_ci i, cos_data.data[i].pri_join_mask); 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ; 183262306a36Sopenharmony_ci} 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_cistatic void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, 183562306a36Sopenharmony_ci u32 *set_configuration_ets_pg, 183662306a36Sopenharmony_ci u32 *pri_pg_tbl) 183762306a36Sopenharmony_ci{ 183862306a36Sopenharmony_ci int i; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { 184162306a36Sopenharmony_ci set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "set_configuration_ets_pg[%d] = 0x%x\n", 184462306a36Sopenharmony_ci i, set_configuration_ets_pg[i]); 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic void bnx2x_dcbx_fw_struct(struct bnx2x *bp, 184962306a36Sopenharmony_ci struct bnx2x_func_tx_start_params *pfc_fw_cfg) 185062306a36Sopenharmony_ci{ 185162306a36Sopenharmony_ci u16 pri_bit = 0; 185262306a36Sopenharmony_ci u8 cos = 0, pri = 0; 185362306a36Sopenharmony_ci struct priority_cos *tt2cos; 185462306a36Sopenharmony_ci u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; 185562306a36Sopenharmony_ci int mfw_configured = SHMEM2_HAS(bp, drv_flags) && 185662306a36Sopenharmony_ci GET_FLAGS(SHMEM2_RD(bp, drv_flags), 185762306a36Sopenharmony_ci 1 << DRV_FLAGS_DCB_MFW_CONFIGURED); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg)); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci /* to disable DCB - the structure must be zeroed */ 186262306a36Sopenharmony_ci if ((bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) && !mfw_configured) 186362306a36Sopenharmony_ci return; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /*shortcut*/ 186662306a36Sopenharmony_ci tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci /* Fw version should be incremented each update */ 186962306a36Sopenharmony_ci pfc_fw_cfg->dcb_version = ++bp->dcb_version; 187062306a36Sopenharmony_ci pfc_fw_cfg->dcb_enabled = 1; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci /* Fill priority parameters */ 187362306a36Sopenharmony_ci for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { 187462306a36Sopenharmony_ci tt2cos[pri].priority = ttp[pri]; 187562306a36Sopenharmony_ci pri_bit = 1 << tt2cos[pri].priority; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci /* Fill COS parameters based on COS calculated to 187862306a36Sopenharmony_ci * make it more general for future use */ 187962306a36Sopenharmony_ci for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) 188062306a36Sopenharmony_ci if (bp->dcbx_port_params.ets.cos_params[cos]. 188162306a36Sopenharmony_ci pri_bitmask & pri_bit) 188262306a36Sopenharmony_ci tt2cos[pri].cos = cos; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci pfc_fw_cfg->dcb_outer_pri[pri] = ttp[pri]; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* we never want the FW to add a 0 vlan tag */ 188862306a36Sopenharmony_ci pfc_fw_cfg->dont_add_pri_0_en = 1; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg); 189162306a36Sopenharmony_ci} 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_civoid bnx2x_dcbx_pmf_update(struct bnx2x *bp) 189462306a36Sopenharmony_ci{ 189562306a36Sopenharmony_ci /* if we need to synchronize DCBX result from prev PMF 189662306a36Sopenharmony_ci * read it from shmem and update bp and netdev accordingly 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_ci if (SHMEM2_HAS(bp, drv_flags) && 189962306a36Sopenharmony_ci GET_FLAGS(SHMEM2_RD(bp, drv_flags), 1 << DRV_FLAGS_DCB_CONFIGURED)) { 190062306a36Sopenharmony_ci /* Read neg results if dcbx is in the FW */ 190162306a36Sopenharmony_ci if (bnx2x_dcbx_read_shmem_neg_results(bp)) 190262306a36Sopenharmony_ci return; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat, 190562306a36Sopenharmony_ci bp->dcbx_error); 190662306a36Sopenharmony_ci bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat, 190762306a36Sopenharmony_ci bp->dcbx_error); 190862306a36Sopenharmony_ci#ifdef BCM_DCBNL 190962306a36Sopenharmony_ci /* 191062306a36Sopenharmony_ci * Add new app tlvs to dcbnl 191162306a36Sopenharmony_ci */ 191262306a36Sopenharmony_ci bnx2x_dcbnl_update_applist(bp, false); 191362306a36Sopenharmony_ci /* 191462306a36Sopenharmony_ci * Send a notification for the new negotiated parameters 191562306a36Sopenharmony_ci */ 191662306a36Sopenharmony_ci dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0); 191762306a36Sopenharmony_ci#endif 191862306a36Sopenharmony_ci /* 191962306a36Sopenharmony_ci * reconfigure the netdevice with the results of the new 192062306a36Sopenharmony_ci * dcbx negotiation. 192162306a36Sopenharmony_ci */ 192262306a36Sopenharmony_ci bnx2x_dcbx_update_tc_mapping(bp); 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci/* DCB netlink */ 192762306a36Sopenharmony_ci#ifdef BCM_DCBNL 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci#define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \ 193062306a36Sopenharmony_ci DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC) 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci /* validate dcbnl call that may change HW state: 193562306a36Sopenharmony_ci * DCB is on and DCBX mode was SUCCESSFULLY set by the user. 193662306a36Sopenharmony_ci */ 193762306a36Sopenharmony_ci return bp->dcb_state && bp->dcbx_mode_uset; 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_get_state(struct net_device *netdev) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 194362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcb_state); 194462306a36Sopenharmony_ci return bp->dcb_state; 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state) 194862306a36Sopenharmony_ci{ 194962306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 195062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off"); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci /* Fail to set state to "enabled" if dcbx is disabled in nvram */ 195362306a36Sopenharmony_ci if (state && ((bp->dcbx_enabled == BNX2X_DCBX_ENABLED_OFF) || 195462306a36Sopenharmony_ci (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_INVALID))) { 195562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Can not set dcbx to enabled while it is disabled in nvm\n"); 195662306a36Sopenharmony_ci return 1; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled); 196062306a36Sopenharmony_ci return 0; 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev, 196462306a36Sopenharmony_ci u8 *perm_addr) 196562306a36Sopenharmony_ci{ 196662306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 196762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "GET-PERM-ADDR\n"); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci /* first the HW mac address */ 197062306a36Sopenharmony_ci memcpy(perm_addr, netdev->dev_addr, netdev->addr_len); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci if (CNIC_LOADED(bp)) 197362306a36Sopenharmony_ci /* second SAN address */ 197462306a36Sopenharmony_ci memcpy(perm_addr+netdev->addr_len, bp->fip_mac, 197562306a36Sopenharmony_ci netdev->addr_len); 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio, 197962306a36Sopenharmony_ci u8 prio_type, u8 pgid, u8 bw_pct, 198062306a36Sopenharmony_ci u8 up_map) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, pgid); 198562306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) 198662306a36Sopenharmony_ci return; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci /** 198962306a36Sopenharmony_ci * bw_pct ignored - band-width percentage devision between user 199062306a36Sopenharmony_ci * priorities within the same group is not 199162306a36Sopenharmony_ci * standard and hence not supported 199262306a36Sopenharmony_ci * 199362306a36Sopenharmony_ci * prio_type ignored - priority levels within the same group are not 199462306a36Sopenharmony_ci * standard and hence are not supported. According 199562306a36Sopenharmony_ci * to the standard pgid 15 is dedicated to strict 199662306a36Sopenharmony_ci * priority traffic (on the port level). 199762306a36Sopenharmony_ci * 199862306a36Sopenharmony_ci * up_map ignored 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid; 200262306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev, 200662306a36Sopenharmony_ci int pgid, u8 bw_pct) 200762306a36Sopenharmony_ci{ 200862306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 200962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "pgid[%d] = %d\n", pgid, bw_pct); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) 201262306a36Sopenharmony_ci return; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct; 201562306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio, 201962306a36Sopenharmony_ci u8 prio_type, u8 pgid, u8 bw_pct, 202062306a36Sopenharmony_ci u8 up_map) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 202362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n"); 202462306a36Sopenharmony_ci} 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev, 202762306a36Sopenharmony_ci int pgid, u8 bw_pct) 202862306a36Sopenharmony_ci{ 202962306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 203062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Nothing to set; No RX support\n"); 203162306a36Sopenharmony_ci} 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio, 203462306a36Sopenharmony_ci u8 *prio_type, u8 *pgid, u8 *bw_pct, 203562306a36Sopenharmony_ci u8 *up_map) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 203862306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "prio = %d\n", prio); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /** 204162306a36Sopenharmony_ci * bw_pct ignored - band-width percentage devision between user 204262306a36Sopenharmony_ci * priorities within the same group is not 204362306a36Sopenharmony_ci * standard and hence not supported 204462306a36Sopenharmony_ci * 204562306a36Sopenharmony_ci * prio_type ignored - priority levels within the same group are not 204662306a36Sopenharmony_ci * standard and hence are not supported. According 204762306a36Sopenharmony_ci * to the standard pgid 15 is dedicated to strict 204862306a36Sopenharmony_ci * priority traffic (on the port level). 204962306a36Sopenharmony_ci * 205062306a36Sopenharmony_ci * up_map ignored 205162306a36Sopenharmony_ci */ 205262306a36Sopenharmony_ci *up_map = *bw_pct = *prio_type = *pgid = 0; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) 205562306a36Sopenharmony_ci return; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio); 205862306a36Sopenharmony_ci} 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev, 206162306a36Sopenharmony_ci int pgid, u8 *bw_pct) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 206462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "pgid = %d\n", pgid); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci *bw_pct = 0; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) 206962306a36Sopenharmony_ci return; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid); 207262306a36Sopenharmony_ci} 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio, 207562306a36Sopenharmony_ci u8 *prio_type, u8 *pgid, u8 *bw_pct, 207662306a36Sopenharmony_ci u8 *up_map) 207762306a36Sopenharmony_ci{ 207862306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 207962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n"); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci *prio_type = *pgid = *bw_pct = *up_map = 0; 208262306a36Sopenharmony_ci} 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev, 208562306a36Sopenharmony_ci int pgid, u8 *bw_pct) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 208862306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Nothing to get; No RX support\n"); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci *bw_pct = 0; 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, 209462306a36Sopenharmony_ci u8 setting) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 209762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "prio[%d] = %d\n", prio, setting); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES) 210062306a36Sopenharmony_ci return; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (setting) { 210362306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_bitmap |= (1 << prio); 210462306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_tx_enable = 1; 210562306a36Sopenharmony_ci } else { 210662306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_bitmap &= ~(1 << prio); 210762306a36Sopenharmony_ci } 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_cistatic void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, 211162306a36Sopenharmony_ci u8 *setting) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 211462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "prio = %d\n", prio); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci *setting = 0; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES) 211962306a36Sopenharmony_ci return; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1; 212262306a36Sopenharmony_ci} 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_set_all(struct net_device *netdev) 212562306a36Sopenharmony_ci{ 212662306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "SET-ALL\n"); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp)) 213162306a36Sopenharmony_ci return 1; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci if (bp->recovery_state != BNX2X_RECOVERY_DONE) { 213462306a36Sopenharmony_ci netdev_err(bp->dev, 213562306a36Sopenharmony_ci "Handling parity error recovery. Try again later\n"); 213662306a36Sopenharmony_ci return 1; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci if (netif_running(bp->dev)) { 213962306a36Sopenharmony_ci bnx2x_update_drv_flags(bp, 214062306a36Sopenharmony_ci 1 << DRV_FLAGS_DCB_MFW_CONFIGURED, 214162306a36Sopenharmony_ci 1); 214262306a36Sopenharmony_ci bnx2x_dcbx_init(bp, true); 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "set_dcbx_params done\n"); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci return 0; 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 215262306a36Sopenharmony_ci u8 rval = 0; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci if (bp->dcb_state) { 215562306a36Sopenharmony_ci switch (capid) { 215662306a36Sopenharmony_ci case DCB_CAP_ATTR_PG: 215762306a36Sopenharmony_ci *cap = true; 215862306a36Sopenharmony_ci break; 215962306a36Sopenharmony_ci case DCB_CAP_ATTR_PFC: 216062306a36Sopenharmony_ci *cap = true; 216162306a36Sopenharmony_ci break; 216262306a36Sopenharmony_ci case DCB_CAP_ATTR_UP2TC: 216362306a36Sopenharmony_ci *cap = false; 216462306a36Sopenharmony_ci break; 216562306a36Sopenharmony_ci case DCB_CAP_ATTR_PG_TCS: 216662306a36Sopenharmony_ci *cap = 0x80; /* 8 priorities for PGs */ 216762306a36Sopenharmony_ci break; 216862306a36Sopenharmony_ci case DCB_CAP_ATTR_PFC_TCS: 216962306a36Sopenharmony_ci *cap = 0x80; /* 8 priorities for PFC */ 217062306a36Sopenharmony_ci break; 217162306a36Sopenharmony_ci case DCB_CAP_ATTR_GSP: 217262306a36Sopenharmony_ci *cap = true; 217362306a36Sopenharmony_ci break; 217462306a36Sopenharmony_ci case DCB_CAP_ATTR_BCN: 217562306a36Sopenharmony_ci *cap = false; 217662306a36Sopenharmony_ci break; 217762306a36Sopenharmony_ci case DCB_CAP_ATTR_DCBX: 217862306a36Sopenharmony_ci *cap = BNX2X_DCBX_CAPS; 217962306a36Sopenharmony_ci break; 218062306a36Sopenharmony_ci default: 218162306a36Sopenharmony_ci BNX2X_ERR("Non valid capability ID\n"); 218262306a36Sopenharmony_ci rval = 1; 218362306a36Sopenharmony_ci break; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci } else { 218662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCB disabled\n"); 218762306a36Sopenharmony_ci rval = 1; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap); 219162306a36Sopenharmony_ci return rval; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 219762306a36Sopenharmony_ci u8 rval = 0; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "tcid %d\n", tcid); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci if (bp->dcb_state) { 220262306a36Sopenharmony_ci switch (tcid) { 220362306a36Sopenharmony_ci case DCB_NUMTCS_ATTR_PG: 220462306a36Sopenharmony_ci *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 : 220562306a36Sopenharmony_ci DCBX_COS_MAX_NUM_E2; 220662306a36Sopenharmony_ci break; 220762306a36Sopenharmony_ci case DCB_NUMTCS_ATTR_PFC: 220862306a36Sopenharmony_ci *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 : 220962306a36Sopenharmony_ci DCBX_COS_MAX_NUM_E2; 221062306a36Sopenharmony_ci break; 221162306a36Sopenharmony_ci default: 221262306a36Sopenharmony_ci BNX2X_ERR("Non valid TC-ID\n"); 221362306a36Sopenharmony_ci rval = 1; 221462306a36Sopenharmony_ci break; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci } else { 221762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCB disabled\n"); 221862306a36Sopenharmony_ci rval = 1; 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci return rval; 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cistatic int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num) 222562306a36Sopenharmony_ci{ 222662306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 222762306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "num tcs = %d; Not supported\n", num); 222862306a36Sopenharmony_ci return -EINVAL; 222962306a36Sopenharmony_ci} 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) 223262306a36Sopenharmony_ci{ 223362306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 223462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (!bp->dcb_state) 223762306a36Sopenharmony_ci return 0; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci return bp->dcbx_local_feat.pfc.enabled; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 224562306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off"); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp)) 224862306a36Sopenharmony_ci return; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_tx_enable = 225162306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0); 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_cistatic void bnx2x_admin_app_set_ent( 225562306a36Sopenharmony_ci struct bnx2x_admin_priority_app_table *app_ent, 225662306a36Sopenharmony_ci u8 idtype, u16 idval, u8 up) 225762306a36Sopenharmony_ci{ 225862306a36Sopenharmony_ci app_ent->valid = 1; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci switch (idtype) { 226162306a36Sopenharmony_ci case DCB_APP_IDTYPE_ETHTYPE: 226262306a36Sopenharmony_ci app_ent->traffic_type = TRAFFIC_TYPE_ETH; 226362306a36Sopenharmony_ci break; 226462306a36Sopenharmony_ci case DCB_APP_IDTYPE_PORTNUM: 226562306a36Sopenharmony_ci app_ent->traffic_type = TRAFFIC_TYPE_PORT; 226662306a36Sopenharmony_ci break; 226762306a36Sopenharmony_ci default: 226862306a36Sopenharmony_ci break; /* never gets here */ 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci app_ent->app_id = idval; 227162306a36Sopenharmony_ci app_ent->priority = up; 227262306a36Sopenharmony_ci} 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_cistatic bool bnx2x_admin_app_is_equal( 227562306a36Sopenharmony_ci struct bnx2x_admin_priority_app_table *app_ent, 227662306a36Sopenharmony_ci u8 idtype, u16 idval) 227762306a36Sopenharmony_ci{ 227862306a36Sopenharmony_ci if (!app_ent->valid) 227962306a36Sopenharmony_ci return false; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci switch (idtype) { 228262306a36Sopenharmony_ci case DCB_APP_IDTYPE_ETHTYPE: 228362306a36Sopenharmony_ci if (app_ent->traffic_type != TRAFFIC_TYPE_ETH) 228462306a36Sopenharmony_ci return false; 228562306a36Sopenharmony_ci break; 228662306a36Sopenharmony_ci case DCB_APP_IDTYPE_PORTNUM: 228762306a36Sopenharmony_ci if (app_ent->traffic_type != TRAFFIC_TYPE_PORT) 228862306a36Sopenharmony_ci return false; 228962306a36Sopenharmony_ci break; 229062306a36Sopenharmony_ci default: 229162306a36Sopenharmony_ci return false; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci if (app_ent->app_id != idval) 229462306a36Sopenharmony_ci return false; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci return true; 229762306a36Sopenharmony_ci} 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_cistatic int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up) 230062306a36Sopenharmony_ci{ 230162306a36Sopenharmony_ci int i, ff; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* iterate over the app entries looking for idtype and idval */ 230462306a36Sopenharmony_ci for (i = 0, ff = -1; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) { 230562306a36Sopenharmony_ci struct bnx2x_admin_priority_app_table *app_ent = 230662306a36Sopenharmony_ci &bp->dcbx_config_params.admin_priority_app_table[i]; 230762306a36Sopenharmony_ci if (bnx2x_admin_app_is_equal(app_ent, idtype, idval)) 230862306a36Sopenharmony_ci break; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci if (ff < 0 && !app_ent->valid) 231162306a36Sopenharmony_ci ff = i; 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci if (i < DCBX_CONFIG_MAX_APP_PROTOCOL) 231462306a36Sopenharmony_ci /* if found overwrite up */ 231562306a36Sopenharmony_ci bp->dcbx_config_params. 231662306a36Sopenharmony_ci admin_priority_app_table[i].priority = up; 231762306a36Sopenharmony_ci else if (ff >= 0) 231862306a36Sopenharmony_ci /* not found use first-free */ 231962306a36Sopenharmony_ci bnx2x_admin_app_set_ent( 232062306a36Sopenharmony_ci &bp->dcbx_config_params.admin_priority_app_table[ff], 232162306a36Sopenharmony_ci idtype, idval, up); 232262306a36Sopenharmony_ci else { 232362306a36Sopenharmony_ci /* app table is full */ 232462306a36Sopenharmony_ci BNX2X_ERR("Application table is too large\n"); 232562306a36Sopenharmony_ci return -EBUSY; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci /* up configured, if not 0 make sure feature is enabled */ 232962306a36Sopenharmony_ci if (up) 233062306a36Sopenharmony_ci bp->dcbx_config_params.admin_application_priority_tx_enable = 1; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci return 0; 233362306a36Sopenharmony_ci} 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_cistatic int bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype, 233662306a36Sopenharmony_ci u16 idval, u8 up) 233762306a36Sopenharmony_ci{ 233862306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "app_type %d, app_id %x, prio bitmap %d\n", 234162306a36Sopenharmony_ci idtype, idval, up); 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci if (!bnx2x_dcbnl_set_valid(bp)) { 234462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbnl call not valid\n"); 234562306a36Sopenharmony_ci return -EINVAL; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci /* verify idtype */ 234962306a36Sopenharmony_ci switch (idtype) { 235062306a36Sopenharmony_ci case DCB_APP_IDTYPE_ETHTYPE: 235162306a36Sopenharmony_ci case DCB_APP_IDTYPE_PORTNUM: 235262306a36Sopenharmony_ci break; 235362306a36Sopenharmony_ci default: 235462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "Wrong ID type\n"); 235562306a36Sopenharmony_ci return -EINVAL; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci return bnx2x_set_admin_app_up(bp, idtype, idval, up); 235862306a36Sopenharmony_ci} 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 236362306a36Sopenharmony_ci u8 state; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF) 236862306a36Sopenharmony_ci state |= DCB_CAP_DCBX_STATIC; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci return state; 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state) 237462306a36Sopenharmony_ci{ 237562306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 237662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "state = %02x\n", state); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci /* set dcbx mode */ 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci if ((state & BNX2X_DCBX_CAPS) != state) { 238162306a36Sopenharmony_ci BNX2X_ERR("Requested DCBX mode %x is beyond advertised capabilities\n", 238262306a36Sopenharmony_ci state); 238362306a36Sopenharmony_ci return 1; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (bp->dcb_state != BNX2X_DCB_STATE_ON) { 238762306a36Sopenharmony_ci BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n"); 238862306a36Sopenharmony_ci return 1; 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (state & DCB_CAP_DCBX_STATIC) 239262306a36Sopenharmony_ci bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF; 239362306a36Sopenharmony_ci else 239462306a36Sopenharmony_ci bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci bp->dcbx_mode_uset = true; 239762306a36Sopenharmony_ci return 0; 239862306a36Sopenharmony_ci} 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, 240162306a36Sopenharmony_ci u8 *flags) 240262306a36Sopenharmony_ci{ 240362306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 240462306a36Sopenharmony_ci u8 rval = 0; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "featid %d\n", featid); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (bp->dcb_state) { 240962306a36Sopenharmony_ci *flags = 0; 241062306a36Sopenharmony_ci switch (featid) { 241162306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_PG: 241262306a36Sopenharmony_ci if (bp->dcbx_local_feat.ets.enabled) 241362306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ENABLE; 241462306a36Sopenharmony_ci if (bp->dcbx_error & (DCBX_LOCAL_ETS_ERROR | 241562306a36Sopenharmony_ci DCBX_REMOTE_MIB_ERROR)) 241662306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ERROR; 241762306a36Sopenharmony_ci break; 241862306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_PFC: 241962306a36Sopenharmony_ci if (bp->dcbx_local_feat.pfc.enabled) 242062306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ENABLE; 242162306a36Sopenharmony_ci if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR | 242262306a36Sopenharmony_ci DCBX_LOCAL_PFC_MISMATCH | 242362306a36Sopenharmony_ci DCBX_REMOTE_MIB_ERROR)) 242462306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ERROR; 242562306a36Sopenharmony_ci break; 242662306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_APP: 242762306a36Sopenharmony_ci if (bp->dcbx_local_feat.app.enabled) 242862306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ENABLE; 242962306a36Sopenharmony_ci if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR | 243062306a36Sopenharmony_ci DCBX_LOCAL_APP_MISMATCH | 243162306a36Sopenharmony_ci DCBX_REMOTE_MIB_ERROR)) 243262306a36Sopenharmony_ci *flags |= DCB_FEATCFG_ERROR; 243362306a36Sopenharmony_ci break; 243462306a36Sopenharmony_ci default: 243562306a36Sopenharmony_ci BNX2X_ERR("Non valid feature-ID\n"); 243662306a36Sopenharmony_ci rval = 1; 243762306a36Sopenharmony_ci break; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci } else { 244062306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "DCB disabled\n"); 244162306a36Sopenharmony_ci rval = 1; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci return rval; 244562306a36Sopenharmony_ci} 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_cistatic u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, 244862306a36Sopenharmony_ci u8 flags) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 245162306a36Sopenharmony_ci u8 rval = 0; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "featid = %d flags = %02x\n", featid, flags); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci /* ignore the 'advertise' flag */ 245662306a36Sopenharmony_ci if (bnx2x_dcbnl_set_valid(bp)) { 245762306a36Sopenharmony_ci switch (featid) { 245862306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_PG: 245962306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_enable = 246062306a36Sopenharmony_ci flags & DCB_FEATCFG_ENABLE ? 1 : 0; 246162306a36Sopenharmony_ci bp->dcbx_config_params.admin_ets_willing = 246262306a36Sopenharmony_ci flags & DCB_FEATCFG_WILLING ? 1 : 0; 246362306a36Sopenharmony_ci break; 246462306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_PFC: 246562306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_enable = 246662306a36Sopenharmony_ci flags & DCB_FEATCFG_ENABLE ? 1 : 0; 246762306a36Sopenharmony_ci bp->dcbx_config_params.admin_pfc_willing = 246862306a36Sopenharmony_ci flags & DCB_FEATCFG_WILLING ? 1 : 0; 246962306a36Sopenharmony_ci break; 247062306a36Sopenharmony_ci case DCB_FEATCFG_ATTR_APP: 247162306a36Sopenharmony_ci /* ignore enable, always enabled */ 247262306a36Sopenharmony_ci bp->dcbx_config_params.admin_app_priority_willing = 247362306a36Sopenharmony_ci flags & DCB_FEATCFG_WILLING ? 1 : 0; 247462306a36Sopenharmony_ci break; 247562306a36Sopenharmony_ci default: 247662306a36Sopenharmony_ci BNX2X_ERR("Non valid feature-ID\n"); 247762306a36Sopenharmony_ci rval = 1; 247862306a36Sopenharmony_ci break; 247962306a36Sopenharmony_ci } 248062306a36Sopenharmony_ci } else { 248162306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "dcbnl call not valid\n"); 248262306a36Sopenharmony_ci rval = 1; 248362306a36Sopenharmony_ci } 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci return rval; 248662306a36Sopenharmony_ci} 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_cistatic int bnx2x_peer_appinfo(struct net_device *netdev, 248962306a36Sopenharmony_ci struct dcb_peer_app_info *info, u16* app_count) 249062306a36Sopenharmony_ci{ 249162306a36Sopenharmony_ci int i; 249262306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "APP-INFO\n"); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0; 249762306a36Sopenharmony_ci info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0; 249862306a36Sopenharmony_ci *app_count = 0; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) 250162306a36Sopenharmony_ci if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield & 250262306a36Sopenharmony_ci DCBX_APP_ENTRY_VALID) 250362306a36Sopenharmony_ci (*app_count)++; 250462306a36Sopenharmony_ci return 0; 250562306a36Sopenharmony_ci} 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_cistatic int bnx2x_peer_apptable(struct net_device *netdev, 250862306a36Sopenharmony_ci struct dcb_app *table) 250962306a36Sopenharmony_ci{ 251062306a36Sopenharmony_ci int i, j; 251162306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci DP(BNX2X_MSG_DCB, "APP-TABLE\n"); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { 251662306a36Sopenharmony_ci struct dcbx_app_priority_entry *ent = 251762306a36Sopenharmony_ci &bp->dcbx_remote_feat.app.app_pri_tbl[i]; 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { 252062306a36Sopenharmony_ci table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent); 252162306a36Sopenharmony_ci table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent); 252262306a36Sopenharmony_ci table[j++].protocol = ent->app_id; 252362306a36Sopenharmony_ci } 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci return 0; 252662306a36Sopenharmony_ci} 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_cistatic int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg) 252962306a36Sopenharmony_ci{ 253062306a36Sopenharmony_ci int i; 253162306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { 253662306a36Sopenharmony_ci pg->pg_bw[i] = 253762306a36Sopenharmony_ci DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i); 253862306a36Sopenharmony_ci pg->prio_pg[i] = 253962306a36Sopenharmony_ci DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i); 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci return 0; 254262306a36Sopenharmony_ci} 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_cistatic int bnx2x_cee_peer_getpfc(struct net_device *netdev, 254562306a36Sopenharmony_ci struct cee_pfc *pfc) 254662306a36Sopenharmony_ci{ 254762306a36Sopenharmony_ci struct bnx2x *bp = netdev_priv(netdev); 254862306a36Sopenharmony_ci pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps; 254962306a36Sopenharmony_ci pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap; 255062306a36Sopenharmony_ci return 0; 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ciconst struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = { 255462306a36Sopenharmony_ci .getstate = bnx2x_dcbnl_get_state, 255562306a36Sopenharmony_ci .setstate = bnx2x_dcbnl_set_state, 255662306a36Sopenharmony_ci .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, 255762306a36Sopenharmony_ci .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, 255862306a36Sopenharmony_ci .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, 255962306a36Sopenharmony_ci .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, 256062306a36Sopenharmony_ci .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, 256162306a36Sopenharmony_ci .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, 256262306a36Sopenharmony_ci .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, 256362306a36Sopenharmony_ci .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, 256462306a36Sopenharmony_ci .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, 256562306a36Sopenharmony_ci .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, 256662306a36Sopenharmony_ci .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, 256762306a36Sopenharmony_ci .setall = bnx2x_dcbnl_set_all, 256862306a36Sopenharmony_ci .getcap = bnx2x_dcbnl_get_cap, 256962306a36Sopenharmony_ci .getnumtcs = bnx2x_dcbnl_get_numtcs, 257062306a36Sopenharmony_ci .setnumtcs = bnx2x_dcbnl_set_numtcs, 257162306a36Sopenharmony_ci .getpfcstate = bnx2x_dcbnl_get_pfc_state, 257262306a36Sopenharmony_ci .setpfcstate = bnx2x_dcbnl_set_pfc_state, 257362306a36Sopenharmony_ci .setapp = bnx2x_dcbnl_set_app_up, 257462306a36Sopenharmony_ci .getdcbx = bnx2x_dcbnl_get_dcbx, 257562306a36Sopenharmony_ci .setdcbx = bnx2x_dcbnl_set_dcbx, 257662306a36Sopenharmony_ci .getfeatcfg = bnx2x_dcbnl_get_featcfg, 257762306a36Sopenharmony_ci .setfeatcfg = bnx2x_dcbnl_set_featcfg, 257862306a36Sopenharmony_ci .peer_getappinfo = bnx2x_peer_appinfo, 257962306a36Sopenharmony_ci .peer_getapptable = bnx2x_peer_apptable, 258062306a36Sopenharmony_ci .cee_peer_getpg = bnx2x_cee_peer_getpg, 258162306a36Sopenharmony_ci .cee_peer_getpfc = bnx2x_cee_peer_getpfc, 258262306a36Sopenharmony_ci}; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci#endif /* BCM_DCBNL */ 2585