f-stack/dpdk/drivers/common/cnxk/roc_npc_aging.c

344 lines
8.2 KiB
C
Raw Normal View History

2025-01-10 11:50:43 +00:00
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(C) 2023 Marvell.
*/
#include "roc_api.h"
#include "roc_priv.h"
int
npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc)
{
struct roc_npc_flow_age *flow_age;
uint8_t *age_mem = NULL;
uint32_t bmap_sz;
int rc = 0;
bmap_sz = plt_bitmap_get_memory_footprint(MCAM_ARR_ELEM_SZ *
MCAM_ARR_SIZE);
age_mem = plt_zmalloc(bmap_sz, 0);
if (age_mem == NULL) {
plt_err("Bmap alloc failed");
rc = NPC_ERR_NO_MEM;
goto done;
}
flow_age = &roc_npc->flow_age;
flow_age->age_mem = age_mem;
flow_age->aged_flows = plt_bitmap_init(MCAM_ARR_ELEM_SZ * MCAM_ARR_SIZE,
age_mem, bmap_sz);
if (!flow_age->aged_flows) {
plt_err("Bitmap init failed");
plt_free(age_mem);
rc = NPC_ERR_NO_MEM;
goto done;
}
done:
return rc;
}
void
npc_aged_flows_bitmap_free(struct roc_npc *roc_npc)
{
struct roc_npc_flow_age *flow_age;
flow_age = &roc_npc->flow_age;
plt_bitmap_free(flow_age->aged_flows);
if (flow_age->age_mem)
plt_free(roc_npc->flow_age.age_mem);
}
static void
check_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct npc_age_flow_list_head *list;
struct npc_age_flow_entry *fl_iter;
struct roc_npc_flow_age *flow_age;
flow_age = &roc_npc->flow_age;
list = &npc->age_flow_list;
TAILQ_FOREACH(fl_iter, list, next) {
if (fl_iter->flow->mcam_id == mcam_id &&
fl_iter->flow->timeout_cycles < plt_tsc_cycles()) {
/* update bitmap */
plt_bitmap_set(flow_age->aged_flows, mcam_id);
if (flow_age->aged_flows_cnt == 0) {
flow_age->start_id = mcam_id;
flow_age->end_id = mcam_id;
}
if (flow_age->start_id > mcam_id)
flow_age->start_id = mcam_id;
else if (flow_age->end_id < mcam_id)
flow_age->end_id = mcam_id;
flow_age->aged_flows_cnt += 1;
break;
}
}
}
static void
update_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct npc_age_flow_list_head *list;
struct npc_age_flow_entry *fl_iter;
list = &npc->age_flow_list;
TAILQ_FOREACH(fl_iter, list, next) {
if (fl_iter->flow->mcam_id == mcam_id) {
fl_iter->flow->timeout_cycles = plt_tsc_cycles() +
fl_iter->flow->timeout * plt_tsc_hz();
break;
}
}
}
static int
npc_mcam_get_hit_status(struct npc *npc, uint64_t *mcam_ids, uint16_t start_id,
uint16_t end_id, uint64_t *hit_status, bool clear)
{
struct npc_mcam_get_hit_status_req *req;
struct npc_mcam_get_hit_status_rsp *rsp;
struct mbox *mbox = mbox_get(npc->mbox);
uint8_t idx_start;
uint8_t idx_end;
int rc;
int i;
req = mbox_alloc_msg_npc_mcam_get_hit_status(mbox);
if (req == NULL)
return -ENOSPC;
idx_start = start_id / MCAM_ARR_ELEM_SZ;
idx_end = end_id / MCAM_ARR_ELEM_SZ;
for (i = idx_start; i <= idx_end; i++)
req->mcam_ids[i] = mcam_ids[i];
req->range_valid_mcam_ids_start = start_id;
req->range_valid_mcam_ids_end = end_id;
req->clear = clear;
rc = mbox_process_msg(mbox, (void *)&rsp);
if (rc)
goto exit;
for (i = idx_start; i <= idx_end; i++)
hit_status[i] = rsp->mcam_hit_status[i];
rc = 0;
exit:
mbox_put(mbox);
return rc;
}
static void
npc_age_wait_until(struct roc_npc_flow_age *flow_age)
{
#define NPC_AGE_WAIT_TIMEOUT_MS 1000
#define NPC_AGE_WAIT_TIMEOUT_US (NPC_AGE_WAIT_TIMEOUT_MS * NPC_AGE_WAIT_TIMEOUT_MS)
uint64_t timeout = 0;
uint64_t sleep = 10 * NPC_AGE_WAIT_TIMEOUT_MS;
do {
plt_delay_us(sleep);
timeout += sleep;
} while (!flow_age->aged_flows_get_thread_exit &&
(timeout < ((uint64_t)flow_age->aging_poll_freq * NPC_AGE_WAIT_TIMEOUT_US)));
}
uint32_t
npc_aged_flows_get(void *args)
{
uint64_t hit_status[MCAM_ARR_SIZE] = {0};
uint64_t mcam_ids[MCAM_ARR_SIZE] = {0};
struct npc_age_flow_list_head *list;
struct npc_age_flow_entry *fl_iter;
struct roc_npc *roc_npc = args;
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct roc_npc_flow_age *flow_age;
bool aging_enabled;
uint32_t start_id;
uint32_t end_id;
uint32_t mcam_id;
uint32_t idx;
uint32_t i;
int rc;
flow_age = &roc_npc->flow_age;
list = &npc->age_flow_list;
while (!flow_age->aged_flows_get_thread_exit) {
start_id = 0;
end_id = 0;
aging_enabled = false;
memset(mcam_ids, 0, sizeof(mcam_ids));
TAILQ_FOREACH(fl_iter, list, next) {
mcam_id = fl_iter->flow->mcam_id;
idx = mcam_id / MCAM_ARR_ELEM_SZ;
mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
if (!aging_enabled) {
start_id = mcam_id;
end_id = mcam_id;
aging_enabled = true;
}
if (mcam_id < start_id)
start_id = mcam_id;
else if (mcam_id > end_id)
end_id = mcam_id;
}
if (!aging_enabled)
goto lbl_sleep;
rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
hit_status, true);
if (rc)
return 0;
plt_seqcount_write_begin(&flow_age->seq_cnt);
flow_age->aged_flows_cnt = 0;
for (i = start_id; i <= end_id; i++) {
idx = i / MCAM_ARR_ELEM_SZ;
if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
check_timeout_cycles(roc_npc, i);
else
update_timeout_cycles(roc_npc, i);
}
}
plt_seqcount_write_end(&flow_age->seq_cnt);
lbl_sleep:
npc_age_wait_until(flow_age);
}
return 0;
}
void
npc_age_flow_list_entry_add(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct npc_age_flow_entry *age_fl_iter;
struct npc_age_flow_entry *new_entry;
new_entry = plt_zmalloc(sizeof(*new_entry), 0);
if (new_entry == NULL) {
plt_err("flow entry alloc failed");
return;
}
new_entry->flow = flow;
roc_npc->flow_age.age_flow_refcnt++;
/* List in ascending order of mcam entries */
TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
return;
}
}
TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
}
void
npc_age_flow_list_entry_delete(struct roc_npc *roc_npc,
struct roc_npc_flow *flow)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct npc_age_flow_list_head *list;
struct roc_npc_flow_age *flow_age;
struct npc_age_flow_entry *curr;
flow_age = &roc_npc->flow_age;
list = &npc->age_flow_list;
curr = TAILQ_FIRST(list);
if (!curr)
return;
while (curr) {
if (flow->mcam_id == curr->flow->mcam_id) {
plt_bitmap_clear(flow_age->aged_flows, flow->mcam_id);
TAILQ_REMOVE(list, curr, next);
plt_free(curr);
break;
}
curr = TAILQ_NEXT(curr, next);
}
roc_npc->flow_age.age_flow_refcnt--;
}
int
npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
const struct roc_npc_action_age *age,
struct roc_npc_flow *flow)
{
struct roc_npc_flow_age *flow_age;
int errcode = 0;
flow_age = &roc_npc->flow_age;
if (age->timeout < flow_age->aging_poll_freq) {
plt_err("Age timeout should be greater or equal to %u seconds",
flow_age->aging_poll_freq);
errcode = NPC_ERR_ACTION_NOTSUP;
goto done;
}
flow->age_context = age->context == NULL ? flow : age->context;
flow->timeout = age->timeout;
flow->timeout_cycles = plt_tsc_cycles() + age->timeout * plt_tsc_hz();
flow->has_age_action = true;
if (flow_age->age_flow_refcnt == 0) {
errcode = npc_aged_flows_bitmap_alloc(roc_npc);
if (errcode != 0)
goto done;
flow_age->aged_flows_get_thread_exit = false;
if (plt_thread_create_control(&flow_age->aged_flows_poll_thread,
"Aged Flows Get Ctrl Thread",
npc_aged_flows_get, roc_npc) != 0) {
plt_err("Failed to create thread for age flows");
npc_aged_flows_bitmap_free(roc_npc);
errcode = NPC_ERR_ACTION_NOTSUP;
goto done;
}
}
done:
return errcode;
}
void
npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
{
struct roc_npc_flow_age *flow_age;
flow_age = &roc_npc->flow_age;
if (plt_thread_is_valid(flow_age->aged_flows_poll_thread)) {
flow_age->aged_flows_get_thread_exit = true;
plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
npc_aged_flows_bitmap_free(roc_npc);
}
}
void *
roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct npc_age_flow_list_head *list;
struct npc_age_flow_entry *fl_iter;
list = &npc->age_flow_list;
TAILQ_FOREACH(fl_iter, list, next) {
if (fl_iter->flow->mcam_id == mcam_id)
return fl_iter->flow->age_context;
}
return NULL;
}