1
2
3
4
5#include "lm5710.h"
6#include "init_defs.h"
7
8/* Vnics per mode */
9#define ECORE_PORT2_MODE_NUM_VNICS 4
10
11
12/* QM queue numbers */
13#define ECORE_ETH_Q		0
14#define ECORE_TOE_Q		3
15#define ECORE_TOE_ACK_Q		6
16#define ECORE_ISCSI_Q		9
17#define ECORE_ISCSI_ACK_Q	11
18#define ECORE_FCOE_Q		10
19
20/* Vnics per mode */
21#define ECORE_PORT4_MODE_NUM_VNICS 2
22
23/* COS offset for port1 in E3 B0 4port mode */
24#define ECORE_E3B0_PORT1_COS_OFFSET 3
25
26/* QM Register addresses */
27#define ECORE_Q_VOQ_REG_ADDR(pf_q_num)\
28	(QM_REG_QVOQIDX_0 + 4 * (pf_q_num))
29#define ECORE_VOQ_Q_REG_ADDR(cos, pf_q_num)\
30	(QM_REG_VOQQMASK_0_LSB + 4 * ((cos) * 2 + ((pf_q_num) >> 5)))
31#define ECORE_Q_CMDQ_REG_ADDR(pf_q_num)\
32	(QM_REG_BYTECRDCMDQ_0 + 4 * ((pf_q_num) >> 4))
33
34/* extracts the QM queue number for the specified port and vnic */
35#define ECORE_PF_Q_NUM(q_num, port, vnic)\
36	((((port) << 1) | (vnic)) * 16 + (q_num))
37
38
39/* Maps the specified queue to the specified COS */
40void ecore_map_q_cos(struct _lm_device_t *pdev, u32_t q_num, u32_t new_cos)
41{
42	/* find current COS mapping */
43	u32_t curr_cos = REG_RD(pdev, QM_REG_QVOQIDX_0 + q_num * 4);
44
45	/* check if queue->COS mapping has changed */
46	if (curr_cos != new_cos) {
47		u32_t num_vnics = ECORE_PORT2_MODE_NUM_VNICS;
48		u32_t reg_addr, reg_bit_map, vnic;
49
50		/* update parameters for 4port mode */
51		if (INIT_MODE_FLAGS(pdev) & MODE_PORT4) {
52			num_vnics = ECORE_PORT4_MODE_NUM_VNICS;
53			if (PORT_ID(pdev)) {
54				curr_cos += ECORE_E3B0_PORT1_COS_OFFSET;
55				new_cos += ECORE_E3B0_PORT1_COS_OFFSET;
56			}
57		}
58
59		/* change queue mapping for each VNIC */
60		for (vnic = 0; vnic < num_vnics; vnic++) {
61			u32_t pf_q_num =
62				ECORE_PF_Q_NUM(q_num, PORT_ID(pdev), vnic);
63			u32_t q_bit_map = 1 << (pf_q_num & 0x1f);
64
65			/* overwrite queue->VOQ mapping */
66			REG_WR(pdev, ECORE_Q_VOQ_REG_ADDR(pf_q_num), new_cos);
67
68			/* clear queue bit from current COS bit map */
69			reg_addr = ECORE_VOQ_Q_REG_ADDR(curr_cos, pf_q_num);
70			reg_bit_map = REG_RD(pdev, reg_addr);
71			REG_WR(pdev, reg_addr, reg_bit_map & (~q_bit_map));
72
73			/* set queue bit in new COS bit map */
74			reg_addr = ECORE_VOQ_Q_REG_ADDR(new_cos, pf_q_num);
75			reg_bit_map = REG_RD(pdev, reg_addr);
76			REG_WR(pdev, reg_addr, reg_bit_map | q_bit_map);
77
78			/* set/clear queue bit in command-queue bit map
79			(E2/E3A0 only, valid COS values are 0/1) */
80			if (!(INIT_MODE_FLAGS(pdev) & MODE_E3_B0)) {
81				reg_addr = ECORE_Q_CMDQ_REG_ADDR(pf_q_num);
82				reg_bit_map = REG_RD(pdev, reg_addr);
83				q_bit_map = 1 << (2 * (pf_q_num & 0xf));
84				reg_bit_map = new_cos ?
85					      (reg_bit_map | q_bit_map) :
86					      (reg_bit_map & (~q_bit_map));
87				REG_WR(pdev, reg_addr, reg_bit_map);
88			}
89		}
90	}
91}
92
93/* Configures the QM according to the specified per-traffic-type COSes */
94void ecore_dcb_config_qm(struct _lm_device_t *pdev, enum cos_mode mode,
95				       struct priority_cos *traffic_cos)
96{
97	ecore_map_q_cos(pdev, ECORE_FCOE_Q,
98			traffic_cos[LLFC_TRAFFIC_TYPE_FCOE].cos);
99	ecore_map_q_cos(pdev, ECORE_ISCSI_Q,
100			traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos);
101	ecore_map_q_cos(pdev, ECORE_ISCSI_ACK_Q,
102		traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos);
103	if (mode != STATIC_COS) {
104		/* required only in OVERRIDE_COS mode */
105		ecore_map_q_cos(pdev, ECORE_ETH_Q,
106				traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
107		ecore_map_q_cos(pdev, ECORE_TOE_Q,
108				traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
109		ecore_map_q_cos(pdev, ECORE_TOE_ACK_Q,
110				traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
111	}
112}
113
114
115/*
116 * congestion managment port init api description
117 * the api works as follows:
118 * the driver should pass the cmng_init_input struct, the port_init function
119 * will prepare the required internal ram structure which will be passed back
120 * to the driver (cmng_init) that will write it into the internal ram.
121 *
122 * IMPORTANT REMARKS:
123 * 1. the cmng_init struct does not represent the contiguous internal ram
124 *    structure. the driver should use the XSTORM_CMNG_PERPORT_VARS_OFFSET
125 *    offset in order to write the port sub struct and the
126 *    PFID_FROM_PORT_AND_VNIC offset for writing the vnic sub struct (in other
127 *    words - don't use memcpy!).
128 * 2. although the cmng_init struct is filled for the maximal vnic number
129 *    possible, the driver should only write the valid vnics into the internal
130 *    ram according to the appropriate port mode.
131 */
132#define BITS_TO_BYTES(x) ((x)/8)
133
134/* CMNG constants, as derived from system spec calculations */
135
136/* default MIN rate in case VNIC min rate is configured to zero- 100Mbps */
137#define DEF_MIN_RATE 100
138
139/* resolution of the rate shaping timer - 400 usec */
140#define RS_PERIODIC_TIMEOUT_USEC 400
141
142/*
143 *  number of bytes in single QM arbitration cycle -
144 *  coefficient for calculating the fairness timer
145 */
146#define QM_ARB_BYTES 160000
147
148/* resolution of Min algorithm 1:100 */
149#define MIN_RES 100
150
151/*
152 *  how many bytes above threshold for
153 *  the minimal credit of Min algorithm
154 */
155#define MIN_ABOVE_THRESH 32768
156
157/*
158 *  Fairness algorithm integration time coefficient -
159 *  for calculating the actual Tfair
160 */
161#define T_FAIR_COEF ((MIN_ABOVE_THRESH + QM_ARB_BYTES) * 8 * MIN_RES)
162
163/* Memory of fairness algorithm - 2 cycles */
164#define FAIR_MEM 2
165#define SAFC_TIMEOUT_USEC 52
166
167#define SDM_TICKS 4
168
169
170void ecore_init_max(const struct cmng_init_input *input_data,
171				  u32_t r_param, struct cmng_init *ram_data)
172{
173	u32_t vnic;
174	struct cmng_vnic *vdata = &ram_data->vnic;
175	struct cmng_struct_per_port *pdata = &ram_data->port;
176	/*
177	 * rate shaping per-port variables
178	 *  100 micro seconds in SDM ticks = 25
179	 *  since each tick is 4 microSeconds
180	 */
181
182	pdata->rs_vars.rs_periodic_timeout =
183	RS_PERIODIC_TIMEOUT_USEC / SDM_TICKS;
184
185	/* this is the threshold below which no timer arming will occur.
186	 *  1.25 coefficient is for the threshold to be a little bigger
187	 *  then the real time to compensate for timer in-accuracy
188	 */
189	pdata->rs_vars.rs_threshold =
190	(5 * RS_PERIODIC_TIMEOUT_USEC * r_param)/4;
191
192	/* rate shaping per-vnic variables */
193	for (vnic = 0; vnic < ECORE_PORT2_MODE_NUM_VNICS; vnic++) {
194		/* global vnic counter */
195		vdata->vnic_max_rate[vnic].vn_counter.rate =
196		input_data->vnic_max_rate[vnic];
197		/*
198		 * maximal Mbps for this vnic
199		 * the quota in each timer period - number of bytes
200		 * transmitted in this period
201		 */
202		vdata->vnic_max_rate[vnic].vn_counter.quota =
203			RS_PERIODIC_TIMEOUT_USEC *
204			(u32_t)vdata->vnic_max_rate[vnic].vn_counter.rate / 8;
205	}
206
207}
208
209void ecore_init_max_per_vn(u16_t vnic_max_rate,
210				  struct rate_shaping_vars_per_vn *ram_data)
211{
212	/* global vnic counter */
213	ram_data->vn_counter.rate = vnic_max_rate;
214
215	/*
216	* maximal Mbps for this vnic
217	* the quota in each timer period - number of bytes
218	* transmitted in this period
219	*/
220	ram_data->vn_counter.quota =
221		RS_PERIODIC_TIMEOUT_USEC * (u32_t)vnic_max_rate / 8;
222}
223
224void ecore_init_min(const struct cmng_init_input *input_data,
225				  u32_t r_param, struct cmng_init *ram_data)
226{
227	u32_t vnic, fair_periodic_timeout_usec, vnicWeightSum, tFair;
228	struct cmng_vnic *vdata = &ram_data->vnic;
229	struct cmng_struct_per_port *pdata = &ram_data->port;
230
231	/* this is the resolution of the fairness timer */
232	fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
233
234	/*
235	 * fairness per-port variables
236	 * for 10G it is 1000usec. for 1G it is 10000usec.
237	 */
238	tFair = T_FAIR_COEF / input_data->port_rate;
239
240	/* this is the threshold below which we won't arm the timer anymore */
241	pdata->fair_vars.fair_threshold = QM_ARB_BYTES;
242
243	/*
244	 *  we multiply by 1e3/8 to get bytes/msec. We don't want the credits
245	 *  to pass a credit of the T_FAIR*FAIR_MEM (algorithm resolution)
246	 */
247	pdata->fair_vars.upper_bound = r_param * tFair * FAIR_MEM;
248
249	/* since each tick is 4 microSeconds */
250	pdata->fair_vars.fairness_timeout =
251				fair_periodic_timeout_usec / SDM_TICKS;
252
253	/* calculate sum of weights */
254	vnicWeightSum = 0;
255
256	for (vnic = 0; vnic < ECORE_PORT2_MODE_NUM_VNICS; vnic++)
257		vnicWeightSum += input_data->vnic_min_rate[vnic];
258
259	/* global vnic counter */
260	if (vnicWeightSum > 0) {
261		/* fairness per-vnic variables */
262		for (vnic = 0; vnic < ECORE_PORT2_MODE_NUM_VNICS; vnic++) {
263			/*
264			 *  this is the credit for each period of the fairness
265			 *  algorithm - number of bytes in T_FAIR (this vnic
266			 *  share of the port rate)
267			 */
268			vdata->vnic_min_rate[vnic].vn_credit_delta =
269				((u32_t)(input_data->vnic_min_rate[vnic]) * 100 *
270				(T_FAIR_COEF / (8 * 100 * vnicWeightSum)));
271			if (vdata->vnic_min_rate[vnic].vn_credit_delta <
272			    pdata->fair_vars.fair_threshold +
273			    MIN_ABOVE_THRESH) {
274				vdata->vnic_min_rate[vnic].vn_credit_delta =
275					pdata->fair_vars.fair_threshold +
276					MIN_ABOVE_THRESH;
277			}
278		}
279	}
280}
281
282void ecore_init_fw_wrr(const struct cmng_init_input *input_data,
283				     u32_t r_param, struct cmng_init *ram_data)
284{
285	u32_t vnic, cos;
286	u32_t cosWeightSum = 0;
287	struct cmng_vnic *vdata = &ram_data->vnic;
288	struct cmng_struct_per_port *pdata = &ram_data->port;
289
290	for (cos = 0; cos < MAX_COS_NUMBER; cos++)
291		cosWeightSum += input_data->cos_min_rate[cos];
292
293	if (cosWeightSum > 0) {
294
295		for (vnic = 0; vnic < ECORE_PORT2_MODE_NUM_VNICS; vnic++) {
296			/*
297			 *  Since cos and vnic shouldn't work together the rate
298			 *  to divide between the coses is the port rate.
299			 */
300			u32_t *ccd = vdata->vnic_min_rate[vnic].cos_credit_delta;
301			for (cos = 0; cos < MAX_COS_NUMBER; cos++) {
302				/*
303				 * this is the credit for each period of
304				 * the fairness algorithm - number of bytes
305				 * in T_FAIR (this cos share of the vnic rate)
306				 */
307				ccd[cos] =
308				    ((u32_t)input_data->cos_min_rate[cos] * 100 *
309				    (T_FAIR_COEF / (8 * 100 * cosWeightSum)));
310				 if (ccd[cos] < pdata->fair_vars.fair_threshold
311						+ MIN_ABOVE_THRESH) {
312					ccd[cos] =
313					    pdata->fair_vars.fair_threshold +
314					    MIN_ABOVE_THRESH;
315				}
316			}
317		}
318	}
319}
320
321void ecore_init_safc(const struct cmng_init_input *input_data,
322				   struct cmng_init *ram_data)
323{
324	/* in microSeconds */
325	ram_data->port.safc_vars.safc_timeout_usec = SAFC_TIMEOUT_USEC;
326}
327
328/* Congestion management port init */
329void ecore_init_cmng(const struct cmng_init_input *input_data,
330				   struct cmng_init *ram_data)
331{
332	u32_t r_param;
333	mm_mem_zero(ram_data,sizeof(struct cmng_init));
334
335	ram_data->port.flags = input_data->flags;
336
337	/*
338	 *  number of bytes transmitted in a rate of 10Gbps
339	 *  in one usec = 1.25KB.
340	 */
341	r_param = BITS_TO_BYTES(input_data->port_rate);
342	ecore_init_max(input_data, r_param, ram_data);
343	ecore_init_min(input_data, r_param, ram_data);
344	ecore_init_fw_wrr(input_data, r_param, ram_data);
345	ecore_init_safc(input_data, ram_data);
346}
347
348