#include "rvu_reg.h"
 #include "rvu.h"
 #include "npc.h"
-#include "rvu_npc_hash.h"
 #include "rvu_npc_fs.h"
+#include "npc_profile.h"
+#include "rvu_npc_hash.h"
 
 #define NPC_BYTESM             GENMASK_ULL(19, 16)
 #define NPC_HDR_OFFSET         GENMASK_ULL(15, 8)
        default:
                return;
        }
+
        npc_set_kw_masks(mcam, type, nr_bits, kwi, offset, intf);
 }
 
 } while (0)
 
        NPC_WRITE_FLOW(NPC_DMAC, dmac, dmac_val, 0, dmac_mask, 0);
+
        NPC_WRITE_FLOW(NPC_SMAC, smac, smac_val, 0, smac_mask, 0);
        NPC_WRITE_FLOW(NPC_ETYPE, etype, ntohs(pkt->etype), 0,
                       ntohs(mask->etype), 0);
                              pkt, mask, opkt, omask);
 }
 
-static struct rvu_npc_mcam_rule *rvu_mcam_find_rule(struct npc_mcam *mcam,
-                                                   u16 entry)
+static struct rvu_npc_mcam_rule *rvu_mcam_find_rule(struct npc_mcam *mcam, u16 entry)
 {
        struct rvu_npc_mcam_rule *iter;
 
        u16 owner = req->hdr.pcifunc;
        struct msg_rsp write_rsp;
        struct mcam_entry *entry;
-       int entry_index, err;
        bool new = false;
+       u16 entry_index;
+       int err;
 
        installed_features = req->features;
        features = req->features;
        }
        mutex_unlock(&mcam->lock);
 }
+
+/* single drop on non hit rule starting from 0th index. This an extension
+ * to RPM mac filter to support more rules.
+ */
+int npc_install_mcam_drop_rule(struct rvu *rvu, int mcam_idx, u16 *counter_idx,
+                              u64 chan_val, u64 chan_mask, u64 exact_val, u64 exact_mask,
+                              u64 bcast_mcast_val, u64 bcast_mcast_mask)
+{
+       struct npc_mcam_alloc_counter_req cntr_req = { 0 };
+       struct npc_mcam_alloc_counter_rsp cntr_rsp = { 0 };
+       struct npc_mcam_write_entry_req req = { 0 };
+       struct npc_mcam *mcam = &rvu->hw->mcam;
+       struct rvu_npc_mcam_rule *rule;
+       struct msg_rsp rsp;
+       bool enabled;
+       int blkaddr;
+       int err;
+
+       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+       if (blkaddr < 0) {
+               dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+               return -ENODEV;
+       }
+
+       /* Bail out if no exact match support */
+       if (!rvu_npc_exact_has_match_table(rvu)) {
+               dev_info(rvu->dev, "%s: No support for exact match feature\n", __func__);
+               return -EINVAL;
+       }
+
+       /* If 0th entry is already used, return err */
+       enabled = is_mcam_entry_enabled(rvu, mcam, blkaddr, mcam_idx);
+       if (enabled) {
+               dev_err(rvu->dev, "%s: failed to add single drop on non hit rule at %d th index\n",
+                       __func__, mcam_idx);
+               return  -EINVAL;
+       }
+
+       /* Add this entry to mcam rules list */
+       rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+       if (!rule)
+               return -ENOMEM;
+
+       /* Disable rule by default. Enable rule when first dmac filter is
+        * installed
+        */
+       rule->enable = false;
+       rule->chan = chan_val;
+       rule->chan_mask = chan_mask;
+       rule->entry = mcam_idx;
+       rvu_mcam_add_rule(mcam, rule);
+
+       /* Reserve slot 0 */
+       npc_mcam_rsrcs_reserve(rvu, blkaddr, mcam_idx);
+
+       /* Allocate counter for this single drop on non hit rule */
+       cntr_req.hdr.pcifunc = 0; /* AF request */
+       cntr_req.contig = true;
+       cntr_req.count = 1;
+       err = rvu_mbox_handler_npc_mcam_alloc_counter(rvu, &cntr_req, &cntr_rsp);
+       if (err) {
+               dev_err(rvu->dev, "%s: Err to allocate cntr for drop rule (err=%d)\n",
+                       __func__, err);
+               return  -EFAULT;
+       }
+       *counter_idx = cntr_rsp.cntr;
+
+       /* Fill in fields for this mcam entry */
+       npc_update_entry(rvu, NPC_EXACT_RESULT, &req.entry_data, exact_val, 0,
+                        exact_mask, 0, NIX_INTF_RX);
+       npc_update_entry(rvu, NPC_CHAN, &req.entry_data, chan_val, 0,
+                        chan_mask, 0, NIX_INTF_RX);
+       npc_update_entry(rvu, NPC_LXMB, &req.entry_data, bcast_mcast_val, 0,
+                        bcast_mcast_mask, 0, NIX_INTF_RX);
+
+       req.intf = NIX_INTF_RX;
+       req.set_cntr = true;
+       req.cntr = cntr_rsp.cntr;
+       req.entry = mcam_idx;
+
+       err = rvu_mbox_handler_npc_mcam_write_entry(rvu, &req, &rsp);
+       if (err) {
+               dev_err(rvu->dev, "%s: Installation of single drop on non hit rule at %d failed\n",
+                       __func__, mcam_idx);
+               return err;
+       }
+
+       dev_err(rvu->dev, "%s: Installed single drop on non hit rule at %d, cntr=%d\n",
+               __func__, mcam_idx, req.cntr);
+
+       /* disable entry at Bank 0, index 0 */
+       npc_enable_mcam_entry(rvu, mcam, blkaddr, mcam_idx, false);
+
+       return 0;
+}
 
        return -ENOSPC;
 }
 
+/**
+ *     rvu_npc_exact_save_drop_rule_chan_and_mask - Save drop rules info in data base.
+ *      @rvu: resource virtualization unit.
+ *     @drop_mcam_idx: Drop rule index in NPC mcam.
+ *     @chan_val: Channel value.
+ *     @chan_mask: Channel Mask.
+ *     @pcifunc: pcifunc of interface.
+ */
+static bool rvu_npc_exact_save_drop_rule_chan_and_mask(struct rvu *rvu, int drop_mcam_idx,
+                                                      u64 chan_val, u64 chan_mask, u16 pcifunc)
+{
+       struct npc_exact_table *table;
+       int i;
+
+       table = rvu->hw->table;
+
+       for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) {
+               if (!table->drop_rule_map[i].valid)
+                       break;
+
+               if (table->drop_rule_map[i].chan_val != (u16)chan_val)
+                       continue;
+
+               if (table->drop_rule_map[i].chan_mask != (u16)chan_mask)
+                       continue;
+
+               return false;
+       }
+
+       if (i == NPC_MCAM_DROP_RULE_MAX)
+               return false;
+
+       table->drop_rule_map[i].drop_rule_idx = drop_mcam_idx;
+       table->drop_rule_map[i].chan_val = (u16)chan_val;
+       table->drop_rule_map[i].chan_mask = (u16)chan_mask;
+       table->drop_rule_map[i].pcifunc = pcifunc;
+       table->drop_rule_map[i].valid = true;
+       return true;
+}
+
+/**
+ *     rvu_npc_exact_calc_drop_rule_chan_and_mask - Calculate Channel number and mask.
+ *      @rvu: resource virtualization unit.
+ *     @intf_type: Interface type (SDK, LBK or CGX)
+ *     @cgx_id: CGX identifier.
+ *     @lmac_id: LAMC identifier.
+ *     @val: Channel number.
+ *     @mask: Channel mask.
+ */
+static bool rvu_npc_exact_calc_drop_rule_chan_and_mask(struct rvu *rvu, u8 intf_type,
+                                                      u8 cgx_id, u8 lmac_id,
+                                                      u64 *val, u64 *mask)
+{
+       u16 chan_val, chan_mask;
+
+       /* No support for SDP and LBK */
+       if (intf_type != NIX_INTF_TYPE_CGX)
+               return false;
+
+       chan_val = rvu_nix_chan_cgx(rvu, cgx_id, lmac_id, 0);
+       chan_mask = 0xfff;
+
+       if (val)
+               *val = chan_val;
+
+       if (mask)
+               *mask = chan_mask;
+
+       return true;
+}
+
+/**
+ *     rvu_npc_exact_drop_rule_to_pcifunc - Retrieve pcifunc
+ *      @rvu: resource virtualization unit.
+ *     @drop_rule_idx: Drop rule index in NPC mcam.
+ *
+ *     Debugfs (exact_drop_cnt) entry displays pcifunc for interface
+ *     by retrieving the pcifunc value from data base.
+ */
+u16 rvu_npc_exact_drop_rule_to_pcifunc(struct rvu *rvu, u32 drop_rule_idx)
+{
+       struct npc_exact_table *table;
+       int i;
+
+       table = rvu->hw->table;
+
+       for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) {
+               if (!table->drop_rule_map[i].valid)
+                       break;
+
+               if (table->drop_rule_map[i].drop_rule_idx != drop_rule_idx)
+                       continue;
+
+               return table->drop_rule_map[i].pcifunc;
+       }
+
+       dev_err(rvu->dev, "%s: drop mcam rule index (%d) >= NPC_MCAM_DROP_RULE_MAX\n",
+               __func__, drop_rule_idx);
+       return -1;
+}
+
+/**
+ *     rvu_npc_exact_get_drop_rule_info - Get drop rule information.
+ *      @rvu: resource virtualization unit.
+ *     @intf_type: Interface type (CGX, SDP or LBK)
+ *     @cgx_id: CGX identifier.
+ *     @lmac_id: LMAC identifier.
+ *     @drop_mcam_idx: NPC mcam drop rule index.
+ *     @val: Channel value.
+ *     @mask: Channel mask.
+ *     @pcifunc: pcifunc of interface corresponding to the drop rule.
+ */
+static bool rvu_npc_exact_get_drop_rule_info(struct rvu *rvu, u8 intf_type, u8 cgx_id,
+                                            u8 lmac_id, u32 *drop_mcam_idx, u64 *val,
+                                            u64 *mask, u16 *pcifunc)
+{
+       struct npc_exact_table *table;
+       u64 chan_val, chan_mask;
+       bool rc;
+       int i;
+
+       table = rvu->hw->table;
+
+       if (intf_type != NIX_INTF_TYPE_CGX) {
+               dev_err(rvu->dev, "%s: No drop rule for LBK/SDP mode\n", __func__);
+               return false;
+       }
+
+       rc = rvu_npc_exact_calc_drop_rule_chan_and_mask(rvu, intf_type, cgx_id,
+                                                       lmac_id, &chan_val, &chan_mask);
+
+       for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) {
+               if (!table->drop_rule_map[i].valid)
+                       break;
+
+               if (table->drop_rule_map[i].chan_val != (u16)chan_val)
+                       continue;
+
+               if (val)
+                       *val = table->drop_rule_map[i].chan_val;
+               if (mask)
+                       *mask = table->drop_rule_map[i].chan_mask;
+               if (pcifunc)
+                       *pcifunc = table->drop_rule_map[i].pcifunc;
+
+               *drop_mcam_idx = i;
+               return true;
+       }
+
+       if (i == NPC_MCAM_DROP_RULE_MAX) {
+               dev_err(rvu->dev, "%s: drop mcam rule index (%d) >= NPC_MCAM_DROP_RULE_MAX\n",
+                       __func__, *drop_mcam_idx);
+               return false;
+       }
+
+       dev_err(rvu->dev, "%s: Could not retrieve for cgx=%d, lmac=%d\n",
+               __func__, cgx_id, lmac_id);
+       return false;
+}
+
+/**
+ *     __rvu_npc_exact_cmd_rules_cnt_update - Update number dmac rules against a drop rule.
+ *      @rvu: resource virtualization unit.
+ *     @drop_mcam_idx: NPC mcam drop rule index.
+ *     @val: +1 or -1.
+ *     @enable_or_disable_cam: If no exact match rules against a drop rule, disable it.
+ *
+ *     when first exact match entry against a drop rule is added, enable_or_disable_cam
+ *     is set to true. When last exact match entry against a drop rule is deleted,
+ *     enable_or_disable_cam is set to true.
+ */
+static u16 __rvu_npc_exact_cmd_rules_cnt_update(struct rvu *rvu, int drop_mcam_idx,
+                                               int val, bool *enable_or_disable_cam)
+{
+       struct npc_exact_table *table;
+       u16 *cnt, old_cnt;
+       bool promisc;
+
+       table = rvu->hw->table;
+       promisc = table->promisc_mode[drop_mcam_idx];
+
+       cnt = &table->cnt_cmd_rules[drop_mcam_idx];
+       old_cnt = *cnt;
+
+       *cnt += val;
+
+       if (!enable_or_disable_cam)
+               goto done;
+
+       *enable_or_disable_cam = false;
+
+       /* If all rules are deleted and not already in promisc mode; disable cam */
+       if (!*cnt && !promisc) {
+               *enable_or_disable_cam = true;
+               goto done;
+       }
+
+       /* If rule got added and not already in promisc mode; enable cam */
+       if (!old_cnt && !promisc) {
+               *enable_or_disable_cam = true;
+               goto done;
+       }
+
+done:
+       return *cnt;
+}
+
 /**
  *      rvu_npc_exact_del_table_entry_by_id - Delete and free table entry.
  *      @rvu: resource virtualization unit.
 {
        struct npc_exact_table_entry *entry = NULL;
        struct npc_exact_table *table;
+       u32 drop_mcam_idx;
+       bool disable_cam;
        int *cnt;
 
        table = rvu->hw->table;
 
        (*cnt)--;
 
+       rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, entry->cgx_id, entry->lmac_id,
+                                        &drop_mcam_idx, NULL, NULL, NULL);
+
+       if (entry->cmd)
+               __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, -1, &disable_cam);
+
+       /* No dmac filter rules; disable drop on hit rule */
+       if (disable_cam) {
+               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, false);
+               dev_dbg(rvu->dev, "%s: Disabling mcam idx %d\n",
+                       __func__, drop_mcam_idx);
+       }
+
        mutex_unlock(&table->lock);
 
        rvu_npc_exact_dealloc_table_entry(rvu, entry->opc_type, entry->ways, entry->index);
        int blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
        enum npc_exact_opc_type opc_type;
        struct npc_exact_table *table;
+       u32 drop_mcam_idx;
+       bool enable_cam;
        u32 index;
        u64 mdata;
        int err;
                return err;
        }
 
+       rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, cgx_id, lmac_id,
+                                        &drop_mcam_idx, NULL, NULL, NULL);
+       if (cmd)
+               __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, 1, &enable_cam);
+
+       /* First command rule; enable drop on hit rule */
+       if (enable_cam) {
+               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, true);
+               dev_dbg(rvu->dev, "%s: Enabling mcam idx %d\n",
+                       __func__, drop_mcam_idx);
+       }
+
        dev_dbg(rvu->dev,
                "%s: Successfully added entry (index=%d, dmac=%pM, ways=%d opc_type=%d\n",
                __func__, index, mac, ways, opc_type);
  *      @rvu: resource virtualization unit.
  *
  *     Initialize HW and SW resources to manage 4way-2K table and fully
+       u8 cgx_id, lmac_id;
  *     associative 32-entry mcam table.
  */
 int rvu_npc_exact_init(struct rvu *rvu)
 {
+       u64 bcast_mcast_val, bcast_mcast_mask;
        struct npc_exact_table *table;
+       u64 exact_val, exact_mask;
+       u64 chan_val, chan_mask;
+       u8 cgx_id, lmac_id;
+       u32 *drop_mcam_idx;
+       u16 max_lmac_cnt;
        u64 npc_const3;
        int table_size;
        int blkaddr;
+       u16 pcifunc;
+       int err, i;
        u64 cfg;
-       int i;
+       bool rc;
 
        /* Read NPC_AF_CONST3 and check for have exact
         * match functionality is present
        rvu_exact_config_table_mask(rvu);
        rvu_exact_config_result_ctrl(rvu, table->mem_table.depth);
 
+       /* - No drop rule for LBK
+        * - Drop rules for SDP and each LMAC.
+        */
+       exact_val = !NPC_EXACT_RESULT_HIT;
+       exact_mask = NPC_EXACT_RESULT_HIT;
+
+       /* nibble - 3   2  1   0
+        *         L3B L3M L2B L2M
+        */
+       bcast_mcast_val = 0b0000;
+       bcast_mcast_mask = 0b0011;
+
+       /* Install SDP drop rule */
+       drop_mcam_idx = &table->num_drop_rules;
+
+       max_lmac_cnt = rvu->cgx_cnt_max * MAX_LMAC_PER_CGX + PF_CGXMAP_BASE;
+       for (i = PF_CGXMAP_BASE; i < max_lmac_cnt; i++) {
+               if (rvu->pf2cgxlmac_map[i] == 0xFF)
+                       continue;
+
+               rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[i], &cgx_id, &lmac_id);
+
+               rc = rvu_npc_exact_calc_drop_rule_chan_and_mask(rvu, NIX_INTF_TYPE_CGX, cgx_id,
+                                                               lmac_id, &chan_val, &chan_mask);
+               if (!rc) {
+                       dev_err(rvu->dev,
+                               "%s: failed, info chan_val=0x%llx chan_mask=0x%llx rule_id=%d\n",
+                               __func__, chan_val, chan_mask, *drop_mcam_idx);
+                       return -EINVAL;
+               }
+
+               /* Filter rules are only for PF */
+               pcifunc = RVU_PFFUNC(i, 0);
+
+               dev_dbg(rvu->dev,
+                       "%s:Drop rule cgx=%d lmac=%d chan(val=0x%llx, mask=0x%llx\n",
+                       __func__, cgx_id, lmac_id, chan_val, chan_mask);
+
+               rc = rvu_npc_exact_save_drop_rule_chan_and_mask(rvu, table->num_drop_rules,
+                                                               chan_val, chan_mask, pcifunc);
+               if (!rc) {
+                       dev_err(rvu->dev,
+                               "%s: failed to set drop info for cgx=%d, lmac=%d, chan=%llx\n",
+                               __func__, cgx_id, lmac_id, chan_val);
+                       return err;
+               }
+
+               err = npc_install_mcam_drop_rule(rvu, *drop_mcam_idx,
+                                                &table->counter_idx[*drop_mcam_idx],
+                                                chan_val, chan_mask,
+                                                exact_val, exact_mask,
+                                                bcast_mcast_val, bcast_mcast_mask);
+               if (err) {
+                       dev_err(rvu->dev,
+                               "failed to configure drop rule (cgx=%d lmac=%d)\n",
+                               cgx_id, lmac_id);
+                       return err;
+               }
+
+               (*drop_mcam_idx)++;
+       }
+
        dev_info(rvu->dev, "initialized exact match table successfully\n");
        return 0;
 }