Branch data Line data Source code
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 : 0 : 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 : 0 : age_mem = plt_zmalloc(bmap_sz, 0);
19 [ # # ]: 0 : if (age_mem == NULL) {
20 : 0 : plt_err("Bmap alloc failed");
21 : : rc = NPC_ERR_NO_MEM;
22 : 0 : goto done;
23 : : }
24 : :
25 : : flow_age = &roc_npc->flow_age;
26 : 0 : flow_age->age_mem = age_mem;
27 : 0 : flow_age->aged_flows = plt_bitmap_init(MCAM_ARR_ELEM_SZ * MCAM_ARR_SIZE,
28 : : age_mem, bmap_sz);
29 [ # # ]: 0 : if (!flow_age->aged_flows) {
30 : 0 : plt_err("Bitmap init failed");
31 : 0 : plt_free(age_mem);
32 : : rc = NPC_ERR_NO_MEM;
33 : 0 : goto done;
34 : : }
35 : :
36 : 0 : done:
37 : 0 : return rc;
38 : : }
39 : :
40 : : void
41 : 0 : 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 [ # # ]: 0 : if (flow_age->age_mem)
48 : 0 : plt_free(roc_npc->flow_age.age_mem);
49 : 0 : }
50 : :
51 : : static void
52 : 0 : 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 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
62 [ # # # # ]: 0 : if (fl_iter->flow->mcam_id == mcam_id &&
63 : 0 : fl_iter->flow->timeout_cycles < plt_tsc_cycles()) {
64 : : /* update bitmap */
65 : 0 : plt_bitmap_set(flow_age->aged_flows, mcam_id);
66 [ # # ]: 0 : if (flow_age->aged_flows_cnt == 0) {
67 : 0 : flow_age->start_id = mcam_id;
68 : 0 : flow_age->end_id = mcam_id;
69 : : }
70 [ # # ]: 0 : if (flow_age->start_id > mcam_id)
71 : 0 : flow_age->start_id = mcam_id;
72 [ # # ]: 0 : else if (flow_age->end_id < mcam_id)
73 : 0 : flow_age->end_id = mcam_id;
74 : 0 : flow_age->aged_flows_cnt += 1;
75 : 0 : break;
76 : : }
77 : : }
78 : 0 : }
79 : :
80 : : static void
81 : 0 : 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 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
89 [ # # ]: 0 : if (fl_iter->flow->mcam_id == mcam_id) {
90 : 0 : fl_iter->flow->timeout_cycles = plt_tsc_cycles() +
91 : 0 : fl_iter->flow->timeout * plt_tsc_hz();
92 : 0 : break;
93 : : }
94 : : }
95 : 0 : }
96 : :
97 : : static int
98 : 0 : 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 : 0 : 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 : 0 : req = mbox_alloc_msg_npc_mcam_get_hit_status(mbox);
110 [ # # ]: 0 : if (req == NULL)
111 : : return -ENOSPC;
112 : :
113 : 0 : idx_start = start_id / MCAM_ARR_ELEM_SZ;
114 : 0 : idx_end = end_id / MCAM_ARR_ELEM_SZ;
115 : :
116 [ # # ]: 0 : for (i = idx_start; i <= idx_end; i++)
117 : 0 : req->mcam_ids[i] = mcam_ids[i];
118 : :
119 : 0 : req->range_valid_mcam_ids_start = start_id;
120 : 0 : req->range_valid_mcam_ids_end = end_id;
121 : 0 : req->clear = clear;
122 : :
123 : : rc = mbox_process_msg(mbox, (void *)&rsp);
124 [ # # ]: 0 : if (rc)
125 : 0 : goto exit;
126 : :
127 [ # # ]: 0 : for (i = idx_start; i <= idx_end; i++)
128 : 0 : hit_status[i] = rsp->mcam_hit_status[i];
129 : :
130 : : rc = 0;
131 : 0 : exit:
132 : : mbox_put(mbox);
133 : 0 : 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 : 0 : plt_delay_us(sleep);
146 : 0 : timeout += sleep;
147 [ # # ]: 0 : } while (!flow_age->aged_flows_get_thread_exit &&
148 [ # # ]: 0 : (timeout < ((uint64_t)flow_age->aging_poll_freq * NPC_AGE_WAIT_TIMEOUT_US)));
149 : : }
150 : :
151 : : uint32_t
152 : 0 : npc_aged_flows_get(void *args)
153 : : {
154 : 0 : 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 [ # # ]: 0 : 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 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
177 : 0 : mcam_id = fl_iter->flow->mcam_id;
178 : 0 : idx = mcam_id / MCAM_ARR_ELEM_SZ;
179 : 0 : mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
180 : :
181 [ # # ]: 0 : if (!aging_enabled) {
182 : : start_id = mcam_id;
183 : : end_id = mcam_id;
184 : : aging_enabled = true;
185 : : }
186 : :
187 [ # # ]: 0 : 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 [ # # ]: 0 : if (!aging_enabled)
194 : 0 : goto lbl_sleep;
195 : :
196 : 0 : rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
197 : : hit_status, true);
198 [ # # ]: 0 : if (rc)
199 : : return 0;
200 : :
201 : 0 : plt_seqcount_write_begin(&flow_age->seq_cnt);
202 : 0 : flow_age->aged_flows_cnt = 0;
203 [ # # ]: 0 : for (i = start_id; i <= end_id; i++) {
204 : 0 : idx = i / MCAM_ARR_ELEM_SZ;
205 [ # # ]: 0 : if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
206 [ # # ]: 0 : if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
207 : 0 : check_timeout_cycles(roc_npc, i);
208 : : else
209 : 0 : 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 : 0 : 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 : 0 : new_entry = plt_zmalloc(sizeof(*new_entry), 0);
229 [ # # ]: 0 : if (new_entry == NULL) {
230 : 0 : plt_err("flow entry alloc failed");
231 : 0 : return;
232 : : }
233 : :
234 : 0 : new_entry->flow = flow;
235 : 0 : roc_npc->flow_age.age_flow_refcnt++;
236 : : /* List in ascending order of mcam entries */
237 [ # # ]: 0 : TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
238 [ # # ]: 0 : if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
239 : 0 : TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
240 : 0 : return;
241 : : }
242 : : }
243 : 0 : TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
244 : : }
245 : :
246 : : void
247 : 0 : 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 : 0 : curr = TAILQ_FIRST(list);
259 : :
260 [ # # ]: 0 : if (!curr)
261 : : return;
262 : :
263 [ # # ]: 0 : while (curr) {
264 [ # # ]: 0 : if (flow->mcam_id == curr->flow->mcam_id) {
265 : 0 : plt_bitmap_clear(flow_age->aged_flows, flow->mcam_id);
266 [ # # ]: 0 : TAILQ_REMOVE(list, curr, next);
267 : 0 : plt_free(curr);
268 : 0 : break;
269 : : }
270 : 0 : curr = TAILQ_NEXT(curr, next);
271 : : }
272 : 0 : roc_npc->flow_age.age_flow_refcnt--;
273 : : }
274 : :
275 : : int
276 : 0 : 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 [ # # ]: 0 : if (age->timeout < flow_age->aging_poll_freq) {
285 : 0 : 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 : 0 : goto done;
289 : : }
290 : :
291 [ # # ]: 0 : flow->age_context = age->context == NULL ? flow : age->context;
292 : 0 : flow->timeout = age->timeout;
293 : 0 : flow->timeout_cycles = plt_tsc_cycles() + age->timeout * plt_tsc_hz();
294 : 0 : flow->has_age_action = true;
295 : :
296 [ # # ]: 0 : if (flow_age->age_flow_refcnt == 0) {
297 : 0 : errcode = npc_aged_flows_bitmap_alloc(roc_npc);
298 [ # # ]: 0 : if (errcode != 0)
299 : 0 : goto done;
300 : :
301 : 0 : flow_age->aged_flows_get_thread_exit = false;
302 [ # # ]: 0 : 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 : 0 : plt_err("Failed to create thread for age flows");
306 : 0 : npc_aged_flows_bitmap_free(roc_npc);
307 : : errcode = NPC_ERR_ACTION_NOTSUP;
308 : 0 : goto done;
309 : : }
310 : : }
311 : 0 : done:
312 : 0 : return errcode;
313 : : }
314 : :
315 : : void
316 : 0 : npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
317 : : {
318 : : struct roc_npc_flow_age *flow_age;
319 : :
320 : 0 : flow_age = &roc_npc->flow_age;
321 [ # # ]: 0 : if (plt_thread_is_valid(flow_age->aged_flows_poll_thread)) {
322 : 0 : flow_age->aged_flows_get_thread_exit = true;
323 : 0 : plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
324 : 0 : npc_aged_flows_bitmap_free(roc_npc);
325 : : }
326 : 0 : }
327 : :
328 : : void *
329 : 0 : 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 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
338 [ # # ]: 0 : if (fl_iter->flow->mcam_id == mcam_id)
339 : 0 : return fl_iter->flow->age_context;
340 : : }
341 : :
342 : : return NULL;
343 : : }
|