[net-next] octeontx2-pf: Install TC filter rules in hardware based on priority
Commit Message
As of today, hardware does not support installing tc filter
rules based on priority. This patch adds support to install
the hardware rules based on priority. The final hardware rules
will not be dependent on rule installation order, it will be strictly
priority based, same as software.
Signed-off-by: Suman Ghosh <sumang@marvell.com>
---
.../net/ethernet/marvell/octeontx2/af/mbox.h | 9 +-
.../marvell/octeontx2/af/rvu_npc_fs.c | 10 +-
.../marvell/octeontx2/af/rvu_switch.c | 6 +-
.../marvell/octeontx2/nic/otx2_common.h | 11 +-
.../marvell/octeontx2/nic/otx2_devlink.c | 1 -
.../marvell/octeontx2/nic/otx2_flows.c | 2 +
.../ethernet/marvell/octeontx2/nic/otx2_tc.c | 315 +++++++++++++-----
7 files changed, 251 insertions(+), 103 deletions(-)
Comments
On Thu, Jul 13, 2023 at 12:10 AM Suman Ghosh <sumang@marvell.com> wrote:
>
> As of today, hardware does not support installing tc filter
> rules based on priority. This patch adds support to install
> the hardware rules based on priority. The final hardware rules
> will not be dependent on rule installation order, it will be strictly
> priority based, same as software.
>
> Signed-off-by: Suman Ghosh <sumang@marvell.com>
> ---
> .../net/ethernet/marvell/octeontx2/af/mbox.h | 9 +-
> .../marvell/octeontx2/af/rvu_npc_fs.c | 10 +-
> .../marvell/octeontx2/af/rvu_switch.c | 6 +-
> .../marvell/octeontx2/nic/otx2_common.h | 11 +-
> .../marvell/octeontx2/nic/otx2_devlink.c | 1 -
> .../marvell/octeontx2/nic/otx2_flows.c | 2 +
> .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 315 +++++++++++++-----
> 7 files changed, 251 insertions(+), 103 deletions(-)
>
>
Suman,
net-next is not yet open, please check the status here
http://vger.kernel.org/~davem/net-next.html
Thanks,
Sunil.
On Thu, 13 Jul 2023 00:46:49 +0530 Sunil Kovvuri wrote:
> net-next is not yet open, please check the status here
> http://vger.kernel.org/~davem/net-next.html
A bit of a change in process, sorry for the confusion.
The vger server was giving us grief so we switched the link to:
https://patchwork.hopto.org/net-next.html
We updated the docs but it will probably take a couple more weeks
before they are rendered online.
On Thu, Jul 13, 2023 at 12:10:11AM +0530, Suman Ghosh wrote:
> As of today, hardware does not support installing tc filter
> rules based on priority. This patch adds support to install
> the hardware rules based on priority. The final hardware rules
> will not be dependent on rule installation order, it will be strictly
> priority based, same as software.
>
> Signed-off-by: Suman Ghosh <sumang@marvell.com>
Hi Suman,
unfortunately this patch does not appear to apply to net-next,
which breaks our processes.
Please consider posting a v2 rebased on net-next.
Thanks!
> ---
> .../net/ethernet/marvell/octeontx2/af/mbox.h | 9 +-
> .../marvell/octeontx2/af/rvu_npc_fs.c | 10 +-
> .../marvell/octeontx2/af/rvu_switch.c | 6 +-
> .../marvell/octeontx2/nic/otx2_common.h | 11 +-
> .../marvell/octeontx2/nic/otx2_devlink.c | 1 -
> .../marvell/octeontx2/nic/otx2_flows.c | 2 +
> .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 315 +++++++++++++-----
> 7 files changed, 251 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> index 8d5d5a0f68c4..ba6e249ee1df 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> @@ -231,7 +231,7 @@ M(NPC_GET_KEX_CFG, 0x600c, npc_get_kex_cfg, \
> M(NPC_INSTALL_FLOW, 0x600d, npc_install_flow, \
> npc_install_flow_req, npc_install_flow_rsp) \
> M(NPC_DELETE_FLOW, 0x600e, npc_delete_flow, \
> - npc_delete_flow_req, msg_rsp) \
> + npc_delete_flow_req, npc_delete_flow_rsp) \
> M(NPC_MCAM_READ_ENTRY, 0x600f, npc_mcam_read_entry, \
> npc_mcam_read_entry_req, \
> npc_mcam_read_entry_rsp) \
> @@ -1467,6 +1467,8 @@ struct npc_install_flow_req {
> u8 vtag0_op;
> u16 vtag1_def;
> u8 vtag1_op;
> + /* old counter value */
> + u16 cntr_val;
> };
>
> struct npc_install_flow_rsp {
> @@ -1482,6 +1484,11 @@ struct npc_delete_flow_req {
> u8 all; /* PF + VFs */
> };
>
> +struct npc_delete_flow_rsp {
> + struct mbox_msghdr hdr;
> + u16 cntr_val;
> +};
> +
> struct npc_mcam_read_entry_req {
> struct mbox_msghdr hdr;
> u16 entry; /* MCAM entry to read */
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
> index 50d3994efa97..e016669bc327 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
> @@ -1148,7 +1148,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
> write_req.enable_entry = (u8)enable;
> /* if counter is available then clear and use it */
> if (req->set_cntr && rule->has_cntr) {
> - rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), 0x00);
> + rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), req->cntr_val);
> write_req.set_cntr = 1;
> write_req.cntr = rule->cntr;
> }
> @@ -1362,12 +1362,13 @@ static int npc_delete_flow(struct rvu *rvu, struct rvu_npc_mcam_rule *rule,
>
> int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
> struct npc_delete_flow_req *req,
> - struct msg_rsp *rsp)
> + struct npc_delete_flow_rsp *rsp)
> {
> struct npc_mcam *mcam = &rvu->hw->mcam;
> struct rvu_npc_mcam_rule *iter, *tmp;
> u16 pcifunc = req->hdr.pcifunc;
> struct list_head del_list;
> + int blkaddr;
>
> INIT_LIST_HEAD(&del_list);
>
> @@ -1383,6 +1384,11 @@ int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
> list_move_tail(&iter->list, &del_list);
> /* single rule */
> } else if (req->entry == iter->entry) {
> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> + if (blkaddr)
> + rsp->cntr_val = rvu_read64(rvu, blkaddr,
> + NPC_AF_MATCH_STATX(iter->cntr));
> +
> list_move_tail(&iter->list, &del_list);
> break;
> }
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> index 3392487f6b47..329b5a02914d 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> @@ -145,6 +145,7 @@ void rvu_switch_enable(struct rvu *rvu)
> struct npc_mcam_alloc_entry_req alloc_req = { 0 };
> struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
> struct npc_delete_flow_req uninstall_req = { 0 };
> + struct npc_delete_flow_rsp uninstall_rsp = { 0 };
> struct npc_mcam_free_entry_req free_req = { 0 };
> struct rvu_switch *rswitch = &rvu->rswitch;
> struct msg_rsp rsp;
> @@ -184,7 +185,7 @@ void rvu_switch_enable(struct rvu *rvu)
> uninstall_rules:
> uninstall_req.start = rswitch->start_entry;
> uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
> - rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
> + rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
> kfree(rswitch->entry2pcifunc);
> free_entries:
> free_req.all = 1;
> @@ -196,6 +197,7 @@ void rvu_switch_enable(struct rvu *rvu)
> void rvu_switch_disable(struct rvu *rvu)
> {
> struct npc_delete_flow_req uninstall_req = { 0 };
> + struct npc_delete_flow_rsp uninstall_rsp = { 0 };
> struct npc_mcam_free_entry_req free_req = { 0 };
> struct rvu_switch *rswitch = &rvu->rswitch;
> struct rvu_hwinfo *hw = rvu->hw;
> @@ -232,7 +234,7 @@ void rvu_switch_disable(struct rvu *rvu)
> uninstall_req.start = rswitch->start_entry;
> uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
> free_req.all = 1;
> - rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
> + rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
> rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
> rswitch->used_entries = 0;
> kfree(rswitch->entry2pcifunc);
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
> index 282db6fe3b08..6f1ff03cdc77 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
> @@ -337,13 +337,8 @@ struct otx2_flow_config {
> u32 *bmap_to_dmacindex;
> unsigned long *dmacflt_bmap;
> struct list_head flow_list;
> -};
> -
> -struct otx2_tc_info {
> - /* hash table to store TC offloaded flows */
> - struct rhashtable flow_table;
> - struct rhashtable_params flow_ht_params;
> - unsigned long *tc_entries_bitmap;
> + struct list_head flow_list_tc;
> + bool ntuple;
> };
>
> struct dev_hw_ops {
> @@ -463,7 +458,6 @@ struct otx2_nic {
> /* NPC MCAM */
> struct otx2_flow_config *flow_cfg;
> struct otx2_mac_table *mac_table;
> - struct otx2_tc_info tc_info;
>
> u64 reset_count;
> struct work_struct reset_task;
> @@ -1001,7 +995,6 @@ int otx2_init_tc(struct otx2_nic *nic);
> void otx2_shutdown_tc(struct otx2_nic *nic);
> int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
> void *type_data);
> -int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic);
> /* CGX/RPM DMAC filters support */
> int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf);
> int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u32 bit_pos);
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> index 777a27047c8e..5f71a72f95e5 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> @@ -41,7 +41,6 @@ static int otx2_dl_mcam_count_set(struct devlink *devlink, u32 id,
> return 0;
>
> otx2_alloc_mcam_entries(pfvf, ctx->val.vu16);
> - otx2_tc_alloc_ent_bitmap(pfvf);
>
> return 0;
> }
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> index 709fc0114fbd..70c3ae2caddd 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> @@ -253,6 +253,7 @@ int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
>
> flow_cfg = pfvf->flow_cfg;
> INIT_LIST_HEAD(&flow_cfg->flow_list);
> + INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
> flow_cfg->max_flows = 0;
>
> return 0;
> @@ -275,6 +276,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
> return -ENOMEM;
>
> INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
> + INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
>
> /* Allocate bare minimum number of MCAM entries needed for
> * unicast and ntuple filters.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> index e64318c110fd..070210e86778 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> @@ -48,9 +48,8 @@ struct otx2_tc_flow_stats {
> };
>
> struct otx2_tc_flow {
> - struct rhash_head node;
> + struct list_head list;
> unsigned long cookie;
> - unsigned int bitpos;
> struct rcu_head rcu;
> struct otx2_tc_flow_stats stats;
> spinlock_t lock; /* lock for stats */
> @@ -58,31 +57,10 @@ struct otx2_tc_flow {
> u16 entry;
> u16 leaf_profile;
> bool is_act_police;
> + u32 prio;
> + struct npc_install_flow_req req;
> };
>
> -int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic)
> -{
> - struct otx2_tc_info *tc = &nic->tc_info;
> -
> - if (!nic->flow_cfg->max_flows)
> - return 0;
> -
> - /* Max flows changed, free the existing bitmap */
> - kfree(tc->tc_entries_bitmap);
> -
> - tc->tc_entries_bitmap =
> - kcalloc(BITS_TO_LONGS(nic->flow_cfg->max_flows),
> - sizeof(long), GFP_KERNEL);
> - if (!tc->tc_entries_bitmap) {
> - netdev_err(nic->netdev,
> - "Unable to alloc TC flow entries bitmap\n");
> - return -ENOMEM;
> - }
> -
> - return 0;
> -}
> -EXPORT_SYMBOL(otx2_tc_alloc_ent_bitmap);
> -
> static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
> u32 *burst_exp, u32 *burst_mantissa)
> {
> @@ -674,8 +652,119 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
> return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
> }
>
> -static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
> +static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)
> +{
> + struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
> + struct otx2_tc_flow *iter, *tmp;
> +
> + if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
> + return;
> +
> + list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list_tc, list) {
> + list_del(&iter->list);
> + kfree(iter);
> + flow_cfg->nr_flows--;
> + }
> +}
> +
> +static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg,
> + unsigned long cookie)
> +{
> + struct otx2_tc_flow *tmp;
> +
> + list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
> + if (tmp->cookie == cookie)
> + return tmp;
> + }
> +
> + return NULL;
> +}
> +
> +static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg,
> + int index)
> +{
> + struct otx2_tc_flow *tmp;
> + int i = 0;
> +
> + list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
> + if (i == index)
> + return tmp;
> +
> + i++;
> + }
> +
> + return NULL;
> +}
> +
> +static void otx2_tc_del_from_flow_list(struct otx2_flow_config *flow_cfg,
> + struct otx2_tc_flow *node)
> {
> + struct list_head *pos, *n;
> + struct otx2_tc_flow *tmp;
> +
> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
> + tmp = list_entry(pos, struct otx2_tc_flow, list);
> + if (node == tmp) {
> + list_del(&node->list);
> + return;
> + }
> + }
> +}
> +
> +static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
> + struct otx2_tc_flow *node)
> +{
> + struct list_head *pos, *n;
> + struct otx2_tc_flow *tmp;
> + int index = 0;
> +
> + /* If the flow list is empty then add the new node */
> + if (list_empty(&flow_cfg->flow_list_tc)) {
> + list_add(&node->list, &flow_cfg->flow_list_tc);
> + return index;
> + }
> +
> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
> + tmp = list_entry(pos, struct otx2_tc_flow, list);
> + if (node->prio < tmp->prio)
> + break;
> +
> + index++;
> + }
> +
> + list_add(&node->list, pos->prev);
> + return index;
> +}
> +
> +static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_install_flow_req *req)
> +{
> + struct npc_install_flow_req *tmp_req;
> + int err;
> +
> + mutex_lock(&nic->mbox.lock);
> + tmp_req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
> + if (!tmp_req) {
> + mutex_unlock(&nic->mbox.lock);
> + return -ENOMEM;
> + }
> +
> + memcpy(tmp_req, req, sizeof(struct npc_install_flow_req));
> + /* Send message to AF */
> + err = otx2_sync_mbox_msg(&nic->mbox);
> + if (err) {
> + netdev_err(nic->netdev, "Failed to install MCAM flow entry %d\n",
> + req->entry);
> + mutex_unlock(&nic->mbox.lock);
> + return -EFAULT;
> + }
> +
> + mutex_unlock(&nic->mbox.lock);
> + return 0;
> +}
> +
> +static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_val)
> +{
> + struct npc_delete_flow_rsp __maybe_unused *rsp;
> struct npc_delete_flow_req *req;
> int err;
>
> @@ -696,22 +785,107 @@ static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
> mutex_unlock(&nic->mbox.lock);
> return -EFAULT;
> }
> +
> + if (cntr_val) {
> + rsp = (struct npc_delete_flow_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
> + 0, &req->hdr);
> + *cntr_val = rsp->cntr_val;
> + }
> +
> mutex_unlock(&nic->mbox.lock);
>
> return 0;
> }
>
> +static int otx2_tc_update_mcam_table_del_req(struct otx2_nic *nic,
> + struct otx2_flow_config *flow_cfg,
> + struct otx2_tc_flow *node)
> +{
> + struct list_head *pos, *n;
> + struct otx2_tc_flow *tmp;
> + int i = 0, index = 0;
> + u16 cntr_val;
> +
> + /* Find and delete the entry from the list and re-install
> + * all the entries from beginning to the index of the
> + * deleted entry to higher mcam indexes.
> + */
> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
> + tmp = list_entry(pos, struct otx2_tc_flow, list);
> + if (node == tmp) {
> + list_del(&tmp->list);
> + break;
> + }
> +
> + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
> + tmp->entry++;
> + tmp->req.entry = tmp->entry;
> + tmp->req.cntr_val = cntr_val;
> + index++;
> + }
> +
> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
> + if (i == index)
> + break;
> +
> + tmp = list_entry(pos, struct otx2_tc_flow, list);
> + otx2_add_mcam_flow_entry(nic, &tmp->req);
> + i++;
> + }
> +
> + return 0;
> +}
> +
> +static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
> + struct otx2_flow_config *flow_cfg,
> + struct otx2_tc_flow *node)
> +{
> + int mcam_idx = flow_cfg->max_flows - flow_cfg->nr_flows - 1;
> + struct otx2_tc_flow *tmp;
> + int list_idx, i;
> + u16 cntr_val;
> +
> + /* Find the index of the entry(list_idx) whose priority
> + * is greater than the new entry and re-install all
> + * the entries from beginning to list_idx to higher
> + * mcam indexes.
> + */
> + list_idx = otx2_tc_add_to_flow_list(flow_cfg, node);
> + for (i = 0; i < list_idx; i++) {
> + tmp = otx2_tc_get_entry_by_index(flow_cfg, i);
> + if (!tmp)
> + return -ENOMEM;
> +
> + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
> + tmp->entry = flow_cfg->flow_ent[mcam_idx];
> + tmp->req.entry = tmp->entry;
> + tmp->req.cntr_val = cntr_val;
> + otx2_add_mcam_flow_entry(nic, &tmp->req);
> + mcam_idx++;
> + }
> +
> + return mcam_idx;
> +}
> +
> +static int otx2_tc_update_mcam_table(struct otx2_nic *nic,
> + struct otx2_flow_config *flow_cfg,
> + struct otx2_tc_flow *node,
> + bool add_req)
> +{
> + if (add_req)
> + return otx2_tc_update_mcam_table_add_req(nic, flow_cfg, node);
> +
> + return otx2_tc_update_mcam_table_del_req(nic, flow_cfg, node);
> +}
> +
> static int otx2_tc_del_flow(struct otx2_nic *nic,
> struct flow_cls_offload *tc_flow_cmd)
> {
> struct otx2_flow_config *flow_cfg = nic->flow_cfg;
> - struct otx2_tc_info *tc_info = &nic->tc_info;
> struct otx2_tc_flow *flow_node;
> int err;
>
> - flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
> - &tc_flow_cmd->cookie,
> - tc_info->flow_ht_params);
> + flow_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
> if (!flow_node) {
> netdev_err(nic->netdev, "tc flow not found for cookie 0x%lx\n",
> tc_flow_cmd->cookie);
> @@ -739,14 +913,10 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
> mutex_unlock(&nic->mbox.lock);
> }
>
> - otx2_del_mcam_flow_entry(nic, flow_node->entry);
> -
> - WARN_ON(rhashtable_remove_fast(&nic->tc_info.flow_table,
> - &flow_node->node,
> - nic->tc_info.flow_ht_params));
> + otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
> + otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
> kfree_rcu(flow_node, rcu);
>
> - clear_bit(flow_node->bitpos, tc_info->tc_entries_bitmap);
> flow_cfg->nr_flows--;
>
> return 0;
> @@ -757,15 +927,14 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> {
> struct netlink_ext_ack *extack = tc_flow_cmd->common.extack;
> struct otx2_flow_config *flow_cfg = nic->flow_cfg;
> - struct otx2_tc_info *tc_info = &nic->tc_info;
> struct otx2_tc_flow *new_node, *old_node;
> struct npc_install_flow_req *req, dummy;
> - int rc, err;
> + int rc, err, mcam_idx;
>
> if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
> return -ENOMEM;
>
> - if (bitmap_full(tc_info->tc_entries_bitmap, flow_cfg->max_flows)) {
> + if (flow_cfg->nr_flows == flow_cfg->max_flows) {
> NL_SET_ERR_MSG_MOD(extack,
> "Free MCAM entry not available to add the flow");
> return -ENOMEM;
> @@ -777,6 +946,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> return -ENOMEM;
> spin_lock_init(&new_node->lock);
> new_node->cookie = tc_flow_cmd->cookie;
> + new_node->prio = tc_flow_cmd->common.prio;
>
> memset(&dummy, 0, sizeof(struct npc_install_flow_req));
>
> @@ -787,12 +957,11 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> }
>
> /* If a flow exists with the same cookie, delete it */
> - old_node = rhashtable_lookup_fast(&tc_info->flow_table,
> - &tc_flow_cmd->cookie,
> - tc_info->flow_ht_params);
> + old_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
> if (old_node)
> otx2_tc_del_flow(nic, tc_flow_cmd);
>
> + mcam_idx = otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true);
> mutex_lock(&nic->mbox.lock);
> req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
> if (!req) {
> @@ -804,10 +973,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
> memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
>
> - new_node->bitpos = find_first_zero_bit(tc_info->tc_entries_bitmap,
> - flow_cfg->max_flows);
> req->channel = nic->hw.rx_chan_base;
> - req->entry = flow_cfg->flow_ent[flow_cfg->max_flows - new_node->bitpos - 1];
> + req->entry = flow_cfg->flow_ent[mcam_idx];
> req->intf = NIX_INTF_RX;
> req->set_cntr = 1;
> new_node->entry = req->entry;
> @@ -817,26 +984,18 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> if (rc) {
> NL_SET_ERR_MSG_MOD(extack, "Failed to install MCAM flow entry");
> mutex_unlock(&nic->mbox.lock);
> - kfree_rcu(new_node, rcu);
> goto free_leaf;
> }
> - mutex_unlock(&nic->mbox.lock);
>
> - /* add new flow to flow-table */
> - rc = rhashtable_insert_fast(&nic->tc_info.flow_table, &new_node->node,
> - nic->tc_info.flow_ht_params);
> - if (rc) {
> - otx2_del_mcam_flow_entry(nic, req->entry);
> - kfree_rcu(new_node, rcu);
> - goto free_leaf;
> - }
> -
> - set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
> + mutex_unlock(&nic->mbox.lock);
> + memcpy(&new_node->req, req, sizeof(struct npc_install_flow_req));
> flow_cfg->nr_flows++;
>
> return 0;
>
> free_leaf:
> + otx2_tc_del_from_flow_list(flow_cfg, new_node);
> + kfree_rcu(new_node, rcu);
> if (new_node->is_act_police) {
> mutex_lock(&nic->mbox.lock);
>
> @@ -863,16 +1022,13 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
> static int otx2_tc_get_flow_stats(struct otx2_nic *nic,
> struct flow_cls_offload *tc_flow_cmd)
> {
> - struct otx2_tc_info *tc_info = &nic->tc_info;
> struct npc_mcam_get_stats_req *req;
> struct npc_mcam_get_stats_rsp *rsp;
> struct otx2_tc_flow_stats *stats;
> struct otx2_tc_flow *flow_node;
> int err;
>
> - flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
> - &tc_flow_cmd->cookie,
> - tc_info->flow_ht_params);
> + flow_node = otx2_tc_get_entry_by_cookie(nic->flow_cfg, tc_flow_cmd->cookie);
> if (!flow_node) {
> netdev_info(nic->netdev, "tc flow not found for cookie %lx",
> tc_flow_cmd->cookie);
> @@ -1020,12 +1176,20 @@ static int otx2_setup_tc_block_ingress_cb(enum tc_setup_type type,
> void *type_data, void *cb_priv)
> {
> struct otx2_nic *nic = cb_priv;
> + bool ntuple;
>
> if (!tc_cls_can_offload_and_chain0(nic->netdev, type_data))
> return -EOPNOTSUPP;
>
> + ntuple = !!(nic->netdev->features & NETIF_F_NTUPLE);
> switch (type) {
> case TC_SETUP_CLSFLOWER:
> + if (ntuple) {
> + netdev_warn(nic->netdev,
> + "Can't install TC flower offload rule when NTUPLE is active");
> + return -EOPNOTSUPP;
> + }
> +
> return otx2_setup_tc_cls_flower(nic, type_data);
> case TC_SETUP_CLSMATCHALL:
> return otx2_setup_tc_ingress_matchall(nic, type_data);
> @@ -1108,41 +1272,16 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
> }
> EXPORT_SYMBOL(otx2_setup_tc);
>
> -static const struct rhashtable_params tc_flow_ht_params = {
> - .head_offset = offsetof(struct otx2_tc_flow, node),
> - .key_offset = offsetof(struct otx2_tc_flow, cookie),
> - .key_len = sizeof(((struct otx2_tc_flow *)0)->cookie),
> - .automatic_shrinking = true,
> -};
> -
> int otx2_init_tc(struct otx2_nic *nic)
> {
> - struct otx2_tc_info *tc = &nic->tc_info;
> - int err;
> -
> /* Exclude receive queue 0 being used for police action */
> set_bit(0, &nic->rq_bmap);
> -
> - if (!nic->flow_cfg) {
> - netdev_err(nic->netdev,
> - "Can't init TC, nic->flow_cfg is not setup\n");
> - return -EINVAL;
> - }
> -
> - err = otx2_tc_alloc_ent_bitmap(nic);
> - if (err)
> - return err;
> -
> - tc->flow_ht_params = tc_flow_ht_params;
> - return rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
> + return 0;
> }
> EXPORT_SYMBOL(otx2_init_tc);
>
> void otx2_shutdown_tc(struct otx2_nic *nic)
> {
> - struct otx2_tc_info *tc = &nic->tc_info;
> -
> - kfree(tc->tc_entries_bitmap);
> - rhashtable_destroy(&tc->flow_table);
> + otx2_destroy_tc_flow_list(nic);
> }
> EXPORT_SYMBOL(otx2_shutdown_tc);
> --
> 2.25.1
>
>
>Hi Suman,
>
>unfortunately this patch does not appear to apply to net-next, which
>breaks our processes.
>
>Please consider posting a v2 rebased on net-next.
>
>Thanks!
[Suman] Sure Simon, will push v2.
>
>> ---
>> .../net/ethernet/marvell/octeontx2/af/mbox.h | 9 +-
>> .../marvell/octeontx2/af/rvu_npc_fs.c | 10 +-
>> .../marvell/octeontx2/af/rvu_switch.c | 6 +-
>> .../marvell/octeontx2/nic/otx2_common.h | 11 +-
>> .../marvell/octeontx2/nic/otx2_devlink.c | 1 -
>> .../marvell/octeontx2/nic/otx2_flows.c | 2 +
>> .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 315
>> +++++++++++++-----
>> 7 files changed, 251 insertions(+), 103 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
>> b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
>> index 8d5d5a0f68c4..ba6e249ee1df 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
>> +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
>> @@ -231,7 +231,7 @@ M(NPC_GET_KEX_CFG, 0x600c, npc_get_kex_cfg,
> \
>> M(NPC_INSTALL_FLOW, 0x600d, npc_install_flow, \
>> npc_install_flow_req, npc_install_flow_rsp) \
>> M(NPC_DELETE_FLOW, 0x600e, npc_delete_flow, \
>> - npc_delete_flow_req, msg_rsp) \
>> + npc_delete_flow_req, npc_delete_flow_rsp) \
>> M(NPC_MCAM_READ_ENTRY, 0x600f, npc_mcam_read_entry,
> \
>> npc_mcam_read_entry_req, \
>> npc_mcam_read_entry_rsp) \
>> @@ -1467,6 +1467,8 @@ struct npc_install_flow_req {
>> u8 vtag0_op;
>> u16 vtag1_def;
>> u8 vtag1_op;
>> + /* old counter value */
>> + u16 cntr_val;
>> };
>>
>> struct npc_install_flow_rsp {
>> @@ -1482,6 +1484,11 @@ struct npc_delete_flow_req {
>> u8 all; /* PF + VFs */
>> };
>>
>> +struct npc_delete_flow_rsp {
>> + struct mbox_msghdr hdr;
>> + u16 cntr_val;
>> +};
>> +
>> struct npc_mcam_read_entry_req {
>> struct mbox_msghdr hdr;
>> u16 entry; /* MCAM entry to read */
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
>> b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
>> index 50d3994efa97..e016669bc327 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
>> @@ -1148,7 +1148,7 @@ static int npc_install_flow(struct rvu *rvu, int
>blkaddr, u16 target,
>> write_req.enable_entry = (u8)enable;
>> /* if counter is available then clear and use it */
>> if (req->set_cntr && rule->has_cntr) {
>> - rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr),
>0x00);
>> + rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr),
>> +req->cntr_val);
>> write_req.set_cntr = 1;
>> write_req.cntr = rule->cntr;
>> }
>> @@ -1362,12 +1362,13 @@ static int npc_delete_flow(struct rvu *rvu,
>> struct rvu_npc_mcam_rule *rule,
>>
>> int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
>> struct npc_delete_flow_req *req,
>> - struct msg_rsp *rsp)
>> + struct npc_delete_flow_rsp *rsp)
>> {
>> struct npc_mcam *mcam = &rvu->hw->mcam;
>> struct rvu_npc_mcam_rule *iter, *tmp;
>> u16 pcifunc = req->hdr.pcifunc;
>> struct list_head del_list;
>> + int blkaddr;
>>
>> INIT_LIST_HEAD(&del_list);
>>
>> @@ -1383,6 +1384,11 @@ int rvu_mbox_handler_npc_delete_flow(struct rvu
>*rvu,
>> list_move_tail(&iter->list, &del_list);
>> /* single rule */
>> } else if (req->entry == iter->entry) {
>> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
>> + if (blkaddr)
>> + rsp->cntr_val = rvu_read64(rvu, blkaddr,
>> + NPC_AF_MATCH_STATX(iter-
>>cntr));
>> +
>> list_move_tail(&iter->list, &del_list);
>> break;
>> }
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
>> b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
>> index 3392487f6b47..329b5a02914d 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
>> @@ -145,6 +145,7 @@ void rvu_switch_enable(struct rvu *rvu)
>> struct npc_mcam_alloc_entry_req alloc_req = { 0 };
>> struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
>> struct npc_delete_flow_req uninstall_req = { 0 };
>> + struct npc_delete_flow_rsp uninstall_rsp = { 0 };
>> struct npc_mcam_free_entry_req free_req = { 0 };
>> struct rvu_switch *rswitch = &rvu->rswitch;
>> struct msg_rsp rsp;
>> @@ -184,7 +185,7 @@ void rvu_switch_enable(struct rvu *rvu)
>> uninstall_rules:
>> uninstall_req.start = rswitch->start_entry;
>> uninstall_req.end = rswitch->start_entry + rswitch->used_entries -
>1;
>> - rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
>> + rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req,
>> +&uninstall_rsp);
>> kfree(rswitch->entry2pcifunc);
>> free_entries:
>> free_req.all = 1;
>> @@ -196,6 +197,7 @@ void rvu_switch_enable(struct rvu *rvu) void
>> rvu_switch_disable(struct rvu *rvu) {
>> struct npc_delete_flow_req uninstall_req = { 0 };
>> + struct npc_delete_flow_rsp uninstall_rsp = { 0 };
>> struct npc_mcam_free_entry_req free_req = { 0 };
>> struct rvu_switch *rswitch = &rvu->rswitch;
>> struct rvu_hwinfo *hw = rvu->hw;
>> @@ -232,7 +234,7 @@ void rvu_switch_disable(struct rvu *rvu)
>> uninstall_req.start = rswitch->start_entry;
>> uninstall_req.end = rswitch->start_entry + rswitch->used_entries -
>1;
>> free_req.all = 1;
>> - rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
>> + rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req,
>> +&uninstall_rsp);
>> rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
>> rswitch->used_entries = 0;
>> kfree(rswitch->entry2pcifunc);
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
>> b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
>> index 282db6fe3b08..6f1ff03cdc77 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
>> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
>> @@ -337,13 +337,8 @@ struct otx2_flow_config {
>> u32 *bmap_to_dmacindex;
>> unsigned long *dmacflt_bmap;
>> struct list_head flow_list;
>> -};
>> -
>> -struct otx2_tc_info {
>> - /* hash table to store TC offloaded flows */
>> - struct rhashtable flow_table;
>> - struct rhashtable_params flow_ht_params;
>> - unsigned long *tc_entries_bitmap;
>> + struct list_head flow_list_tc;
>> + bool ntuple;
>> };
>>
>> struct dev_hw_ops {
>> @@ -463,7 +458,6 @@ struct otx2_nic {
>> /* NPC MCAM */
>> struct otx2_flow_config *flow_cfg;
>> struct otx2_mac_table *mac_table;
>> - struct otx2_tc_info tc_info;
>>
>> u64 reset_count;
>> struct work_struct reset_task;
>> @@ -1001,7 +995,6 @@ int otx2_init_tc(struct otx2_nic *nic); void
>> otx2_shutdown_tc(struct otx2_nic *nic); int otx2_setup_tc(struct
>> net_device *netdev, enum tc_setup_type type,
>> void *type_data);
>> -int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic);
>> /* CGX/RPM DMAC filters support */
>> int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf); int
>> otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u32 bit_pos);
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
>> b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
>> index 777a27047c8e..5f71a72f95e5 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
>> @@ -41,7 +41,6 @@ static int otx2_dl_mcam_count_set(struct devlink
>*devlink, u32 id,
>> return 0;
>>
>> otx2_alloc_mcam_entries(pfvf, ctx->val.vu16);
>> - otx2_tc_alloc_ent_bitmap(pfvf);
>>
>> return 0;
>> }
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
>> b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
>> index 709fc0114fbd..70c3ae2caddd 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
>> @@ -253,6 +253,7 @@ int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
>>
>> flow_cfg = pfvf->flow_cfg;
>> INIT_LIST_HEAD(&flow_cfg->flow_list);
>> + INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
>> flow_cfg->max_flows = 0;
>>
>> return 0;
>> @@ -275,6 +276,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
>> return -ENOMEM;
>>
>> INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
>> + INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
>>
>> /* Allocate bare minimum number of MCAM entries needed for
>> * unicast and ntuple filters.
>> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
>> b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
>> index e64318c110fd..070210e86778 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
>> @@ -48,9 +48,8 @@ struct otx2_tc_flow_stats { };
>>
>> struct otx2_tc_flow {
>> - struct rhash_head node;
>> + struct list_head list;
>> unsigned long cookie;
>> - unsigned int bitpos;
>> struct rcu_head rcu;
>> struct otx2_tc_flow_stats stats;
>> spinlock_t lock; /* lock for stats */
>> @@ -58,31 +57,10 @@ struct otx2_tc_flow {
>> u16 entry;
>> u16 leaf_profile;
>> bool is_act_police;
>> + u32 prio;
>> + struct npc_install_flow_req req;
>> };
>>
>> -int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic) -{
>> - struct otx2_tc_info *tc = &nic->tc_info;
>> -
>> - if (!nic->flow_cfg->max_flows)
>> - return 0;
>> -
>> - /* Max flows changed, free the existing bitmap */
>> - kfree(tc->tc_entries_bitmap);
>> -
>> - tc->tc_entries_bitmap =
>> - kcalloc(BITS_TO_LONGS(nic->flow_cfg->max_flows),
>> - sizeof(long), GFP_KERNEL);
>> - if (!tc->tc_entries_bitmap) {
>> - netdev_err(nic->netdev,
>> - "Unable to alloc TC flow entries bitmap\n");
>> - return -ENOMEM;
>> - }
>> -
>> - return 0;
>> -}
>> -EXPORT_SYMBOL(otx2_tc_alloc_ent_bitmap);
>> -
>> static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32
>burst,
>> u32 *burst_exp, u32 *burst_mantissa) { @@ -
>674,8 +652,119
>> @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct
>otx2_tc_flow *node,
>> return otx2_tc_parse_actions(nic, &rule->action, req, f, node); }
>>
>> -static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
>> +static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf) {
>> + struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
>> + struct otx2_tc_flow *iter, *tmp;
>> +
>> + if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
>> + return;
>> +
>> + list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list_tc, list)
>{
>> + list_del(&iter->list);
>> + kfree(iter);
>> + flow_cfg->nr_flows--;
>> + }
>> +}
>> +
>> +static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct
>otx2_flow_config *flow_cfg,
>> + unsigned long cookie)
>> +{
>> + struct otx2_tc_flow *tmp;
>> +
>> + list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
>> + if (tmp->cookie == cookie)
>> + return tmp;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct
>otx2_flow_config *flow_cfg,
>> + int index)
>> +{
>> + struct otx2_tc_flow *tmp;
>> + int i = 0;
>> +
>> + list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
>> + if (i == index)
>> + return tmp;
>> +
>> + i++;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static void otx2_tc_del_from_flow_list(struct otx2_flow_config
>*flow_cfg,
>> + struct otx2_tc_flow *node)
>> {
>> + struct list_head *pos, *n;
>> + struct otx2_tc_flow *tmp;
>> +
>> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
>> + tmp = list_entry(pos, struct otx2_tc_flow, list);
>> + if (node == tmp) {
>> + list_del(&node->list);
>> + return;
>> + }
>> + }
>> +}
>> +
>> +static int otx2_tc_add_to_flow_list(struct otx2_flow_config
>*flow_cfg,
>> + struct otx2_tc_flow *node)
>> +{
>> + struct list_head *pos, *n;
>> + struct otx2_tc_flow *tmp;
>> + int index = 0;
>> +
>> + /* If the flow list is empty then add the new node */
>> + if (list_empty(&flow_cfg->flow_list_tc)) {
>> + list_add(&node->list, &flow_cfg->flow_list_tc);
>> + return index;
>> + }
>> +
>> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
>> + tmp = list_entry(pos, struct otx2_tc_flow, list);
>> + if (node->prio < tmp->prio)
>> + break;
>> +
>> + index++;
>> + }
>> +
>> + list_add(&node->list, pos->prev);
>> + return index;
>> +}
>> +
>> +static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct
>> +npc_install_flow_req *req) {
>> + struct npc_install_flow_req *tmp_req;
>> + int err;
>> +
>> + mutex_lock(&nic->mbox.lock);
>> + tmp_req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
>> + if (!tmp_req) {
>> + mutex_unlock(&nic->mbox.lock);
>> + return -ENOMEM;
>> + }
>> +
>> + memcpy(tmp_req, req, sizeof(struct npc_install_flow_req));
>> + /* Send message to AF */
>> + err = otx2_sync_mbox_msg(&nic->mbox);
>> + if (err) {
>> + netdev_err(nic->netdev, "Failed to install MCAM flow entry
>%d\n",
>> + req->entry);
>> + mutex_unlock(&nic->mbox.lock);
>> + return -EFAULT;
>> + }
>> +
>> + mutex_unlock(&nic->mbox.lock);
>> + return 0;
>> +}
>> +
>> +static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry,
>> +u16 *cntr_val) {
>> + struct npc_delete_flow_rsp __maybe_unused *rsp;
>> struct npc_delete_flow_req *req;
>> int err;
>>
>> @@ -696,22 +785,107 @@ static int otx2_del_mcam_flow_entry(struct
>otx2_nic *nic, u16 entry)
>> mutex_unlock(&nic->mbox.lock);
>> return -EFAULT;
>> }
>> +
>> + if (cntr_val) {
>> + rsp = (struct npc_delete_flow_rsp *)otx2_mbox_get_rsp(&nic-
>>mbox.mbox,
>> + 0, &req->hdr);
>> + *cntr_val = rsp->cntr_val;
>> + }
>> +
>> mutex_unlock(&nic->mbox.lock);
>>
>> return 0;
>> }
>>
>> +static int otx2_tc_update_mcam_table_del_req(struct otx2_nic *nic,
>> + struct otx2_flow_config *flow_cfg,
>> + struct otx2_tc_flow *node)
>> +{
>> + struct list_head *pos, *n;
>> + struct otx2_tc_flow *tmp;
>> + int i = 0, index = 0;
>> + u16 cntr_val;
>> +
>> + /* Find and delete the entry from the list and re-install
>> + * all the entries from beginning to the index of the
>> + * deleted entry to higher mcam indexes.
>> + */
>> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
>> + tmp = list_entry(pos, struct otx2_tc_flow, list);
>> + if (node == tmp) {
>> + list_del(&tmp->list);
>> + break;
>> + }
>> +
>> + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
>> + tmp->entry++;
>> + tmp->req.entry = tmp->entry;
>> + tmp->req.cntr_val = cntr_val;
>> + index++;
>> + }
>> +
>> + list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
>> + if (i == index)
>> + break;
>> +
>> + tmp = list_entry(pos, struct otx2_tc_flow, list);
>> + otx2_add_mcam_flow_entry(nic, &tmp->req);
>> + i++;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
>> + struct otx2_flow_config *flow_cfg,
>> + struct otx2_tc_flow *node)
>> +{
>> + int mcam_idx = flow_cfg->max_flows - flow_cfg->nr_flows - 1;
>> + struct otx2_tc_flow *tmp;
>> + int list_idx, i;
>> + u16 cntr_val;
>> +
>> + /* Find the index of the entry(list_idx) whose priority
>> + * is greater than the new entry and re-install all
>> + * the entries from beginning to list_idx to higher
>> + * mcam indexes.
>> + */
>> + list_idx = otx2_tc_add_to_flow_list(flow_cfg, node);
>> + for (i = 0; i < list_idx; i++) {
>> + tmp = otx2_tc_get_entry_by_index(flow_cfg, i);
>> + if (!tmp)
>> + return -ENOMEM;
>> +
>> + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
>> + tmp->entry = flow_cfg->flow_ent[mcam_idx];
>> + tmp->req.entry = tmp->entry;
>> + tmp->req.cntr_val = cntr_val;
>> + otx2_add_mcam_flow_entry(nic, &tmp->req);
>> + mcam_idx++;
>> + }
>> +
>> + return mcam_idx;
>> +}
>> +
>> +static int otx2_tc_update_mcam_table(struct otx2_nic *nic,
>> + struct otx2_flow_config *flow_cfg,
>> + struct otx2_tc_flow *node,
>> + bool add_req)
>> +{
>> + if (add_req)
>> + return otx2_tc_update_mcam_table_add_req(nic, flow_cfg, node);
>> +
>> + return otx2_tc_update_mcam_table_del_req(nic, flow_cfg, node); }
>> +
>> static int otx2_tc_del_flow(struct otx2_nic *nic,
>> struct flow_cls_offload *tc_flow_cmd) {
>> struct otx2_flow_config *flow_cfg = nic->flow_cfg;
>> - struct otx2_tc_info *tc_info = &nic->tc_info;
>> struct otx2_tc_flow *flow_node;
>> int err;
>>
>> - flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
>> - &tc_flow_cmd->cookie,
>> - tc_info->flow_ht_params);
>> + flow_node = otx2_tc_get_entry_by_cookie(flow_cfg,
>> +tc_flow_cmd->cookie);
>> if (!flow_node) {
>> netdev_err(nic->netdev, "tc flow not found for cookie
>0x%lx\n",
>> tc_flow_cmd->cookie);
>> @@ -739,14 +913,10 @@ static int otx2_tc_del_flow(struct otx2_nic
>*nic,
>> mutex_unlock(&nic->mbox.lock);
>> }
>>
>> - otx2_del_mcam_flow_entry(nic, flow_node->entry);
>> -
>> - WARN_ON(rhashtable_remove_fast(&nic->tc_info.flow_table,
>> - &flow_node->node,
>> - nic->tc_info.flow_ht_params));
>> + otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
>> + otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
>> kfree_rcu(flow_node, rcu);
>>
>> - clear_bit(flow_node->bitpos, tc_info->tc_entries_bitmap);
>> flow_cfg->nr_flows--;
>>
>> return 0;
>> @@ -757,15 +927,14 @@ static int otx2_tc_add_flow(struct otx2_nic
>> *nic, {
>> struct netlink_ext_ack *extack = tc_flow_cmd->common.extack;
>> struct otx2_flow_config *flow_cfg = nic->flow_cfg;
>> - struct otx2_tc_info *tc_info = &nic->tc_info;
>> struct otx2_tc_flow *new_node, *old_node;
>> struct npc_install_flow_req *req, dummy;
>> - int rc, err;
>> + int rc, err, mcam_idx;
>>
>> if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
>> return -ENOMEM;
>>
>> - if (bitmap_full(tc_info->tc_entries_bitmap, flow_cfg->max_flows)) {
>> + if (flow_cfg->nr_flows == flow_cfg->max_flows) {
>> NL_SET_ERR_MSG_MOD(extack,
>> "Free MCAM entry not available to add the flow");
>> return -ENOMEM;
>> @@ -777,6 +946,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
>> return -ENOMEM;
>> spin_lock_init(&new_node->lock);
>> new_node->cookie = tc_flow_cmd->cookie;
>> + new_node->prio = tc_flow_cmd->common.prio;
>>
>> memset(&dummy, 0, sizeof(struct npc_install_flow_req));
>>
>> @@ -787,12 +957,11 @@ static int otx2_tc_add_flow(struct otx2_nic
>*nic,
>> }
>>
>> /* If a flow exists with the same cookie, delete it */
>> - old_node = rhashtable_lookup_fast(&tc_info->flow_table,
>> - &tc_flow_cmd->cookie,
>> - tc_info->flow_ht_params);
>> + old_node = otx2_tc_get_entry_by_cookie(flow_cfg,
>> +tc_flow_cmd->cookie);
>> if (old_node)
>> otx2_tc_del_flow(nic, tc_flow_cmd);
>>
>> + mcam_idx = otx2_tc_update_mcam_table(nic, flow_cfg, new_node,
>true);
>> mutex_lock(&nic->mbox.lock);
>> req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
>> if (!req) {
>> @@ -804,10 +973,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
>> memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
>> memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
>>
>> - new_node->bitpos = find_first_zero_bit(tc_info->tc_entries_bitmap,
>> - flow_cfg->max_flows);
>> req->channel = nic->hw.rx_chan_base;
>> - req->entry = flow_cfg->flow_ent[flow_cfg->max_flows - new_node-
>>bitpos - 1];
>> + req->entry = flow_cfg->flow_ent[mcam_idx];
>> req->intf = NIX_INTF_RX;
>> req->set_cntr = 1;
>> new_node->entry = req->entry;
>> @@ -817,26 +984,18 @@ static int otx2_tc_add_flow(struct otx2_nic
>*nic,
>> if (rc) {
>> NL_SET_ERR_MSG_MOD(extack, "Failed to install MCAM flow
>entry");
>> mutex_unlock(&nic->mbox.lock);
>> - kfree_rcu(new_node, rcu);
>> goto free_leaf;
>> }
>> - mutex_unlock(&nic->mbox.lock);
>>
>> - /* add new flow to flow-table */
>> - rc = rhashtable_insert_fast(&nic->tc_info.flow_table, &new_node-
>>node,
>> - nic->tc_info.flow_ht_params);
>> - if (rc) {
>> - otx2_del_mcam_flow_entry(nic, req->entry);
>> - kfree_rcu(new_node, rcu);
>> - goto free_leaf;
>> - }
>> -
>> - set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
>> + mutex_unlock(&nic->mbox.lock);
>> + memcpy(&new_node->req, req, sizeof(struct npc_install_flow_req));
>> flow_cfg->nr_flows++;
>>
>> return 0;
>>
>> free_leaf:
>> + otx2_tc_del_from_flow_list(flow_cfg, new_node);
>> + kfree_rcu(new_node, rcu);
>> if (new_node->is_act_police) {
>> mutex_lock(&nic->mbox.lock);
>>
>> @@ -863,16 +1022,13 @@ static int otx2_tc_add_flow(struct otx2_nic
>> *nic, static int otx2_tc_get_flow_stats(struct otx2_nic *nic,
>> struct flow_cls_offload *tc_flow_cmd) {
>> - struct otx2_tc_info *tc_info = &nic->tc_info;
>> struct npc_mcam_get_stats_req *req;
>> struct npc_mcam_get_stats_rsp *rsp;
>> struct otx2_tc_flow_stats *stats;
>> struct otx2_tc_flow *flow_node;
>> int err;
>>
>> - flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
>> - &tc_flow_cmd->cookie,
>> - tc_info->flow_ht_params);
>> + flow_node = otx2_tc_get_entry_by_cookie(nic->flow_cfg,
>> +tc_flow_cmd->cookie);
>> if (!flow_node) {
>> netdev_info(nic->netdev, "tc flow not found for cookie %lx",
>> tc_flow_cmd->cookie);
>> @@ -1020,12 +1176,20 @@ static int otx2_setup_tc_block_ingress_cb(enum
>tc_setup_type type,
>> void *type_data, void *cb_priv) {
>> struct otx2_nic *nic = cb_priv;
>> + bool ntuple;
>>
>> if (!tc_cls_can_offload_and_chain0(nic->netdev, type_data))
>> return -EOPNOTSUPP;
>>
>> + ntuple = !!(nic->netdev->features & NETIF_F_NTUPLE);
>> switch (type) {
>> case TC_SETUP_CLSFLOWER:
>> + if (ntuple) {
>> + netdev_warn(nic->netdev,
>> + "Can't install TC flower offload rule when
>NTUPLE is active");
>> + return -EOPNOTSUPP;
>> + }
>> +
>> return otx2_setup_tc_cls_flower(nic, type_data);
>> case TC_SETUP_CLSMATCHALL:
>> return otx2_setup_tc_ingress_matchall(nic, type_data); @@ -
>1108,41
>> +1272,16 @@ int otx2_setup_tc(struct net_device *netdev, enum
>> tc_setup_type type, } EXPORT_SYMBOL(otx2_setup_tc);
>>
>> -static const struct rhashtable_params tc_flow_ht_params = {
>> - .head_offset = offsetof(struct otx2_tc_flow, node),
>> - .key_offset = offsetof(struct otx2_tc_flow, cookie),
>> - .key_len = sizeof(((struct otx2_tc_flow *)0)->cookie),
>> - .automatic_shrinking = true,
>> -};
>> -
>> int otx2_init_tc(struct otx2_nic *nic) {
>> - struct otx2_tc_info *tc = &nic->tc_info;
>> - int err;
>> -
>> /* Exclude receive queue 0 being used for police action */
>> set_bit(0, &nic->rq_bmap);
>> -
>> - if (!nic->flow_cfg) {
>> - netdev_err(nic->netdev,
>> - "Can't init TC, nic->flow_cfg is not setup\n");
>> - return -EINVAL;
>> - }
>> -
>> - err = otx2_tc_alloc_ent_bitmap(nic);
>> - if (err)
>> - return err;
>> -
>> - tc->flow_ht_params = tc_flow_ht_params;
>> - return rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
>> + return 0;
>> }
>> EXPORT_SYMBOL(otx2_init_tc);
>>
>> void otx2_shutdown_tc(struct otx2_nic *nic) {
>> - struct otx2_tc_info *tc = &nic->tc_info;
>> -
>> - kfree(tc->tc_entries_bitmap);
>> - rhashtable_destroy(&tc->flow_table);
>> + otx2_destroy_tc_flow_list(nic);
>> }
>> EXPORT_SYMBOL(otx2_shutdown_tc);
>> --
>> 2.25.1
>>
>>
@@ -231,7 +231,7 @@ M(NPC_GET_KEX_CFG, 0x600c, npc_get_kex_cfg, \
M(NPC_INSTALL_FLOW, 0x600d, npc_install_flow, \
npc_install_flow_req, npc_install_flow_rsp) \
M(NPC_DELETE_FLOW, 0x600e, npc_delete_flow, \
- npc_delete_flow_req, msg_rsp) \
+ npc_delete_flow_req, npc_delete_flow_rsp) \
M(NPC_MCAM_READ_ENTRY, 0x600f, npc_mcam_read_entry, \
npc_mcam_read_entry_req, \
npc_mcam_read_entry_rsp) \
@@ -1467,6 +1467,8 @@ struct npc_install_flow_req {
u8 vtag0_op;
u16 vtag1_def;
u8 vtag1_op;
+ /* old counter value */
+ u16 cntr_val;
};
struct npc_install_flow_rsp {
@@ -1482,6 +1484,11 @@ struct npc_delete_flow_req {
u8 all; /* PF + VFs */
};
+struct npc_delete_flow_rsp {
+ struct mbox_msghdr hdr;
+ u16 cntr_val;
+};
+
struct npc_mcam_read_entry_req {
struct mbox_msghdr hdr;
u16 entry; /* MCAM entry to read */
@@ -1148,7 +1148,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
write_req.enable_entry = (u8)enable;
/* if counter is available then clear and use it */
if (req->set_cntr && rule->has_cntr) {
- rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), 0x00);
+ rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), req->cntr_val);
write_req.set_cntr = 1;
write_req.cntr = rule->cntr;
}
@@ -1362,12 +1362,13 @@ static int npc_delete_flow(struct rvu *rvu, struct rvu_npc_mcam_rule *rule,
int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
struct npc_delete_flow_req *req,
- struct msg_rsp *rsp)
+ struct npc_delete_flow_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_npc_mcam_rule *iter, *tmp;
u16 pcifunc = req->hdr.pcifunc;
struct list_head del_list;
+ int blkaddr;
INIT_LIST_HEAD(&del_list);
@@ -1383,6 +1384,11 @@ int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
list_move_tail(&iter->list, &del_list);
/* single rule */
} else if (req->entry == iter->entry) {
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr)
+ rsp->cntr_val = rvu_read64(rvu, blkaddr,
+ NPC_AF_MATCH_STATX(iter->cntr));
+
list_move_tail(&iter->list, &del_list);
break;
}
@@ -145,6 +145,7 @@ void rvu_switch_enable(struct rvu *rvu)
struct npc_mcam_alloc_entry_req alloc_req = { 0 };
struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
struct npc_delete_flow_req uninstall_req = { 0 };
+ struct npc_delete_flow_rsp uninstall_rsp = { 0 };
struct npc_mcam_free_entry_req free_req = { 0 };
struct rvu_switch *rswitch = &rvu->rswitch;
struct msg_rsp rsp;
@@ -184,7 +185,7 @@ void rvu_switch_enable(struct rvu *rvu)
uninstall_rules:
uninstall_req.start = rswitch->start_entry;
uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
- rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
+ rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
kfree(rswitch->entry2pcifunc);
free_entries:
free_req.all = 1;
@@ -196,6 +197,7 @@ void rvu_switch_enable(struct rvu *rvu)
void rvu_switch_disable(struct rvu *rvu)
{
struct npc_delete_flow_req uninstall_req = { 0 };
+ struct npc_delete_flow_rsp uninstall_rsp = { 0 };
struct npc_mcam_free_entry_req free_req = { 0 };
struct rvu_switch *rswitch = &rvu->rswitch;
struct rvu_hwinfo *hw = rvu->hw;
@@ -232,7 +234,7 @@ void rvu_switch_disable(struct rvu *rvu)
uninstall_req.start = rswitch->start_entry;
uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
free_req.all = 1;
- rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
+ rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
rswitch->used_entries = 0;
kfree(rswitch->entry2pcifunc);
@@ -337,13 +337,8 @@ struct otx2_flow_config {
u32 *bmap_to_dmacindex;
unsigned long *dmacflt_bmap;
struct list_head flow_list;
-};
-
-struct otx2_tc_info {
- /* hash table to store TC offloaded flows */
- struct rhashtable flow_table;
- struct rhashtable_params flow_ht_params;
- unsigned long *tc_entries_bitmap;
+ struct list_head flow_list_tc;
+ bool ntuple;
};
struct dev_hw_ops {
@@ -463,7 +458,6 @@ struct otx2_nic {
/* NPC MCAM */
struct otx2_flow_config *flow_cfg;
struct otx2_mac_table *mac_table;
- struct otx2_tc_info tc_info;
u64 reset_count;
struct work_struct reset_task;
@@ -1001,7 +995,6 @@ int otx2_init_tc(struct otx2_nic *nic);
void otx2_shutdown_tc(struct otx2_nic *nic);
int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data);
-int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic);
/* CGX/RPM DMAC filters support */
int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf);
int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u32 bit_pos);
@@ -41,7 +41,6 @@ static int otx2_dl_mcam_count_set(struct devlink *devlink, u32 id,
return 0;
otx2_alloc_mcam_entries(pfvf, ctx->val.vu16);
- otx2_tc_alloc_ent_bitmap(pfvf);
return 0;
}
@@ -253,6 +253,7 @@ int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
flow_cfg = pfvf->flow_cfg;
INIT_LIST_HEAD(&flow_cfg->flow_list);
+ INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
flow_cfg->max_flows = 0;
return 0;
@@ -275,6 +276,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
return -ENOMEM;
INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
+ INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
/* Allocate bare minimum number of MCAM entries needed for
* unicast and ntuple filters.
@@ -48,9 +48,8 @@ struct otx2_tc_flow_stats {
};
struct otx2_tc_flow {
- struct rhash_head node;
+ struct list_head list;
unsigned long cookie;
- unsigned int bitpos;
struct rcu_head rcu;
struct otx2_tc_flow_stats stats;
spinlock_t lock; /* lock for stats */
@@ -58,31 +57,10 @@ struct otx2_tc_flow {
u16 entry;
u16 leaf_profile;
bool is_act_police;
+ u32 prio;
+ struct npc_install_flow_req req;
};
-int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic)
-{
- struct otx2_tc_info *tc = &nic->tc_info;
-
- if (!nic->flow_cfg->max_flows)
- return 0;
-
- /* Max flows changed, free the existing bitmap */
- kfree(tc->tc_entries_bitmap);
-
- tc->tc_entries_bitmap =
- kcalloc(BITS_TO_LONGS(nic->flow_cfg->max_flows),
- sizeof(long), GFP_KERNEL);
- if (!tc->tc_entries_bitmap) {
- netdev_err(nic->netdev,
- "Unable to alloc TC flow entries bitmap\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(otx2_tc_alloc_ent_bitmap);
-
static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
u32 *burst_exp, u32 *burst_mantissa)
{
@@ -674,8 +652,119 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
}
-static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
+static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)
+{
+ struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
+ struct otx2_tc_flow *iter, *tmp;
+
+ if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
+ return;
+
+ list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list_tc, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ flow_cfg->nr_flows--;
+ }
+}
+
+static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg,
+ unsigned long cookie)
+{
+ struct otx2_tc_flow *tmp;
+
+ list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
+ if (tmp->cookie == cookie)
+ return tmp;
+ }
+
+ return NULL;
+}
+
+static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg,
+ int index)
+{
+ struct otx2_tc_flow *tmp;
+ int i = 0;
+
+ list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
+ if (i == index)
+ return tmp;
+
+ i++;
+ }
+
+ return NULL;
+}
+
+static void otx2_tc_del_from_flow_list(struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node == tmp) {
+ list_del(&node->list);
+ return;
+ }
+ }
+}
+
+static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+ int index = 0;
+
+ /* If the flow list is empty then add the new node */
+ if (list_empty(&flow_cfg->flow_list_tc)) {
+ list_add(&node->list, &flow_cfg->flow_list_tc);
+ return index;
+ }
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node->prio < tmp->prio)
+ break;
+
+ index++;
+ }
+
+ list_add(&node->list, pos->prev);
+ return index;
+}
+
+static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_install_flow_req *req)
+{
+ struct npc_install_flow_req *tmp_req;
+ int err;
+
+ mutex_lock(&nic->mbox.lock);
+ tmp_req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
+ if (!tmp_req) {
+ mutex_unlock(&nic->mbox.lock);
+ return -ENOMEM;
+ }
+
+ memcpy(tmp_req, req, sizeof(struct npc_install_flow_req));
+ /* Send message to AF */
+ err = otx2_sync_mbox_msg(&nic->mbox);
+ if (err) {
+ netdev_err(nic->netdev, "Failed to install MCAM flow entry %d\n",
+ req->entry);
+ mutex_unlock(&nic->mbox.lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&nic->mbox.lock);
+ return 0;
+}
+
+static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_val)
+{
+ struct npc_delete_flow_rsp __maybe_unused *rsp;
struct npc_delete_flow_req *req;
int err;
@@ -696,22 +785,107 @@ static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
mutex_unlock(&nic->mbox.lock);
return -EFAULT;
}
+
+ if (cntr_val) {
+ rsp = (struct npc_delete_flow_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
+ 0, &req->hdr);
+ *cntr_val = rsp->cntr_val;
+ }
+
mutex_unlock(&nic->mbox.lock);
return 0;
}
+static int otx2_tc_update_mcam_table_del_req(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+ int i = 0, index = 0;
+ u16 cntr_val;
+
+ /* Find and delete the entry from the list and re-install
+ * all the entries from beginning to the index of the
+ * deleted entry to higher mcam indexes.
+ */
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node == tmp) {
+ list_del(&tmp->list);
+ break;
+ }
+
+ otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
+ tmp->entry++;
+ tmp->req.entry = tmp->entry;
+ tmp->req.cntr_val = cntr_val;
+ index++;
+ }
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ if (i == index)
+ break;
+
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ otx2_add_mcam_flow_entry(nic, &tmp->req);
+ i++;
+ }
+
+ return 0;
+}
+
+static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ int mcam_idx = flow_cfg->max_flows - flow_cfg->nr_flows - 1;
+ struct otx2_tc_flow *tmp;
+ int list_idx, i;
+ u16 cntr_val;
+
+ /* Find the index of the entry(list_idx) whose priority
+ * is greater than the new entry and re-install all
+ * the entries from beginning to list_idx to higher
+ * mcam indexes.
+ */
+ list_idx = otx2_tc_add_to_flow_list(flow_cfg, node);
+ for (i = 0; i < list_idx; i++) {
+ tmp = otx2_tc_get_entry_by_index(flow_cfg, i);
+ if (!tmp)
+ return -ENOMEM;
+
+ otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
+ tmp->entry = flow_cfg->flow_ent[mcam_idx];
+ tmp->req.entry = tmp->entry;
+ tmp->req.cntr_val = cntr_val;
+ otx2_add_mcam_flow_entry(nic, &tmp->req);
+ mcam_idx++;
+ }
+
+ return mcam_idx;
+}
+
+static int otx2_tc_update_mcam_table(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node,
+ bool add_req)
+{
+ if (add_req)
+ return otx2_tc_update_mcam_table_add_req(nic, flow_cfg, node);
+
+ return otx2_tc_update_mcam_table_del_req(nic, flow_cfg, node);
+}
+
static int otx2_tc_del_flow(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *flow_node;
int err;
- flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ flow_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
if (!flow_node) {
netdev_err(nic->netdev, "tc flow not found for cookie 0x%lx\n",
tc_flow_cmd->cookie);
@@ -739,14 +913,10 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
mutex_unlock(&nic->mbox.lock);
}
- otx2_del_mcam_flow_entry(nic, flow_node->entry);
-
- WARN_ON(rhashtable_remove_fast(&nic->tc_info.flow_table,
- &flow_node->node,
- nic->tc_info.flow_ht_params));
+ otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
+ otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
kfree_rcu(flow_node, rcu);
- clear_bit(flow_node->bitpos, tc_info->tc_entries_bitmap);
flow_cfg->nr_flows--;
return 0;
@@ -757,15 +927,14 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
{
struct netlink_ext_ack *extack = tc_flow_cmd->common.extack;
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *new_node, *old_node;
struct npc_install_flow_req *req, dummy;
- int rc, err;
+ int rc, err, mcam_idx;
if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
return -ENOMEM;
- if (bitmap_full(tc_info->tc_entries_bitmap, flow_cfg->max_flows)) {
+ if (flow_cfg->nr_flows == flow_cfg->max_flows) {
NL_SET_ERR_MSG_MOD(extack,
"Free MCAM entry not available to add the flow");
return -ENOMEM;
@@ -777,6 +946,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
return -ENOMEM;
spin_lock_init(&new_node->lock);
new_node->cookie = tc_flow_cmd->cookie;
+ new_node->prio = tc_flow_cmd->common.prio;
memset(&dummy, 0, sizeof(struct npc_install_flow_req));
@@ -787,12 +957,11 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
}
/* If a flow exists with the same cookie, delete it */
- old_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ old_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
if (old_node)
otx2_tc_del_flow(nic, tc_flow_cmd);
+ mcam_idx = otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true);
mutex_lock(&nic->mbox.lock);
req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
if (!req) {
@@ -804,10 +973,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
- new_node->bitpos = find_first_zero_bit(tc_info->tc_entries_bitmap,
- flow_cfg->max_flows);
req->channel = nic->hw.rx_chan_base;
- req->entry = flow_cfg->flow_ent[flow_cfg->max_flows - new_node->bitpos - 1];
+ req->entry = flow_cfg->flow_ent[mcam_idx];
req->intf = NIX_INTF_RX;
req->set_cntr = 1;
new_node->entry = req->entry;
@@ -817,26 +984,18 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
if (rc) {
NL_SET_ERR_MSG_MOD(extack, "Failed to install MCAM flow entry");
mutex_unlock(&nic->mbox.lock);
- kfree_rcu(new_node, rcu);
goto free_leaf;
}
- mutex_unlock(&nic->mbox.lock);
- /* add new flow to flow-table */
- rc = rhashtable_insert_fast(&nic->tc_info.flow_table, &new_node->node,
- nic->tc_info.flow_ht_params);
- if (rc) {
- otx2_del_mcam_flow_entry(nic, req->entry);
- kfree_rcu(new_node, rcu);
- goto free_leaf;
- }
-
- set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
+ mutex_unlock(&nic->mbox.lock);
+ memcpy(&new_node->req, req, sizeof(struct npc_install_flow_req));
flow_cfg->nr_flows++;
return 0;
free_leaf:
+ otx2_tc_del_from_flow_list(flow_cfg, new_node);
+ kfree_rcu(new_node, rcu);
if (new_node->is_act_police) {
mutex_lock(&nic->mbox.lock);
@@ -863,16 +1022,13 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
static int otx2_tc_get_flow_stats(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct npc_mcam_get_stats_req *req;
struct npc_mcam_get_stats_rsp *rsp;
struct otx2_tc_flow_stats *stats;
struct otx2_tc_flow *flow_node;
int err;
- flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ flow_node = otx2_tc_get_entry_by_cookie(nic->flow_cfg, tc_flow_cmd->cookie);
if (!flow_node) {
netdev_info(nic->netdev, "tc flow not found for cookie %lx",
tc_flow_cmd->cookie);
@@ -1020,12 +1176,20 @@ static int otx2_setup_tc_block_ingress_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct otx2_nic *nic = cb_priv;
+ bool ntuple;
if (!tc_cls_can_offload_and_chain0(nic->netdev, type_data))
return -EOPNOTSUPP;
+ ntuple = !!(nic->netdev->features & NETIF_F_NTUPLE);
switch (type) {
case TC_SETUP_CLSFLOWER:
+ if (ntuple) {
+ netdev_warn(nic->netdev,
+ "Can't install TC flower offload rule when NTUPLE is active");
+ return -EOPNOTSUPP;
+ }
+
return otx2_setup_tc_cls_flower(nic, type_data);
case TC_SETUP_CLSMATCHALL:
return otx2_setup_tc_ingress_matchall(nic, type_data);
@@ -1108,41 +1272,16 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
}
EXPORT_SYMBOL(otx2_setup_tc);
-static const struct rhashtable_params tc_flow_ht_params = {
- .head_offset = offsetof(struct otx2_tc_flow, node),
- .key_offset = offsetof(struct otx2_tc_flow, cookie),
- .key_len = sizeof(((struct otx2_tc_flow *)0)->cookie),
- .automatic_shrinking = true,
-};
-
int otx2_init_tc(struct otx2_nic *nic)
{
- struct otx2_tc_info *tc = &nic->tc_info;
- int err;
-
/* Exclude receive queue 0 being used for police action */
set_bit(0, &nic->rq_bmap);
-
- if (!nic->flow_cfg) {
- netdev_err(nic->netdev,
- "Can't init TC, nic->flow_cfg is not setup\n");
- return -EINVAL;
- }
-
- err = otx2_tc_alloc_ent_bitmap(nic);
- if (err)
- return err;
-
- tc->flow_ht_params = tc_flow_ht_params;
- return rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
+ return 0;
}
EXPORT_SYMBOL(otx2_init_tc);
void otx2_shutdown_tc(struct otx2_nic *nic)
{
- struct otx2_tc_info *tc = &nic->tc_info;
-
- kfree(tc->tc_entries_bitmap);
- rhashtable_destroy(&tc->flow_table);
+ otx2_destroy_tc_flow_list(nic);
}
EXPORT_SYMBOL(otx2_shutdown_tc);