15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3*672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2007-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko */
65e111ed8SAndrew Rybchenko
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko
105e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_sram_buf_tbl_set(__in efx_nic_t * enp,__in uint32_t id,__in efsys_mem_t * esmp,__in size_t n)115e111ed8SAndrew Rybchenko efx_sram_buf_tbl_set(
125e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
135e111ed8SAndrew Rybchenko __in uint32_t id,
145e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp,
155e111ed8SAndrew Rybchenko __in size_t n)
165e111ed8SAndrew Rybchenko {
175e111ed8SAndrew Rybchenko efx_qword_t qword;
185e111ed8SAndrew Rybchenko uint32_t start = id;
195e111ed8SAndrew Rybchenko uint32_t stop = start + n;
205e111ed8SAndrew Rybchenko efsys_dma_addr_t addr;
215e111ed8SAndrew Rybchenko efx_oword_t oword;
225e111ed8SAndrew Rybchenko unsigned int count;
235e111ed8SAndrew Rybchenko efx_rc_t rc;
245e111ed8SAndrew Rybchenko
255e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
275e111ed8SAndrew Rybchenko
285e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
295e111ed8SAndrew Rybchenko if (EFX_FAMILY_IS_EF10(enp)) {
305e111ed8SAndrew Rybchenko /*
315e111ed8SAndrew Rybchenko * FIXME: the efx_sram_buf_tbl_*() functionality needs to be
325e111ed8SAndrew Rybchenko * pulled inside the Falcon/Siena queue create/destroy code,
335e111ed8SAndrew Rybchenko * and then the original functions can be removed (see bug30834
345e111ed8SAndrew Rybchenko * comment #1). But, for now, we just ensure that they are
355e111ed8SAndrew Rybchenko * no-ops for EF10, to allow bringing up existing drivers
365e111ed8SAndrew Rybchenko * without modification.
375e111ed8SAndrew Rybchenko */
385e111ed8SAndrew Rybchenko
395e111ed8SAndrew Rybchenko return (0);
405e111ed8SAndrew Rybchenko }
415e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
425e111ed8SAndrew Rybchenko
435e111ed8SAndrew Rybchenko if (stop >= EFX_BUF_TBL_SIZE) {
445e111ed8SAndrew Rybchenko rc = EFBIG;
455e111ed8SAndrew Rybchenko goto fail1;
465e111ed8SAndrew Rybchenko }
475e111ed8SAndrew Rybchenko
485e111ed8SAndrew Rybchenko /* Add the entries into the buffer table */
495e111ed8SAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp);
505e111ed8SAndrew Rybchenko for (id = start; id != stop; id++) {
515e111ed8SAndrew Rybchenko EFX_POPULATE_QWORD_5(qword,
525e111ed8SAndrew Rybchenko FRF_AZ_IP_DAT_BUF_SIZE, 0, FRF_AZ_BUF_ADR_REGION, 0,
535e111ed8SAndrew Rybchenko FRF_AZ_BUF_ADR_FBUF_DW0,
545e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) & 0xffffffff),
555e111ed8SAndrew Rybchenko FRF_AZ_BUF_ADR_FBUF_DW1,
565e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) >> 32),
575e111ed8SAndrew Rybchenko FRF_AZ_BUF_OWNER_ID_FBUF, 0);
585e111ed8SAndrew Rybchenko
595e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_FULL_TBL,
605e111ed8SAndrew Rybchenko id, &qword);
615e111ed8SAndrew Rybchenko
625e111ed8SAndrew Rybchenko addr += EFX_BUF_SIZE;
635e111ed8SAndrew Rybchenko }
645e111ed8SAndrew Rybchenko
655e111ed8SAndrew Rybchenko EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1);
665e111ed8SAndrew Rybchenko
675e111ed8SAndrew Rybchenko /* Flush the write buffer */
685e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_2(oword, FRF_AZ_BUF_UPD_CMD, 1,
695e111ed8SAndrew Rybchenko FRF_AZ_BUF_CLR_CMD, 0);
705e111ed8SAndrew Rybchenko EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
715e111ed8SAndrew Rybchenko
725e111ed8SAndrew Rybchenko /* Poll for the last entry being written to the buffer table */
735e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(id, ==, stop);
745e111ed8SAndrew Rybchenko addr -= EFX_BUF_SIZE;
755e111ed8SAndrew Rybchenko
765e111ed8SAndrew Rybchenko count = 0;
775e111ed8SAndrew Rybchenko do {
785e111ed8SAndrew Rybchenko EFSYS_PROBE1(wait, unsigned int, count);
795e111ed8SAndrew Rybchenko
805e111ed8SAndrew Rybchenko /* Spin for 1 ms */
815e111ed8SAndrew Rybchenko EFSYS_SPIN(1000);
825e111ed8SAndrew Rybchenko
835e111ed8SAndrew Rybchenko EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL,
845e111ed8SAndrew Rybchenko id - 1, &qword);
855e111ed8SAndrew Rybchenko
865e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) ==
875e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) & 0xffffffff) &&
885e111ed8SAndrew Rybchenko EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) ==
895e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) >> 32))
905e111ed8SAndrew Rybchenko goto verify;
915e111ed8SAndrew Rybchenko
925e111ed8SAndrew Rybchenko } while (++count < 100);
935e111ed8SAndrew Rybchenko
945e111ed8SAndrew Rybchenko rc = ETIMEDOUT;
955e111ed8SAndrew Rybchenko goto fail2;
965e111ed8SAndrew Rybchenko
975e111ed8SAndrew Rybchenko verify:
985e111ed8SAndrew Rybchenko /* Verify the rest of the entries in the buffer table */
995e111ed8SAndrew Rybchenko while (--id != start) {
1005e111ed8SAndrew Rybchenko addr -= EFX_BUF_SIZE;
1015e111ed8SAndrew Rybchenko
1025e111ed8SAndrew Rybchenko /* Read the buffer table entry */
1035e111ed8SAndrew Rybchenko EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL,
1045e111ed8SAndrew Rybchenko id - 1, &qword);
1055e111ed8SAndrew Rybchenko
1065e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) !=
1075e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) & 0xffffffff) ||
1085e111ed8SAndrew Rybchenko EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) !=
1095e111ed8SAndrew Rybchenko (uint32_t)((addr >> 12) >> 32)) {
1105e111ed8SAndrew Rybchenko rc = EFAULT;
1115e111ed8SAndrew Rybchenko goto fail3;
1125e111ed8SAndrew Rybchenko }
1135e111ed8SAndrew Rybchenko }
1145e111ed8SAndrew Rybchenko
1155e111ed8SAndrew Rybchenko return (0);
1165e111ed8SAndrew Rybchenko
1175e111ed8SAndrew Rybchenko fail3:
1185e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
1195e111ed8SAndrew Rybchenko
1205e111ed8SAndrew Rybchenko id = stop;
1215e111ed8SAndrew Rybchenko
1225e111ed8SAndrew Rybchenko fail2:
1235e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1245e111ed8SAndrew Rybchenko
1255e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0,
1265e111ed8SAndrew Rybchenko FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, id - 1,
1275e111ed8SAndrew Rybchenko FRF_AZ_BUF_CLR_START_ID, start);
1285e111ed8SAndrew Rybchenko EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
1295e111ed8SAndrew Rybchenko
1305e111ed8SAndrew Rybchenko fail1:
1315e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1325e111ed8SAndrew Rybchenko
1335e111ed8SAndrew Rybchenko return (rc);
1345e111ed8SAndrew Rybchenko }
1355e111ed8SAndrew Rybchenko
1365e111ed8SAndrew Rybchenko void
efx_sram_buf_tbl_clear(__in efx_nic_t * enp,__in uint32_t id,__in size_t n)1375e111ed8SAndrew Rybchenko efx_sram_buf_tbl_clear(
1385e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1395e111ed8SAndrew Rybchenko __in uint32_t id,
1405e111ed8SAndrew Rybchenko __in size_t n)
1415e111ed8SAndrew Rybchenko {
1425e111ed8SAndrew Rybchenko efx_oword_t oword;
1435e111ed8SAndrew Rybchenko uint32_t start = id;
1445e111ed8SAndrew Rybchenko uint32_t stop = start + n;
1455e111ed8SAndrew Rybchenko
1465e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1475e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
1485e111ed8SAndrew Rybchenko
1495e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
1505e111ed8SAndrew Rybchenko if (EFX_FAMILY_IS_EF10(enp)) {
1515e111ed8SAndrew Rybchenko /*
1525e111ed8SAndrew Rybchenko * FIXME: the efx_sram_buf_tbl_*() functionality needs to be
1535e111ed8SAndrew Rybchenko * pulled inside the Falcon/Siena queue create/destroy code,
1545e111ed8SAndrew Rybchenko * and then the original functions can be removed (see bug30834
1555e111ed8SAndrew Rybchenko * comment #1). But, for now, we just ensure that they are
1565e111ed8SAndrew Rybchenko * no-ops for EF10, to allow bringing up existing drivers
1575e111ed8SAndrew Rybchenko * without modification.
1585e111ed8SAndrew Rybchenko */
1595e111ed8SAndrew Rybchenko
1605e111ed8SAndrew Rybchenko return;
1615e111ed8SAndrew Rybchenko }
1625e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
1635e111ed8SAndrew Rybchenko
1645e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(stop, <, EFX_BUF_TBL_SIZE);
1655e111ed8SAndrew Rybchenko
1665e111ed8SAndrew Rybchenko EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1);
1675e111ed8SAndrew Rybchenko
1685e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0,
1695e111ed8SAndrew Rybchenko FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, stop - 1,
1705e111ed8SAndrew Rybchenko FRF_AZ_BUF_CLR_START_ID, start);
1715e111ed8SAndrew Rybchenko EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
1725e111ed8SAndrew Rybchenko }
1735e111ed8SAndrew Rybchenko
1745e111ed8SAndrew Rybchenko
1755e111ed8SAndrew Rybchenko #if EFSYS_OPT_DIAG
1765e111ed8SAndrew Rybchenko
1775e111ed8SAndrew Rybchenko static void
efx_sram_byte_increment_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)1785e111ed8SAndrew Rybchenko efx_sram_byte_increment_set(
1795e111ed8SAndrew Rybchenko __in size_t row,
1805e111ed8SAndrew Rybchenko __in boolean_t negate,
1815e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
1825e111ed8SAndrew Rybchenko {
1835e111ed8SAndrew Rybchenko size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
1845e111ed8SAndrew Rybchenko unsigned int index;
1855e111ed8SAndrew Rybchenko
1865e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(negate))
1875e111ed8SAndrew Rybchenko
1885e111ed8SAndrew Rybchenko for (index = 0; index < sizeof (efx_qword_t); index++)
1895e111ed8SAndrew Rybchenko eqp->eq_u8[index] = offset + index;
1905e111ed8SAndrew Rybchenko }
1915e111ed8SAndrew Rybchenko
1925e111ed8SAndrew Rybchenko static void
efx_sram_all_the_same_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)1935e111ed8SAndrew Rybchenko efx_sram_all_the_same_set(
1945e111ed8SAndrew Rybchenko __in size_t row,
1955e111ed8SAndrew Rybchenko __in boolean_t negate,
1965e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
1975e111ed8SAndrew Rybchenko {
1985e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(row))
1995e111ed8SAndrew Rybchenko
2005e111ed8SAndrew Rybchenko if (negate)
2015e111ed8SAndrew Rybchenko EFX_SET_QWORD(*eqp);
2025e111ed8SAndrew Rybchenko else
2035e111ed8SAndrew Rybchenko EFX_ZERO_QWORD(*eqp);
2045e111ed8SAndrew Rybchenko }
2055e111ed8SAndrew Rybchenko
2065e111ed8SAndrew Rybchenko static void
efx_sram_bit_alternate_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)2075e111ed8SAndrew Rybchenko efx_sram_bit_alternate_set(
2085e111ed8SAndrew Rybchenko __in size_t row,
2095e111ed8SAndrew Rybchenko __in boolean_t negate,
2105e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
2115e111ed8SAndrew Rybchenko {
2125e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(row))
2135e111ed8SAndrew Rybchenko
2145e111ed8SAndrew Rybchenko EFX_POPULATE_QWORD_2(*eqp,
2155e111ed8SAndrew Rybchenko EFX_DWORD_0, (negate) ? 0x55555555 : 0xaaaaaaaa,
2165e111ed8SAndrew Rybchenko EFX_DWORD_1, (negate) ? 0x55555555 : 0xaaaaaaaa);
2175e111ed8SAndrew Rybchenko }
2185e111ed8SAndrew Rybchenko
2195e111ed8SAndrew Rybchenko static void
efx_sram_byte_alternate_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)2205e111ed8SAndrew Rybchenko efx_sram_byte_alternate_set(
2215e111ed8SAndrew Rybchenko __in size_t row,
2225e111ed8SAndrew Rybchenko __in boolean_t negate,
2235e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
2245e111ed8SAndrew Rybchenko {
2255e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(row))
2265e111ed8SAndrew Rybchenko
2275e111ed8SAndrew Rybchenko EFX_POPULATE_QWORD_2(*eqp,
2285e111ed8SAndrew Rybchenko EFX_DWORD_0, (negate) ? 0x00ff00ff : 0xff00ff00,
2295e111ed8SAndrew Rybchenko EFX_DWORD_1, (negate) ? 0x00ff00ff : 0xff00ff00);
2305e111ed8SAndrew Rybchenko }
2315e111ed8SAndrew Rybchenko
2325e111ed8SAndrew Rybchenko static void
efx_sram_byte_changing_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)2335e111ed8SAndrew Rybchenko efx_sram_byte_changing_set(
2345e111ed8SAndrew Rybchenko __in size_t row,
2355e111ed8SAndrew Rybchenko __in boolean_t negate,
2365e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
2375e111ed8SAndrew Rybchenko {
2385e111ed8SAndrew Rybchenko size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
2395e111ed8SAndrew Rybchenko unsigned int index;
2405e111ed8SAndrew Rybchenko
2415e111ed8SAndrew Rybchenko for (index = 0; index < sizeof (efx_qword_t); index++) {
2425e111ed8SAndrew Rybchenko uint8_t byte;
2435e111ed8SAndrew Rybchenko
2445e111ed8SAndrew Rybchenko if (offset / 256 == 0)
2455e111ed8SAndrew Rybchenko byte = (uint8_t)((offset % 257) % 256);
2465e111ed8SAndrew Rybchenko else
2475e111ed8SAndrew Rybchenko byte = (uint8_t)(~((offset - 8) % 257) % 256);
2485e111ed8SAndrew Rybchenko
2495e111ed8SAndrew Rybchenko eqp->eq_u8[index] = (negate) ? ~byte : byte;
2505e111ed8SAndrew Rybchenko }
2515e111ed8SAndrew Rybchenko }
2525e111ed8SAndrew Rybchenko
2535e111ed8SAndrew Rybchenko static void
efx_sram_bit_sweep_set(__in size_t row,__in boolean_t negate,__out efx_qword_t * eqp)2545e111ed8SAndrew Rybchenko efx_sram_bit_sweep_set(
2555e111ed8SAndrew Rybchenko __in size_t row,
2565e111ed8SAndrew Rybchenko __in boolean_t negate,
2575e111ed8SAndrew Rybchenko __out efx_qword_t *eqp)
2585e111ed8SAndrew Rybchenko {
2595e111ed8SAndrew Rybchenko size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
2605e111ed8SAndrew Rybchenko
2615e111ed8SAndrew Rybchenko if (negate) {
2625e111ed8SAndrew Rybchenko EFX_SET_QWORD(*eqp);
2635e111ed8SAndrew Rybchenko EFX_CLEAR_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
2645e111ed8SAndrew Rybchenko } else {
2655e111ed8SAndrew Rybchenko EFX_ZERO_QWORD(*eqp);
2665e111ed8SAndrew Rybchenko EFX_SET_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
2675e111ed8SAndrew Rybchenko }
2685e111ed8SAndrew Rybchenko }
2695e111ed8SAndrew Rybchenko
2705e111ed8SAndrew Rybchenko efx_sram_pattern_fn_t __efx_sram_pattern_fns[] = {
2715e111ed8SAndrew Rybchenko efx_sram_byte_increment_set,
2725e111ed8SAndrew Rybchenko efx_sram_all_the_same_set,
2735e111ed8SAndrew Rybchenko efx_sram_bit_alternate_set,
2745e111ed8SAndrew Rybchenko efx_sram_byte_alternate_set,
2755e111ed8SAndrew Rybchenko efx_sram_byte_changing_set,
2765e111ed8SAndrew Rybchenko efx_sram_bit_sweep_set
2775e111ed8SAndrew Rybchenko };
2785e111ed8SAndrew Rybchenko
2795e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_sram_test(__in efx_nic_t * enp,__in efx_pattern_type_t type)2805e111ed8SAndrew Rybchenko efx_sram_test(
2815e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2825e111ed8SAndrew Rybchenko __in efx_pattern_type_t type)
2835e111ed8SAndrew Rybchenko {
2845e111ed8SAndrew Rybchenko efx_sram_pattern_fn_t func;
2855e111ed8SAndrew Rybchenko
2865e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2875e111ed8SAndrew Rybchenko
2885e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
2895e111ed8SAndrew Rybchenko
2905e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
2915e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
2925e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
2935e111ed8SAndrew Rybchenko
2945e111ed8SAndrew Rybchenko /* SRAM testing is only available on Siena. */
2955e111ed8SAndrew Rybchenko if (enp->en_family != EFX_FAMILY_SIENA)
2965e111ed8SAndrew Rybchenko return (0);
2975e111ed8SAndrew Rybchenko
2985e111ed8SAndrew Rybchenko /* Select pattern generator */
2995e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(type, <, EFX_PATTERN_NTYPES);
3005e111ed8SAndrew Rybchenko func = __efx_sram_pattern_fns[type];
3015e111ed8SAndrew Rybchenko
3025e111ed8SAndrew Rybchenko return (siena_sram_test(enp, func));
3035e111ed8SAndrew Rybchenko }
3045e111ed8SAndrew Rybchenko
3055e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_DIAG */
306