Commit 8a1c38d1 authored by Eilon Greenstein's avatar Eilon Greenstein Committed by David S. Miller
Browse files

bnx2x: BW shaper enhancements



Some of the configuration can be set when loading the device and shouldn't be
re-calculated after each link up indication since it is not dependent on the
link speed

Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 748e5439
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -883,6 +883,9 @@ struct bnx2x {
	struct bnx2x_common	common;
	struct bnx2x_port	port;

	struct cmng_struct_per_port cmng;
	u32			vn_weight_sum;

	u32			mf_config;
	u16			e1hov;
	u8			e1hmf;
+14 −11
Original line number Diff line number Diff line
@@ -2640,17 +2640,19 @@ struct ustorm_eth_rx_producers {
 */
struct cmng_flags_per_port {
	u8 con_number[NUM_OF_PROTOCOLS];
#if defined(__BIG_ENDIAN)
	u8 fairness_enable;
	u8 rate_shaping_enable;
	u8 cmng_protocol_enable;
	u8 cmng_vn_enable;
#elif defined(__LITTLE_ENDIAN)
	u8 cmng_vn_enable;
	u8 cmng_protocol_enable;
	u8 rate_shaping_enable;
	u8 fairness_enable;
#endif
	u32 cmng_enables;
#define CMNG_FLAGS_PER_PORT_FAIRNESS_VN (0x1<<0)
#define CMNG_FLAGS_PER_PORT_FAIRNESS_VN_SHIFT 0
#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN (0x1<<1)
#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN_SHIFT 1
#define CMNG_FLAGS_PER_PORT_FAIRNESS_PROTOCOL (0x1<<2)
#define CMNG_FLAGS_PER_PORT_FAIRNESS_PROTOCOL_SHIFT 2
#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_PROTOCOL (0x1<<3)
#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_PROTOCOL_SHIFT 3
#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS (0x1<<4)
#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_SHIFT 4
#define __CMNG_FLAGS_PER_PORT_RESERVED0 (0x7FFFFFF<<5)
#define __CMNG_FLAGS_PER_PORT_RESERVED0_SHIFT 5
};


@@ -2803,6 +2805,7 @@ struct eth_stats_query {
 * per-vnic fairness variables
 */
struct fairness_vars_per_vn {
	u32 cos_credit_delta[MAX_COS_NUMBER];
	u32 protocol_credit_delta[NUM_OF_PROTOCOLS];
	u32 vn_credit_delta;
	u32 __reserved0;
+136 −178
Original line number Diff line number Diff line
@@ -2054,119 +2054,42 @@ static u8 bnx2x_link_test(struct bnx2x *bp)
	return rc;
}

/* Calculates the sum of vn_min_rates.
   It's needed for further normalizing of the min_rates.

   Returns:
     sum of vn_min_rates
       or
     0 - if all the min_rates are 0.
     In the later case fairness algorithm should be deactivated.
     If not all min_rates are zero then those that are zeroes will
     be set to 1.
 */
static u32 bnx2x_calc_vn_wsum(struct bnx2x *bp)
{
	int i, port = BP_PORT(bp);
	u32 wsum = 0;
	int all_zero = 1;

	for (i = 0; i < E1HVN_MAX; i++) {
		u32 vn_cfg =
			SHMEM_RD(bp, mf_cfg.func_mf_config[2*i + port].config);
		u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
				     FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
		if (!(vn_cfg & FUNC_MF_CFG_FUNC_HIDE)) {
			/* If min rate is zero - set it to 1 */
			if (!vn_min_rate)
				vn_min_rate = DEF_MIN_RATE;
			else
				all_zero = 0;

			wsum += vn_min_rate;
		}
	}

	/* ... only if all min rates are zeros - disable FAIRNESS */
	if (all_zero)
		return 0;

	return wsum;
}

static void bnx2x_init_port_minmax(struct bnx2x *bp,
				   int en_fness,
				   u16 port_rate,
				   struct cmng_struct_per_port *m_cmng_port)
static void bnx2x_init_port_minmax(struct bnx2x *bp)
{
	u32 r_param = port_rate / 8;
	int port = BP_PORT(bp);
	int i;

	memset(m_cmng_port, 0, sizeof(struct cmng_struct_per_port));

	/* Enable minmax only if we are in e1hmf mode */
	if (IS_E1HMF(bp)) {
	u32 r_param = bp->link_vars.line_speed / 8;
	u32 fair_periodic_timeout_usec;
	u32 t_fair;

		/* Enable rate shaping and fairness */
		m_cmng_port->flags.cmng_vn_enable = 1;
		m_cmng_port->flags.fairness_enable = en_fness ? 1 : 0;
		m_cmng_port->flags.rate_shaping_enable = 1;

		if (!en_fness)
			DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
			   "  fairness will be disabled\n");
	memset(&(bp->cmng.rs_vars), 0,
	       sizeof(struct rate_shaping_vars_per_port));
	memset(&(bp->cmng.fair_vars), 0, sizeof(struct fairness_vars_per_port));

	/* 100 usec in SDM ticks = 25 since each tick is 4 usec */
		m_cmng_port->rs_vars.rs_periodic_timeout =
						RS_PERIODIC_TIMEOUT_USEC / 4;
	bp->cmng.rs_vars.rs_periodic_timeout = RS_PERIODIC_TIMEOUT_USEC / 4;

	/* this is the threshold below which no timer arming will occur
	   1.25 coefficient is for the threshold to be a little bigger
	   than the real time, to compensate for timer in-accuracy */
		m_cmng_port->rs_vars.rs_threshold =
	bp->cmng.rs_vars.rs_threshold =
				(RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4;

	/* resolution of fairness timer */
	fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
	/* for 10G it is 1000usec. for 1G it is 10000usec. */
		t_fair = T_FAIR_COEF / port_rate;
	t_fair = T_FAIR_COEF / bp->link_vars.line_speed;

		/* this is the threshold below which we won't arm
		   the timer anymore */
		m_cmng_port->fair_vars.fair_threshold = QM_ARB_BYTES;
	/* this is the threshold below which we won't arm the timer anymore */
	bp->cmng.fair_vars.fair_threshold = QM_ARB_BYTES;

	/* we multiply by 1e3/8 to get bytes/msec.
	   We don't want the credits to pass a credit
		   of the T_FAIR*FAIR_MEM (algorithm resolution) */
		m_cmng_port->fair_vars.upper_bound =
						r_param * t_fair * FAIR_MEM;
	   of the t_fair*FAIR_MEM (algorithm resolution) */
	bp->cmng.fair_vars.upper_bound = r_param * t_fair * FAIR_MEM;
	/* since each tick is 4 usec */
		m_cmng_port->fair_vars.fairness_timeout =
						fair_periodic_timeout_usec / 4;

	} else {
		/* Disable rate shaping and fairness */
		m_cmng_port->flags.cmng_vn_enable = 0;
		m_cmng_port->flags.fairness_enable = 0;
		m_cmng_port->flags.rate_shaping_enable = 0;

		DP(NETIF_MSG_IFUP,
		   "Single function mode  minmax will be disabled\n");
	bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4;
}

	/* Store it to internal memory */
	for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
		REG_WR(bp, BAR_XSTRORM_INTMEM +
		       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4,
		       ((u32 *)(m_cmng_port))[i]);
}

static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func,
				   u32 wsum, u16 port_rate,
				 struct cmng_struct_per_port *m_cmng_port)
static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
{
	struct rate_shaping_vars_per_vn m_rs_vn;
	struct fairness_vars_per_vn m_fair_vn;
@@ -2182,17 +2105,18 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func,
	} else {
		vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
				FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
		/* If FAIRNESS is enabled (not all min rates are zeroes) and
		/* If fairness is enabled (not all min rates are zeroes) and
		   if current min rate is zero - set it to 1.
		   This is a requirement of the algorithm. */
		if ((vn_min_rate == 0) && wsum)
		if (bp->vn_weight_sum && (vn_min_rate == 0))
			vn_min_rate = DEF_MIN_RATE;
		vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
				FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
	}

	DP(NETIF_MSG_IFUP, "func %d: vn_min_rate=%d  vn_max_rate=%d  "
	   "wsum=%d\n", func, vn_min_rate, vn_max_rate, wsum);
	DP(NETIF_MSG_IFUP,
	   "func %d: vn_min_rate=%d  vn_max_rate=%d  vn_weight_sum=%d\n",
	   func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);

	memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
	memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn));
@@ -2204,55 +2128,20 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func,
	m_rs_vn.vn_counter.quota =
				(vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8;

#ifdef BNX2X_PER_PROT_QOS
	/* per protocol counter */
	for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++) {
		/* maximal Mbps for this protocol */
		m_rs_vn.protocol_counters[protocol].rate =
						protocol_max_rate[protocol];
		/* the quota in each timer period -
		   number of bytes transmitted in this period */
		m_rs_vn.protocol_counters[protocol].quota =
			(u32)(rs_periodic_timeout_usec *
			  ((double)m_rs_vn.
				   protocol_counters[protocol].rate/8));
	}
#endif

	if (wsum) {
	if (bp->vn_weight_sum) {
		/* credit for each period of the fairness algorithm:
		   number of bytes in T_FAIR (the vn share the port rate).
		   wsum should not be larger than 10000, thus
		   T_FAIR_COEF / (8 * wsum) will always be grater than zero */
		   vn_weight_sum should not be larger than 10000, thus
		   T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
		   than zero */
		m_fair_vn.vn_credit_delta =
			max((u64)(vn_min_rate * (T_FAIR_COEF / (8 * wsum))),
			    (u64)(m_cmng_port->fair_vars.fair_threshold * 2));
			max((u32)(vn_min_rate * (T_FAIR_COEF /
						 (8 * bp->vn_weight_sum))),
			    (u32)(bp->cmng.fair_vars.fair_threshold * 2));
		DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta=%d\n",
		   m_fair_vn.vn_credit_delta);
	}

#ifdef BNX2X_PER_PROT_QOS
	do {
		u32 protocolWeightSum = 0;

		for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++)
			protocolWeightSum +=
					drvInit.protocol_min_rate[protocol];
		/* per protocol counter -
		   NOT NEEDED IF NO PER-PROTOCOL CONGESTION MANAGEMENT */
		if (protocolWeightSum > 0) {
			for (protocol = 0;
			     protocol < NUM_OF_PROTOCOLS; protocol++)
				/* credit for each period of the
				   fairness algorithm - number of bytes in
				   T_FAIR (the protocol share the vn rate) */
				m_fair_vn.protocol_credit_delta[protocol] =
					(u32)((vn_min_rate / 8) * t_fair *
					protocol_min_rate / protocolWeightSum);
		}
	} while (0);
#endif

	/* Store it to internal memory */
	for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++)
		REG_WR(bp, BAR_XSTRORM_INTMEM +
@@ -2265,11 +2154,10 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func,
		       ((u32 *)(&m_fair_vn))[i]);
}


/* This function is called upon link interrupt */
static void bnx2x_link_attn(struct bnx2x *bp)
{
	int vn;

	/* Make sure that we are synced with the current statistics */
	bnx2x_stats_handle(bp, STATS_EVENT_STOP);

@@ -2294,36 +2182,38 @@ static void bnx2x_link_attn(struct bnx2x *bp)
	bnx2x_link_report(bp);

	if (IS_E1HMF(bp)) {
		int port = BP_PORT(bp);
		int func;
		int vn;

		for (vn = VN_0; vn < E1HVN_MAX; vn++) {
			if (vn == BP_E1HVN(bp))
				continue;

			func = ((vn << 1) | BP_PORT(bp));
			func = ((vn << 1) | port);

			/* Set the attention towards other drivers
			   on the same port */
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
			       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
		}
	}

	if (CHIP_IS_E1H(bp) && (bp->link_vars.line_speed > 0)) {
		struct cmng_struct_per_port m_cmng_port;
		u32 wsum;
		int port = BP_PORT(bp);
		if (bp->link_vars.link_up) {
			int i;

			/* Init rate shaping and fairness contexts */
			bnx2x_init_port_minmax(bp);

		/* Init RATE SHAPING and FAIRNESS contexts */
		wsum = bnx2x_calc_vn_wsum(bp);
		bnx2x_init_port_minmax(bp, (int)wsum,
					bp->link_vars.line_speed,
					&m_cmng_port);
		if (IS_E1HMF(bp))
			for (vn = VN_0; vn < E1HVN_MAX; vn++)
				bnx2x_init_vn_minmax(bp, 2*vn + port,
					wsum, bp->link_vars.line_speed,
						     &m_cmng_port);
				bnx2x_init_vn_minmax(bp, 2*vn + port);

			/* Store it to internal memory */
			for (i = 0;
			     i < sizeof(struct cmng_struct_per_port) / 4; i++)
				REG_WR(bp, BAR_XSTRORM_INTMEM +
				  XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
				       ((u32 *)(&bp->cmng))[i]);
		}
	}
}

@@ -4848,6 +4738,47 @@ static void bnx2x_init_internal_port(struct bnx2x *bp)
	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
}

/* Calculates the sum of vn_min_rates.
   It's needed for further normalizing of the min_rates.
   Returns:
     sum of vn_min_rates.
       or
     0 - if all the min_rates are 0.
     In the later case fainess algorithm should be deactivated.
     If not all min_rates are zero then those that are zeroes will be set to 1.
 */
static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
{
	int all_zero = 1;
	int port = BP_PORT(bp);
	int vn;

	bp->vn_weight_sum = 0;
	for (vn = VN_0; vn < E1HVN_MAX; vn++) {
		int func = 2*vn + port;
		u32 vn_cfg =
			SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
		u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
				   FUNC_MF_CFG_MIN_BW_SHIFT) * 100;

		/* Skip hidden vns */
		if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
			continue;

		/* If min rate is zero - set it to 1 */
		if (!vn_min_rate)
			vn_min_rate = DEF_MIN_RATE;
		else
			all_zero = 0;

		bp->vn_weight_sum += vn_min_rate;
	}

	/* ... only if all min rates are zeros - disable fairness */
	if (all_zero)
		bp->vn_weight_sum = 0;
}

static void bnx2x_init_internal_func(struct bnx2x *bp)
{
	struct tstorm_eth_function_common_config tstorm_config = {0};
@@ -4977,6 +4908,45 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
			 USTORM_MAX_AGG_SIZE_OFFSET(port, FP_CL_ID(fp)),
			 max_agg_size);
	}

	memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));

	/* Init rate shaping and fairness contexts */
	if (IS_E1HMF(bp)) {
		int vn;

		/* During init there is no active link
		   Until link is up, set link rate to 10Gbps */
		bp->link_vars.line_speed = SPEED_10000;
		bnx2x_init_port_minmax(bp);

		bnx2x_calc_vn_weight_sum(bp);

		for (vn = VN_0; vn < E1HVN_MAX; vn++)
			bnx2x_init_vn_minmax(bp, 2*vn + port);

		/* Enable rate shaping and fairness */
		bp->cmng.flags.cmng_enables =
					CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
		if (bp->vn_weight_sum)
			bp->cmng.flags.cmng_enables |=
					CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
		else
			DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
			   "  fairness will be disabled\n");
	} else {
		/* rate shaping and fairness are disabled */
		DP(NETIF_MSG_IFUP,
		   "single function mode  minmax will be disabled\n");
	}


	/* Store it to internal memory */
	if (bp->port.pmf)
		for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
			REG_WR(bp, BAR_XSTRORM_INTMEM +
			       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4,
			       ((u32 *)(&bp->cmng))[i]);
}

static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
@@ -5780,22 +5750,10 @@ static int bnx2x_init_port(struct bnx2x *bp)
	REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);

	if (CHIP_IS_E1H(bp)) {
		u32 wsum;
		struct cmng_struct_per_port m_cmng_port;
		int vn;

		/* 0x2 disable e1hov, 0x1 enable */
		REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
		       (IS_E1HMF(bp) ? 0x1 : 0x2));

		/* Init RATE SHAPING and FAIRNESS contexts.
		   Initialize as if there is 10G link. */
		wsum = bnx2x_calc_vn_wsum(bp);
		bnx2x_init_port_minmax(bp, (int)wsum, 10000, &m_cmng_port);
		if (IS_E1HMF(bp))
			for (vn = VN_0; vn < E1HVN_MAX; vn++)
				bnx2x_init_vn_minmax(bp, 2*vn + port,
					wsum, 10000, &m_cmng_port);
	}

	/* Port MCP comes here */