octeontx2-af: Unlock contexts in the queue context cache in case of fault detection
authorSuman Ghosh <sumang@marvell.com>
Tue, 7 Mar 2023 10:49:08 +0000 (16:19 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Mar 2023 13:06:32 +0000 (13:06 +0000)
NDC caches contexts of frequently used queue's (Rx and Tx queues)
contexts. Due to a HW errata when NDC detects fault/poision while
accessing contexts it could go into an illegal state where a cache
line could get locked forever. To makesure all cache lines in NDC
are available for optimum performance upon fault/lockerror/posion
errors scan through all cache lines in NDC and clear the lock bit.

Fixes: 4a3581cd5995 ("octeontx2-af: NPA AQ instruction enqueue support")
Signed-off-by: Suman Ghosh <sumang@marvell.com>
Signed-off-by: Sunil Kovvuri Goutham <sgoutham@marvell.com>
Signed-off-by: Sai Krishna <saikrishnag@marvell.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h

index 389663a..ef721ca 100644 (file)
@@ -884,6 +884,9 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf,
 int rvu_cpt_ctx_flush(struct rvu *rvu, u16 pcifunc);
 int rvu_cpt_init(struct rvu *rvu);
 
+#define NDC_AF_BANK_MASK       GENMASK_ULL(7, 0)
+#define NDC_AF_BANK_LINE_MASK  GENMASK_ULL(31, 16)
+
 /* CN10K RVU */
 int rvu_set_channels_base(struct rvu *rvu);
 void rvu_program_channels(struct rvu *rvu);
@@ -902,6 +905,8 @@ static inline void rvu_dbg_init(struct rvu *rvu) {}
 static inline void rvu_dbg_exit(struct rvu *rvu) {}
 #endif
 
+int rvu_ndc_fix_locked_cacheline(struct rvu *rvu, int blkaddr);
+
 /* RVU Switch */
 void rvu_switch_enable(struct rvu *rvu);
 void rvu_switch_disable(struct rvu *rvu);
index fa280eb..26cfa50 100644 (file)
@@ -198,9 +198,6 @@ enum cpt_eng_type {
        CPT_IE_TYPE = 3,
 };
 
-#define NDC_MAX_BANK(rvu, blk_addr) (rvu_read64(rvu, \
-                                               blk_addr, NDC_AF_CONST) & 0xFF)
-
 #define rvu_dbg_NULL NULL
 #define rvu_dbg_open_NULL NULL
 
@@ -1448,6 +1445,7 @@ static int ndc_blk_hits_miss_stats(struct seq_file *s, int idx, int blk_addr)
        struct nix_hw *nix_hw;
        struct rvu *rvu;
        int bank, max_bank;
+       u64 ndc_af_const;
 
        if (blk_addr == BLKADDR_NDC_NPA0) {
                rvu = s->private;
@@ -1456,7 +1454,8 @@ static int ndc_blk_hits_miss_stats(struct seq_file *s, int idx, int blk_addr)
                rvu = nix_hw->rvu;
        }
 
-       max_bank = NDC_MAX_BANK(rvu, blk_addr);
+       ndc_af_const = rvu_read64(rvu, blk_addr, NDC_AF_CONST);
+       max_bank = FIELD_GET(NDC_AF_BANK_MASK, ndc_af_const);
        for (bank = 0; bank < max_bank; bank++) {
                seq_printf(s, "BANK:%d\n", bank);
                seq_printf(s, "\tHits:\t%lld\n",
index 26e639e..4ad707e 100644 (file)
@@ -790,6 +790,7 @@ static int nix_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
        struct nix_aq_res_s *result;
        int timeout = 1000;
        u64 reg, head;
+       int ret;
 
        result = (struct nix_aq_res_s *)aq->res->base;
 
@@ -813,9 +814,22 @@ static int nix_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
                        return -EBUSY;
        }
 
-       if (result->compcode != NIX_AQ_COMP_GOOD)
+       if (result->compcode != NIX_AQ_COMP_GOOD) {
                /* TODO: Replace this with some error code */
+               if (result->compcode == NIX_AQ_COMP_CTX_FAULT ||
+                   result->compcode == NIX_AQ_COMP_LOCKERR ||
+                   result->compcode == NIX_AQ_COMP_CTX_POISON) {
+                       ret = rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NIX0_RX);
+                       ret |= rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NIX0_TX);
+                       ret |= rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NIX1_RX);
+                       ret |= rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NIX1_TX);
+                       if (ret)
+                               dev_err(rvu->dev,
+                                       "%s: Not able to unlock cachelines\n", __func__);
+               }
+
                return -EBUSY;
+       }
 
        return 0;
 }
index 70bd036..4f5ca5a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2018 Marvell.
  *
  */
-
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 
@@ -42,9 +42,18 @@ static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
                        return -EBUSY;
        }
 
-       if (result->compcode != NPA_AQ_COMP_GOOD)
+       if (result->compcode != NPA_AQ_COMP_GOOD) {
                /* TODO: Replace this with some error code */
+               if (result->compcode == NPA_AQ_COMP_CTX_FAULT ||
+                   result->compcode == NPA_AQ_COMP_LOCKERR ||
+                   result->compcode == NPA_AQ_COMP_CTX_POISON) {
+                       if (rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NPA0))
+                               dev_err(rvu->dev,
+                                       "%s: Not able to unlock cachelines\n", __func__);
+               }
+
                return -EBUSY;
+       }
 
        return 0;
 }
@@ -545,3 +554,48 @@ void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
 
        npa_ctx_free(rvu, pfvf);
 }
+
+/* Due to an Hardware errata, in some corner cases, AQ context lock
+ * operations can result in a NDC way getting into an illegal state
+ * of not valid but locked.
+ *
+ * This API solves the problem by clearing the lock bit of the NDC block.
+ * The operation needs to be done for each line of all the NDC banks.
+ */
+int rvu_ndc_fix_locked_cacheline(struct rvu *rvu, int blkaddr)
+{
+       int bank, max_bank, line, max_line, err;
+       u64 reg, ndc_af_const;
+
+       /* Set the ENABLE bit(63) to '0' */
+       reg = rvu_read64(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL);
+       rvu_write64(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL, reg & GENMASK_ULL(62, 0));
+
+       /* Poll until the BUSY bits(47:32) are set to '0' */
+       err = rvu_poll_reg(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL, GENMASK_ULL(47, 32), true);
+       if (err) {
+               dev_err(rvu->dev, "Timed out while polling for NDC CAM busy bits.\n");
+               return err;
+       }
+
+       ndc_af_const = rvu_read64(rvu, blkaddr, NDC_AF_CONST);
+       max_bank = FIELD_GET(NDC_AF_BANK_MASK, ndc_af_const);
+       max_line = FIELD_GET(NDC_AF_BANK_LINE_MASK, ndc_af_const);
+       for (bank = 0; bank < max_bank; bank++) {
+               for (line = 0; line < max_line; line++) {
+                       /* Check if 'cache line valid bit(63)' is not set
+                        * but 'cache line lock bit(60)' is set and on
+                        * success, reset the lock bit(60).
+                        */
+                       reg = rvu_read64(rvu, blkaddr,
+                                        NDC_AF_BANKX_LINEX_METADATA(bank, line));
+                       if (!(reg & BIT_ULL(63)) && (reg & BIT_ULL(60))) {
+                               rvu_write64(rvu, blkaddr,
+                                           NDC_AF_BANKX_LINEX_METADATA(bank, line),
+                                           reg & ~BIT_ULL(60));
+                       }
+               }
+       }
+
+       return 0;
+}
index 1729b22..7007f0b 100644 (file)
 #define NDC_AF_INTR_ENA_W1S            (0x00068)
 #define NDC_AF_INTR_ENA_W1C            (0x00070)
 #define NDC_AF_ACTIVE_PC               (0x00078)
+#define NDC_AF_CAMS_RD_INTERVAL                (0x00080)
 #define NDC_AF_BP_TEST_ENABLE          (0x001F8)
 #define NDC_AF_BP_TEST(a)              (0x00200 | (a) << 3)
 #define NDC_AF_BLK_RST                 (0x002F0)
                (0x00F00 | (a) << 5 | (b) << 4)
 #define NDC_AF_BANKX_HIT_PC(a)         (0x01000 | (a) << 3)
 #define NDC_AF_BANKX_MISS_PC(a)                (0x01100 | (a) << 3)
+#define NDC_AF_BANKX_LINEX_METADATA(a, b) \
+               (0x10000 | (a) << 12 | (b) << 3)
 
 /* LBK */
 #define LBK_CONST                      (0x10ull)