xref: /freebsd/sys/dev/cxgb/common/cxgb_mc5.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 /**************************************************************************
2 SPDX-License-Identifier: BSD-2-Clause
3 
4 Copyright (c) 2007, Chelsio Inc.
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12 
13  2. Neither the name of the Chelsio Corporation nor the names of its
14     contributors may be used to endorse or promote products derived from
15     this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
28 
29 ***************************************************************************/
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <common/cxgb_common.h>
35 #include <common/cxgb_regs.h>
36 
37 enum {
38 	IDT75P52100 = 4,
39 	IDT75N43102 = 5
40 };
41 
42 /* DBGI command mode */
43 enum {
44 	DBGI_MODE_MBUS = 0,
45 	DBGI_MODE_IDT52100 = 5
46 };
47 
48 /* IDT 75P52100 commands */
49 #define IDT_CMD_READ   0
50 #define IDT_CMD_WRITE  1
51 #define IDT_CMD_SEARCH 2
52 #define IDT_CMD_LEARN  3
53 
54 /* IDT LAR register address and value for 144-bit mode (low 32 bits) */
55 #define IDT_LAR_ADR0   	0x180006
56 #define IDT_LAR_MODE144	0xffff0000
57 
58 /* IDT SCR and SSR addresses (low 32 bits) */
59 #define IDT_SCR_ADR0  0x180000
60 #define IDT_SSR0_ADR0 0x180002
61 #define IDT_SSR1_ADR0 0x180004
62 
63 /* IDT GMR base address (low 32 bits) */
64 #define IDT_GMR_BASE_ADR0 0x180020
65 
66 /* IDT data and mask array base addresses (low 32 bits) */
67 #define IDT_DATARY_BASE_ADR0 0
68 #define IDT_MSKARY_BASE_ADR0 0x80000
69 
70 /* IDT 75N43102 commands */
71 #define IDT4_CMD_SEARCH144 3
72 #define IDT4_CMD_WRITE     4
73 #define IDT4_CMD_READ      5
74 
75 /* IDT 75N43102 SCR address (low 32 bits) */
76 #define IDT4_SCR_ADR0  0x3
77 
78 /* IDT 75N43102 GMR base addresses (low 32 bits) */
79 #define IDT4_GMR_BASE0 0x10
80 #define IDT4_GMR_BASE1 0x20
81 #define IDT4_GMR_BASE2 0x30
82 
83 /* IDT 75N43102 data and mask array base addresses (low 32 bits) */
84 #define IDT4_DATARY_BASE_ADR0 0x1000000
85 #define IDT4_MSKARY_BASE_ADR0 0x2000000
86 
87 #define MAX_WRITE_ATTEMPTS 5
88 
89 #define MAX_ROUTES 2048
90 
91 /*
92  * Issue a command to the TCAM and wait for its completion.  The address and
93  * any data required by the command must have been setup by the caller.
94  */
95 static int mc5_cmd_write(adapter_t *adapter, u32 cmd)
96 {
97 	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
98 	return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
99 			       F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
100 }
101 
102 static inline void dbgi_wr_data3(adapter_t *adapter, u32 v1, u32 v2, u32 v3)
103 {
104 	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
105 	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
106 	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
107 }
108 
109 static inline void dbgi_rd_rsp3(adapter_t *adapter, u32 *v1, u32 *v2, u32 *v3)
110 {
111 	*v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
112 	*v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
113 	*v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
114 }
115 
116 /*
117  * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
118  * command cmd.  The data to be written must have been set up by the caller.
119  * Returns -1 on failure, 0 on success.
120  */
121 static int mc5_write(adapter_t *adapter, u32 addr_lo, u32 cmd)
122 {
123 	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
124 	if (mc5_cmd_write(adapter, cmd) == 0)
125 		return 0;
126 	CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", addr_lo);
127 	return -1;
128 }
129 
130 static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
131 				u32 data_array_base, u32 write_cmd,
132 			        int addr_shift)
133 {
134 	unsigned int i;
135 	adapter_t *adap = mc5->adapter;
136 
137 	/*
138 	 * We need the size of the TCAM data and mask arrays in terms of
139 	 * 72-bit entries.
140 	 */
141 	unsigned int size72 = mc5->tcam_size;
142 	unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
143 
144 	if (mc5->mode == MC5_MODE_144_BIT) {
145 		size72 *= 2;      /* 1 144-bit entry is 2 72-bit entries */
146 		server_base *= 2;
147 	}
148 
149 	/* Clear the data array */
150 	dbgi_wr_data3(adap, 0, 0, 0);
151 	for (i = 0; i < size72; i++)
152 		if (mc5_write(adap, data_array_base + (i << addr_shift),
153 			      write_cmd))
154 			return -1;
155 
156 	/* Initialize the mask array. */
157 	for (i = 0; i < server_base; i++) {
158 		dbgi_wr_data3(adap, 0x3fffffff, 0xfff80000, 0xff);
159 		if (mc5_write(adap, mask_array_base + (i << addr_shift),
160 			      write_cmd))
161 			return -1;
162 		i++;
163 		dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
164 		if (mc5_write(adap, mask_array_base + (i << addr_shift),
165 			      write_cmd))
166 			return -1;
167 	}
168 
169 	dbgi_wr_data3(adap,
170 		      mc5->mode == MC5_MODE_144_BIT ? 0xfffffff9 : 0xfffffffd,
171 		      0xffffffff, 0xff);
172 	for (; i < size72; i++)
173 		if (mc5_write(adap, mask_array_base + (i << addr_shift),
174 			      write_cmd))
175 			return -1;
176 
177 	return 0;
178 }
179 
180 static int init_idt52100(struct mc5 *mc5)
181 {
182 	int i;
183 	adapter_t *adap = mc5->adapter;
184 
185 	t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
186 		     V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
187 	t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
188 
189 	/*
190 	 * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
191 	 * GMRs 8-9 for ACK- and AOPEN searches.
192 	 */
193 	t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
194 	t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
195 	t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
196 	t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
197 	t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
198 	t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
199 	t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
200 	t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
201 	t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
202 	t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
203 	t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
204 	t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
205 
206 	/* Set DBGI command mode for IDT TCAM. */
207 	t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
208 
209 	/* Set up LAR */
210 	dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
211 	if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
212 		goto err;
213 
214 	/* Set up SSRs */
215 	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
216 	if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
217 	    mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
218 		goto err;
219 
220 	/* Set up GMRs */
221 	for (i = 0; i < 32; ++i) {
222 		if (i >= 12 && i < 15)
223 			dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
224 		else if (i == 15)
225 			dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
226 		else
227 			dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
228 
229 		if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
230 			goto err;
231 	}
232 
233 	/* Set up SCR */
234 	dbgi_wr_data3(adap, 1, 0, 0);
235 	if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
236 		goto err;
237 
238 	return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
239 				    IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
240  err:
241 	return -EIO;
242 }
243 
244 static int init_idt43102(struct mc5 *mc5)
245 {
246 	int i;
247 	adapter_t *adap = mc5->adapter;
248 
249 	t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
250 		     adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
251 					     V_RDLAT(0xd) | V_SRCHLAT(0x12));
252 
253 	/*
254 	 * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
255 	 * for ACK- and AOPEN searches.
256 	 */
257 	t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
258 	t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
259 	t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
260 		     IDT4_CMD_SEARCH144 | 0x3800);
261 	t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
262 	t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
263 	t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
264 	t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
265 	t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
266 	t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
267 
268 	t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
269 
270 	/* Set DBGI command mode for IDT TCAM. */
271 	t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
272 
273 	/* Set up GMRs */
274 	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
275 	for (i = 0; i < 7; ++i)
276 		if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
277 			goto err;
278 
279 	for (i = 0; i < 4; ++i)
280 		if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
281 			goto err;
282 
283 	dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
284 	if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
285 	    mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
286 	    mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
287 		goto err;
288 
289 	dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
290 	if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
291 		goto err;
292 
293 	/* Set up SCR */
294 	dbgi_wr_data3(adap, 0xf0000000, 0, 0);
295 	if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
296 		goto err;
297 
298 	return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
299 				    IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
300  err:
301 	return -EIO;
302 }
303 
304 /* Put MC5 in DBGI mode. */
305 static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
306 {
307 	t3_set_reg_field(mc5->adapter, A_MC5_DB_CONFIG, F_PRTYEN | F_MBUSEN,
308 			 F_DBGIEN);
309 }
310 
311 /* Put MC5 in M-Bus mode. */
312 static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
313 {
314 	t3_set_reg_field(mc5->adapter, A_MC5_DB_CONFIG, F_DBGIEN,
315 			 V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
316 }
317 
318 /**
319  *	t3_mc5_init - initialize MC5 and the TCAM
320  *	@mc5: the MC5 handle
321  *	@nservers: desired number the TCP servers (listening ports)
322  *	@nfilters: desired number of HW filters (classifiers)
323  *	@nroutes: desired number of routes
324  *
325  *	Initialize MC5 and the TCAM and partition the TCAM for the requested
326  *	number of servers, filters, and routes.  The number of routes is
327  *	typically 0 except for specialized uses of the T3 adapters.
328  */
329 int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
330 		unsigned int nroutes)
331 {
332 	int err;
333 	unsigned int tcam_size = mc5->tcam_size;
334 	unsigned int mode72 = mc5->mode == MC5_MODE_72_BIT;
335 	adapter_t *adap = mc5->adapter;
336 
337 	if (!tcam_size)
338 		return 0;
339 
340 	if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
341 		return -EINVAL;
342 
343 	if (nfilters)
344 		mc5->parity_enabled = 0;
345 
346 	/* Reset the TCAM */
347 	t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_TMMODE | F_COMPEN,
348 			 V_COMPEN(mode72) | V_TMMODE(mode72) | F_TMRST);
349 	if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
350 		CH_ERR(adap, "TCAM reset timed out\n");
351 		return -1;
352 	}
353 
354 	t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
355 	t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
356 		     tcam_size - nroutes - nfilters);
357 	t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
358 		     tcam_size - nroutes - nfilters - nservers);
359 
360 	/* All the TCAM addresses we access have only the low 32 bits non 0 */
361 	t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
362 	t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
363 
364 	mc5_dbgi_mode_enable(mc5);
365 
366 	switch (mc5->part_type) {
367 	case IDT75P52100:
368 		err = init_idt52100(mc5);
369 		break;
370 	case IDT75N43102:
371 		err = init_idt43102(mc5);
372 		break;
373 	default:
374 		CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
375 		err = -EINVAL;
376 		break;
377 	}
378 
379 	mc5_dbgi_mode_disable(mc5);
380 	return err;
381 }
382 
383 /**
384  *	read_mc5_range - dump a part of the memory managed by MC5
385  *	@mc5: the MC5 handle
386  *	@start: the start address for the dump
387  *	@n: number of 72-bit words to read
388  *	@buf: result buffer
389  *
390  *	Read n 72-bit words from MC5 memory from the given start location.
391  */
392 int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
393 		      unsigned int n, u32 *buf)
394 {
395 	u32 read_cmd;
396 	int err = 0;
397 	adapter_t *adap = mc5->adapter;
398 
399 	if (mc5->part_type == IDT75P52100)
400 		read_cmd = IDT_CMD_READ;
401 	else if (mc5->part_type == IDT75N43102)
402 		read_cmd = IDT4_CMD_READ;
403 	else
404 		return -EINVAL;
405 
406 	mc5_dbgi_mode_enable(mc5);
407 
408 	while (n--) {
409 		t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
410 		if (mc5_cmd_write(adap, read_cmd)) {
411 			err = -EIO;
412 			break;
413 		}
414 		dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
415 		buf += 3;
416 	}
417 
418 	mc5_dbgi_mode_disable(mc5);
419 	return err;
420 }
421 
422 #define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
423 
424 /**
425  *	t3_mc5_intr_handler - MC5 interrupt handler
426  *	@mc5: the MC5 handle
427  *
428  *	The MC5 interrupt handler.
429  */
430 void t3_mc5_intr_handler(struct mc5 *mc5)
431 {
432 	adapter_t *adap = mc5->adapter;
433 	u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
434 
435 	if ((cause & F_PARITYERR) && mc5->parity_enabled) {
436 		CH_ALERT(adap, "MC5 parity error\n");
437 		mc5->stats.parity_err++;
438 	}
439 
440 	if (cause & F_REQQPARERR) {
441 		CH_ALERT(adap, "MC5 request queue parity error\n");
442 		mc5->stats.reqq_parity_err++;
443 	}
444 
445 	if (cause & F_DISPQPARERR) {
446 		CH_ALERT(adap, "MC5 dispatch queue parity error\n");
447 		mc5->stats.dispq_parity_err++;
448 	}
449 
450 	if (cause & F_ACTRGNFULL)
451 		mc5->stats.active_rgn_full++;
452 	if (cause & F_NFASRCHFAIL)
453 		mc5->stats.nfa_srch_err++;
454 	if (cause & F_UNKNOWNCMD)
455 		mc5->stats.unknown_cmd++;
456 	if (cause & F_DELACTEMPTY)
457 		mc5->stats.del_act_empty++;
458 	if (cause & MC5_INT_FATAL)
459 		t3_fatal_err(adap);
460 
461 	t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
462 }
463 
464 /**
465  *	t3_mc5_prep - initialize the SW state for MC5
466  *	@adapter: the adapter
467  *	@mc5: the MC5 handle
468  *	@mode: whether the TCAM will be in 72- or 144-bit mode
469  *
470  *	Initialize the SW state associated with MC5.  Among other things
471  *	this determines the size of the attached TCAM.
472  */
473 void __devinit t3_mc5_prep(adapter_t *adapter, struct mc5 *mc5, int mode)
474 {
475 #define K * 1024
476 
477 	static unsigned int tcam_part_size[] = {  /* in K 72-bit entries */
478 		64 K, 128 K, 256 K, 32 K
479 	};
480 
481 #undef K
482 
483 	u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
484 
485 	mc5->adapter = adapter;
486 	mc5->parity_enabled = 1;
487 	mc5->mode = (unsigned char) mode;
488 	mc5->part_type = (unsigned char) G_TMTYPE(cfg);
489 	if (cfg & F_TMTYPEHI)
490 		mc5->part_type |= 4;
491 
492 	mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
493 	if (mode == MC5_MODE_144_BIT)
494 		mc5->tcam_size /= 2;
495 }
496