+}
+
+/******************************************************************/
+/* ETS section */
+/******************************************************************/
+static void elink_ets_e2e3a0_disabled(struct elink_params *params)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x_softc *sc = params->sc;
+
+ ELINK_DEBUG_P0(sc, "ETS E2E3 disabled configuration");
+
+ /* mapping between entry priority to client number (0,1,2 -debug and
+ * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
+ * 3bits client num.
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
+ */
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
+ /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries, 3 -
+ * COS0 entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
+ /* defines which entries (clients) are subjected to WFQ arbitration */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
+ /* For strict priority entries defines the number of consecutive
+ * slots for the highest priority.
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+ /* mapping between the CREDIT_WEIGHT registers and actual client
+ * numbers
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
+ REG_WR(sc, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
+ /* ETS mode disable */
+ REG_WR(sc, PBF_REG_ETS_ENABLED, 0);
+ /* If ETS mode is enabled (there is no strict priority) defines a WFQ
+ * weight for COS0/COS1.
+ */
+ REG_WR(sc, PBF_REG_COS0_WEIGHT, 0x2710);
+ REG_WR(sc, PBF_REG_COS1_WEIGHT, 0x2710);
+ /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
+ REG_WR(sc, PBF_REG_COS0_UPPER_BOUND, 0x989680);
+ REG_WR(sc, PBF_REG_COS1_UPPER_BOUND, 0x989680);
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(sc, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
+}
+/******************************************************************************
+ * Description:
+ * Getting min_w_val will be set according to line speed .
+ *.
+ ******************************************************************************/
+static uint32_t elink_ets_get_min_w_val_nig(const struct elink_vars *vars)
+{
+ uint32_t min_w_val = 0;
+ /* Calculate min_w_val.*/
+ if (vars->link_up) {
+ if (vars->line_speed == ELINK_SPEED_20000)
+ min_w_val = ELINK_ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
+ else
+ min_w_val = ELINK_ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS;
+ } else {
+ min_w_val = ELINK_ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
+ }
+ /* If the link isn't up (static configuration for example ) The
+ * link will be according to 20GBPS.
+ */
+ return min_w_val;
+}
+/******************************************************************************
+ * Description:
+ * Getting credit upper bound form min_w_val.
+ *.
+ ******************************************************************************/
+static uint32_t elink_ets_get_credit_upper_bound(const uint32_t min_w_val)
+{
+ const uint32_t credit_upper_bound = (uint32_t)
+ ELINK_MAXVAL((150 * min_w_val),
+ ELINK_MAX_PACKET_SIZE);
+ return credit_upper_bound;
+}
+/******************************************************************************
+ * Description:
+ * Set credit upper bound for NIG.
+ *.
+ ******************************************************************************/
+static void elink_ets_e3b0_set_credit_upper_bound_nig(
+ const struct elink_params *params,
+ const uint32_t min_w_val)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint8_t port = params->port;
+ const uint32_t credit_upper_bound =
+ elink_ets_get_credit_upper_bound(min_w_val);
+
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 :
+ NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5, credit_upper_bound);
+
+ if (!port) {
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6,
+ credit_upper_bound);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7,
+ credit_upper_bound);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8,
+ credit_upper_bound);
+ }
+}
+/******************************************************************************
+ * Description:
+ * Will return the NIG ETS registers to init values.Except
+ * credit_upper_bound.
+ * That isn't used in this configuration (No WFQ is enabled) and will be
+ * configured according to spec
+ *.
+ ******************************************************************************/
+static void elink_ets_e3b0_nig_disabled(const struct elink_params *params,
+ const struct elink_vars *vars)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint8_t port = params->port;
+ const uint32_t min_w_val = elink_ets_get_min_w_val_nig(vars);
+ /* Mapping between entry priority to client number (0,1,2 -debug and
+ * management clients, 3 - COS0 client, 4 - COS1, ... 8 -
+ * COS5)(HIGHEST) 4bits client num.TODO_ETS - Should be done by
+ * reset value or init tool
+ */
+ if (port) {
+ REG_WR(sc, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210);
+ REG_WR(sc, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0);
+ } else {
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, 0x8);
+ }
+ /* For strict priority entries defines the number of consecutive
+ * slots for the highest priority.
+ */
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS :
+ NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+ /* Mapping between the CREDIT_WEIGHT registers and actual client
+ * numbers
+ */
+ if (port) {
+ /*Port 1 has 6 COS*/
+ REG_WR(sc, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543);
+ REG_WR(sc, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0);
+ } else {
+ /*Port 0 has 9 COS*/
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB,
+ 0x43210876);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x5);
+ }
+
+ /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries, 3 -
+ * COS0 entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+ if (port)
+ REG_WR(sc, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f);
+ else
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff);
+ /* defines which entries (clients) are subjected to WFQ arbitration */
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
+ NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
+
+ /* Please notice the register address are note continuous and a
+ * for here is note appropriate.In 2 port mode port0 only COS0-5
+ * can be used. DEBUG1,DEBUG1,MGMT are never used for WFQ* In 4
+ * port mode port1 only COS0-2 can be used. DEBUG1,DEBUG1,MGMT
+ * are never used for WFQ
+ */
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0);
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0);
+ if (!port) {
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0);
+ }
+
+ elink_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val);
+}
+/******************************************************************************
+ * Description:
+ * Set credit upper bound for PBF.
+ *.
+ ******************************************************************************/
+static void elink_ets_e3b0_set_credit_upper_bound_pbf(
+ const struct elink_params *params,
+ const uint32_t min_w_val)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint32_t credit_upper_bound =
+ elink_ets_get_credit_upper_bound(min_w_val);
+ const uint8_t port = params->port;
+ uint32_t base_upper_bound = 0;
+ uint8_t max_cos = 0;
+ uint8_t i = 0;
+ /* In 2 port mode port0 has COS0-5 that can be used for WFQ.In 4
+ * port mode port1 has COS0-2 that can be used for WFQ.
+ */
+ if (!port) {
+ base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P0;
+ max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0;
+ } else {
+ base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1;
+ max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1;
+ }
+
+ for (i = 0; i < max_cos; i++)
+ REG_WR(sc, base_upper_bound + (i << 2), credit_upper_bound);
+}
+
+/******************************************************************************
+ * Description:
+ * Will return the PBF ETS registers to init values.Except
+ * credit_upper_bound.
+ * That isn't used in this configuration (No WFQ is enabled) and will be
+ * configured according to spec
+ *.
+ ******************************************************************************/
+static void elink_ets_e3b0_pbf_disabled(const struct elink_params *params)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint8_t port = params->port;
+ const uint32_t min_w_val_pbf = ELINK_ETS_E3B0_PBF_MIN_W_VAL;
+ uint8_t i = 0;
+ uint32_t base_weight = 0;
+ uint8_t max_cos = 0;
+
+ /* Mapping between entry priority to client number 0 - COS0
+ * client, 2 - COS1, ... 5 - COS5)(HIGHEST) 4bits client num.
+ * TODO_ETS - Should be done by reset value or init tool
+ */
+ if (port)
+ /* 0x688 (|011|0 10|00 1|000) */
+ REG_WR(sc, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1, 0x688);
+ else
+ /* (10 1|100 |011|0 10|00 1|000) */
+ REG_WR(sc, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0, 0x2C688);
+
+ /* TODO_ETS - Should be done by reset value or init tool */
+ if (port)
+ /* 0x688 (|011|0 10|00 1|000)*/
+ REG_WR(sc, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688);
+ else
+ /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */
+ REG_WR(sc, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688);
+
+ REG_WR(sc, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 :
+ PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0, 0x100);
+
+
+ REG_WR(sc, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
+ PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0, 0);
+
+ REG_WR(sc, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
+ PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0, 0);
+ /* In 2 port mode port0 has COS0-5 that can be used for WFQ.
+ * In 4 port mode port1 has COS0-2 that can be used for WFQ.
+ */
+ if (!port) {
+ base_weight = PBF_REG_COS0_WEIGHT_P0;
+ max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0;
+ } else {
+ base_weight = PBF_REG_COS0_WEIGHT_P1;
+ max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1;
+ }
+
+ for (i = 0; i < max_cos; i++)
+ REG_WR(sc, base_weight + (0x4 * i), 0);
+
+ elink_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
+}
+/******************************************************************************
+ * Description:
+ * E3B0 disable will return basically the values to init values.
+ *.
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_disabled(const struct elink_params *params,
+ const struct elink_vars *vars)
+{
+ struct bnx2x_softc *sc = params->sc;
+
+ if (!CHIP_IS_E3B0(sc)) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_disabled the chip isn't E3B0");
+ return ELINK_STATUS_ERROR;
+ }
+
+ elink_ets_e3b0_nig_disabled(params, vars);
+
+ elink_ets_e3b0_pbf_disabled(params);
+
+ return ELINK_STATUS_OK;
+}
+
+/******************************************************************************
+ * Description:
+ * Disable will return basically the values to init values.
+ *
+ ******************************************************************************/
+elink_status_t elink_ets_disabled(struct elink_params *params,
+ struct elink_vars *vars)
+{
+ struct bnx2x_softc *sc = params->sc;
+ elink_status_t elink_status = ELINK_STATUS_OK;
+
+ if ((CHIP_IS_E2(sc)) || (CHIP_IS_E3A0(sc))) {
+ elink_ets_e2e3a0_disabled(params);
+ } else if (CHIP_IS_E3B0(sc)) {
+ elink_status = elink_ets_e3b0_disabled(params, vars);
+ } else {
+ ELINK_DEBUG_P0(sc, "elink_ets_disabled - chip not supported");
+ return ELINK_STATUS_ERROR;
+ }
+
+ return elink_status;
+}
+
+/******************************************************************************
+ * Description
+ * Set the COS mapping to SP and BW until this point all the COS are not
+ * set as SP or BW.
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_cli_map(const struct elink_params *params,
+ __rte_unused const struct elink_ets_params *ets_params,
+ const uint8_t cos_sp_bitmap,
+ const uint8_t cos_bw_bitmap)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint8_t port = params->port;
+ const uint8_t nig_cli_sp_bitmap = 0x7 | (cos_sp_bitmap << 3);
+ const uint8_t pbf_cli_sp_bitmap = cos_sp_bitmap;
+ const uint8_t nig_cli_subject2wfq_bitmap = cos_bw_bitmap << 3;
+ const uint8_t pbf_cli_subject2wfq_bitmap = cos_bw_bitmap;
+
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT :
+ NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap);
+
+ REG_WR(sc, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
+ PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0, pbf_cli_sp_bitmap);
+
+ REG_WR(sc, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
+ NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ,
+ nig_cli_subject2wfq_bitmap);
+
+ REG_WR(sc, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
+ PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0,
+ pbf_cli_subject2wfq_bitmap);
+
+ return ELINK_STATUS_OK;
+}
+
+/******************************************************************************
+ * Description:
+ * This function is needed because NIG ARB_CREDIT_WEIGHT_X are
+ * not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_set_cos_bw(struct bnx2x_softc *sc,
+ const uint8_t cos_entry,
+ const uint32_t min_w_val_nig,
+ const uint32_t min_w_val_pbf,
+ const uint16_t total_bw,
+ const uint8_t bw,
+ const uint8_t port)
+{
+ uint32_t nig_reg_address_crd_weight = 0;
+ uint32_t pbf_reg_address_crd_weight = 0;
+ /* Calculate and set BW for this COS - use 1 instead of 0 for BW */
+ const uint32_t cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw;
+ const uint32_t cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw;
+
+ switch (cos_entry) {
+ case 0:
+ nig_reg_address_crd_weight =
+ (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0;
+ pbf_reg_address_crd_weight = (port) ?
+ PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0;
+ break;
+ case 1:
+ nig_reg_address_crd_weight = (port) ?
+ NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1;
+ pbf_reg_address_crd_weight = (port) ?
+ PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0;
+ break;
+ case 2:
+ nig_reg_address_crd_weight = (port) ?
+ NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2;
+
+ pbf_reg_address_crd_weight = (port) ?
+ PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0;
+ break;
+ case 3:
+ if (port)
+ return ELINK_STATUS_ERROR;
+ nig_reg_address_crd_weight =
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3;
+ pbf_reg_address_crd_weight =
+ PBF_REG_COS3_WEIGHT_P0;
+ break;
+ case 4:
+ if (port)
+ return ELINK_STATUS_ERROR;
+ nig_reg_address_crd_weight =
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4;
+ pbf_reg_address_crd_weight = PBF_REG_COS4_WEIGHT_P0;
+ break;
+ case 5:
+ if (port)
+ return ELINK_STATUS_ERROR;
+ nig_reg_address_crd_weight =
+ NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5;
+ pbf_reg_address_crd_weight = PBF_REG_COS5_WEIGHT_P0;
+ break;
+ }
+
+ REG_WR(sc, nig_reg_address_crd_weight, cos_bw_nig);
+
+ REG_WR(sc, pbf_reg_address_crd_weight, cos_bw_pbf);
+
+ return ELINK_STATUS_OK;
+}
+/******************************************************************************
+ * Description:
+ * Calculate the total BW.A value of 0 isn't legal.
+ *
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_get_total_bw(
+ const struct elink_params *params,
+ struct elink_ets_params *ets_params,
+ uint16_t *total_bw)
+{
+ struct bnx2x_softc *sc = params->sc;
+ uint8_t cos_idx = 0;
+ uint8_t is_bw_cos_exist = 0;
+
+ *total_bw = 0;
+ /* Calculate total BW requested */
+ for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
+ if (ets_params->cos[cos_idx].state == elink_cos_state_bw) {
+ is_bw_cos_exist = 1;
+ if (!ets_params->cos[cos_idx].params.bw_params.bw) {
+ ELINK_DEBUG_P0(sc, "elink_ets_E3B0_config BW"
+ " was set to 0");
+ /* This is to prevent a state when ramrods
+ * can't be sent
+ */
+ ets_params->cos[cos_idx].params.bw_params.bw
+ = 1;
+ }
+ *total_bw +=
+ ets_params->cos[cos_idx].params.bw_params.bw;
+ }
+ }
+
+ /* Check total BW is valid */
+ if ((is_bw_cos_exist == 1) && (*total_bw != 100)) {
+ if (*total_bw == 0) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_E3B0_config total BW shouldn't be 0");
+ return ELINK_STATUS_ERROR;
+ }
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_E3B0_config total BW should be 100");
+ /* We can handle a case where the BW isn't 100 this can happen
+ * if the TC are joined.
+ */
+ }
+ return ELINK_STATUS_OK;
+}
+
+/******************************************************************************
+ * Description:
+ * Invalidate all the sp_pri_to_cos.
+ *
+ ******************************************************************************/
+static void elink_ets_e3b0_sp_pri_to_cos_init(uint8_t *sp_pri_to_cos)
+{
+ uint8_t pri = 0;
+ for (pri = 0; pri < ELINK_DCBX_MAX_NUM_COS; pri++)
+ sp_pri_to_cos[pri] = DCBX_INVALID_COS;
+}
+/******************************************************************************
+ * Description:
+ * Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
+ * according to sp_pri_to_cos.
+ *
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_sp_pri_to_cos_set(
+ const struct elink_params *params,
+ uint8_t *sp_pri_to_cos,
+ const uint8_t pri,
+ const uint8_t cos_entry)
+{
+ struct bnx2x_softc *sc = params->sc;
+ const uint8_t port = params->port;
+ const uint8_t max_num_of_cos = (port) ?
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 :
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0;
+
+ if (pri >= max_num_of_cos) {
+ ELINK_DEBUG_P0(sc, "elink_ets_e3b0_sp_pri_to_cos_set invalid "
+ "parameter Illegal strict priority");
+ return ELINK_STATUS_ERROR;
+ }
+
+ if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) {
+ ELINK_DEBUG_P0(sc, "elink_ets_e3b0_sp_pri_to_cos_set invalid "
+ "parameter There can't be two COS's with "
+ "the same strict pri");
+ return ELINK_STATUS_ERROR;
+ }
+
+ sp_pri_to_cos[pri] = cos_entry;
+ return ELINK_STATUS_OK;
+}
+
+/******************************************************************************
+ * Description:
+ * Returns the correct value according to COS and priority in
+ * the sp_pri_cli register.
+ *
+ ******************************************************************************/
+static uint64_t elink_e3b0_sp_get_pri_cli_reg(const uint8_t cos,
+ const uint8_t cos_offset,
+ const uint8_t pri_set,
+ const uint8_t pri_offset,
+ const uint8_t entry_size)
+{
+ uint64_t pri_cli_nig = 0;
+ pri_cli_nig = ((uint64_t)(cos + cos_offset)) << (entry_size *
+ (pri_set + pri_offset));
+
+ return pri_cli_nig;
+}
+/******************************************************************************
+ * Description:
+ * Returns the correct value according to COS and priority in the
+ * sp_pri_cli register for NIG.
+ *
+ ******************************************************************************/
+static uint64_t elink_e3b0_sp_get_pri_cli_reg_nig(const uint8_t cos,
+ const uint8_t pri_set)
+{
+ /* MCP Dbg0 and dbg1 are always with higher strict pri*/
+ const uint8_t nig_cos_offset = 3;
+ const uint8_t nig_pri_offset = 3;
+
+ return elink_e3b0_sp_get_pri_cli_reg(cos, nig_cos_offset, pri_set,
+ nig_pri_offset, 4);
+}
+
+/******************************************************************************
+ * Description:
+ * Returns the correct value according to COS and priority in the
+ * sp_pri_cli register for PBF.
+ *
+ ******************************************************************************/
+static uint64_t elink_e3b0_sp_get_pri_cli_reg_pbf(const uint8_t cos,
+ const uint8_t pri_set)
+{
+ const uint8_t pbf_cos_offset = 0;
+ const uint8_t pbf_pri_offset = 0;
+
+ return elink_e3b0_sp_get_pri_cli_reg(cos, pbf_cos_offset, pri_set,
+ pbf_pri_offset, 3);
+}
+
+/******************************************************************************
+ * Description:
+ * Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
+ * according to sp_pri_to_cos.(which COS has higher priority)
+ *
+ ******************************************************************************/
+static elink_status_t elink_ets_e3b0_sp_set_pri_cli_reg(
+ const struct elink_params *params,
+ uint8_t *sp_pri_to_cos)
+{
+ struct bnx2x_softc *sc = params->sc;
+ uint8_t i = 0;
+ const uint8_t port = params->port;
+ /* MCP Dbg0 and dbg1 are always with higher strict pri*/
+ uint64_t pri_cli_nig = 0x210;
+ uint32_t pri_cli_pbf = 0x0;
+ uint8_t pri_set = 0;
+ uint8_t pri_bitmask = 0;
+ const uint8_t max_num_of_cos = (port) ?
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 :
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0;
+
+ uint8_t cos_bit_to_set = (1 << max_num_of_cos) - 1;
+
+ /* Set all the strict priority first */
+ for (i = 0; i < max_num_of_cos; i++) {
+ if (sp_pri_to_cos[i] != DCBX_INVALID_COS) {
+ if (sp_pri_to_cos[i] >= ELINK_DCBX_MAX_NUM_COS) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_sp_set_pri_cli_reg "
+ "invalid cos entry");
+ return ELINK_STATUS_ERROR;
+ }
+
+ pri_cli_nig |= elink_e3b0_sp_get_pri_cli_reg_nig(
+ sp_pri_to_cos[i], pri_set);
+
+ pri_cli_pbf |= elink_e3b0_sp_get_pri_cli_reg_pbf(
+ sp_pri_to_cos[i], pri_set);
+ pri_bitmask = 1 << sp_pri_to_cos[i];
+ /* COS is used remove it from bitmap.*/
+ if (!(pri_bitmask & cos_bit_to_set)) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_sp_set_pri_cli_reg "
+ "invalid There can't be two COS's with"
+ " the same strict pri");
+ return ELINK_STATUS_ERROR;
+ }
+ cos_bit_to_set &= ~pri_bitmask;
+ pri_set++;
+ }
+ }
+
+ /* Set all the Non strict priority i= COS*/
+ for (i = 0; i < max_num_of_cos; i++) {
+ pri_bitmask = 1 << i;
+ /* Check if COS was already used for SP */
+ if (pri_bitmask & cos_bit_to_set) {
+ /* COS wasn't used for SP */
+ pri_cli_nig |= elink_e3b0_sp_get_pri_cli_reg_nig(
+ i, pri_set);
+
+ pri_cli_pbf |= elink_e3b0_sp_get_pri_cli_reg_pbf(
+ i, pri_set);
+ /* COS is used remove it from bitmap.*/
+ cos_bit_to_set &= ~pri_bitmask;
+ pri_set++;
+ }
+ }
+
+ if (pri_set != max_num_of_cos) {
+ ELINK_DEBUG_P0(sc, "elink_ets_e3b0_sp_set_pri_cli_reg not all "
+ "entries were set");
+ return ELINK_STATUS_ERROR;
+ }
+
+ if (port) {
+ /* Only 6 usable clients*/
+ REG_WR(sc, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB,
+ (uint32_t)pri_cli_nig);
+
+ REG_WR(sc, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1, pri_cli_pbf);
+ } else {
+ /* Only 9 usable clients*/
+ const uint32_t pri_cli_nig_lsb = (uint32_t)(pri_cli_nig);
+ const uint32_t pri_cli_nig_msb = (uint32_t)
+ ((pri_cli_nig >> 32) & 0xF);
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB,
+ pri_cli_nig_lsb);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB,
+ pri_cli_nig_msb);
+
+ REG_WR(sc, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0, pri_cli_pbf);
+ }
+ return ELINK_STATUS_OK;
+}
+
+/******************************************************************************
+ * Description:
+ * Configure the COS to ETS according to BW and SP settings.
+ ******************************************************************************/
+elink_status_t elink_ets_e3b0_config(const struct elink_params *params,
+ const struct elink_vars *vars,
+ struct elink_ets_params *ets_params)
+{
+ struct bnx2x_softc *sc = params->sc;
+ elink_status_t elink_status = ELINK_STATUS_OK;
+ const uint8_t port = params->port;
+ uint16_t total_bw = 0;
+ const uint32_t min_w_val_nig = elink_ets_get_min_w_val_nig(vars);
+ const uint32_t min_w_val_pbf = ELINK_ETS_E3B0_PBF_MIN_W_VAL;
+ uint8_t cos_bw_bitmap = 0;
+ uint8_t cos_sp_bitmap = 0;
+ uint8_t sp_pri_to_cos[ELINK_DCBX_MAX_NUM_COS] = {0};
+ const uint8_t max_num_of_cos = (port) ?
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 :
+ ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0;
+ uint8_t cos_entry = 0;
+
+ if (!CHIP_IS_E3B0(sc)) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_disabled the chip isn't E3B0");
+ return ELINK_STATUS_ERROR;
+ }
+
+ if (ets_params->num_of_cos > max_num_of_cos) {
+ ELINK_DEBUG_P0(sc, "elink_ets_E3B0_config the number of COS "
+ "isn't supported");
+ return ELINK_STATUS_ERROR;
+ }
+
+ /* Prepare sp strict priority parameters*/
+ elink_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos);
+
+ /* Prepare BW parameters*/
+ elink_status = elink_ets_e3b0_get_total_bw(params, ets_params,
+ &total_bw);
+ if (elink_status != ELINK_STATUS_OK) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_E3B0_config get_total_bw failed");
+ return ELINK_STATUS_ERROR;
+ }
+
+ /* Upper bound is set according to current link speed (min_w_val
+ * should be the same for upper bound and COS credit val).
+ */
+ elink_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig);
+ elink_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
+
+
+ for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) {
+ if (elink_cos_state_bw == ets_params->cos[cos_entry].state) {
+ cos_bw_bitmap |= (1 << cos_entry);
+ /* The function also sets the BW in HW(not the mappin
+ * yet)
+ */
+ elink_status = elink_ets_e3b0_set_cos_bw(
+ sc, cos_entry, min_w_val_nig, min_w_val_pbf,
+ total_bw,
+ ets_params->cos[cos_entry].params.bw_params.bw,
+ port);
+ } else if (elink_cos_state_strict ==
+ ets_params->cos[cos_entry].state){
+ cos_sp_bitmap |= (1 << cos_entry);
+
+ elink_status = elink_ets_e3b0_sp_pri_to_cos_set(
+ params,
+ sp_pri_to_cos,
+ ets_params->cos[cos_entry].params.sp_params.pri,
+ cos_entry);
+
+ } else {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_config cos state not valid");
+ return ELINK_STATUS_ERROR;
+ }
+ if (elink_status != ELINK_STATUS_OK) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_e3b0_config set cos bw failed");
+ return elink_status;
+ }
+ }
+
+ /* Set SP register (which COS has higher priority) */
+ elink_status = elink_ets_e3b0_sp_set_pri_cli_reg(params,
+ sp_pri_to_cos);
+
+ if (elink_status != ELINK_STATUS_OK) {
+ ELINK_DEBUG_P0(sc,
+ "elink_ets_E3B0_config set_pri_cli_reg failed");
+ return elink_status;
+ }
+
+ /* Set client mapping of BW and strict */
+ elink_status = elink_ets_e3b0_cli_map(params, ets_params,
+ cos_sp_bitmap,
+ cos_bw_bitmap);
+
+ if (elink_status != ELINK_STATUS_OK) {
+ ELINK_DEBUG_P0(sc, "elink_ets_E3B0_config SP failed");
+ return elink_status;
+ }
+ return ELINK_STATUS_OK;
+}
+static void elink_ets_bw_limit_common(const struct elink_params *params)
+{
+ /* ETS disabled configuration */
+ struct bnx2x_softc *sc = params->sc;
+ ELINK_DEBUG_P0(sc, "ETS enabled BW limit configuration");
+ /* Defines which entries (clients) are subjected to WFQ arbitration
+ * COS0 0x8
+ * COS1 0x10
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
+ /* Mapping between the ARB_CREDIT_WEIGHT registers and actual
+ * client numbers (WEIGHT_0 does not actually have to represent
+ * client 0)
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
+ ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
+ ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+
+ /* ETS mode enabled*/
+ REG_WR(sc, PBF_REG_ETS_ENABLED, 1);
+
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(sc, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
+ /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
+ * entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
+
+ /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
+ REG_WR(sc, PBF_REG_COS0_UPPER_BOUND,
+ ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+ REG_WR(sc, PBF_REG_COS1_UPPER_BOUND,
+ ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+}
+
+void elink_ets_bw_limit(const struct elink_params *params,
+ const uint32_t cos0_bw,
+ const uint32_t cos1_bw)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x_softc *sc = params->sc;
+ const uint32_t total_bw = cos0_bw + cos1_bw;
+ uint32_t cos0_credit_weight = 0;
+ uint32_t cos1_credit_weight = 0;
+
+ ELINK_DEBUG_P0(sc, "ETS enabled BW limit configuration");
+
+ if ((!total_bw) ||
+ (!cos0_bw) ||
+ (!cos1_bw)) {
+ ELINK_DEBUG_P0(sc, "Total BW can't be zero");
+ return;
+ }
+
+ cos0_credit_weight = (cos0_bw * ELINK_ETS_BW_LIMIT_CREDIT_WEIGHT) /
+ total_bw;
+ cos1_credit_weight = (cos1_bw * ELINK_ETS_BW_LIMIT_CREDIT_WEIGHT) /
+ total_bw;
+
+ elink_ets_bw_limit_common(params);
+
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
+
+ REG_WR(sc, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
+ REG_WR(sc, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
+}
+
+elink_status_t elink_ets_strict(const struct elink_params *params,
+ const uint8_t strict_cos)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x_softc *sc = params->sc;
+ uint32_t val = 0;
+
+ ELINK_DEBUG_P0(sc, "ETS enabled strict configuration");
+ /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries,
+ * 3 - COS0 entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
+ /* For strict priority entries defines the number of consecutive slots
+ * for the highest priority.
+ */
+ REG_WR(sc, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+ /* ETS mode disable */
+ REG_WR(sc, PBF_REG_ETS_ENABLED, 0);
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(sc, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
+
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(sc, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
+
+ /* Mapping between entry priority to client number (0,1,2 -debug and
+ * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
+ * 3bits client num.
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
+ * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
+ */
+ val = (!strict_cos) ? 0x2318 : 0x22E0;
+ REG_WR(sc, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);