xref: /dpdk/drivers/common/cnxk/roc_nix_tm_mark.c (revision e746aec1)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2022 Marvell.
3  */
4 
5 #include "roc_api.h"
6 #include "roc_priv.h"
7 
8 static const uint8_t y_mask_val[ROC_NIX_TM_MARK_MAX][2] = {
9 	[ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8},
10 	[ROC_NIX_TM_MARK_IPV4_DSCP] = {0x1, 0x2},
11 	[ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc},
12 	[ROC_NIX_TM_MARK_IPV6_DSCP] = {0x1, 0x2},
13 	[ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3},
14 };
15 
16 static const uint8_t r_mask_val[ROC_NIX_TM_MARK_MAX][2] = {
17 	[ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8},
18 	[ROC_NIX_TM_MARK_IPV4_DSCP] = {0x0, 0x3},
19 	[ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc},
20 	[ROC_NIX_TM_MARK_IPV6_DSCP] = {0x0, 0x3},
21 	[ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3},
22 };
23 
24 static const uint8_t mark_off[ROC_NIX_TM_MARK_MAX] = {
25 	[ROC_NIX_TM_MARK_VLAN_DEI] = 0x3,  /* Byte 14 Bit[4:1] */
26 	[ROC_NIX_TM_MARK_IPV4_DSCP] = 0x1, /* Byte 1 Bit[6:3] */
27 	[ROC_NIX_TM_MARK_IPV4_ECN] = 0x6, /* Byte 1 Bit[1:0], Byte 2 Bit[7:6] */
28 	[ROC_NIX_TM_MARK_IPV6_DSCP] = 0x5, /* Byte 0 Bit[2:0], Byte 1 Bit[7] */
29 	[ROC_NIX_TM_MARK_IPV6_ECN] = 0x0,  /* Byte 1 Bit[7:4] */
30 };
31 
32 static const uint64_t mark_flag[ROC_NIX_TM_MARK_MAX] = {
33 	[ROC_NIX_TM_MARK_VLAN_DEI] = NIX_TM_MARK_VLAN_DEI_EN,
34 	[ROC_NIX_TM_MARK_IPV4_DSCP] = NIX_TM_MARK_IP_DSCP_EN,
35 	[ROC_NIX_TM_MARK_IPV4_ECN] = NIX_TM_MARK_IP_ECN_EN,
36 	[ROC_NIX_TM_MARK_IPV6_DSCP] = NIX_TM_MARK_IP_DSCP_EN,
37 	[ROC_NIX_TM_MARK_IPV6_ECN] = NIX_TM_MARK_IP_ECN_EN,
38 };
39 
40 static uint8_t
prepare_tm_shaper_red_algo(struct nix_tm_node * tm_node,volatile uint64_t * reg,volatile uint64_t * regval,volatile uint64_t * regval_mask)41 prepare_tm_shaper_red_algo(struct nix_tm_node *tm_node, volatile uint64_t *reg,
42 			   volatile uint64_t *regval,
43 			   volatile uint64_t *regval_mask)
44 {
45 	uint32_t schq = tm_node->hw_id;
46 	uint8_t k = 0;
47 
48 	plt_tm_dbg("Shaper read alg node %s(%u) lvl %u id %u, red_alg %x (%p)",
49 		   nix_tm_hwlvl2str(tm_node->hw_lvl), schq, tm_node->lvl,
50 		   tm_node->id, tm_node->red_algo, tm_node);
51 
52 	/* Configure just RED algo */
53 	regval[k] = ((uint64_t)tm_node->red_algo << 9);
54 	regval_mask[k] = ~(BIT_ULL(10) | BIT_ULL(9));
55 
56 	switch (tm_node->hw_lvl) {
57 	case NIX_TXSCH_LVL_SMQ:
58 		reg[k] = NIX_AF_MDQX_SHAPE(schq);
59 		k++;
60 		break;
61 	case NIX_TXSCH_LVL_TL4:
62 		reg[k] = NIX_AF_TL4X_SHAPE(schq);
63 		k++;
64 		break;
65 	case NIX_TXSCH_LVL_TL3:
66 		reg[k] = NIX_AF_TL3X_SHAPE(schq);
67 		k++;
68 		break;
69 	case NIX_TXSCH_LVL_TL2:
70 		reg[k] = NIX_AF_TL2X_SHAPE(schq);
71 		k++;
72 		break;
73 	default:
74 		break;
75 	}
76 
77 	return k;
78 }
79 
80 /* Only called while device is stopped */
81 static int
nix_tm_update_red_algo(struct nix * nix,bool red_send)82 nix_tm_update_red_algo(struct nix *nix, bool red_send)
83 {
84 	struct mbox *mbox = (&nix->dev)->mbox;
85 	struct nix_txschq_config *req;
86 	struct nix_tm_node_list *list;
87 	struct nix_tm_node *tm_node;
88 	uint8_t k;
89 	int rc;
90 
91 	list = nix_tm_node_list(nix, nix->tm_tree);
92 	TAILQ_FOREACH(tm_node, list, node) {
93 		/* Skip leaf nodes */
94 		if (nix_tm_is_leaf(nix, tm_node->lvl))
95 			continue;
96 
97 		if (tm_node->hw_lvl == NIX_TXSCH_LVL_TL1)
98 			continue;
99 
100 		/* Skip if no update of red_algo is needed */
101 		if ((red_send && (tm_node->red_algo == NIX_REDALG_SEND)) ||
102 		    (!red_send && (tm_node->red_algo != NIX_REDALG_SEND)))
103 			continue;
104 
105 		/* Update Red algo */
106 		if (red_send)
107 			tm_node->red_algo = NIX_REDALG_SEND;
108 		else
109 			tm_node->red_algo = NIX_REDALG_STD;
110 
111 		/* Update txschq config  */
112 		req = mbox_alloc_msg_nix_txschq_cfg(mbox);
113 		if (req == NULL)
114 			return -ENOSPC;
115 
116 		req->lvl = tm_node->hw_lvl;
117 		k = prepare_tm_shaper_red_algo(tm_node, req->reg, req->regval,
118 					       req->regval_mask);
119 		req->num_regs = k;
120 
121 		rc = mbox_process(mbox);
122 		if (rc)
123 			return rc;
124 	}
125 	return 0;
126 }
127 
128 /* Return's true if queue reconfig is needed */
129 static bool
nix_tm_update_markfmt(struct nix * nix,enum roc_nix_tm_mark type,int mark_yellow,int mark_red)130 nix_tm_update_markfmt(struct nix *nix, enum roc_nix_tm_mark type,
131 		      int mark_yellow, int mark_red)
132 {
133 	uint64_t new_markfmt, old_markfmt;
134 	uint8_t *tm_markfmt;
135 	uint8_t en_shift;
136 	uint64_t mask;
137 
138 	if (type >= ROC_NIX_TM_MARK_MAX)
139 		return false;
140 
141 	/* Pre-allocated mark formats for type:color combinations */
142 	tm_markfmt = nix->tm_markfmt[type];
143 
144 	if (!mark_yellow && !mark_red) {
145 		/* Null format to disable */
146 		new_markfmt = nix->tm_markfmt_null;
147 	} else {
148 		/* Marking enabled with combination of yellow and red */
149 		if (mark_yellow && mark_red)
150 			new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y_R];
151 		else if (mark_yellow)
152 			new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y];
153 		else
154 			new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_R];
155 	}
156 
157 	mask = 0xFFull;
158 	/* Format of fast path markfmt
159 	 * ipv6_ecn[8]:ipv4_ecn[8]:ipv6_dscp[8]:ipv4_dscp[8]:vlan_dei[16]
160 	 * fmt[7] = ptr offset for IPv4/IPv6 on l2_len.
161 	 * fmt[6:0] = markfmt idx.
162 	 */
163 	switch (type) {
164 	case ROC_NIX_TM_MARK_VLAN_DEI:
165 		en_shift = NIX_TM_MARK_VLAN_DEI_SHIFT;
166 		mask = 0xFFFFull;
167 		new_markfmt |= new_markfmt << 8;
168 		break;
169 	case ROC_NIX_TM_MARK_IPV4_DSCP:
170 		new_markfmt |= BIT_ULL(7);
171 		en_shift = NIX_TM_MARK_IPV4_DSCP_SHIFT;
172 		break;
173 	case ROC_NIX_TM_MARK_IPV4_ECN:
174 		new_markfmt |= BIT_ULL(7);
175 		en_shift = NIX_TM_MARK_IPV4_ECN_SHIFT;
176 		break;
177 	case ROC_NIX_TM_MARK_IPV6_DSCP:
178 		en_shift = NIX_TM_MARK_IPV6_DSCP_SHIFT;
179 		break;
180 	case ROC_NIX_TM_MARK_IPV6_ECN:
181 		new_markfmt |= BIT_ULL(7);
182 		en_shift = NIX_TM_MARK_IPV6_ECN_SHIFT;
183 		break;
184 	default:
185 		return false;
186 	}
187 
188 	/* Skip if same as old config */
189 	old_markfmt = (nix->tm_markfmt_en >> en_shift) & mask;
190 	if (old_markfmt == new_markfmt)
191 		return false;
192 
193 	/* Need queue reconfig */
194 	nix->tm_markfmt_en &= ~(mask << en_shift);
195 	nix->tm_markfmt_en |= (new_markfmt << en_shift);
196 
197 	return true;
198 }
199 
200 int
nix_tm_mark_init(struct nix * nix)201 nix_tm_mark_init(struct nix *nix)
202 {
203 	struct mbox *mbox = (&nix->dev)->mbox;
204 	struct nix_mark_format_cfg_rsp *rsp;
205 	struct nix_mark_format_cfg *req;
206 	int rc, i, j;
207 
208 	/* Check for supported revisions */
209 	if (roc_model_is_cn96_ax() || roc_model_is_cn95_a0())
210 		return 0;
211 
212 	/* Null mark format */
213 	req = mbox_alloc_msg_nix_mark_format_cfg(mbox);
214 	if (req == NULL)
215 		return -ENOSPC;
216 
217 	rc = mbox_process_msg(mbox, (void *)&rsp);
218 	if (rc) {
219 		plt_err("TM failed to alloc null mark format, rc=%d", rc);
220 		goto exit;
221 	}
222 
223 	nix->tm_markfmt_null = rsp->mark_format_idx;
224 
225 	/* Alloc vlan, dscp, ecn mark formats */
226 	for (i = 0; i < ROC_NIX_TM_MARK_MAX; i++) {
227 		for (j = 0; j < ROC_NIX_TM_MARK_COLOR_MAX; j++) {
228 			req = mbox_alloc_msg_nix_mark_format_cfg(mbox);
229 			if (req == NULL)
230 				return -ENOSPC;
231 
232 			req->offset = mark_off[i];
233 
234 			switch (j) {
235 			case ROC_NIX_TM_MARK_COLOR_Y:
236 				req->y_mask = y_mask_val[i][0];
237 				req->y_val = y_mask_val[i][1];
238 				break;
239 			case ROC_NIX_TM_MARK_COLOR_R:
240 				req->r_mask = r_mask_val[i][0];
241 				req->r_val = r_mask_val[i][1];
242 				break;
243 			case ROC_NIX_TM_MARK_COLOR_Y_R:
244 				req->y_mask = y_mask_val[i][0];
245 				req->y_val = y_mask_val[i][1];
246 				req->r_mask = r_mask_val[i][0];
247 				req->r_val = r_mask_val[i][1];
248 				break;
249 			}
250 
251 			rc = mbox_process_msg(mbox, (void *)&rsp);
252 			if (rc) {
253 				plt_err("TM failed to alloc mark fmt "
254 					"type %u color %u, rc=%d",
255 					i, j, rc);
256 				goto exit;
257 			}
258 
259 			nix->tm_markfmt[i][j] = rsp->mark_format_idx;
260 			plt_tm_dbg("Mark type: %u, Mark Color:%u, id:%u\n", i,
261 				   j, nix->tm_markfmt[i][j]);
262 		}
263 	}
264 	/* Update null mark format as default */
265 	nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_VLAN_DEI, 0, 0);
266 	nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_DSCP, 0, 0);
267 	nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_ECN, 0, 0);
268 	nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_DSCP, 0, 0);
269 	nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_ECN, 0, 0);
270 exit:
271 	return rc;
272 }
273 
274 int
roc_nix_tm_mark_config(struct roc_nix * roc_nix,enum roc_nix_tm_mark type,int mark_yellow,int mark_red)275 roc_nix_tm_mark_config(struct roc_nix *roc_nix, enum roc_nix_tm_mark type,
276 		       int mark_yellow, int mark_red)
277 {
278 	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
279 	int rc;
280 
281 	if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
282 		return -EINVAL;
283 
284 	rc = nix_tm_update_markfmt(nix, type, mark_yellow, mark_red);
285 	if (!rc)
286 		return 0;
287 
288 	if (!mark_yellow && !mark_red)
289 		nix->tm_flags &= ~mark_flag[type];
290 	else
291 		nix->tm_flags |= mark_flag[type];
292 
293 	/* Update red algo for change in mark_red */
294 	return nix_tm_update_red_algo(nix, !!mark_red);
295 }
296 
297 uint64_t
roc_nix_tm_mark_format_get(struct roc_nix * roc_nix,uint64_t * flags)298 roc_nix_tm_mark_format_get(struct roc_nix *roc_nix, uint64_t *flags)
299 {
300 	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
301 
302 	*flags = ((nix->tm_flags & NIX_TM_MARK_EN_MASK) >> 3);
303 	return nix->tm_markfmt_en;
304 }
305