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