#include "fbnic.h"
#define FBNIC_BOUNDS(section) { \
.start = FBNIC_CSR_START_##section, \
.end = FBNIC_CSR_END_##section + 1, \
}
struct fbnic_csr_bounds {
u32 start;
u32 end;
};
static const struct fbnic_csr_bounds fbnic_csr_sects[] = {
FBNIC_BOUNDS(INTR),
FBNIC_BOUNDS(INTR_CQ),
FBNIC_BOUNDS(QM_TX),
FBNIC_BOUNDS(QM_RX),
FBNIC_BOUNDS(TCE),
FBNIC_BOUNDS(TCE_RAM),
FBNIC_BOUNDS(TMI),
FBNIC_BOUNDS(PTP),
FBNIC_BOUNDS(RXB),
FBNIC_BOUNDS(RPC),
FBNIC_BOUNDS(FAB),
FBNIC_BOUNDS(MASTER),
FBNIC_BOUNDS(PCS),
FBNIC_BOUNDS(RSFEC),
FBNIC_BOUNDS(MAC_MAC),
FBNIC_BOUNDS(SIG),
FBNIC_BOUNDS(PCIE_SS_COMPHY),
FBNIC_BOUNDS(PUL_USER),
FBNIC_BOUNDS(QUEUE),
FBNIC_BOUNDS(RPC_RAM),
};
#define FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY 14
#define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64
#define FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY 4
#define FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES 32
#define FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY 9
#define FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES 8
#define FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY 9
#define FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES 8
#define FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY 9
#define FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES 8
#define FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY 9
#define FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES 8
#define FBNIC_RPC_RSS_TBL_DW_PER_ENTRY 2
#define FBNIC_RPC_RSS_TBL_NUM_ENTRIES 256
static void fbnic_csr_get_regs_rpc_ram(struct fbnic_dev *fbd, u32 **data_p)
{
u32 start = FBNIC_CSR_START_RPC_RAM;
u32 end = FBNIC_CSR_END_RPC_RAM;
u32 *data = *data_p;
u32 i, j;
*(data++) = start;
*(data++) = end;
for (i = 0; i < FBNIC_RPC_TCAM_ACT_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_ACT(i, j));
}
for (i = 0; i < FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_MACDA(i, j));
}
for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(i, j));
}
for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(i, j));
}
for (i = 0; i < FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPSRC(i, j));
}
for (i = 0; i < FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPDST(i, j));
}
for (i = 0; i < FBNIC_RPC_RSS_TBL_NUM_ENTRIES; i++) {
for (j = 0; j < FBNIC_RPC_RSS_TBL_DW_PER_ENTRY; j++)
*(data++) = rd32(fbd, FBNIC_RPC_RSS_TBL(i, j));
}
*data_p = data;
}
void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version)
{
const struct fbnic_csr_bounds *bound;
u32 *start = data;
int i, j;
*regs_version = 1u;
for (i = 0, bound = fbnic_csr_sects;
i < ARRAY_SIZE(fbnic_csr_sects) - 1; i++, ++bound) {
*(data++) = bound->start;
*(data++) = bound->end - 1;
for (j = bound->start; j < bound->end; j++)
*(data++) = rd32(fbd, j);
}
fbnic_csr_get_regs_rpc_ram(fbd, &data);
WARN_ON(data - start != fbnic_csr_regs_len(fbd));
}
int fbnic_csr_regs_len(struct fbnic_dev *fbd)
{
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(fbnic_csr_sects); i++)
len += fbnic_csr_sects[i].end - fbnic_csr_sects[i].start + 2;
return len;
}
struct fbnic_csr_reg_test_data {
int reg;
u16 reg_offset;
u8 array_len;
u32 read;
u32 write;
};
#define FBNIC_QUEUE_REG_TEST(_name, _read, _write) { \
.reg = FBNIC_QUEUE(0) + FBNIC_QUEUE_##_name, \
.reg_offset = FBNIC_QUEUE_STRIDE, \
.array_len = 64, \
.read = _read, \
.write = _write \
}
static const struct fbnic_csr_reg_test_data pattern_test[] = {
FBNIC_QUEUE_REG_TEST(TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET,
FBNIC_QUEUE_TWQ_CTL_RESET),
FBNIC_QUEUE_REG_TEST(TWQ0_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(TWQ0_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TWQ0_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TWQ0_BAH, ~0, ~0),
FBNIC_QUEUE_REG_TEST(TWQ1_CTL, FBNIC_QUEUE_TWQ_CTL_RESET,
FBNIC_QUEUE_TWQ_CTL_RESET),
FBNIC_QUEUE_REG_TEST(TWQ1_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(TWQ1_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TWQ1_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TWQ1_BAH, ~0, ~0),
FBNIC_QUEUE_REG_TEST(TCQ_CTL, FBNIC_QUEUE_TCQ_CTL_RESET,
FBNIC_QUEUE_TCQ_CTL_RESET),
FBNIC_QUEUE_REG_TEST(TCQ_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(TCQ_SIZE, FBNIC_QUEUE_TCQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(TCQ_BAH, ~0, ~0),
FBNIC_QUEUE_REG_TEST(RCQ_CTL, FBNIC_QUEUE_RCQ_CTL_RESET,
FBNIC_QUEUE_RCQ_CTL_RESET),
FBNIC_QUEUE_REG_TEST(RCQ_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(RCQ_SIZE, FBNIC_QUEUE_RCQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(RCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(RCQ_BAH, ~0, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_CTL, FBNIC_QUEUE_BDQ_CTL_RESET,
FBNIC_QUEUE_BDQ_CTL_RESET),
FBNIC_QUEUE_REG_TEST(BDQ_HPQ_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_HPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAH, ~0, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_PPQ_PTRS, 0, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_PPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0),
FBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAH, ~0, ~0),
};
static enum fbnic_reg_self_test_codes
fbnic_csr_reg_pattern_test(struct fbnic_dev *fbd, int index,
const struct fbnic_csr_reg_test_data *test_data)
{
static const u32 pattern[] = { ~0, 0x5A5A5A5A, 0xA5A5A5A5, 0};
enum fbnic_reg_self_test_codes reg;
int i;
reg = test_data->reg + test_data->reg_offset * index;
for (i = 0; i < ARRAY_SIZE(pattern); i++) {
u32 val = pattern[i] & test_data->write;
u32 result;
wr32(fbd, reg, val);
result = rd32(fbd, reg);
val &= test_data->read;
if (result == val)
continue;
dev_err(fbd->dev,
"%s: reg 0x%06X failed, expected 0x%08X received 0x%08X\n",
__func__, reg, val, result);
return reg;
}
return FBNIC_REG_TEST_SUCCESS;
}
enum fbnic_reg_self_test_codes fbnic_csr_regs_test(struct fbnic_dev *fbd)
{
const struct fbnic_csr_reg_test_data *test_data;
for (test_data = pattern_test;
test_data < pattern_test + ARRAY_SIZE(pattern_test); test_data++) {
u32 i;
for (i = 0; i < test_data->array_len; i++) {
enum fbnic_reg_self_test_codes reg =
fbnic_csr_reg_pattern_test(fbd, i, test_data);
if (reg)
return reg;
}
}
return FBNIC_REG_TEST_SUCCESS;
}