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 : : uint32_t
137 : 0 : npc_aged_flows_get(void *args)
138 : : {
139 : 0 : uint64_t hit_status[MCAM_ARR_SIZE] = {0};
140 : : uint64_t mcam_ids[MCAM_ARR_SIZE] = {0};
141 : : struct npc_age_flow_list_head *list;
142 : : struct npc_age_flow_entry *fl_iter;
143 : : struct roc_npc *roc_npc = args;
144 : : struct npc *npc = roc_npc_to_npc_priv(roc_npc);
145 : : struct roc_npc_flow_age *flow_age;
146 : : bool aging_enabled;
147 : : uint32_t start_id;
148 : : uint32_t end_id;
149 : : uint32_t mcam_id;
150 : : uint32_t idx;
151 : : uint32_t i;
152 : : int rc;
153 : :
154 : : flow_age = &roc_npc->flow_age;
155 : : list = &npc->age_flow_list;
156 [ # # ]: 0 : while (!flow_age->aged_flows_get_thread_exit) {
157 : : start_id = 0;
158 : : end_id = 0;
159 : : aging_enabled = false;
160 : : memset(mcam_ids, 0, sizeof(mcam_ids));
161 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
162 : 0 : mcam_id = fl_iter->flow->mcam_id;
163 : 0 : idx = mcam_id / MCAM_ARR_ELEM_SZ;
164 : 0 : mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
165 : :
166 [ # # ]: 0 : if (!aging_enabled) {
167 : : start_id = mcam_id;
168 : : end_id = mcam_id;
169 : : aging_enabled = true;
170 : : }
171 : :
172 [ # # ]: 0 : if (mcam_id < start_id)
173 : : start_id = mcam_id;
174 : : else if (mcam_id > end_id)
175 : : end_id = mcam_id;
176 : : }
177 : :
178 [ # # ]: 0 : if (!aging_enabled)
179 : 0 : goto lbl_sleep;
180 : :
181 : 0 : rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
182 : : hit_status, true);
183 [ # # ]: 0 : if (rc)
184 : : return 0;
185 : :
186 : 0 : plt_seqcount_write_begin(&flow_age->seq_cnt);
187 : 0 : flow_age->aged_flows_cnt = 0;
188 [ # # ]: 0 : for (i = start_id; i <= end_id; i++) {
189 : 0 : idx = i / MCAM_ARR_ELEM_SZ;
190 [ # # ]: 0 : if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
191 [ # # ]: 0 : if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
192 : 0 : check_timeout_cycles(roc_npc, i);
193 : : else
194 : 0 : update_timeout_cycles(roc_npc, i);
195 : : }
196 : : }
197 : : plt_seqcount_write_end(&flow_age->seq_cnt);
198 : :
199 : 0 : lbl_sleep:
200 : 0 : sleep(flow_age->aging_poll_freq);
201 : : }
202 : :
203 : : return 0;
204 : : }
205 : :
206 : : void
207 : 0 : npc_age_flow_list_entry_add(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
208 : : {
209 : : struct npc *npc = roc_npc_to_npc_priv(roc_npc);
210 : : struct npc_age_flow_entry *age_fl_iter;
211 : : struct npc_age_flow_entry *new_entry;
212 : :
213 : 0 : new_entry = plt_zmalloc(sizeof(*new_entry), 0);
214 [ # # ]: 0 : if (new_entry == NULL) {
215 : 0 : plt_err("flow entry alloc failed");
216 : 0 : return;
217 : : }
218 : :
219 : 0 : new_entry->flow = flow;
220 : 0 : roc_npc->flow_age.age_flow_refcnt++;
221 : : /* List in ascending order of mcam entries */
222 [ # # ]: 0 : TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
223 [ # # ]: 0 : if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
224 : 0 : TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
225 : 0 : return;
226 : : }
227 : : }
228 : 0 : TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
229 : : }
230 : :
231 : : void
232 : 0 : npc_age_flow_list_entry_delete(struct roc_npc *roc_npc,
233 : : struct roc_npc_flow *flow)
234 : : {
235 : : struct npc *npc = roc_npc_to_npc_priv(roc_npc);
236 : : struct npc_age_flow_list_head *list;
237 : : struct npc_age_flow_entry *curr;
238 : :
239 : : list = &npc->age_flow_list;
240 : 0 : curr = TAILQ_FIRST(list);
241 : :
242 [ # # ]: 0 : if (!curr)
243 : : return;
244 : :
245 [ # # ]: 0 : while (curr) {
246 [ # # ]: 0 : if (flow->mcam_id == curr->flow->mcam_id) {
247 [ # # ]: 0 : TAILQ_REMOVE(list, curr, next);
248 : 0 : plt_free(curr);
249 : 0 : break;
250 : : }
251 : 0 : curr = TAILQ_NEXT(curr, next);
252 : : }
253 : 0 : roc_npc->flow_age.age_flow_refcnt--;
254 : : }
255 : :
256 : : int
257 : 0 : npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
258 : : const struct roc_npc_action_age *age,
259 : : struct roc_npc_flow *flow)
260 : : {
261 : : struct roc_npc_flow_age *flow_age;
262 : : int errcode = 0;
263 : :
264 : : flow_age = &roc_npc->flow_age;
265 [ # # ]: 0 : if (age->timeout < flow_age->aging_poll_freq) {
266 : 0 : plt_err("Age timeout should be greater or equal to %u seconds",
267 : : flow_age->aging_poll_freq);
268 : : errcode = NPC_ERR_ACTION_NOTSUP;
269 : 0 : goto done;
270 : : }
271 : :
272 [ # # ]: 0 : flow->age_context = age->context == NULL ? flow : age->context;
273 : 0 : flow->timeout = age->timeout;
274 : 0 : flow->timeout_cycles = plt_tsc_cycles() + age->timeout * plt_tsc_hz();
275 : 0 : flow->has_age_action = true;
276 : :
277 [ # # ]: 0 : if (flow_age->age_flow_refcnt == 0) {
278 : 0 : errcode = npc_aged_flows_bitmap_alloc(roc_npc);
279 [ # # ]: 0 : if (errcode != 0)
280 : 0 : goto done;
281 : :
282 : 0 : flow_age->aged_flows_get_thread_exit = false;
283 [ # # ]: 0 : if (plt_thread_create_control(&flow_age->aged_flows_poll_thread,
284 : : "Aged Flows Get Ctrl Thread",
285 : : npc_aged_flows_get, roc_npc) != 0) {
286 : 0 : plt_err("Failed to create thread for age flows");
287 : 0 : npc_aged_flows_bitmap_free(roc_npc);
288 : : errcode = NPC_ERR_ACTION_NOTSUP;
289 : 0 : goto done;
290 : : }
291 : : }
292 : 0 : done:
293 : 0 : return errcode;
294 : : }
295 : :
296 : : void
297 : 0 : npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
298 : : {
299 : : struct roc_npc_flow_age *flow_age;
300 : :
301 : 0 : flow_age = &roc_npc->flow_age;
302 : 0 : flow_age->aged_flows_get_thread_exit = true;
303 : 0 : plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
304 : 0 : npc_aged_flows_bitmap_free(roc_npc);
305 : 0 : }
306 : :
307 : : void *
308 : 0 : roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id)
309 : : {
310 : : struct npc *npc = roc_npc_to_npc_priv(roc_npc);
311 : : struct npc_age_flow_list_head *list;
312 : : struct npc_age_flow_entry *fl_iter;
313 : :
314 : : list = &npc->age_flow_list;
315 : :
316 [ # # ]: 0 : TAILQ_FOREACH(fl_iter, list, next) {
317 [ # # ]: 0 : if (fl_iter->flow->mcam_id == mcam_id)
318 : 0 : return fl_iter->flow->age_context;
319 : : }
320 : :
321 : : return NULL;
322 : : }
|