xref: /dpdk/drivers/common/cnxk/roc_npc_aging.c (revision 118ba4e3f2a39e6fc10075c680310f4cdabc1bd7)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2023 Marvell.
3  */
4 
5 #include "roc_api.h"
6 #include "roc_priv.h"
7 
8 int
9 npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc)
10 {
11 	struct roc_npc_flow_age *flow_age;
12 	uint8_t *age_mem = NULL;
13 	uint32_t bmap_sz;
14 	int rc = 0;
15 
16 	bmap_sz = plt_bitmap_get_memory_footprint(MCAM_ARR_ELEM_SZ *
17 						  MCAM_ARR_SIZE);
18 	age_mem = plt_zmalloc(bmap_sz, 0);
19 	if (age_mem == NULL) {
20 		plt_err("Bmap alloc failed");
21 		rc = NPC_ERR_NO_MEM;
22 		goto done;
23 	}
24 
25 	flow_age = &roc_npc->flow_age;
26 	flow_age->age_mem = age_mem;
27 	flow_age->aged_flows = plt_bitmap_init(MCAM_ARR_ELEM_SZ * MCAM_ARR_SIZE,
28 					       age_mem, bmap_sz);
29 	if (!flow_age->aged_flows) {
30 		plt_err("Bitmap init failed");
31 		plt_free(age_mem);
32 		rc = NPC_ERR_NO_MEM;
33 		goto done;
34 	}
35 
36 done:
37 	return rc;
38 }
39 
40 void
41 npc_aged_flows_bitmap_free(struct roc_npc *roc_npc)
42 {
43 	struct roc_npc_flow_age *flow_age;
44 
45 	flow_age = &roc_npc->flow_age;
46 	plt_bitmap_free(flow_age->aged_flows);
47 	if (flow_age->age_mem)
48 		plt_free(roc_npc->flow_age.age_mem);
49 }
50 
51 static void
52 check_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
53 {
54 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
55 	struct npc_age_flow_list_head *list;
56 	struct npc_age_flow_entry *fl_iter;
57 	struct roc_npc_flow_age *flow_age;
58 
59 	flow_age = &roc_npc->flow_age;
60 	list = &npc->age_flow_list;
61 	TAILQ_FOREACH(fl_iter, list, next) {
62 		if (fl_iter->flow->mcam_id == mcam_id &&
63 		    fl_iter->flow->timeout_cycles < plt_tsc_cycles()) {
64 			/* update bitmap */
65 			plt_bitmap_set(flow_age->aged_flows, mcam_id);
66 			if (flow_age->aged_flows_cnt == 0) {
67 				flow_age->start_id = mcam_id;
68 				flow_age->end_id = mcam_id;
69 			}
70 			if (flow_age->start_id > mcam_id)
71 				flow_age->start_id = mcam_id;
72 			else if (flow_age->end_id < mcam_id)
73 				flow_age->end_id = mcam_id;
74 			flow_age->aged_flows_cnt += 1;
75 			break;
76 		}
77 	}
78 }
79 
80 static void
81 update_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
82 {
83 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
84 	struct npc_age_flow_list_head *list;
85 	struct npc_age_flow_entry *fl_iter;
86 
87 	list = &npc->age_flow_list;
88 	TAILQ_FOREACH(fl_iter, list, next) {
89 		if (fl_iter->flow->mcam_id == mcam_id) {
90 			fl_iter->flow->timeout_cycles = plt_tsc_cycles() +
91 				fl_iter->flow->timeout * plt_tsc_hz();
92 			break;
93 		}
94 	}
95 }
96 
97 static int
98 npc_mcam_get_hit_status(struct npc *npc, uint64_t *mcam_ids, uint16_t start_id,
99 			uint16_t end_id, uint64_t *hit_status, bool clear)
100 {
101 	struct npc_mcam_get_hit_status_req *req;
102 	struct npc_mcam_get_hit_status_rsp *rsp;
103 	struct mbox *mbox = mbox_get(npc->mbox);
104 	uint8_t idx_start;
105 	uint8_t idx_end;
106 	int rc;
107 	int i;
108 
109 	req = mbox_alloc_msg_npc_mcam_get_hit_status(mbox);
110 	if (req == NULL)
111 		return -ENOSPC;
112 
113 	idx_start = start_id / MCAM_ARR_ELEM_SZ;
114 	idx_end = end_id / MCAM_ARR_ELEM_SZ;
115 
116 	for (i = idx_start; i <= idx_end; i++)
117 		req->mcam_ids[i] = mcam_ids[i];
118 
119 	req->range_valid_mcam_ids_start = start_id;
120 	req->range_valid_mcam_ids_end = end_id;
121 	req->clear = clear;
122 
123 	rc = mbox_process_msg(mbox, (void *)&rsp);
124 	if (rc)
125 		goto exit;
126 
127 	for (i = idx_start; i <= idx_end; i++)
128 		hit_status[i] = rsp->mcam_hit_status[i];
129 
130 	rc = 0;
131 exit:
132 	mbox_put(mbox);
133 	return rc;
134 }
135 
136 static void
137 npc_age_wait_until(struct roc_npc_flow_age *flow_age)
138 {
139 #define NPC_AGE_WAIT_TIMEOUT_MS 1000
140 #define NPC_AGE_WAIT_TIMEOUT_US (NPC_AGE_WAIT_TIMEOUT_MS * NPC_AGE_WAIT_TIMEOUT_MS)
141 	uint64_t timeout = 0;
142 	uint64_t sleep = 10 * NPC_AGE_WAIT_TIMEOUT_MS;
143 
144 	do {
145 		plt_delay_us(sleep);
146 		timeout += sleep;
147 	} while (!flow_age->aged_flows_get_thread_exit &&
148 		 (timeout < ((uint64_t)flow_age->aging_poll_freq * NPC_AGE_WAIT_TIMEOUT_US)));
149 }
150 
151 uint32_t
152 npc_aged_flows_get(void *args)
153 {
154 	uint64_t hit_status[MCAM_ARR_SIZE] = {0};
155 	uint64_t mcam_ids[MCAM_ARR_SIZE] = {0};
156 	struct npc_age_flow_list_head *list;
157 	struct npc_age_flow_entry *fl_iter;
158 	struct roc_npc *roc_npc = args;
159 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
160 	struct roc_npc_flow_age *flow_age;
161 	bool aging_enabled;
162 	uint32_t start_id;
163 	uint32_t end_id;
164 	uint32_t mcam_id;
165 	uint32_t idx;
166 	uint32_t i;
167 	int rc;
168 
169 	flow_age = &roc_npc->flow_age;
170 	list = &npc->age_flow_list;
171 	while (!flow_age->aged_flows_get_thread_exit) {
172 		start_id = 0;
173 		end_id = 0;
174 		aging_enabled = false;
175 		memset(mcam_ids, 0, sizeof(mcam_ids));
176 		TAILQ_FOREACH(fl_iter, list, next) {
177 			mcam_id = fl_iter->flow->mcam_id;
178 			idx = mcam_id / MCAM_ARR_ELEM_SZ;
179 			mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
180 
181 			if (!aging_enabled) {
182 				start_id = mcam_id;
183 				end_id = mcam_id;
184 				aging_enabled = true;
185 			}
186 
187 			if (mcam_id < start_id)
188 				start_id = mcam_id;
189 			else if (mcam_id > end_id)
190 				end_id = mcam_id;
191 		}
192 
193 		if (!aging_enabled)
194 			goto lbl_sleep;
195 
196 		rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
197 					     hit_status, true);
198 		if (rc)
199 			return 0;
200 
201 		plt_seqcount_write_begin(&flow_age->seq_cnt);
202 		flow_age->aged_flows_cnt = 0;
203 		for (i = start_id; i <= end_id; i++) {
204 			idx = i / MCAM_ARR_ELEM_SZ;
205 			if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
206 				if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
207 					check_timeout_cycles(roc_npc, i);
208 				else
209 					update_timeout_cycles(roc_npc, i);
210 			}
211 		}
212 		plt_seqcount_write_end(&flow_age->seq_cnt);
213 
214 lbl_sleep:
215 		npc_age_wait_until(flow_age);
216 	}
217 
218 	return 0;
219 }
220 
221 void
222 npc_age_flow_list_entry_add(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
223 {
224 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
225 	struct npc_age_flow_entry *age_fl_iter;
226 	struct npc_age_flow_entry *new_entry;
227 
228 	new_entry = plt_zmalloc(sizeof(*new_entry), 0);
229 	if (new_entry == NULL) {
230 		plt_err("flow entry alloc failed");
231 		return;
232 	}
233 
234 	new_entry->flow = flow;
235 	roc_npc->flow_age.age_flow_refcnt++;
236 	/* List in ascending order of mcam entries */
237 	TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
238 		if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
239 			TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
240 			return;
241 		}
242 	}
243 	TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
244 }
245 
246 void
247 npc_age_flow_list_entry_delete(struct roc_npc *roc_npc,
248 			       struct roc_npc_flow *flow)
249 {
250 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
251 	struct npc_age_flow_list_head *list;
252 	struct roc_npc_flow_age *flow_age;
253 	struct npc_age_flow_entry *curr;
254 
255 	flow_age = &roc_npc->flow_age;
256 
257 	list = &npc->age_flow_list;
258 	curr = TAILQ_FIRST(list);
259 
260 	if (!curr)
261 		return;
262 
263 	while (curr) {
264 		if (flow->mcam_id == curr->flow->mcam_id) {
265 			plt_bitmap_clear(flow_age->aged_flows, flow->mcam_id);
266 			TAILQ_REMOVE(list, curr, next);
267 			plt_free(curr);
268 			break;
269 		}
270 		curr = TAILQ_NEXT(curr, next);
271 	}
272 	roc_npc->flow_age.age_flow_refcnt--;
273 }
274 
275 int
276 npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
277 			     const struct roc_npc_action_age *age,
278 			     struct roc_npc_flow *flow)
279 {
280 	struct roc_npc_flow_age *flow_age;
281 	int errcode = 0;
282 
283 	flow_age = &roc_npc->flow_age;
284 	if (age->timeout < flow_age->aging_poll_freq) {
285 		plt_err("Age timeout should be greater or equal to %u seconds",
286 			flow_age->aging_poll_freq);
287 		errcode = NPC_ERR_ACTION_NOTSUP;
288 		goto done;
289 	}
290 
291 	flow->age_context = age->context == NULL ? flow : age->context;
292 	flow->timeout = age->timeout;
293 	flow->timeout_cycles = plt_tsc_cycles() + age->timeout * plt_tsc_hz();
294 	flow->has_age_action = true;
295 
296 	if (flow_age->age_flow_refcnt == 0) {
297 		errcode = npc_aged_flows_bitmap_alloc(roc_npc);
298 		if (errcode != 0)
299 			goto done;
300 
301 		flow_age->aged_flows_get_thread_exit = false;
302 		if (plt_thread_create_control(&flow_age->aged_flows_poll_thread,
303 					   "Aged Flows Get Ctrl Thread",
304 					   npc_aged_flows_get, roc_npc) != 0) {
305 			plt_err("Failed to create thread for age flows");
306 			npc_aged_flows_bitmap_free(roc_npc);
307 			errcode = NPC_ERR_ACTION_NOTSUP;
308 			goto done;
309 		}
310 	}
311 done:
312 	return errcode;
313 }
314 
315 void
316 npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
317 {
318 	struct roc_npc_flow_age *flow_age;
319 
320 	flow_age = &roc_npc->flow_age;
321 	if (plt_thread_is_valid(flow_age->aged_flows_poll_thread)) {
322 		flow_age->aged_flows_get_thread_exit = true;
323 		plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
324 		npc_aged_flows_bitmap_free(roc_npc);
325 	}
326 }
327 
328 void *
329 roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id)
330 {
331 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
332 	struct npc_age_flow_list_head *list;
333 	struct npc_age_flow_entry *fl_iter;
334 
335 	list = &npc->age_flow_list;
336 
337 	TAILQ_FOREACH(fl_iter, list, next) {
338 		if (fl_iter->flow->mcam_id == mcam_id)
339 			return fl_iter->flow->age_context;
340 	}
341 
342 	return NULL;
343 }
344