1 | /* |
2 | * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. |
3 | * |
4 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU |
6 | * General Public License (GPL) Version 2, available from the file |
7 | * COPYING in the main directory of this source tree, or the |
8 | * OpenIB.org BSD license below: |
9 | * |
10 | * Redistribution and use in source and binary forms, with or |
11 | * without modification, are permitted provided that the following |
12 | * conditions are met: |
13 | * |
14 | * - Redistributions of source code must retain the above |
15 | * copyright notice, this list of conditions and the following |
16 | * disclaimer. |
17 | * |
18 | * - Redistributions in binary form must reproduce the above |
19 | * copyright notice, this list of conditions and the following |
20 | * disclaimer in the documentation and/or other materials |
21 | * provided with the distribution. |
22 | * |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
30 | * SOFTWARE. |
31 | */ |
32 | #include "common.h" |
33 | #include "regs.h" |
34 | |
35 | enum { |
36 | IDT75P52100 = 4, |
37 | IDT75N43102 = 5 |
38 | }; |
39 | |
40 | /* DBGI command mode */ |
41 | enum { |
42 | DBGI_MODE_MBUS = 0, |
43 | DBGI_MODE_IDT52100 = 5 |
44 | }; |
45 | |
46 | /* IDT 75P52100 commands */ |
47 | #define IDT_CMD_READ 0 |
48 | #define IDT_CMD_WRITE 1 |
49 | #define IDT_CMD_SEARCH 2 |
50 | #define IDT_CMD_LEARN 3 |
51 | |
52 | /* IDT LAR register address and value for 144-bit mode (low 32 bits) */ |
53 | #define IDT_LAR_ADR0 0x180006 |
54 | #define IDT_LAR_MODE144 0xffff0000 |
55 | |
56 | /* IDT SCR and SSR addresses (low 32 bits) */ |
57 | #define IDT_SCR_ADR0 0x180000 |
58 | #define IDT_SSR0_ADR0 0x180002 |
59 | #define IDT_SSR1_ADR0 0x180004 |
60 | |
61 | /* IDT GMR base address (low 32 bits) */ |
62 | #define IDT_GMR_BASE_ADR0 0x180020 |
63 | |
64 | /* IDT data and mask array base addresses (low 32 bits) */ |
65 | #define IDT_DATARY_BASE_ADR0 0 |
66 | #define IDT_MSKARY_BASE_ADR0 0x80000 |
67 | |
68 | /* IDT 75N43102 commands */ |
69 | #define IDT4_CMD_SEARCH144 3 |
70 | #define IDT4_CMD_WRITE 4 |
71 | #define IDT4_CMD_READ 5 |
72 | |
73 | /* IDT 75N43102 SCR address (low 32 bits) */ |
74 | #define IDT4_SCR_ADR0 0x3 |
75 | |
76 | /* IDT 75N43102 GMR base addresses (low 32 bits) */ |
77 | #define IDT4_GMR_BASE0 0x10 |
78 | #define IDT4_GMR_BASE1 0x20 |
79 | #define IDT4_GMR_BASE2 0x30 |
80 | |
81 | /* IDT 75N43102 data and mask array base addresses (low 32 bits) */ |
82 | #define IDT4_DATARY_BASE_ADR0 0x1000000 |
83 | #define IDT4_MSKARY_BASE_ADR0 0x2000000 |
84 | |
85 | #define MAX_WRITE_ATTEMPTS 5 |
86 | |
87 | #define MAX_ROUTES 2048 |
88 | |
89 | /* |
90 | * Issue a command to the TCAM and wait for its completion. The address and |
91 | * any data required by the command must have been setup by the caller. |
92 | */ |
93 | static int mc5_cmd_write(struct adapter *adapter, u32 cmd) |
94 | { |
95 | t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, val: cmd); |
96 | return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, |
97 | F_DBGIRSPVALID, polarity: 1, MAX_WRITE_ATTEMPTS, delay: 1); |
98 | } |
99 | |
100 | static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, |
101 | u32 v3) |
102 | { |
103 | t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, val: v1); |
104 | t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, val: v2); |
105 | t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, val: v3); |
106 | } |
107 | |
108 | /* |
109 | * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM |
110 | * command cmd. The data to be written must have been set up by the caller. |
111 | * Returns -1 on failure, 0 on success. |
112 | */ |
113 | static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) |
114 | { |
115 | t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, val: addr_lo); |
116 | if (mc5_cmd_write(adapter, cmd) == 0) |
117 | return 0; |
118 | CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n" , |
119 | addr_lo); |
120 | return -1; |
121 | } |
122 | |
123 | static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, |
124 | u32 data_array_base, u32 write_cmd, |
125 | int addr_shift) |
126 | { |
127 | unsigned int i; |
128 | struct adapter *adap = mc5->adapter; |
129 | |
130 | /* |
131 | * We need the size of the TCAM data and mask arrays in terms of |
132 | * 72-bit entries. |
133 | */ |
134 | unsigned int size72 = mc5->tcam_size; |
135 | unsigned int server_base = t3_read_reg(adapter: adap, A_MC5_DB_SERVER_INDEX); |
136 | |
137 | if (mc5->mode == MC5_MODE_144_BIT) { |
138 | size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ |
139 | server_base *= 2; |
140 | } |
141 | |
142 | /* Clear the data array */ |
143 | dbgi_wr_data3(adapter: adap, v1: 0, v2: 0, v3: 0); |
144 | for (i = 0; i < size72; i++) |
145 | if (mc5_write(adapter: adap, addr_lo: data_array_base + (i << addr_shift), |
146 | cmd: write_cmd)) |
147 | return -1; |
148 | |
149 | /* Initialize the mask array. */ |
150 | dbgi_wr_data3(adapter: adap, v1: 0xffffffff, v2: 0xffffffff, v3: 0xff); |
151 | for (i = 0; i < size72; i++) { |
152 | if (i == server_base) /* entering server or routing region */ |
153 | t3_write_reg(adapter: adap, A_MC5_DB_DBGI_REQ_DATA0, |
154 | val: mc5->mode == MC5_MODE_144_BIT ? |
155 | 0xfffffff9 : 0xfffffffd); |
156 | if (mc5_write(adapter: adap, addr_lo: mask_array_base + (i << addr_shift), |
157 | cmd: write_cmd)) |
158 | return -1; |
159 | } |
160 | return 0; |
161 | } |
162 | |
163 | static int init_idt52100(struct mc5 *mc5) |
164 | { |
165 | int i; |
166 | struct adapter *adap = mc5->adapter; |
167 | |
168 | t3_write_reg(adapter: adap, A_MC5_DB_RSP_LATENCY, |
169 | V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); |
170 | t3_write_reg(adapter: adap, A_MC5_DB_PART_ID_INDEX, val: 2); |
171 | |
172 | /* |
173 | * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and |
174 | * GMRs 8-9 for ACK- and AOPEN searches. |
175 | */ |
176 | t3_write_reg(adapter: adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); |
177 | t3_write_reg(adapter: adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); |
178 | t3_write_reg(adapter: adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); |
179 | t3_write_reg(adapter: adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); |
180 | t3_write_reg(adapter: adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); |
181 | t3_write_reg(adapter: adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); |
182 | t3_write_reg(adapter: adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); |
183 | t3_write_reg(adapter: adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); |
184 | t3_write_reg(adapter: adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); |
185 | t3_write_reg(adapter: adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); |
186 | t3_write_reg(adapter: adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); |
187 | t3_write_reg(adapter: adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); |
188 | |
189 | /* Set DBGI command mode for IDT TCAM. */ |
190 | t3_write_reg(adapter: adap, A_MC5_DB_DBGI_CONFIG, val: DBGI_MODE_IDT52100); |
191 | |
192 | /* Set up LAR */ |
193 | dbgi_wr_data3(adapter: adap, IDT_LAR_MODE144, v2: 0, v3: 0); |
194 | if (mc5_write(adapter: adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) |
195 | goto err; |
196 | |
197 | /* Set up SSRs */ |
198 | dbgi_wr_data3(adapter: adap, v1: 0xffffffff, v2: 0xffffffff, v3: 0); |
199 | if (mc5_write(adapter: adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || |
200 | mc5_write(adapter: adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) |
201 | goto err; |
202 | |
203 | /* Set up GMRs */ |
204 | for (i = 0; i < 32; ++i) { |
205 | if (i >= 12 && i < 15) |
206 | dbgi_wr_data3(adapter: adap, v1: 0xfffffff9, v2: 0xffffffff, v3: 0xff); |
207 | else if (i == 15) |
208 | dbgi_wr_data3(adapter: adap, v1: 0xfffffff9, v2: 0xffff8007, v3: 0xff); |
209 | else |
210 | dbgi_wr_data3(adapter: adap, v1: 0xffffffff, v2: 0xffffffff, v3: 0xff); |
211 | |
212 | if (mc5_write(adapter: adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) |
213 | goto err; |
214 | } |
215 | |
216 | /* Set up SCR */ |
217 | dbgi_wr_data3(adapter: adap, v1: 1, v2: 0, v3: 0); |
218 | if (mc5_write(adapter: adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) |
219 | goto err; |
220 | |
221 | return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, |
222 | IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, addr_shift: 0); |
223 | err: |
224 | return -EIO; |
225 | } |
226 | |
227 | static int init_idt43102(struct mc5 *mc5) |
228 | { |
229 | int i; |
230 | struct adapter *adap = mc5->adapter; |
231 | |
232 | t3_write_reg(adapter: adap, A_MC5_DB_RSP_LATENCY, |
233 | val: adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : |
234 | V_RDLAT(0xd) | V_SRCHLAT(0x12)); |
235 | |
236 | /* |
237 | * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask |
238 | * for ACK- and AOPEN searches. |
239 | */ |
240 | t3_write_reg(adapter: adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); |
241 | t3_write_reg(adapter: adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); |
242 | t3_write_reg(adapter: adap, A_MC5_DB_AOPEN_SRCH_CMD, |
243 | IDT4_CMD_SEARCH144 | 0x3800); |
244 | t3_write_reg(adapter: adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); |
245 | t3_write_reg(adapter: adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); |
246 | t3_write_reg(adapter: adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); |
247 | t3_write_reg(adapter: adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); |
248 | t3_write_reg(adapter: adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); |
249 | t3_write_reg(adapter: adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); |
250 | |
251 | t3_write_reg(adapter: adap, A_MC5_DB_PART_ID_INDEX, val: 3); |
252 | |
253 | /* Set DBGI command mode for IDT TCAM. */ |
254 | t3_write_reg(adapter: adap, A_MC5_DB_DBGI_CONFIG, val: DBGI_MODE_IDT52100); |
255 | |
256 | /* Set up GMRs */ |
257 | dbgi_wr_data3(adapter: adap, v1: 0xffffffff, v2: 0xffffffff, v3: 0xff); |
258 | for (i = 0; i < 7; ++i) |
259 | if (mc5_write(adapter: adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) |
260 | goto err; |
261 | |
262 | for (i = 0; i < 4; ++i) |
263 | if (mc5_write(adapter: adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) |
264 | goto err; |
265 | |
266 | dbgi_wr_data3(adapter: adap, v1: 0xfffffff9, v2: 0xffffffff, v3: 0xff); |
267 | if (mc5_write(adapter: adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || |
268 | mc5_write(adapter: adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || |
269 | mc5_write(adapter: adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) |
270 | goto err; |
271 | |
272 | dbgi_wr_data3(adapter: adap, v1: 0xfffffff9, v2: 0xffff8007, v3: 0xff); |
273 | if (mc5_write(adapter: adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) |
274 | goto err; |
275 | |
276 | /* Set up SCR */ |
277 | dbgi_wr_data3(adapter: adap, v1: 0xf0000000, v2: 0, v3: 0); |
278 | if (mc5_write(adapter: adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) |
279 | goto err; |
280 | |
281 | return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, |
282 | IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, addr_shift: 1); |
283 | err: |
284 | return -EIO; |
285 | } |
286 | |
287 | /* Put MC5 in DBGI mode. */ |
288 | static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5) |
289 | { |
290 | t3_write_reg(adapter: mc5->adapter, A_MC5_DB_CONFIG, |
291 | V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN); |
292 | } |
293 | |
294 | /* Put MC5 in M-Bus mode. */ |
295 | static void mc5_dbgi_mode_disable(const struct mc5 *mc5) |
296 | { |
297 | t3_write_reg(adapter: mc5->adapter, A_MC5_DB_CONFIG, |
298 | V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | |
299 | V_COMPEN(mc5->mode == MC5_MODE_72_BIT) | |
300 | V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); |
301 | } |
302 | |
303 | /* |
304 | * Initialization that requires the OS and protocol layers to already |
305 | * be initialized goes here. |
306 | */ |
307 | int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, |
308 | unsigned int nroutes) |
309 | { |
310 | u32 cfg; |
311 | int err; |
312 | unsigned int tcam_size = mc5->tcam_size; |
313 | struct adapter *adap = mc5->adapter; |
314 | |
315 | if (!tcam_size) |
316 | return 0; |
317 | |
318 | if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) |
319 | return -EINVAL; |
320 | |
321 | /* Reset the TCAM */ |
322 | cfg = t3_read_reg(adapter: adap, A_MC5_DB_CONFIG) & ~F_TMMODE; |
323 | cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; |
324 | t3_write_reg(adapter: adap, A_MC5_DB_CONFIG, val: cfg); |
325 | if (t3_wait_op_done(adapter: adap, A_MC5_DB_CONFIG, F_TMRDY, polarity: 1, attempts: 500, delay: 0)) { |
326 | CH_ERR(adap, "TCAM reset timed out\n" ); |
327 | return -1; |
328 | } |
329 | |
330 | t3_write_reg(adapter: adap, A_MC5_DB_ROUTING_TABLE_INDEX, val: tcam_size - nroutes); |
331 | t3_write_reg(adapter: adap, A_MC5_DB_FILTER_TABLE, |
332 | val: tcam_size - nroutes - nfilters); |
333 | t3_write_reg(adapter: adap, A_MC5_DB_SERVER_INDEX, |
334 | val: tcam_size - nroutes - nfilters - nservers); |
335 | |
336 | mc5->parity_enabled = 1; |
337 | |
338 | /* All the TCAM addresses we access have only the low 32 bits non 0 */ |
339 | t3_write_reg(adapter: adap, A_MC5_DB_DBGI_REQ_ADDR1, val: 0); |
340 | t3_write_reg(adapter: adap, A_MC5_DB_DBGI_REQ_ADDR2, val: 0); |
341 | |
342 | mc5_dbgi_mode_enable(mc5); |
343 | |
344 | switch (mc5->part_type) { |
345 | case IDT75P52100: |
346 | err = init_idt52100(mc5); |
347 | break; |
348 | case IDT75N43102: |
349 | err = init_idt43102(mc5); |
350 | break; |
351 | default: |
352 | CH_ERR(adap, "Unsupported TCAM type %d\n" , mc5->part_type); |
353 | err = -EINVAL; |
354 | break; |
355 | } |
356 | |
357 | mc5_dbgi_mode_disable(mc5); |
358 | return err; |
359 | } |
360 | |
361 | |
362 | #define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) |
363 | |
364 | /* |
365 | * MC5 interrupt handler |
366 | */ |
367 | void t3_mc5_intr_handler(struct mc5 *mc5) |
368 | { |
369 | struct adapter *adap = mc5->adapter; |
370 | u32 cause = t3_read_reg(adapter: adap, A_MC5_DB_INT_CAUSE); |
371 | |
372 | if ((cause & F_PARITYERR) && mc5->parity_enabled) { |
373 | CH_ALERT(adap, "MC5 parity error\n" ); |
374 | mc5->stats.parity_err++; |
375 | } |
376 | |
377 | if (cause & F_REQQPARERR) { |
378 | CH_ALERT(adap, "MC5 request queue parity error\n" ); |
379 | mc5->stats.reqq_parity_err++; |
380 | } |
381 | |
382 | if (cause & F_DISPQPARERR) { |
383 | CH_ALERT(adap, "MC5 dispatch queue parity error\n" ); |
384 | mc5->stats.dispq_parity_err++; |
385 | } |
386 | |
387 | if (cause & F_ACTRGNFULL) |
388 | mc5->stats.active_rgn_full++; |
389 | if (cause & F_NFASRCHFAIL) |
390 | mc5->stats.nfa_srch_err++; |
391 | if (cause & F_UNKNOWNCMD) |
392 | mc5->stats.unknown_cmd++; |
393 | if (cause & F_DELACTEMPTY) |
394 | mc5->stats.del_act_empty++; |
395 | if (cause & MC5_INT_FATAL) |
396 | t3_fatal_err(adapter: adap); |
397 | |
398 | t3_write_reg(adapter: adap, A_MC5_DB_INT_CAUSE, val: cause); |
399 | } |
400 | |
401 | void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) |
402 | { |
403 | #define K * 1024 |
404 | |
405 | static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ |
406 | 64 K, 128 K, 256 K, 32 K |
407 | }; |
408 | |
409 | #undef K |
410 | |
411 | u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); |
412 | |
413 | mc5->adapter = adapter; |
414 | mc5->mode = (unsigned char)mode; |
415 | mc5->part_type = (unsigned char)G_TMTYPE(cfg); |
416 | if (cfg & F_TMTYPEHI) |
417 | mc5->part_type |= 4; |
418 | |
419 | mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; |
420 | if (mode == MC5_MODE_144_BIT) |
421 | mc5->tcam_size /= 2; |
422 | } |
423 | |