OSDN Git Service

octeontx2-af: Install TC filter rules in hardware based on priority
authorSuman Ghosh <sumang@marvell.com>
Fri, 21 Jul 2023 04:39:25 +0000 (10:09 +0530)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 25 Jul 2023 07:44:19 +0000 (09:44 +0200)
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>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Link: https://lore.kernel.org/r/20230721043925.2627806-1-sumang@marvell.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c

index eba307e..ed66c59 100644 (file)
@@ -235,7 +235,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)              \
@@ -1491,6 +1491,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 {
@@ -1506,6 +1508,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 */
index 9523194..9c365cc 100644 (file)
@@ -1192,7 +1192,7 @@ find_rule:
        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;
        }
@@ -1407,12 +1407,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);
 
@@ -1428,6 +1429,10 @@ 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;
                        }
index 592b317..854045e 100644 (file)
@@ -158,6 +158,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;
@@ -197,7 +198,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;
@@ -209,6 +210,7 @@ exit:
 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;
@@ -250,7 +252,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);
index 37d792f..25e99fd 100644 (file)
@@ -361,13 +361,8 @@ struct otx2_flow_config {
        struct list_head        flow_list;
        u32                     dmacflt_max_flows;
        u16                     max_flows;
-};
-
-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 {
@@ -492,7 +487,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;
@@ -1064,7 +1058,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);
index 63ef7c4..4e11304 100644 (file)
@@ -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;
 }
index c47d91d..9efcec5 100644 (file)
@@ -764,6 +764,7 @@ static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
        struct otx2_nic *pfvf = netdev_priv(dev);
        int ret = -EOPNOTSUPP;
 
+       pfvf->flow_cfg->ntuple = ntuple;
        switch (nfc->cmd) {
        case ETHTOOL_SRXFH:
                ret = otx2_set_rss_hash_opts(pfvf, nfc);
index 2d7713a..4762dbe 100644 (file)
@@ -276,6 +276,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;
@@ -298,6 +299,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.
index 5e56b6c..1e6fc23 100644 (file)
@@ -34,9 +34,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 */
@@ -44,31 +43,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)
 {
@@ -707,8 +685,117 @@ 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 *rsp;
        struct npc_delete_flow_req *req;
        int err;
 
@@ -729,22 +816,113 @@ 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);
+               if (IS_ERR(rsp)) {
+                       netdev_err(nic->netdev, "Failed to get MCAM delete response for entry %d\n",
+                                  entry);
+                       mutex_unlock(&nic->mbox.lock);
+                       return -EFAULT;
+               }
+
+               *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);
@@ -772,16 +950,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;
 }
 
@@ -790,15 +962,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;
@@ -810,6 +981,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));
 
@@ -820,12 +992,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) {
@@ -836,11 +1007,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;
@@ -850,26 +1018,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;
-       }
+       mutex_unlock(&nic->mbox.lock);
+       memcpy(&new_node->req, req, sizeof(struct npc_install_flow_req));
 
-       set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
        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);
 
@@ -896,16 +1056,13 @@ free_leaf:
 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);
@@ -1053,12 +1210,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);
@@ -1143,18 +1308,8 @@ 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);
 
@@ -1164,25 +1319,12 @@ int otx2_init_tc(struct otx2_nic *nic)
                return -EINVAL;
        }
 
-       err = otx2_tc_alloc_ent_bitmap(nic);
-       if (err)
-               return err;
-
-       tc->flow_ht_params = tc_flow_ht_params;
-       err = rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
-       if (err) {
-               kfree(tc->tc_entries_bitmap);
-               tc->tc_entries_bitmap = NULL;
-       }
-       return err;
+       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);