net/sfc/base: import diagnostics support
authorAndrew Rybchenko <arybchenko@solarflare.com>
Tue, 29 Nov 2016 16:18:44 +0000 (16:18 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 17 Jan 2017 18:39:26 +0000 (19:39 +0100)
EFSYS_OPT_DIAG should be enabled to use it.

From Solarflare Communications Inc.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
drivers/net/sfc/base/ef10_impl.h
drivers/net/sfc/base/ef10_nic.c
drivers/net/sfc/base/efx.h
drivers/net/sfc/base/efx_check.h
drivers/net/sfc/base/efx_impl.h
drivers/net/sfc/base/efx_nic.c
drivers/net/sfc/base/efx_sram.c
drivers/net/sfc/base/siena_impl.h
drivers/net/sfc/base/siena_nic.c
drivers/net/sfc/base/siena_sram.c

index 697e99b..6afe0bc 100644 (file)
@@ -192,6 +192,14 @@ extern     __checkReturn   efx_rc_t
 ef10_nic_init(
        __in            efx_nic_t *enp);
 
+#if EFSYS_OPT_DIAG
+
+extern __checkReturn   efx_rc_t
+ef10_nic_register_test(
+       __in            efx_nic_t *enp);
+
+#endif /* EFSYS_OPT_DIAG */
+
 extern                 void
 ef10_nic_fini(
        __in            efx_nic_t *enp);
index 538e18c..0eb72a7 100644 (file)
@@ -1765,5 +1765,32 @@ ef10_nic_unprobe(
        (void) efx_mcdi_drv_attach(enp, B_FALSE);
 }
 
+#if EFSYS_OPT_DIAG
+
+       __checkReturn   efx_rc_t
+ef10_nic_register_test(
+       __in            efx_nic_t *enp)
+{
+       efx_rc_t rc;
+
+       /* FIXME */
+       _NOTE(ARGUNUSED(enp))
+       _NOTE(CONSTANTCONDITION)
+       if (B_FALSE) {
+               rc = ENOTSUP;
+               goto fail1;
+       }
+       /* FIXME */
+
+       return (0);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_DIAG */
+
 
 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
index df56aa2..c7108a9 100644 (file)
@@ -146,6 +146,14 @@ extern     __checkReturn   efx_rc_t
 efx_nic_reset(
        __in            efx_nic_t *enp);
 
+#if EFSYS_OPT_DIAG
+
+extern __checkReturn   efx_rc_t
+efx_nic_register_test(
+       __in            efx_nic_t *enp);
+
+#endif /* EFSYS_OPT_DIAG */
+
 extern         void
 efx_nic_fini(
        __in            efx_nic_t *enp);
@@ -689,6 +697,31 @@ efx_nic_get_vi_pool(
 
 /* NVRAM */
 
+#if EFSYS_OPT_DIAG
+
+typedef enum efx_pattern_type_t {
+       EFX_PATTERN_BYTE_INCREMENT = 0,
+       EFX_PATTERN_ALL_THE_SAME,
+       EFX_PATTERN_BIT_ALTERNATE,
+       EFX_PATTERN_BYTE_ALTERNATE,
+       EFX_PATTERN_BYTE_CHANGING,
+       EFX_PATTERN_BIT_SWEEP,
+       EFX_PATTERN_NTYPES
+} efx_pattern_type_t;
+
+typedef                        void
+(*efx_sram_pattern_fn_t)(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp);
+
+extern __checkReturn   efx_rc_t
+efx_sram_test(
+       __in            efx_nic_t *enp,
+       __in            efx_pattern_type_t type);
+
+#endif /* EFSYS_OPT_DIAG */
+
 extern __checkReturn   efx_rc_t
 efx_sram_buf_tbl_set(
        __in            efx_nic_t *enp,
index ef88645..feaccd0 100644 (file)
 # endif
 #endif /* EFSYS_OPT_DECODE_INTR_FATAL */
 
+#if EFSYS_OPT_DIAG
+/* Support diagnostic hardware tests */
+# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
+#  error "DIAG requires SIENA or HUNTINGTON or MEDFORD"
+# endif
+#endif /* EFSYS_OPT_DIAG */
+
 #ifdef EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE
 # error "FALCON_NIC_CFG_OVERRIDE is obsolete and is not supported."
 #endif
index 97057e4..a7c6b29 100644 (file)
@@ -271,6 +271,9 @@ typedef struct efx_nic_ops_s {
        efx_rc_t        (*eno_get_vi_pool)(efx_nic_t *, uint32_t *);
        efx_rc_t        (*eno_get_bar_region)(efx_nic_t *, efx_nic_region_t,
                                        uint32_t *, size_t *);
+#if EFSYS_OPT_DIAG
+       efx_rc_t        (*eno_register_test)(efx_nic_t *);
+#endif /* EFSYS_OPT_DIAG */
        void            (*eno_fini)(efx_nic_t *);
        void            (*eno_unprobe)(efx_nic_t *);
 } efx_nic_ops_t;
@@ -829,6 +832,32 @@ extern                     void
 efx_phy_unprobe(
        __in            efx_nic_t *enp);
 
+#if EFSYS_OPT_DIAG
+
+extern efx_sram_pattern_fn_t   __efx_sram_pattern_fns[];
+
+typedef struct efx_register_set_s {
+       unsigned int            address;
+       unsigned int            step;
+       unsigned int            rows;
+       efx_oword_t             mask;
+} efx_register_set_t;
+
+extern __checkReturn   efx_rc_t
+efx_nic_test_registers(
+       __in            efx_nic_t *enp,
+       __in            efx_register_set_t *rsp,
+       __in            size_t count);
+
+extern __checkReturn   efx_rc_t
+efx_nic_test_tables(
+       __in            efx_nic_t *enp,
+       __in            efx_register_set_t *rsp,
+       __in            efx_pattern_type_t pattern,
+       __in            size_t count);
+
+#endif /* EFSYS_OPT_DIAG */
+
 #if EFSYS_OPT_MCDI
 
 extern __checkReturn           efx_rc_t
index 3ce8514..047d4a0 100644 (file)
@@ -184,6 +184,9 @@ static const efx_nic_ops_t  __efx_nic_siena_ops = {
        siena_nic_init,                 /* eno_init */
        NULL,                           /* eno_get_vi_pool */
        NULL,                           /* eno_get_bar_region */
+#if EFSYS_OPT_DIAG
+       siena_nic_register_test,        /* eno_register_test */
+#endif /* EFSYS_OPT_DIAG */
        siena_nic_fini,                 /* eno_fini */
        siena_nic_unprobe,              /* eno_unprobe */
 };
@@ -200,6 +203,9 @@ static const efx_nic_ops_t  __efx_nic_hunt_ops = {
        ef10_nic_init,                  /* eno_init */
        ef10_nic_get_vi_pool,           /* eno_get_vi_pool */
        ef10_nic_get_bar_region,        /* eno_get_bar_region */
+#if EFSYS_OPT_DIAG
+       ef10_nic_register_test,         /* eno_register_test */
+#endif /* EFSYS_OPT_DIAG */
        ef10_nic_fini,                  /* eno_fini */
        ef10_nic_unprobe,               /* eno_unprobe */
 };
@@ -216,6 +222,9 @@ static const efx_nic_ops_t  __efx_nic_medford_ops = {
        ef10_nic_init,                  /* eno_init */
        ef10_nic_get_vi_pool,           /* eno_get_vi_pool */
        ef10_nic_get_bar_region,        /* eno_get_bar_region */
+#if EFSYS_OPT_DIAG
+       ef10_nic_register_test,         /* eno_register_test */
+#endif /* EFSYS_OPT_DIAG */
        ef10_nic_fini,                  /* eno_fini */
        ef10_nic_unprobe,               /* eno_unprobe */
 };
@@ -607,6 +616,165 @@ efx_nic_cfg_get(
        return (&(enp->en_nic_cfg));
 }
 
+#if EFSYS_OPT_DIAG
+
+       __checkReturn   efx_rc_t
+efx_nic_register_test(
+       __in            efx_nic_t *enp)
+{
+       const efx_nic_ops_t *enop = enp->en_enop;
+       efx_rc_t rc;
+
+       EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+       EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
+       EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
+
+       if ((rc = enop->eno_register_test(enp)) != 0)
+               goto fail1;
+
+       return (0);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+       __checkReturn   efx_rc_t
+efx_nic_test_registers(
+       __in            efx_nic_t *enp,
+       __in            efx_register_set_t *rsp,
+       __in            size_t count)
+{
+       unsigned int bit;
+       efx_oword_t original;
+       efx_oword_t reg;
+       efx_oword_t buf;
+       efx_rc_t rc;
+
+       while (count > 0) {
+               /* This function is only suitable for registers */
+               EFSYS_ASSERT(rsp->rows == 1);
+
+               /* bit sweep on and off */
+               EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
+                           B_TRUE);
+               for (bit = 0; bit < 128; bit++) {
+                       /* Is this bit in the mask? */
+                       if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
+                               continue;
+
+                       /* Test this bit can be set in isolation */
+                       reg = original;
+                       EFX_AND_OWORD(reg, rsp->mask);
+                       EFX_SET_OWORD_BIT(reg, bit);
+
+                       EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
+                                   B_TRUE);
+                       EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
+                                   B_TRUE);
+
+                       EFX_AND_OWORD(buf, rsp->mask);
+                       if (memcmp(&reg, &buf, sizeof (reg))) {
+                               rc = EIO;
+                               goto fail1;
+                       }
+
+                       /* Test this bit can be cleared in isolation */
+                       EFX_OR_OWORD(reg, rsp->mask);
+                       EFX_CLEAR_OWORD_BIT(reg, bit);
+
+                       EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
+                                   B_TRUE);
+                       EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
+                                   B_TRUE);
+
+                       EFX_AND_OWORD(buf, rsp->mask);
+                       if (memcmp(&reg, &buf, sizeof (reg))) {
+                               rc = EIO;
+                               goto fail2;
+                       }
+               }
+
+               /* Restore the old value */
+               EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
+                           B_TRUE);
+
+               --count;
+               ++rsp;
+       }
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       /* Restore the old value */
+       EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
+
+       return (rc);
+}
+
+       __checkReturn   efx_rc_t
+efx_nic_test_tables(
+       __in            efx_nic_t *enp,
+       __in            efx_register_set_t *rsp,
+       __in            efx_pattern_type_t pattern,
+       __in            size_t count)
+{
+       efx_sram_pattern_fn_t func;
+       unsigned int index;
+       unsigned int address;
+       efx_oword_t reg;
+       efx_oword_t buf;
+       efx_rc_t rc;
+
+       EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
+       func = __efx_sram_pattern_fns[pattern];
+
+       while (count > 0) {
+               /* Write */
+               address = rsp->address;
+               for (index = 0; index < rsp->rows; ++index) {
+                       func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
+                       func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
+                       EFX_AND_OWORD(reg, rsp->mask);
+                       EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
+
+                       address += rsp->step;
+               }
+
+               /* Read */
+               address = rsp->address;
+               for (index = 0; index < rsp->rows; ++index) {
+                       func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
+                       func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
+                       EFX_AND_OWORD(reg, rsp->mask);
+                       EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
+                       if (memcmp(&reg, &buf, sizeof (reg))) {
+                               rc = EIO;
+                               goto fail1;
+                       }
+
+                       address += rsp->step;
+               }
+
+               ++rsp;
+               --count;
+       }
+
+       return (0);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_DIAG */
+
        __checkReturn   efx_rc_t
 efx_nic_calculate_pcie_link_bandwidth(
        __in            uint32_t pcie_link_width,
index a55b06e..5f4edea 100644 (file)
@@ -198,3 +198,134 @@ efx_sram_buf_tbl_clear(
 }
 
 
+#if EFSYS_OPT_DIAG
+
+static                 void
+efx_sram_byte_increment_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
+       unsigned int index;
+
+       _NOTE(ARGUNUSED(negate))
+
+       for (index = 0; index < sizeof (efx_qword_t); index++)
+               eqp->eq_u8[index] = offset + index;
+}
+
+static                 void
+efx_sram_all_the_same_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       _NOTE(ARGUNUSED(row))
+
+       if (negate)
+               EFX_SET_QWORD(*eqp);
+       else
+               EFX_ZERO_QWORD(*eqp);
+}
+
+static                 void
+efx_sram_bit_alternate_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       _NOTE(ARGUNUSED(row))
+
+       EFX_POPULATE_QWORD_2(*eqp,
+           EFX_DWORD_0, (negate) ? 0x55555555 : 0xaaaaaaaa,
+           EFX_DWORD_1, (negate) ? 0x55555555 : 0xaaaaaaaa);
+}
+
+static                 void
+efx_sram_byte_alternate_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       _NOTE(ARGUNUSED(row))
+
+       EFX_POPULATE_QWORD_2(*eqp,
+           EFX_DWORD_0, (negate) ? 0x00ff00ff : 0xff00ff00,
+           EFX_DWORD_1, (negate) ? 0x00ff00ff : 0xff00ff00);
+}
+
+static                 void
+efx_sram_byte_changing_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
+       unsigned int index;
+
+       for (index = 0; index < sizeof (efx_qword_t); index++) {
+               uint8_t byte;
+
+               if (offset / 256 == 0)
+                       byte = (uint8_t)((offset % 257) % 256);
+               else
+                       byte = (uint8_t)(~((offset - 8) % 257) % 256);
+
+               eqp->eq_u8[index] = (negate) ? ~byte : byte;
+       }
+}
+
+static                 void
+efx_sram_bit_sweep_set(
+       __in            size_t row,
+       __in            boolean_t negate,
+       __out           efx_qword_t *eqp)
+{
+       size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
+
+       if (negate) {
+               EFX_SET_QWORD(*eqp);
+               EFX_CLEAR_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
+       } else {
+               EFX_ZERO_QWORD(*eqp);
+               EFX_SET_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
+       }
+}
+
+efx_sram_pattern_fn_t  __efx_sram_pattern_fns[] = {
+       efx_sram_byte_increment_set,
+       efx_sram_all_the_same_set,
+       efx_sram_bit_alternate_set,
+       efx_sram_byte_alternate_set,
+       efx_sram_byte_changing_set,
+       efx_sram_bit_sweep_set
+};
+
+       __checkReturn   efx_rc_t
+efx_sram_test(
+       __in            efx_nic_t *enp,
+       __in            efx_pattern_type_t type)
+{
+       efx_sram_pattern_fn_t func;
+
+       EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+
+       EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
+
+       EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
+       EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
+       EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
+
+       /* SRAM testing is only available on Siena. */
+       if (enp->en_family != EFX_FAMILY_SIENA)
+               return (0);
+
+       /* Select pattern generator */
+       EFSYS_ASSERT3U(type, <, EFX_PATTERN_NTYPES);
+       func = __efx_sram_pattern_fns[type];
+
+       return (siena_sram_test(enp, func));
+}
+
+#endif /* EFSYS_OPT_DIAG */
index 2c2a098..c316867 100644 (file)
@@ -54,6 +54,14 @@ extern       __checkReturn   efx_rc_t
 siena_nic_init(
        __in            efx_nic_t *enp);
 
+#if EFSYS_OPT_DIAG
+
+extern __checkReturn   efx_rc_t
+siena_nic_register_test(
+       __in            efx_nic_t *enp);
+
+#endif /* EFSYS_OPT_DIAG */
+
 extern                 void
 siena_nic_fini(
        __in            efx_nic_t *enp);
@@ -68,6 +76,15 @@ extern                       void
 siena_sram_init(
        __in            efx_nic_t *enp);
 
+#if EFSYS_OPT_DIAG
+
+extern __checkReturn   efx_rc_t
+siena_sram_test(
+       __in            efx_nic_t *enp,
+       __in            efx_sram_pattern_fn_t func);
+
+#endif /* EFSYS_OPT_DIAG */
+
 #if EFSYS_OPT_MCDI
 
 extern __checkReturn   efx_rc_t
index 7be16dc..2d079c2 100644 (file)
@@ -354,4 +354,136 @@ siena_nic_unprobe(
        (void) efx_mcdi_drv_attach(enp, B_FALSE);
 }
 
+#if EFSYS_OPT_DIAG
+
+static efx_register_set_t __siena_registers[] = {
+       { FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
+       { FR_CZ_USR_EV_CFG_OFST, 0, 1 },
+       { FR_AZ_RX_CFG_REG_OFST, 0, 1 },
+       { FR_AZ_TX_CFG_REG_OFST, 0, 1 },
+       { FR_AZ_TX_RESERVED_REG_OFST, 0, 1 },
+       { FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 },
+       { FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 },
+       { FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 },
+       { FR_AZ_DP_CTRL_REG_OFST, 0, 1 },
+       { FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1},
+       { FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1},
+       { FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1},
+       { FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
+};
+
+static const uint32_t __siena_register_masks[] = {
+       0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
+       0x000103FF, 0x00000000, 0x00000000, 0x00000000,
+       0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
+       0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF,
+       0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF,
+       0x001FFFFF, 0x00000000, 0x00000000, 0x00000000,
+       0x00000003, 0x00000000, 0x00000000, 0x00000000,
+       0x000003FF, 0x00000000, 0x00000000, 0x00000000,
+       0x00000FFF, 0x00000000, 0x00000000, 0x00000000,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
+};
+
+static efx_register_set_t __siena_tables[] = {
+       { FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
+           FR_AZ_RX_FILTER_TBL0_ROWS },
+       { FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
+           FR_CZ_RX_MAC_FILTER_TBL0_ROWS },
+       { FR_AZ_RX_DESC_PTR_TBL_OFST,
+           FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS },
+       { FR_AZ_TX_DESC_PTR_TBL_OFST,
+           FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS },
+       { FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS },
+       { FR_CZ_TX_FILTER_TBL0_OFST,
+           FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS },
+       { FR_CZ_TX_MAC_FILTER_TBL0_OFST,
+           FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
+};
+
+static const uint32_t __siena_table_masks[] = {
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
+       0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
+       0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,
+       0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000,
+       0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF,
+       0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000,
+};
+
+       __checkReturn   efx_rc_t
+siena_nic_register_test(
+       __in            efx_nic_t *enp)
+{
+       efx_register_set_t *rsp;
+       const uint32_t *dwordp;
+       unsigned int nitems;
+       unsigned int count;
+       efx_rc_t rc;
+
+       /* Fill out the register mask entries */
+       EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
+                   == EFX_ARRAY_SIZE(__siena_registers) * 4);
+
+       nitems = EFX_ARRAY_SIZE(__siena_registers);
+       dwordp = __siena_register_masks;
+       for (count = 0; count < nitems; ++count) {
+               rsp = __siena_registers + count;
+               rsp->mask.eo_u32[0] = *dwordp++;
+               rsp->mask.eo_u32[1] = *dwordp++;
+               rsp->mask.eo_u32[2] = *dwordp++;
+               rsp->mask.eo_u32[3] = *dwordp++;
+       }
+
+       /* Fill out the register table entries */
+       EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
+                   == EFX_ARRAY_SIZE(__siena_tables) * 4);
+
+       nitems = EFX_ARRAY_SIZE(__siena_tables);
+       dwordp = __siena_table_masks;
+       for (count = 0; count < nitems; ++count) {
+               rsp = __siena_tables + count;
+               rsp->mask.eo_u32[0] = *dwordp++;
+               rsp->mask.eo_u32[1] = *dwordp++;
+               rsp->mask.eo_u32[2] = *dwordp++;
+               rsp->mask.eo_u32[3] = *dwordp++;
+       }
+
+       if ((rc = efx_nic_test_registers(enp, __siena_registers,
+           EFX_ARRAY_SIZE(__siena_registers))) != 0)
+               goto fail1;
+
+       if ((rc = efx_nic_test_tables(enp, __siena_tables,
+           EFX_PATTERN_BYTE_ALTERNATE,
+           EFX_ARRAY_SIZE(__siena_tables))) != 0)
+               goto fail2;
+
+       if ((rc = efx_nic_test_tables(enp, __siena_tables,
+           EFX_PATTERN_BYTE_CHANGING,
+           EFX_ARRAY_SIZE(__siena_tables))) != 0)
+               goto fail3;
+
+       if ((rc = efx_nic_test_tables(enp, __siena_tables,
+           EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
+               goto fail4;
+
+       return (0);
+
+fail4:
+       EFSYS_PROBE(fail4);
+fail3:
+       EFSYS_PROBE(fail3);
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_DIAG */
+
 #endif /* EFSYS_OPT_SIENA */
index 411ef9d..572c2e9 100644 (file)
@@ -71,4 +71,108 @@ siena_sram_init(
        EFX_BAR_WRITEO(enp, FR_AZ_SRM_UPD_EVQ_REG, &oword);
 }
 
+#if EFSYS_OPT_DIAG
+
+       __checkReturn   efx_rc_t
+siena_sram_test(
+       __in            efx_nic_t *enp,
+       __in            efx_sram_pattern_fn_t func)
+{
+       efx_oword_t oword;
+       efx_qword_t qword;
+       efx_qword_t verify;
+       size_t rows;
+       unsigned int wptr;
+       unsigned int rptr;
+       efx_rc_t rc;
+
+       EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
+
+       /* Reconfigure into HALF buffer table mode */
+       EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 0);
+       EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);
+
+       /*
+        * Move the descriptor caches up to the top of SRAM, and test
+        * all of SRAM below them. We only miss out one row here.
+        */
+       rows = SIENA_SRAM_ROWS - 1;
+       EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_RX_DC_BASE_ADR, rows);
+       EFX_BAR_WRITEO(enp, FR_AZ_SRM_RX_DC_CFG_REG, &oword);
+
+       EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_TX_DC_BASE_ADR, rows + 1);
+       EFX_BAR_WRITEO(enp, FR_AZ_SRM_TX_DC_CFG_REG, &oword);
+
+       /*
+        * Write the pattern through BUF_HALF_TBL. Write
+        * in 64 entry batches, waiting 1us in between each batch
+        * to guarantee not to overflow the SRAM fifo
+        */
+       for (wptr = 0, rptr = 0; wptr < rows; ++wptr) {
+               func(wptr, B_FALSE, &qword);
+               EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_HALF_TBL, wptr, &qword);
+
+               if ((wptr - rptr) < 64 && wptr < rows - 1)
+                       continue;
+
+               EFSYS_SPIN(1);
+
+               for (; rptr <= wptr; ++rptr) {
+                       func(rptr, B_FALSE, &qword);
+                       EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_HALF_TBL, rptr,
+                           &verify);
+
+                       if (!EFX_QWORD_IS_EQUAL(verify, qword)) {
+                               rc = EFAULT;
+                               goto fail1;
+                       }
+               }
+       }
+
+       /* And do the same negated */
+       for (wptr = 0, rptr = 0; wptr < rows; ++wptr) {
+               func(wptr, B_TRUE, &qword);
+               EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_HALF_TBL, wptr, &qword);
+
+               if ((wptr - rptr) < 64 && wptr < rows - 1)
+                       continue;
+
+               EFSYS_SPIN(1);
+
+               for (; rptr <= wptr; ++rptr) {
+                       func(rptr, B_TRUE, &qword);
+                       EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_HALF_TBL, rptr,
+                           &verify);
+
+                       if (!EFX_QWORD_IS_EQUAL(verify, qword)) {
+                               rc = EFAULT;
+                               goto fail2;
+                       }
+               }
+       }
+
+       /* Restore back to FULL buffer table mode */
+       EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 1);
+       EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);
+
+       /*
+        * We don't need to reconfigure SRAM again because the API
+        * requires efx_nic_fini() to be called after an sram test.
+        */
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       /* Restore back to FULL buffer table mode */
+       EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 1);
+       EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_DIAG */
+
 #endif /* EFSYS_OPT_SIENA */