1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#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;
/* FBNIC_RPC_TCAM_ACT */
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));
}
/* FBNIC_RPC_TCAM_MACDA */
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));
}
/* FBNIC_RPC_TCAM_OUTER_IPSRC */
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));
}
/* FBNIC_RPC_TCAM_OUTER_IPDST */
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));
}
/* FBNIC_RPC_TCAM_IPSRC */
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));
}
/* FBNIC_RPC_TCAM_IPDST */
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));
}
/* FBNIC_RPC_RSS_TBL */
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;
/* Skip RPC_RAM section which cannot be dumped linearly */
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);
}
/* Dump the RPC_RAM as special case registers */
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;
/* Dump includes start and end information of each section
* which results in an offset of 2
*/
for (i = 0; i < ARRAY_SIZE(fbnic_csr_sects); i++)
len += fbnic_csr_sects[i].end - fbnic_csr_sects[i].start + 2;
return len;
}
/* CSR register test data
*
* The register test will be used to verify hardware is behaving as expected.
*
* The test itself will have us writing to registers that should have no
* side effects due to us resetting after the test has been completed.
* While the test is being run the interface should be offline.
*/
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);
/* Note that FBNIC_INTR_STATUS(0) could be tested and fail
* and the result would not be reported since the register
* offset is 0. However as that register isn't included in
* the register test that isn't an issue.
*/
return reg;
}
return FBNIC_REG_TEST_SUCCESS;
}
/**
* fbnic_csr_regs_test() - Verify behavior of NIC registers
* @fbd: device to test
*
* This function is meant to test the bit values of various registers in
* the NIC device. Specifically this test will verify which bits are
* writable and which ones are not. It will write varying patterns of bits
* to the registers testing for sticky bits, or bits that are writable but
* should not be.
*
* Return: FBNIC_REG_TEST_SUCCESS on success, register number on failure
**/
enum fbnic_reg_self_test_codes fbnic_csr_regs_test(struct fbnic_dev *fbd)
{
const struct fbnic_csr_reg_test_data
|