The patch adds driver implementation for performing the idlechk tests.

Signed-off-by: Sudarsana Reddy Kalluru <skall...@marvell.com>
Signed-off-by: Igor Russkikh <irussk...@marvell.com>
Reported-by: kernel test robot <l...@intel.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x.h        |  10 +-
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c   |   7 +
 .../net/ethernet/broadcom/bnx2x/bnx2x_self_test.c  | 268 ++++++++++++++++++++-
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c  |   2 +
 4 files changed, 277 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h 
b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 4f5b2b8..dee61d9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1979,6 +1979,9 @@ struct bnx2x_func_init_params {
 
 #define skip_queue(bp, idx)    (NO_FCOE(bp) && IS_FCOE_IDX(idx))
 
+/*self test*/
+int bnx2x_idle_chk(struct bnx2x *bp);
+
 /**
  * bnx2x_set_mac_one - configure a single MAC address
  *
@@ -2430,13 +2433,6 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, 
u8 idu_sb_id,
 #define HC_SEG_ACCESS_ATTN             4
 #define HC_SEG_ACCESS_NORM             0   /*Driver decision 0-1*/
 
-static const u32 dmae_reg_go_c[] = {
-       DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
-       DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
-       DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
-       DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
-};
-
 void bnx2x_set_ethtool_ops(struct bnx2x *bp, struct net_device *netdev);
 void bnx2x_notify_link_changed(struct bnx2x *bp);
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c 
b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index db5107e7..06dfb90 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -276,6 +276,13 @@ enum bnx2x_board_type {
 
 MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 
+const u32 dmae_reg_go_c[] = {
+       DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
+       DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
+       DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
+       DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
+};
+
 /* Global resources for unloading a previously loaded device */
 #define BNX2X_PREV_WAIT_NEEDED 1
 static DEFINE_SEMAPHORE(bnx2x_prev_sem);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_self_test.c 
b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_self_test.c
index 93a7f7e..32a2295 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_self_test.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_self_test.c
@@ -18,7 +18,11 @@
 #define MAX_FAIL_MSG 256
 
 /* statistics and error reporting */
-static int idle_chk_errors;
+static int idle_chk_errors, idle_chk_warnings;
+
+/* masks for all chip types */
+static int is_e1, is_e1h, is_e2, is_e3a0, is_e3b0;
+
 
 /* struct for the argument list for a predicate in the self test databasei */
 struct st_pred_args {
@@ -30,7 +34,7 @@ struct st_pred_args {
        u32 imm4; /* 4th value in predicate condition, left-to-right */
 };
 
-/*struct representing self test record - a single test*/
+/* struct representing self test record - a single test */
 struct st_record {
        u8 chip_mask;
        u8 macro;
@@ -111,7 +115,7 @@ static int peq_neq_neq_r2(struct st_pred_args *args)
 /* struct holding the database of self test checks (registers and predicates) 
*/
 /* lines start from 2 since line 1 is heading in csv */
 #define ST_DB_LINES 468
-struct st_record st_database[ST_DB_LINES] = {
+static struct st_record st_database[ST_DB_LINES] = {
 /*line 2*/{(0x3), 1, 0x2114,
        NA, 1, 0, pand_neq,
        NA, IDLE_CHK_ERROR,
@@ -2920,3 +2924,261 @@ struct st_record st_database[ST_DB_LINES] = {
        "NIG: PBF IF5 FIFO is not empty",
        {NA, NA, 1, NA, NA, NA} },
 };
+
+/* handle self test fails according to severity and type */
+static void bnx2x_self_test_log(struct bnx2x *bp, u8 severity, char *message)
+{
+       switch (severity) {
+       case IDLE_CHK_ERROR:
+               BNX2X_ERR("ERROR %s", message);
+               idle_chk_errors++;
+               break;
+       case IDLE_CHK_ERROR_NO_TRAFFIC:
+               DP(NETIF_MSG_HW, "INFO %s", message);
+               break;
+       case IDLE_CHK_WARNING:
+               DP(NETIF_MSG_HW, "WARNING %s", message);
+               idle_chk_warnings++;
+               break;
+       }
+}
+
+/* specific test for QM rd/wr pointers and rd/wr banks */
+static void bnx2x_idle_chk6(struct bnx2x *bp,
+                           struct st_record *rec, char *message)
+{
+       u32 rd_ptr, wr_ptr, rd_bank, wr_bank;
+       int i;
+
+       for (i = 0; i < rec->loop; i++) {
+               /* read regs */
+               rec->pred_args.val1 =
+                       REG_RD(bp, rec->reg1 + i * rec->incr);
+               rec->pred_args.val2 =
+                       REG_RD(bp, rec->reg1 + i * rec->incr + 4);
+
+               /* calc read and write pointers */
+               rd_ptr = ((rec->pred_args.val1 & 0x3FFFFFC0) >> 6);
+               wr_ptr = ((((rec->pred_args.val1 & 0xC0000000) >> 30) & 0x3) |
+                       ((rec->pred_args.val2 & 0x3FFFFF) << 2));
+
+               /* perfrom pointer test */
+               if (rd_ptr != wr_ptr) {
+                       snprintf(message, MAX_FAIL_MSG,
+                                "QM: PTRTBL entry %d- rd_ptr is not equal to 
wr_ptr. Values are 0x%x and 0x%x\n",
+                                i, rd_ptr, wr_ptr);
+                       bnx2x_self_test_log(bp, rec->severity, message);
+               }
+
+               /* calculate read and write banks */
+               rd_bank = ((rec->pred_args.val1 & 0x30) >> 4);
+               wr_bank = (rec->pred_args.val1 & 0x03);
+
+               /* perform bank test */
+               if (rd_bank != wr_bank) {
+                       snprintf(message, MAX_FAIL_MSG,
+                                "QM: PTRTBL entry %d - rd_bank is not equal to 
wr_bank. Values are 0x%x 0x%x\n",
+                                i, rd_bank, wr_bank);
+                       bnx2x_self_test_log(bp, rec->severity, message);
+               }
+       }
+}
+
+/* specific test for cfc info ram and cid cam */
+static void bnx2x_idle_chk7(struct bnx2x *bp,
+                           struct st_record *rec, char *message)
+{
+       int i;
+
+       /* iterate through lcids */
+       for (i = 0; i < rec->loop; i++) {
+               /* make sure cam entry is valid (bit 0) */
+               if ((REG_RD(bp, (rec->reg2 + i * 4)) & 0x1) != 0x1)
+                       continue;
+
+               /* get connection type (multiple reads due to widebus) */
+               REG_RD(bp, (rec->reg1 + i * rec->incr));
+               REG_RD(bp, (rec->reg1 + i * rec->incr + 4));
+               rec->pred_args.val1 =
+                       REG_RD(bp, (rec->reg1 + i * rec->incr + 8));
+               REG_RD(bp, (rec->reg1 + i * rec->incr + 12));
+
+               /* obtain connection type */
+               if (is_e1 || is_e1h) {
+                       /* E1 E1H (bits 4..7) */
+                       rec->pred_args.val1 &= 0x78;
+                       rec->pred_args.val1 >>= 3;
+               } else {
+                       /* E2 E3A0 E3B0 (bits 26..29) */
+                       rec->pred_args.val1 &= 0x1E000000;
+                       rec->pred_args.val1 >>= 25;
+               }
+
+               /* get activity counter value */
+               rec->pred_args.val2 = REG_RD(bp, rec->reg3 + i * 4);
+
+               /* validate ac value is legal for con_type at idle state */
+               if (rec->bnx2x_predicate(&rec->pred_args)) {
+                       snprintf(message, MAX_FAIL_MSG,
+                                "%s. Values are 0x%x 0x%x\n", rec->fail_msg,
+                                rec->pred_args.val1, rec->pred_args.val2);
+                       bnx2x_self_test_log(bp, rec->severity, message);
+               }
+       }
+}
+
+/* self test procedure
+ * scan auto-generated database
+ * for each line:
+ * 1.  compare chip mask
+ * 2.  determine type (according to maro number)
+ * 3.  read registers
+ * 4.  call predicate
+ * 5.  collate results and statistics
+ */
+int bnx2x_idle_chk(struct bnx2x *bp)
+{
+       u16 i;                          /* loop counter */
+       u16 st_ind;                     /* self test database access index */
+       struct st_record rec;           /* current record variable */
+       char message[MAX_FAIL_MSG];     /* message to log */
+
+       /*init stats*/
+       idle_chk_errors = 0;
+       idle_chk_warnings = 0;
+
+       /*create masks for all chip types*/
+       is_e1   = CHIP_IS_E1(bp);
+       is_e1h  = CHIP_IS_E1H(bp);
+       is_e2   = CHIP_IS_E2(bp);
+       is_e3a0 = CHIP_IS_E3A0(bp);
+       is_e3b0 = CHIP_IS_E3B0(bp);
+
+       /*database main loop*/
+       for (st_ind = 0; st_ind < ST_DB_LINES; st_ind++) {
+               rec = st_database[st_ind];
+
+               /*check if test applies to chip*/
+               if (!((rec.chip_mask & IDLE_CHK_E1) && is_e1) &&
+                   !((rec.chip_mask & IDLE_CHK_E1H) && is_e1h) &&
+                   !((rec.chip_mask & IDLE_CHK_E2) && is_e2) &&
+                   !((rec.chip_mask & IDLE_CHK_E3A0) && is_e3a0) &&
+                   !((rec.chip_mask & IDLE_CHK_E3B0) && is_e3b0))
+                       continue;
+
+               /* identify macro */
+               switch (rec.macro) {
+               case 1:
+                       /* read single reg and call predicate */
+                       rec.pred_args.val1 = REG_RD(bp, rec.reg1);
+                       DP(BNX2X_MSG_IDLE, "mac1 add %x\n", rec.reg1);
+                       if (rec.bnx2x_predicate(&rec.pred_args)) {
+                               snprintf(message, sizeof(message),
+                                        "%s.Value is 0x%x\n", rec.fail_msg,
+                                        rec.pred_args.val1);
+                               bnx2x_self_test_log(bp, rec.severity, message);
+                       }
+                       break;
+               case 2:
+                       /* read repeatedly starting from reg1 and call
+                        * predicate after each read
+                        */
+                       for (i = 0; i < rec.loop; i++) {
+                               rec.pred_args.val1 =
+                                       REG_RD(bp, rec.reg1 + i * rec.incr);
+                               DP(BNX2X_MSG_IDLE, "mac2 add %x\n", rec.reg1);
+                               if (rec.bnx2x_predicate(&rec.pred_args)) {
+                                       snprintf(message, sizeof(message),
+                                                "%s. Value is 0x%x in loop 
%d\n",
+                                                rec.fail_msg,
+                                                rec.pred_args.val1, i);
+                                       bnx2x_self_test_log(bp, rec.severity,
+                                                           message);
+                               }
+                       }
+                       break;
+               case 3:
+                       /* read two regs and call predicate */
+                       rec.pred_args.val1 = REG_RD(bp, rec.reg1);
+                       rec.pred_args.val2 = REG_RD(bp, rec.reg2);
+                       DP(BNX2X_MSG_IDLE, "mac3 add1 %x add2 %x\n",
+                          rec.reg1, rec.reg2);
+                       if (rec.bnx2x_predicate(&rec.pred_args)) {
+                               snprintf(message, sizeof(message),
+                                        "%s. Values are 0x%x 0x%x\n",
+                                        rec.fail_msg, rec.pred_args.val1,
+                                        rec.pred_args.val2);
+                               bnx2x_self_test_log(bp, rec.severity, message);
+                       }
+                       break;
+               case 4:
+                       /*unused to-date*/
+                       for (i = 0; i < rec.loop; i++) {
+                               rec.pred_args.val1 =
+                                       REG_RD(bp, rec.reg1 + i * rec.incr);
+                               rec.pred_args.val2 =
+                                       (REG_RD(bp,
+                                               rec.reg2 + i * rec.incr)) >> 1;
+                               if (rec.bnx2x_predicate(&rec.pred_args)) {
+                                       snprintf(message, sizeof(message),
+                                                "%s. Values are 0x%x 0x%x in 
loop %d\n",
+                                                rec.fail_msg,
+                                                rec.pred_args.val1,
+                                                rec.pred_args.val2, i);
+                                       bnx2x_self_test_log(bp, rec.severity,
+                                                           message);
+                               }
+                       }
+                       break;
+               case 5:
+                       /* compare two regs, pending
+                        * the value of a condition reg
+                        */
+                       rec.pred_args.val1 = REG_RD(bp, rec.reg1);
+                       rec.pred_args.val2 = REG_RD(bp, rec.reg2);
+                       DP(BNX2X_MSG_IDLE, "mac3 add1 %x add2 %x add3 %x\n",
+                          rec.reg1, rec.reg2, rec.reg3);
+                       if (REG_RD(bp, rec.reg3) != 0) {
+                               if (rec.bnx2x_predicate(&rec.pred_args)) {
+                                       snprintf(message, sizeof(message),
+                                                "%s. Values are 0x%x 0x%x\n",
+                                                rec.fail_msg,
+                                                rec.pred_args.val1,
+                                                rec.pred_args.val2);
+                                       bnx2x_self_test_log(bp, rec.severity,
+                                                           message);
+                               }
+                       }
+                       break;
+               case 6:
+                       /* compare read and write pointers
+                        * and read and write banks in QM
+                        */
+                       bnx2x_idle_chk6(bp, &rec, message);
+                       break;
+               case 7:
+                       /* compare cfc info cam with cid cam */
+                       bnx2x_idle_chk7(bp, &rec, message);
+                       break;
+               default:
+                       DP(BNX2X_MSG_IDLE,
+                          "unknown macro in self test data base. macro %d line 
%d",
+                          rec.macro, st_ind);
+               }
+       }
+
+       /* abort if interface is not running */
+       if (!netif_running(bp->dev))
+               return idle_chk_errors;
+
+       /* return value accorindg to statistics */
+       if (idle_chk_errors == 0) {
+               DP(BNX2X_MSG_IDLE,
+                  "completed successfully (logged %d warnings)\n",
+                  idle_chk_warnings);
+       } else {
+               BNX2X_ERR("failed (with %d errors, %d warnings)\n",
+                         idle_chk_errors, idle_chk_warnings);
+       }
+       return idle_chk_errors;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c 
b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 7e0919a..0b193ed 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -23,6 +23,8 @@
 #include "bnx2x_cmn.h"
 #include "bnx2x_sriov.h"
 
+extern const u32 dmae_reg_go_c[];
+
 /* Statistics */
 
 /*
-- 
1.8.3.1

Reply via email to