]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
authorRatheesh Kannoth <rkannoth@marvell.com>
Wed, 29 Apr 2026 02:27:13 +0000 (07:57 +0530)
committerJakub Kicinski <kuba@kernel.org>
Fri, 1 May 2026 01:50:15 +0000 (18:50 -0700)
npc_mcam_idx_2_key_type() can fail; callers used to ignore it and still
used kw_type when enabling, configuring, copying, and reading MCAM entries.
That could program or decode hardware with an undefined key type.

Return -EINVAL when key-type lookup fails. Return -EINVAL from
npc_cn20k_copy_mcam_entry() when src and dest key types differ instead of
failing silently.

Change npc_cn20k_{enable,config,copy,read}_mcam_entry() to return int on
success or error. Thread those errors through the cn20k MCAM write and read
mbox handlers, the cn20k baseline steer read path, NPC defrag move
(disable/copy/enable with dev_err and -EFAULT), and the DMAC update path in
rvu_npc_fs.c.

Make npc_copy_mcam_entry() return int so the cn20k branch can return
npc_cn20k_copy_mcam_entry() without a void/int mismatch, and fail
NPC_MCAM_SHIFT_ENTRY when copy fails.

Cc: Suman Ghosh <sumang@marvell.com>
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Link: https://lore.kernel.org/netdev/adiQJvuKlEhq2ILx@stanley.mountain/
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260429022722.1110289-2-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c

index 7291fdb89b03f67cf6fa2e4f5663757890aa5228..7170dcf262007163ae6ef0b98d114ae29f72aac0 100644 (file)
@@ -798,7 +798,7 @@ program_mkex_extr:
                iounmap(mkex_prfl_addr);
 }
 
-void
+int
 npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
                            int index, bool enable)
 {
@@ -808,7 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
        u64 cfg, hw_prio;
        u8 kw_type;
 
-       npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+       if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+               return -EINVAL;
+
        if (kw_type == NPC_MCAM_KEY_X2) {
                cfg = rvu_read64(rvu, blkaddr,
                                 NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
@@ -819,7 +821,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
                rvu_write64(rvu, blkaddr,
                            NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
                            cfg);
-               return;
+               return 0;
        }
 
        /* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks
@@ -836,6 +838,8 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
                            NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
                            cfg);
        }
+
+       return 0;
 }
 
 void
@@ -1042,9 +1046,9 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
        }
 }
 
-void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
-                                u8 intf, struct cn20k_mcam_entry *entry,
-                                bool enable, u8 hw_prio, u8 req_kw_type)
+int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
+                               u8 intf, struct cn20k_mcam_entry *entry,
+                               bool enable, u8 hw_prio, u8 req_kw_type)
 {
        struct npc_mcam *mcam = &rvu->hw->mcam;
        int mcam_idx = index % mcam->banksize;
@@ -1052,10 +1056,13 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
        int kw = 0;
        u8 kw_type;
 
+       if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+               return -EINVAL;
+
        /* Disable before mcam entry update */
-       npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
+       if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false))
+               return -EINVAL;
 
-       npc_mcam_idx_2_key_type(rvu, index, &kw_type);
        /* CAM1 takes the comparison value and
         * CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'.
         * CAM1<n> = 0 & CAM0<n> = 1 => match if key<n> = 0
@@ -1120,9 +1127,11 @@ set_cfg:
        /* PF installing VF rule */
        npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
                                    kw_type, enable, hw_prio);
+
+       return 0;
 }
 
-void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
 {
        struct npc_mcam *mcam = &rvu->hw->mcam;
        u64 cfg, sreg, dreg, soff, doff;
@@ -1132,10 +1141,15 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
 
        dbank = npc_get_bank(mcam, dest);
        sbank = npc_get_bank(mcam, src);
-       npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
-       npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype);
+
+       if (npc_mcam_idx_2_key_type(rvu, src, &src_kwtype))
+               return -EINVAL;
+
+       if (npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype))
+               return -EINVAL;
+
        if (src_kwtype != dest_kwtype)
-               return;
+               return -EINVAL;
 
        src &= (mcam->banksize - 1);
        dest &= (mcam->banksize - 1);
@@ -1170,6 +1184,8 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
                if (src_kwtype == NPC_MCAM_KEY_X2)
                        break;
        }
+
+       return 0;
 }
 
 static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
@@ -1179,16 +1195,17 @@ static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
        entry->kw_mask[idx] = cam1 ^ cam0;
 }
 
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
-                              struct cn20k_mcam_entry *entry,
-                              u8 *intf, u8 *ena, u8 *hw_prio)
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+                             struct cn20k_mcam_entry *entry,
+                             u8 *intf, u8 *ena, u8 *hw_prio)
 {
        struct npc_mcam *mcam = &rvu->hw->mcam;
        u64 cam0, cam1, bank_cfg, cfg;
        int kw = 0, bank;
        u8 kw_type;
 
-       npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+       if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+               return -EINVAL;
 
        bank = npc_get_bank(mcam, index);
        index &= (mcam->banksize - 1);
@@ -1298,6 +1315,8 @@ read_action:
        cfg = rvu_read64(rvu, blkaddr,
                         NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
        entry->vtag_action = cfg;
+
+       return 0;
 }
 
 int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
@@ -1335,11 +1354,10 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
        if (is_pffunc_af(req->hdr.pcifunc))
                nix_intf = req->intf;
 
-       npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
-                                   &req->entry_data, req->enable_entry,
-                                   req->hw_prio, req->req_kw_type);
+       rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
+                                        &req->entry_data, req->enable_entry,
+                                        req->hw_prio, req->req_kw_type);
 
-       rc = 0;
 exit:
        mutex_unlock(&mcam->lock);
        return rc;
@@ -1361,11 +1379,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_read_entry(struct rvu *rvu,
 
        mutex_lock(&mcam->lock);
        rc = npc_mcam_verify_entry(mcam, pcifunc, req->entry);
-       if (!rc)
-               npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
-                                         &rsp->entry_data, &rsp->intf,
-                                         &rsp->enable, &rsp->hw_prio);
+       if (rc)
+               goto fail;
 
+       rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
+                                      &rsp->entry_data, &rsp->intf,
+                                      &rsp->enable, &rsp->hw_prio);
+fail:
        mutex_unlock(&mcam->lock);
        return rc;
 }
@@ -1375,11 +1395,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
                                                          struct npc_mcam_alloc_and_write_entry_rsp *rsp)
 {
        struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+       struct npc_mcam_free_entry_req free_req = { 0 };
        struct npc_mcam_alloc_entry_req entry_req;
        struct npc_mcam_alloc_entry_rsp entry_rsp;
        struct npc_mcam *mcam = &rvu->hw->mcam;
        u16 entry = NPC_MCAM_ENTRY_INVALID;
-       int blkaddr, rc;
+       struct msg_rsp free_rsp;
+       int blkaddr, rc, err;
        u8 nix_intf;
 
        blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
@@ -1415,12 +1437,23 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
        else
                nix_intf = pfvf->nix_rx_intf;
 
-       npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
-                                   &req->entry_data, req->enable_entry,
-                                   req->hw_prio, req->req_kw_type);
+       rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
+                                        &req->entry_data, req->enable_entry,
+                                        req->hw_prio, req->req_kw_type);
 
        mutex_unlock(&mcam->lock);
 
+       if (rc) {
+               free_req.hdr.pcifunc = req->hdr.pcifunc;
+               free_req.entry = entry_rsp.entry;
+               err = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &free_rsp);
+               if (err)
+                       dev_err(rvu->dev,
+                               "%s: Error to free mcam idx %u\n",
+                               __func__, entry_rsp.entry);
+               return rc;
+       }
+
        rsp->entry = entry_rsp.entry;
        return 0;
 }
@@ -1480,9 +1513,9 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
 
 read_entry:
        /* Read the mcam entry */
-       npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
-                                 &rsp->entry, &intf,
-                                 &enable, &hw_prio);
+       rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
+                                      &rsp->entry, &intf,
+                                      &enable, &hw_prio);
        mutex_unlock(&mcam->lock);
 out:
        return rc;
@@ -3607,9 +3640,30 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
                                   NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx,
                                                                      bank));
 
-               npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false);
-               npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx);
-               npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true);
+               /* If bug happened during copy/enable mcam, then there is a bug in allocation
+                * algorithm itself. There is no point in rewinding and returning, as it
+                * will face further issue. Return error after printing error
+                */
+               if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false)) {
+                       dev_err(rvu->dev,
+                               "%s: Error happened while disabling old_mid=%u\n",
+                               __func__, old_midx);
+                       return -EFAULT;
+               }
+
+               if (npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx)) {
+                       dev_err(rvu->dev,
+                               "%s: Error happened while copying old_midx=%u new_midx=%u\n",
+                               __func__, old_midx, new_midx);
+                       return -EFAULT;
+               }
+
+               if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true)) {
+                       dev_err(rvu->dev,
+                               "%s: Error happened while enabling new_mid=%u\n",
+                               __func__, new_midx);
+                       return -EFAULT;
+               }
 
                midx = new_midx % mcam->banksize;
                bank = new_midx / mcam->banksize;
index 815d0b257a7e1161ef3ed9c59a68a9c512f0e6fb..8f3eea9cfb1d303acfaeeca77be55b1c1c5da63e 100644 (file)
@@ -320,16 +320,16 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc);
 int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
                                u16 *mcast, u16 *promisc, u16 *ucast);
 
-void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
-                                u8 intf, struct cn20k_mcam_entry *entry,
-                                bool enable, u8 hw_prio, u8 req_kw_type);
-void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
-                                int index, bool enable);
-void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
-                              u16 src, u16 dest);
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
-                              struct cn20k_mcam_entry *entry, u8 *intf,
-                              u8 *ena, u8 *hw_prio);
+int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
+                               u8 intf, struct cn20k_mcam_entry *entry,
+                               bool enable, u8 hw_prio, u8 req_kw_type);
+int npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
+                               int index, bool enable);
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
+                             u16 src, u16 dest);
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+                             struct cn20k_mcam_entry *entry, u8 *intf,
+                             u8 *ena, u8 *hw_prio);
 void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr,
                                int bank, int index);
 int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
index c2ca5ed1d028a4355ff158054cf8aca3235428db..ecaf0946b85207f88fb6fd63de7ec7ebd763130f 100644 (file)
@@ -241,7 +241,10 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
                if (index < 0 || index >= mcam->banksize * mcam->banks)
                        return;
 
-               return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
+               if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable))
+                       dev_err(rvu->dev, "Error to %s mcam %u entry\n",
+                               enable ? "enable" : "disable", index);
+               return;
        }
 
        index &= (mcam->banksize - 1);
@@ -589,8 +592,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
                          NPC_AF_MCAMEX_BANKX_CFG(src, sbank)) & 1;
 }
 
-static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
-                               int blkaddr, u16 src, u16 dest)
+static int npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
+                              int blkaddr, u16 src, u16 dest)
 {
        int dbank = npc_get_bank(mcam, dest);
        int sbank = npc_get_bank(mcam, src);
@@ -630,6 +633,7 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
                         NPC_AF_MCAMEX_BANKX_CFG(src, sbank));
        rvu_write64(rvu, blkaddr,
                    NPC_AF_MCAMEX_BANKX_CFG(dest, dbank), cfg);
+       return 0;
 }
 
 u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
@@ -3266,7 +3270,10 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
                npc_enable_mcam_entry(rvu, mcam, blkaddr, new_entry, false);
 
                /* Copy rule from old entry to new entry */
-               npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry);
+               if (npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry)) {
+                       rc = NPC_MCAM_INVALID_REQ;
+                       break;
+               }
 
                /* Copy counter mapping, if any */
                cntr = mcam->entry2cntr_map[old_entry];
@@ -3284,7 +3291,8 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
 
        /* If shift has failed then report the failed index */
        if (index != req->shift_count) {
-               rc = NPC_MCAM_PERM_DENIED;
+               if (!rc)
+                       rc = NPC_MCAM_PERM_DENIED;
                rsp->failed_entry_idx = index;
        }
 
index b45798d9fdabd338ba6a7df60624a3f8edbfaf3d..fe10554b1f0e2419774fca67e9724df7b6549c43 100644 (file)
@@ -1980,13 +1980,15 @@ static int npc_update_dmac_value(struct rvu *rvu, int npcblkaddr,
 
        ether_addr_copy(rule->packet.dmac, pfvf->mac_addr);
 
-       if (is_cn20k(rvu->pdev))
-               npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
-                                         cn20k_entry, &intf,
-                                         &enable, &hw_prio);
-       else
+       if (is_cn20k(rvu->pdev)) {
+               if (npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
+                                             cn20k_entry, &intf,
+                                             &enable, &hw_prio))
+                       return -EINVAL;
+       } else {
                npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry,
                                    entry, &intf, &enable);
+       }
 
        npc_update_entry(rvu, NPC_DMAC, &mdata,
                         ether_addr_to_u64(pfvf->mac_addr), 0,
@@ -2038,8 +2040,12 @@ void npc_mcam_enable_flows(struct rvu *rvu, u16 target)
                                continue;
                        }
 
-                       if (rule->vfvlan_cfg)
-                               npc_update_dmac_value(rvu, blkaddr, rule, pfvf);
+                       if (rule->vfvlan_cfg) {
+                               if (npc_update_dmac_value(rvu, blkaddr, rule, pfvf))
+                                       dev_err(rvu->dev,
+                                               "Update dmac failed for %u, target=%#x\n",
+                                               rule->entry, target);
+                       }
 
                        if (rule->rx_action.op == NIX_RX_ACTION_DEFAULT) {
                                if (!def_ucast_rule)