xref: /illumos-gate/usr/src/uts/common/io/chxge/com/mc5.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
1*d39a76e7Sxw161283 /*
2*d39a76e7Sxw161283  * CDDL HEADER START
3*d39a76e7Sxw161283  *
4*d39a76e7Sxw161283  * The contents of this file are subject to the terms of the
5*d39a76e7Sxw161283  * Common Development and Distribution License (the "License").
6*d39a76e7Sxw161283  * You may not use this file except in compliance with the License.
7*d39a76e7Sxw161283  *
8*d39a76e7Sxw161283  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d39a76e7Sxw161283  * or http://www.opensolaris.org/os/licensing.
10*d39a76e7Sxw161283  * See the License for the specific language governing permissions
11*d39a76e7Sxw161283  * and limitations under the License.
12*d39a76e7Sxw161283  *
13*d39a76e7Sxw161283  * When distributing Covered Code, include this CDDL HEADER in each
14*d39a76e7Sxw161283  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d39a76e7Sxw161283  * If applicable, add the following below this CDDL HEADER, with the
16*d39a76e7Sxw161283  * fields enclosed by brackets "[]" replaced with your own identifying
17*d39a76e7Sxw161283  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d39a76e7Sxw161283  *
19*d39a76e7Sxw161283  * CDDL HEADER END
20*d39a76e7Sxw161283  */
21*d39a76e7Sxw161283 
22*d39a76e7Sxw161283 /*
23*d39a76e7Sxw161283  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24*d39a76e7Sxw161283  */
25*d39a76e7Sxw161283 
26*d39a76e7Sxw161283 #include "common.h"
27*d39a76e7Sxw161283 #include "regs.h"
28*d39a76e7Sxw161283 #include "mc5.h"
29*d39a76e7Sxw161283 
30*d39a76e7Sxw161283 /* DBGI command mode */
31*d39a76e7Sxw161283 enum {
32*d39a76e7Sxw161283       	DBGI_MODE_MBUS,
33*d39a76e7Sxw161283 	DBGI_MODE_LARA_7000,
34*d39a76e7Sxw161283 	DBGI_MODE_LARA_8000,
35*d39a76e7Sxw161283 	DBGI_MODE_NETL_4000,
36*d39a76e7Sxw161283 	DBGI_MODE_NETL_5000,
37*d39a76e7Sxw161283 	DBGI_MODE_IDT_52100
38*d39a76e7Sxw161283 };
39*d39a76e7Sxw161283 
40*d39a76e7Sxw161283 /* Lara command register address and values (low 32 bits) */
41*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_ADR0		0x00180038
42*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_72KEY_DATA0	0x00000182
43*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_144KEY_DATA0	0x00AAAB82
44*d39a76e7Sxw161283 
45*d39a76e7Sxw161283 /* Lara config register address and values (low 32 bits) */
46*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_ADR0		0x0018003D
47*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_72KEY_DATA0	0x00000000
48*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_144KEY_DATA0	0x55555555
49*d39a76e7Sxw161283 
50*d39a76e7Sxw161283 /* Lara GMR base addresses (low 32 bits) */
51*d39a76e7Sxw161283 #define MC5_LRA_GMRREG_BASE_ADR0_1	0x00180020
52*d39a76e7Sxw161283 #define MC5_LRA_GMRREG_BASE_ADR0_2	0x00180060
53*d39a76e7Sxw161283 
54*d39a76e7Sxw161283 /* Lara 7000 data and mask array base addresses (low 32 bits) */
55*d39a76e7Sxw161283 #define MC5_LRA_DATARY_BASE_ADR0	0x00000000
56*d39a76e7Sxw161283 #define MC5_LRA_MSKARY_BASE_ADR0	0x00080000
57*d39a76e7Sxw161283 
58*d39a76e7Sxw161283 /* Lara commands */
59*d39a76e7Sxw161283 #define MC5_LRA_CMD_READ		0x00000000
60*d39a76e7Sxw161283 #define MC5_LRA_CMD_WRITE		0x00010001
61*d39a76e7Sxw161283 #define MC5_LRA_CMD_SEARCH		0x00020002
62*d39a76e7Sxw161283 #define MC5_LRA_CMD_LEARN		0x00030003
63*d39a76e7Sxw161283 
64*d39a76e7Sxw161283 /* IDT 75P52100 commands */
65*d39a76e7Sxw161283 #define MC5_IDT_CMD_READ		0x0
66*d39a76e7Sxw161283 #define MC5_IDT_CMD_WRITE		0x1
67*d39a76e7Sxw161283 #define MC5_IDT_CMD_SEARCH		0x2
68*d39a76e7Sxw161283 #define MC5_IDT_CMD_LEARN		0x3
69*d39a76e7Sxw161283 #define MC5_IDT_CMD_NFA_SEARCH		0x4
70*d39a76e7Sxw161283 
71*d39a76e7Sxw161283 /* IDT LAR register address and value for 144-bit mode (low 32 bits) */
72*d39a76e7Sxw161283 #define MC5_IDT_LAR_ADR0		0x180006
73*d39a76e7Sxw161283 #define MC5_IDT_LAR_MODE144		0xffff0000
74*d39a76e7Sxw161283 
75*d39a76e7Sxw161283 /* IDT SCR and SSR addresses (low 32 bits) */
76*d39a76e7Sxw161283 #define MC5_IDT_SCR_ADR0		0x180000
77*d39a76e7Sxw161283 #define MC5_IDT_SSR0_ADR0		0x180002
78*d39a76e7Sxw161283 #define MC5_IDT_SSR1_ADR0		0x180004
79*d39a76e7Sxw161283 
80*d39a76e7Sxw161283 /* IDT GMR base address (low 32 bits) */
81*d39a76e7Sxw161283 #define MC5_IDT_GMR_BASE_ADR0		0x180020
82*d39a76e7Sxw161283 
83*d39a76e7Sxw161283 /* IDT data and mask array base addresses (low 32 bits) */
84*d39a76e7Sxw161283 #define MC5_IDT_DATARY_BASE_ADR0	0x00000000
85*d39a76e7Sxw161283 #define MC5_IDT_MSKARY_BASE_ADR0	0x00080000
86*d39a76e7Sxw161283 
87*d39a76e7Sxw161283 #define IDT_ELOOKUP_2Mb			0x7000
88*d39a76e7Sxw161283 #define IDT_ELOOKUP_9Mb			0x16000
89*d39a76e7Sxw161283 
90*d39a76e7Sxw161283 enum {
91*d39a76e7Sxw161283 	LARA_7000,
92*d39a76e7Sxw161283 	LARA_8000,
93*d39a76e7Sxw161283 	NETLOGIC_4000,
94*d39a76e7Sxw161283 	NETLOGIC_5000,
95*d39a76e7Sxw161283 	IDT75P52100
96*d39a76e7Sxw161283 };
97*d39a76e7Sxw161283 
98*d39a76e7Sxw161283 static unsigned int tcam_part_size[] = {
99*d39a76e7Sxw161283 	4718592, /* 4.5Mb */
100*d39a76e7Sxw161283 	9437184, /* 9Mb */
101*d39a76e7Sxw161283 	18874368 /* 18Mb */
102*d39a76e7Sxw161283 };
103*d39a76e7Sxw161283 
104*d39a76e7Sxw161283 struct pemc5 {
105*d39a76e7Sxw161283 	adapter_t *adapter;
106*d39a76e7Sxw161283 	unsigned int tcam_size;
107*d39a76e7Sxw161283 	unsigned int part_size;
108*d39a76e7Sxw161283 	unsigned char part_type;
109*d39a76e7Sxw161283 	unsigned char parity_enabled;
110*d39a76e7Sxw161283 	unsigned char issue_syn;
111*d39a76e7Sxw161283 	unsigned char mode;
112*d39a76e7Sxw161283 	struct pemc5_intr_counts intr_counts;
113*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72
114*d39a76e7Sxw161283 	u32 lip[MC5_LIP_NUM_OF_ENTRIES];
115*d39a76e7Sxw161283 	unsigned int lip_index;
116*d39a76e7Sxw161283 #endif
117*d39a76e7Sxw161283 };
118*d39a76e7Sxw161283 
119*d39a76e7Sxw161283 #define MAX_WRITE_ATTEMPTS 5
120*d39a76e7Sxw161283 
121*d39a76e7Sxw161283 /*
122*d39a76e7Sxw161283  * Issue a command to the TCAM and wait for its completion.  The address and
123*d39a76e7Sxw161283  * any data required by the command must have been setup by the caller.
124*d39a76e7Sxw161283  */
mc5_cmd_write(adapter_t * adapter,u32 cmd)125*d39a76e7Sxw161283 static int mc5_cmd_write(adapter_t *adapter, u32 cmd)
126*d39a76e7Sxw161283 {
127*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_CMD, cmd);
128*d39a76e7Sxw161283 	return t1_wait_op_done(adapter, A_MC5_DBGI_RSP_STATUS,
129*d39a76e7Sxw161283 		F_DBGI_RSP_VALID, 1, MAX_WRITE_ATTEMPTS, 1);
130*d39a76e7Sxw161283 }
131*d39a76e7Sxw161283 
132*d39a76e7Sxw161283 
t1_mc5_get_tcam_size(struct pemc5 * mc5)133*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_size(struct pemc5 *mc5)
134*d39a76e7Sxw161283 {
135*d39a76e7Sxw161283 	return mc5->tcam_size;
136*d39a76e7Sxw161283 }
137*d39a76e7Sxw161283 
set_tcam_rtbl_base(struct pemc5 * mc5,unsigned int rtbl_base)138*d39a76e7Sxw161283 static int set_tcam_rtbl_base(struct pemc5 *mc5, unsigned int rtbl_base)
139*d39a76e7Sxw161283 {
140*d39a76e7Sxw161283 	if (rtbl_base >= t1_mc5_get_tcam_size(mc5)) return -1;
141*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_ROUTING_TABLE_INDEX, rtbl_base);
142*d39a76e7Sxw161283 	return 0;
143*d39a76e7Sxw161283 }
144*d39a76e7Sxw161283 
t1_mc5_get_tcam_rtbl_base(struct pemc5 * mc5)145*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_rtbl_base(struct pemc5 *mc5)
146*d39a76e7Sxw161283 {
147*d39a76e7Sxw161283 	return t1_read_reg_4(mc5->adapter, A_MC5_ROUTING_TABLE_INDEX);
148*d39a76e7Sxw161283 }
149*d39a76e7Sxw161283 
t1_mc5_get_tcam_rtbl_size(struct pemc5 * mc5)150*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_rtbl_size(struct pemc5 *mc5)
151*d39a76e7Sxw161283 {
152*d39a76e7Sxw161283 	unsigned int tcam_size = t1_mc5_get_tcam_size(mc5);
153*d39a76e7Sxw161283 	unsigned int tcam_rtable_base = t1_mc5_get_tcam_rtbl_base(mc5);
154*d39a76e7Sxw161283 
155*d39a76e7Sxw161283 	return tcam_size - tcam_rtable_base;
156*d39a76e7Sxw161283 }
157*d39a76e7Sxw161283 
set_tcam_server_base(struct pemc5 * mc5,unsigned int server_base)158*d39a76e7Sxw161283 static int set_tcam_server_base(struct pemc5 *mc5, unsigned int server_base)
159*d39a76e7Sxw161283 {
160*d39a76e7Sxw161283 	if (server_base >= t1_mc5_get_tcam_size(mc5)) return -1;
161*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_SERVER_INDEX, server_base);
162*d39a76e7Sxw161283 	return 0;
163*d39a76e7Sxw161283 }
164*d39a76e7Sxw161283 
t1_mc5_get_tcam_server_base(struct pemc5 * mc5)165*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_server_base(struct pemc5 *mc5)
166*d39a76e7Sxw161283 {
167*d39a76e7Sxw161283 	return t1_read_reg_4(mc5->adapter, A_MC5_SERVER_INDEX);
168*d39a76e7Sxw161283 }
169*d39a76e7Sxw161283 
t1_mc5_get_tcam_server_size(struct pemc5 * mc5)170*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_server_size(struct pemc5 *mc5)
171*d39a76e7Sxw161283 {
172*d39a76e7Sxw161283 	unsigned int tcam_rtable_base = t1_mc5_get_tcam_rtbl_base(mc5);
173*d39a76e7Sxw161283 	unsigned int tcam_server_base = t1_mc5_get_tcam_server_base(mc5);
174*d39a76e7Sxw161283 
175*d39a76e7Sxw161283 	return tcam_rtable_base - tcam_server_base;
176*d39a76e7Sxw161283 }
177*d39a76e7Sxw161283 
dbgi_wr_addr3(adapter_t * adapter,u32 v1,u32 v2,u32 v3)178*d39a76e7Sxw161283 static inline void dbgi_wr_addr3(adapter_t *adapter, u32 v1, u32 v2, u32 v3)
179*d39a76e7Sxw161283 {
180*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR0, v1);
181*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR1, v2);
182*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR2, v3);
183*d39a76e7Sxw161283 }
184*d39a76e7Sxw161283 
dbgi_wr_data3(adapter_t * adapter,u32 v1,u32 v2,u32 v3)185*d39a76e7Sxw161283 static inline void dbgi_wr_data3(adapter_t *adapter, u32 v1, u32 v2, u32 v3)
186*d39a76e7Sxw161283 {
187*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA0, v1);
188*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA1, v2);
189*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA2, v3);
190*d39a76e7Sxw161283 }
191*d39a76e7Sxw161283 
dbgi_rd_rsp3(adapter_t * adapter,u32 * v1,u32 * v2,u32 * v3)192*d39a76e7Sxw161283 static inline void dbgi_rd_rsp3(adapter_t *adapter, u32 *v1, u32 *v2, u32 *v3)
193*d39a76e7Sxw161283 {
194*d39a76e7Sxw161283 	*v1 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA0);
195*d39a76e7Sxw161283 	*v2 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA1);
196*d39a76e7Sxw161283 	*v3 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA2);
197*d39a76e7Sxw161283 }
198*d39a76e7Sxw161283 
199*d39a76e7Sxw161283 /*
200*d39a76e7Sxw161283  * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
201*d39a76e7Sxw161283  * command cmd.  The data to be written must have been set up by the caller.
202*d39a76e7Sxw161283  * Returns -1 on failure, 0 on success.
203*d39a76e7Sxw161283  */
mc5_write(adapter_t * adapter,u32 addr_lo,u32 cmd)204*d39a76e7Sxw161283 static int mc5_write(adapter_t *adapter, u32 addr_lo, u32 cmd)
205*d39a76e7Sxw161283 {
206*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR0, addr_lo);
207*d39a76e7Sxw161283 	if (mc5_cmd_write(adapter, cmd) == 0)
208*d39a76e7Sxw161283 		return 0;
209*d39a76e7Sxw161283 	CH_ERR("%s: MC5 timeout writing to TCAM address 0x%x\n",
210*d39a76e7Sxw161283 	       adapter_name(adapter), addr_lo);
211*d39a76e7Sxw161283 	return -1;
212*d39a76e7Sxw161283 }
213*d39a76e7Sxw161283 
init_mask_data_array(struct pemc5 * mc5,u32 mask_array_base,u32 data_array_base,u32 write_cmd)214*d39a76e7Sxw161283 static int init_mask_data_array(struct pemc5 *mc5, u32 mask_array_base,
215*d39a76e7Sxw161283 				u32 data_array_base, u32 write_cmd)
216*d39a76e7Sxw161283 {
217*d39a76e7Sxw161283 	unsigned int i;
218*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
219*d39a76e7Sxw161283 
220*d39a76e7Sxw161283 	/*
221*d39a76e7Sxw161283 	 * We need the size of the TCAM data and mask arrays in terms of
222*d39a76e7Sxw161283 	 * 72-bit entries.
223*d39a76e7Sxw161283 	 */
224*d39a76e7Sxw161283 	unsigned int size72 = tcam_part_size[mc5->part_size] / 72;
225*d39a76e7Sxw161283 	unsigned int server_base = t1_mc5_get_tcam_server_base(mc5);
226*d39a76e7Sxw161283 	if (mc5->mode == MC5_MODE_144_BIT)
227*d39a76e7Sxw161283 		server_base *= 2;  /* 1 144-bit entry is 2 72-bit entries */
228*d39a76e7Sxw161283 
229*d39a76e7Sxw161283 	/* Clear the data array */
230*d39a76e7Sxw161283 	dbgi_wr_data3(adap, 0, 0, 0);
231*d39a76e7Sxw161283 	for (i = 0; i < size72; i++)
232*d39a76e7Sxw161283 		if (mc5_write(adap, data_array_base + i, write_cmd))
233*d39a76e7Sxw161283 			return -1;
234*d39a76e7Sxw161283 
235*d39a76e7Sxw161283 	/* Initialize the mask array. */
236*d39a76e7Sxw161283 	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
237*d39a76e7Sxw161283 	for (i = 0; i < size72; i++) {
238*d39a76e7Sxw161283 		if (i == server_base)   /* entering server or routing region */
239*d39a76e7Sxw161283 			t1_write_reg_4(adap, A_MC5_DBGI_REQ_DATA0,
240*d39a76e7Sxw161283 				       mc5->mode == MC5_MODE_144_BIT ?
241*d39a76e7Sxw161283 				       0xfffffff9 : 0xfffffffd);
242*d39a76e7Sxw161283 		if (mc5_write(adap, mask_array_base + i, write_cmd))
243*d39a76e7Sxw161283 			return -1;
244*d39a76e7Sxw161283 	}
245*d39a76e7Sxw161283 	return 0;
246*d39a76e7Sxw161283 }
247*d39a76e7Sxw161283 
init_lara7000(struct pemc5 * mc5)248*d39a76e7Sxw161283 static int init_lara7000(struct pemc5 *mc5)
249*d39a76e7Sxw161283 {
250*d39a76e7Sxw161283 	int i;
251*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
252*d39a76e7Sxw161283 
253*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_RSP_LATENCY,
254*d39a76e7Sxw161283 		       t1_is_asic(adap) ? 0x0a0a0a0a : 0x09090909);
255*d39a76e7Sxw161283 
256*d39a76e7Sxw161283 	if (mc5->parity_enabled) {
257*d39a76e7Sxw161283 		t1_write_reg_4(adap, A_MC5_AOPEN_SRCH_CMD, 0x20022);
258*d39a76e7Sxw161283 		t1_write_reg_4(adap, A_MC5_SYN_SRCH_CMD, 0x20022);
259*d39a76e7Sxw161283 		t1_write_reg_4(adap, A_MC5_ACK_SRCH_CMD, 0x20022);
260*d39a76e7Sxw161283 	}
261*d39a76e7Sxw161283 
262*d39a76e7Sxw161283 	/* Set DBGI command mode for Lara TCAM. */
263*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DBGI_CONFIG, DBGI_MODE_LARA_7000);
264*d39a76e7Sxw161283 
265*d39a76e7Sxw161283 	dbgi_wr_data3(adap, mc5->mode == MC5_MODE_144_BIT ?
266*d39a76e7Sxw161283 		      MC5_LRA_CMDREG_144KEY_DATA0 : MC5_LRA_CMDREG_72KEY_DATA0,
267*d39a76e7Sxw161283 		      0, 0);
268*d39a76e7Sxw161283 	if (mc5_write(adap, MC5_LRA_CMDREG_ADR0, MC5_LRA_CMD_WRITE))
269*d39a76e7Sxw161283 		goto err;
270*d39a76e7Sxw161283 
271*d39a76e7Sxw161283 	dbgi_wr_data3(adap, mc5->mode == MC5_MODE_144_BIT ?
272*d39a76e7Sxw161283 		      MC5_LRA_CFGREG_144KEY_DATA0 : MC5_LRA_CFGREG_72KEY_DATA0,
273*d39a76e7Sxw161283 		      0, 0);
274*d39a76e7Sxw161283 	if (mc5_write(adap, MC5_LRA_CFGREG_ADR0, MC5_LRA_CMD_WRITE))
275*d39a76e7Sxw161283 		goto err;
276*d39a76e7Sxw161283 
277*d39a76e7Sxw161283 	/* Global Mask Registers (GMR) 0-15 */
278*d39a76e7Sxw161283 	for (i = 0; i < 16; i++) {
279*d39a76e7Sxw161283 		if (i == 8 || i == 9)
280*d39a76e7Sxw161283 			dbgi_wr_data3(adap, mc5->mode == MC5_MODE_72_BIT ?
281*d39a76e7Sxw161283 				      0xfffffffd : 0xfffffff9, 0xffffffff,
282*d39a76e7Sxw161283 				      0xff);
283*d39a76e7Sxw161283 		else
284*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
285*d39a76e7Sxw161283 
286*d39a76e7Sxw161283 		if (mc5_write(adap, MC5_LRA_GMRREG_BASE_ADR0_1 + i,
287*d39a76e7Sxw161283 			      MC5_LRA_CMD_WRITE))
288*d39a76e7Sxw161283 			goto err;
289*d39a76e7Sxw161283 	}
290*d39a76e7Sxw161283 
291*d39a76e7Sxw161283 	/* Global Mask Registers (GMR) 16-31 */
292*d39a76e7Sxw161283 	for (i = 0; i < 16; i++) {
293*d39a76e7Sxw161283 		if (i <= 1 && mc5->mode == MC5_MODE_72_BIT)
294*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xfffffffd, 0xffffc003, 0xff);
295*d39a76e7Sxw161283 		else if (i == 0)
296*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
297*d39a76e7Sxw161283 		else if (i == 1)
298*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
299*d39a76e7Sxw161283 		else
300*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
301*d39a76e7Sxw161283 
302*d39a76e7Sxw161283 		if (mc5_write(adap, MC5_LRA_GMRREG_BASE_ADR0_2 + i,
303*d39a76e7Sxw161283 			      MC5_LRA_CMD_WRITE))
304*d39a76e7Sxw161283 			goto err;
305*d39a76e7Sxw161283 	}
306*d39a76e7Sxw161283 	return init_mask_data_array(mc5, MC5_LRA_MSKARY_BASE_ADR0,
307*d39a76e7Sxw161283 				    MC5_LRA_DATARY_BASE_ADR0,
308*d39a76e7Sxw161283 				    MC5_LRA_CMD_WRITE);
309*d39a76e7Sxw161283  err:
310*d39a76e7Sxw161283 	return -EIO;
311*d39a76e7Sxw161283 }
312*d39a76e7Sxw161283 
init_idt52100(struct pemc5 * mc5)313*d39a76e7Sxw161283 static int init_idt52100(struct pemc5 *mc5)
314*d39a76e7Sxw161283 {
315*d39a76e7Sxw161283 	int i;
316*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
317*d39a76e7Sxw161283 
318*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_RSP_LATENCY, 0x151515);
319*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_PART_ID_INDEX, 2);
320*d39a76e7Sxw161283 
321*d39a76e7Sxw161283 	/*
322*d39a76e7Sxw161283 	 * Use GMRs 8-9 for ACK and AOPEN searches, GMRs 12-13 for SYN search,
323*d39a76e7Sxw161283 	 * and GMRs 14-15 for ELOOKUP.
324*d39a76e7Sxw161283 	 */
325*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_POPEN_DATA_WR_CMD, MC5_IDT_CMD_WRITE);
326*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_POPEN_MASK_WR_CMD, MC5_IDT_CMD_WRITE);
327*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_AOPEN_SRCH_CMD, MC5_IDT_CMD_SEARCH);
328*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_AOPEN_LRN_CMD, MC5_IDT_CMD_LEARN);
329*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_SYN_SRCH_CMD, MC5_IDT_CMD_SEARCH | 0x6000);
330*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_SYN_LRN_CMD, MC5_IDT_CMD_LEARN);
331*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_ACK_SRCH_CMD, MC5_IDT_CMD_SEARCH);
332*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_ACK_LRN_CMD, MC5_IDT_CMD_LEARN);
333*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_ILOOKUP_CMD, MC5_IDT_CMD_SEARCH);
334*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_ELOOKUP_CMD, MC5_IDT_CMD_SEARCH | 0x7000);
335*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DATA_WRITE_CMD, MC5_IDT_CMD_WRITE);
336*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DATA_READ_CMD, MC5_IDT_CMD_READ);
337*d39a76e7Sxw161283 
338*d39a76e7Sxw161283 	/* Set DBGI command mode for IDT TCAM. */
339*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DBGI_CONFIG, DBGI_MODE_IDT_52100);
340*d39a76e7Sxw161283 
341*d39a76e7Sxw161283 	/* Set up LAR */
342*d39a76e7Sxw161283 	dbgi_wr_data3(adap, MC5_IDT_LAR_MODE144, 0, 0);
343*d39a76e7Sxw161283 	if (mc5_write(adap, MC5_IDT_LAR_ADR0, MC5_IDT_CMD_WRITE))
344*d39a76e7Sxw161283 		goto err;
345*d39a76e7Sxw161283 
346*d39a76e7Sxw161283 	/* Set up SSRs */
347*d39a76e7Sxw161283 	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
348*d39a76e7Sxw161283 	if (mc5_write(adap, MC5_IDT_SSR0_ADR0, MC5_IDT_CMD_WRITE) ||
349*d39a76e7Sxw161283 	    mc5_write(adap, MC5_IDT_SSR1_ADR0, MC5_IDT_CMD_WRITE))
350*d39a76e7Sxw161283 		goto err;
351*d39a76e7Sxw161283 
352*d39a76e7Sxw161283 	/* Set up GMRs */
353*d39a76e7Sxw161283 	for (i = 0; i < 32; ++i) {
354*d39a76e7Sxw161283 		if (i >= 12 && i < 15)
355*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
356*d39a76e7Sxw161283 		else if (i == 15)
357*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
358*d39a76e7Sxw161283 		else
359*d39a76e7Sxw161283 			dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
360*d39a76e7Sxw161283 
361*d39a76e7Sxw161283 		if (mc5_write(adap, MC5_IDT_GMR_BASE_ADR0 + i,
362*d39a76e7Sxw161283 			      MC5_IDT_CMD_WRITE))
363*d39a76e7Sxw161283 			goto err;
364*d39a76e7Sxw161283 	}
365*d39a76e7Sxw161283 
366*d39a76e7Sxw161283 	/* Set up SCR */
367*d39a76e7Sxw161283 	dbgi_wr_data3(adap, 1, 0, 0);
368*d39a76e7Sxw161283 	if (mc5_write(adap, MC5_IDT_SCR_ADR0, MC5_IDT_CMD_WRITE))
369*d39a76e7Sxw161283 		goto err;
370*d39a76e7Sxw161283 
371*d39a76e7Sxw161283 	return init_mask_data_array(mc5, MC5_IDT_MSKARY_BASE_ADR0,
372*d39a76e7Sxw161283 				    MC5_IDT_DATARY_BASE_ADR0,
373*d39a76e7Sxw161283 				    MC5_IDT_CMD_WRITE);
374*d39a76e7Sxw161283  err:
375*d39a76e7Sxw161283 	return -EIO;
376*d39a76e7Sxw161283 }
377*d39a76e7Sxw161283 
378*d39a76e7Sxw161283 /* Put MC5 in DBGI mode. */
mc5_dbgi_mode_enable(struct pemc5 * mc5)379*d39a76e7Sxw161283 static inline void mc5_dbgi_mode_enable(struct pemc5 *mc5)
380*d39a76e7Sxw161283 {
381*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_CONFIG,
382*d39a76e7Sxw161283 		       V_MODE(mc5->mode == MC5_MODE_72_BIT) |
383*d39a76e7Sxw161283 		       F_DBGI_ENABLE | V_NUM_LIP(MC5_LIP_NUM_OF_ENTRIES - 1));
384*d39a76e7Sxw161283 }
385*d39a76e7Sxw161283 
386*d39a76e7Sxw161283 /* Put MC5 in M-Bus mode. */
mc5_dbgi_mode_disable(struct pemc5 * mc5)387*d39a76e7Sxw161283 static void mc5_dbgi_mode_disable(struct pemc5 *mc5)
388*d39a76e7Sxw161283 {
389*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_CONFIG,
390*d39a76e7Sxw161283 		       V_MODE(mc5->mode == MC5_MODE_72_BIT) |
391*d39a76e7Sxw161283 		       V_COMPRESSION_ENABLE(mc5->mode == MC5_MODE_72_BIT) |
392*d39a76e7Sxw161283 		       V_PARITY_ENABLE(mc5->parity_enabled) |
393*d39a76e7Sxw161283 		       V_SYN_ISSUE_MODE(mc5->issue_syn) | F_M_BUS_ENABLE |
394*d39a76e7Sxw161283 		       V_NUM_LIP(MC5_LIP_NUM_OF_ENTRIES - 1));
395*d39a76e7Sxw161283 }
396*d39a76e7Sxw161283 
397*d39a76e7Sxw161283 /*
398*d39a76e7Sxw161283  * Initialization that requires the OS and protocol layers to already
399*d39a76e7Sxw161283  * be intialized goes here.
400*d39a76e7Sxw161283  */
t1_mc5_init(struct pemc5 * mc5,unsigned int nservers,unsigned int nroutes,int parity,int syn)401*d39a76e7Sxw161283 int t1_mc5_init(struct pemc5 *mc5, unsigned int nservers,
402*d39a76e7Sxw161283 		unsigned int nroutes, int parity, int syn)
403*d39a76e7Sxw161283 {
404*d39a76e7Sxw161283 	u32 cfg;
405*d39a76e7Sxw161283 	int err = 0;
406*d39a76e7Sxw161283 	unsigned int tcam_size = t1_mc5_get_tcam_size(mc5);
407*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
408*d39a76e7Sxw161283 
409*d39a76e7Sxw161283 	/* Reset the TCAM */
410*d39a76e7Sxw161283 	cfg = t1_read_reg_4(adap, A_MC5_CONFIG) & ~F_MODE;
411*d39a76e7Sxw161283 	cfg |= V_MODE(mc5->mode == MC5_MODE_72_BIT) | F_TCAM_RESET;
412*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_CONFIG, cfg);
413*d39a76e7Sxw161283 	if (t1_wait_op_done(adap, A_MC5_CONFIG, F_TCAM_READY, 1, 500, 0)) {
414*d39a76e7Sxw161283 		CH_ERR("%s: TCAM reset timed out\n", adapter_name(adap));
415*d39a76e7Sxw161283 		return -1;
416*d39a76e7Sxw161283 	}
417*d39a76e7Sxw161283 
418*d39a76e7Sxw161283 	if (set_tcam_rtbl_base(mc5, tcam_size - nroutes) ||
419*d39a76e7Sxw161283 	    set_tcam_server_base(mc5, tcam_size - nroutes - nservers))
420*d39a76e7Sxw161283 		return -EINVAL;
421*d39a76e7Sxw161283 
422*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72
423*d39a76e7Sxw161283 	if (mc5->mode == MC5_MODE_72_BIT)
424*d39a76e7Sxw161283 		t1_mc5_lip_write_entries(mc5);
425*d39a76e7Sxw161283 #endif
426*d39a76e7Sxw161283 	mc5->issue_syn = (unsigned char)syn;
427*d39a76e7Sxw161283 	mc5->parity_enabled = (unsigned char)parity;
428*d39a76e7Sxw161283 
429*d39a76e7Sxw161283 	/* All the TCAM addresses we access have only the low 32 bits non 0 */
430*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR1, 0);
431*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR2, 0);
432*d39a76e7Sxw161283 
433*d39a76e7Sxw161283 	mc5_dbgi_mode_enable(mc5);
434*d39a76e7Sxw161283 
435*d39a76e7Sxw161283 	switch (mc5->part_type) {
436*d39a76e7Sxw161283 	case LARA_7000:
437*d39a76e7Sxw161283 		err = init_lara7000(mc5);
438*d39a76e7Sxw161283 		break;
439*d39a76e7Sxw161283 	case IDT75P52100:
440*d39a76e7Sxw161283 		err = init_idt52100(mc5);
441*d39a76e7Sxw161283 		break;
442*d39a76e7Sxw161283 	default:
443*d39a76e7Sxw161283 		CH_ERR("%s: unsupported TCAM type\n", adapter_name(adap));
444*d39a76e7Sxw161283 		err = -EINVAL;
445*d39a76e7Sxw161283 		break;
446*d39a76e7Sxw161283 	}
447*d39a76e7Sxw161283 
448*d39a76e7Sxw161283 	mc5_dbgi_mode_disable(mc5);
449*d39a76e7Sxw161283 	return err;
450*d39a76e7Sxw161283 }
451*d39a76e7Sxw161283 
452*d39a76e7Sxw161283 /*
453*d39a76e7Sxw161283  *	read_mc5_range - dump a part of the memory managed by MC5
454*d39a76e7Sxw161283  *	@mc5: the MC5 handle
455*d39a76e7Sxw161283  *	@start: the start address for the dump
456*d39a76e7Sxw161283  *	@n: number of 72-bit words to read
457*d39a76e7Sxw161283  *	@buf: result buffer
458*d39a76e7Sxw161283  *
459*d39a76e7Sxw161283  *	Read n 72-bit words from MC5 memory from the given start location.
460*d39a76e7Sxw161283  */
t1_read_mc5_range(struct pemc5 * mc5,unsigned int start,unsigned int n,u32 * buf)461*d39a76e7Sxw161283 int t1_read_mc5_range(struct pemc5 *mc5, unsigned int start,
462*d39a76e7Sxw161283 		      unsigned int n, u32 *buf)
463*d39a76e7Sxw161283 {
464*d39a76e7Sxw161283 	u32 read_cmd;
465*d39a76e7Sxw161283 	/* int err = 0; */
466*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
467*d39a76e7Sxw161283 
468*d39a76e7Sxw161283 	if (mc5->part_type == LARA_7000)
469*d39a76e7Sxw161283 		read_cmd = MC5_LRA_CMD_READ;
470*d39a76e7Sxw161283 	else if (mc5->part_type == IDT75P52100)
471*d39a76e7Sxw161283 		read_cmd = MC5_IDT_CMD_READ;
472*d39a76e7Sxw161283 	else
473*d39a76e7Sxw161283 		return -EINVAL;
474*d39a76e7Sxw161283 
475*d39a76e7Sxw161283 	mc5_dbgi_mode_enable(mc5);
476*d39a76e7Sxw161283 
477*d39a76e7Sxw161283 	while (n--) {
478*d39a76e7Sxw161283 		t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR0, start++);
479*d39a76e7Sxw161283 		if (mc5_cmd_write(adap, read_cmd)) {
480*d39a76e7Sxw161283 			/* err = -EIO; */
481*d39a76e7Sxw161283 			break;
482*d39a76e7Sxw161283 		}
483*d39a76e7Sxw161283 		dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
484*d39a76e7Sxw161283 		buf += 3;
485*d39a76e7Sxw161283 	}
486*d39a76e7Sxw161283 
487*d39a76e7Sxw161283 	mc5_dbgi_mode_disable(mc5);
488*d39a76e7Sxw161283 	return 0;
489*d39a76e7Sxw161283 }
490*d39a76e7Sxw161283 
491*d39a76e7Sxw161283 #define MC5_INT_MASK (F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR | \
492*d39a76e7Sxw161283 	F_MC5_INT_HIT_IN_RT_REGION_ERR | F_MC5_INT_LIP0_ERR | \
493*d39a76e7Sxw161283 	F_MC5_INT_LIP_MISS_ERR | F_MC5_INT_PARITY_ERR | \
494*d39a76e7Sxw161283 	F_MC5_INT_ACTIVE_REGION_FULL | F_MC5_INT_NFA_SRCH_ERR | \
495*d39a76e7Sxw161283 	F_MC5_INT_UNKNOWN_CMD | F_MC5_INT_DEL_ACT_EMPTY)
496*d39a76e7Sxw161283 #define MC5_INT_FATAL (F_MC5_INT_PARITY_ERR | F_MC5_INT_REQUESTQ_PARITY_ERR | \
497*d39a76e7Sxw161283 	F_MC5_INT_DISPATCHQ_PARITY_ERR)
498*d39a76e7Sxw161283 
t1_mc5_intr_enable(struct pemc5 * mc5)499*d39a76e7Sxw161283 void t1_mc5_intr_enable(struct pemc5 *mc5)
500*d39a76e7Sxw161283 {
501*d39a76e7Sxw161283 	u32 mask = MC5_INT_MASK;
502*d39a76e7Sxw161283 
503*d39a76e7Sxw161283 	if (!mc5->parity_enabled)
504*d39a76e7Sxw161283 		mask &= ~F_MC5_INT_PARITY_ERR;
505*d39a76e7Sxw161283 
506*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
507*d39a76e7Sxw161283 	if (!t1_is_asic(mc5->adapter)) {
508*d39a76e7Sxw161283 		/*
509*d39a76e7Sxw161283 		 * Enable child block for MC5.
510*d39a76e7Sxw161283 		 *
511*d39a76e7Sxw161283 		 * NOTE: Assumes TP parent interrupt block is enabled.
512*d39a76e7Sxw161283 		 *       MC5 requires TP parent block to be enabled.
513*d39a76e7Sxw161283 		 */
514*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, mask);
515*d39a76e7Sxw161283 	} else
516*d39a76e7Sxw161283 #endif
517*d39a76e7Sxw161283 	{
518*d39a76e7Sxw161283 		u32 pl_intr = t1_read_reg_4(mc5->adapter, A_PL_ENABLE);
519*d39a76e7Sxw161283 
520*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_PL_ENABLE,
521*d39a76e7Sxw161283 			       pl_intr | F_PL_INTR_MC5);
522*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE,
523*d39a76e7Sxw161283 			       mask | F_MC5_INT_REQUESTQ_PARITY_ERR |
524*d39a76e7Sxw161283 			       F_MC5_INT_DISPATCHQ_PARITY_ERR);
525*d39a76e7Sxw161283 	}
526*d39a76e7Sxw161283 }
527*d39a76e7Sxw161283 
t1_mc5_intr_disable(struct pemc5 * mc5)528*d39a76e7Sxw161283 void t1_mc5_intr_disable(struct pemc5 *mc5)
529*d39a76e7Sxw161283 {
530*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
531*d39a76e7Sxw161283 	if (!t1_is_asic(mc5->adapter))
532*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, 0);
533*d39a76e7Sxw161283 	else
534*d39a76e7Sxw161283 #endif
535*d39a76e7Sxw161283 	{
536*d39a76e7Sxw161283 		u32 pl_intr = t1_read_reg_4(mc5->adapter, A_PL_ENABLE);
537*d39a76e7Sxw161283 
538*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_PL_ENABLE,
539*d39a76e7Sxw161283 			       pl_intr & ~F_PL_INTR_MC5);
540*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, 0);
541*d39a76e7Sxw161283 	}
542*d39a76e7Sxw161283 }
543*d39a76e7Sxw161283 
t1_mc5_intr_clear(struct pemc5 * mc5)544*d39a76e7Sxw161283 void t1_mc5_intr_clear(struct pemc5 *mc5)
545*d39a76e7Sxw161283 {
546*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
547*d39a76e7Sxw161283 	if (!t1_is_asic(mc5->adapter)) {
548*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_CAUSE, 0xffffffff);
549*d39a76e7Sxw161283 	} else
550*d39a76e7Sxw161283 #endif
551*d39a76e7Sxw161283 	{
552*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_PL_CAUSE, F_PL_INTR_MC5);
553*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_INT_CAUSE, 0xffffffff);
554*d39a76e7Sxw161283 	}
555*d39a76e7Sxw161283 }
556*d39a76e7Sxw161283 
557*d39a76e7Sxw161283 /*
558*d39a76e7Sxw161283  * We don't really do anything with MC5 interrupts, just record them.
559*d39a76e7Sxw161283  */
t1_mc5_intr_handler(struct pemc5 * mc5)560*d39a76e7Sxw161283 void t1_mc5_intr_handler(struct pemc5 *mc5)
561*d39a76e7Sxw161283 {
562*d39a76e7Sxw161283 	adapter_t *adap = mc5->adapter;
563*d39a76e7Sxw161283 	u32 cause = t1_read_reg_4(adap, A_MC5_INT_CAUSE);
564*d39a76e7Sxw161283 
565*d39a76e7Sxw161283 	if (cause & F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR)
566*d39a76e7Sxw161283 		mc5->intr_counts.hit_out_active_region_err++;
567*d39a76e7Sxw161283 
568*d39a76e7Sxw161283 	if (cause & F_MC5_INT_HIT_IN_ACTIVE_REGION_ERR)
569*d39a76e7Sxw161283 		mc5->intr_counts.hit_in_active_region_err++;
570*d39a76e7Sxw161283 
571*d39a76e7Sxw161283 	if (cause & F_MC5_INT_HIT_IN_RT_REGION_ERR)
572*d39a76e7Sxw161283 		mc5->intr_counts.hit_in_routing_region_err++;
573*d39a76e7Sxw161283 
574*d39a76e7Sxw161283 	if (cause & F_MC5_INT_MISS_ERR)
575*d39a76e7Sxw161283 		mc5->intr_counts.miss_err++;
576*d39a76e7Sxw161283 
577*d39a76e7Sxw161283 	if (cause & F_MC5_INT_LIP0_ERR)
578*d39a76e7Sxw161283 		mc5->intr_counts.lip_equal_zero_err++;
579*d39a76e7Sxw161283 
580*d39a76e7Sxw161283 	if (cause & F_MC5_INT_LIP_MISS_ERR)
581*d39a76e7Sxw161283 		mc5->intr_counts.lip_miss_err++;
582*d39a76e7Sxw161283 
583*d39a76e7Sxw161283 	if ((cause & F_MC5_INT_PARITY_ERR) && mc5->parity_enabled) {
584*d39a76e7Sxw161283 		CH_ALERT("%s: MC5 parity error\n", adapter_name(adap));
585*d39a76e7Sxw161283 		mc5->intr_counts.parity_err++;
586*d39a76e7Sxw161283 	}
587*d39a76e7Sxw161283 
588*d39a76e7Sxw161283 	if (cause & F_MC5_INT_ACTIVE_REGION_FULL)
589*d39a76e7Sxw161283 		mc5->intr_counts.active_region_full_err++;
590*d39a76e7Sxw161283 
591*d39a76e7Sxw161283 	if (cause & F_MC5_INT_NFA_SRCH_ERR)
592*d39a76e7Sxw161283 		mc5->intr_counts.next_free_addr_srch_err++;
593*d39a76e7Sxw161283 
594*d39a76e7Sxw161283 	if (cause & F_MC5_INT_SYN_COOKIE)
595*d39a76e7Sxw161283 		mc5->intr_counts.syn_cookie++;
596*d39a76e7Sxw161283 
597*d39a76e7Sxw161283 	if (cause & F_MC5_INT_SYN_COOKIE_BAD)
598*d39a76e7Sxw161283 		mc5->intr_counts.syn_cookie_bad_message++;
599*d39a76e7Sxw161283 
600*d39a76e7Sxw161283 	if (cause & F_MC5_INT_SYN_COOKIE_OFF)
601*d39a76e7Sxw161283 		mc5->intr_counts.syn_cookie_off_message++;
602*d39a76e7Sxw161283 
603*d39a76e7Sxw161283 	if (cause & F_MC5_INT_UNKNOWN_CMD)
604*d39a76e7Sxw161283 		mc5->intr_counts.receive_unknown_cmd++;
605*d39a76e7Sxw161283 
606*d39a76e7Sxw161283 	if (cause & F_MC5_INT_REQUESTQ_PARITY_ERR) {
607*d39a76e7Sxw161283 		CH_ALERT("%s: MC5 request queue parity error\n",
608*d39a76e7Sxw161283 			 adapter_name(adap));
609*d39a76e7Sxw161283 		mc5->intr_counts.parity_in_request_q_err++;
610*d39a76e7Sxw161283 	}
611*d39a76e7Sxw161283 
612*d39a76e7Sxw161283 	if (cause & F_MC5_INT_DISPATCHQ_PARITY_ERR) {
613*d39a76e7Sxw161283 		CH_ALERT("%s: MC5 dispatch queue parity error\n",
614*d39a76e7Sxw161283 			 adapter_name(adap));
615*d39a76e7Sxw161283 		mc5->intr_counts.parity_in_dispatch_q_err++;
616*d39a76e7Sxw161283 	}
617*d39a76e7Sxw161283 
618*d39a76e7Sxw161283 	if (cause & F_MC5_INT_DEL_ACT_EMPTY)
619*d39a76e7Sxw161283 		mc5->intr_counts.del_and_act_is_empty++;
620*d39a76e7Sxw161283 
621*d39a76e7Sxw161283 	if (cause & MC5_INT_FATAL)
622*d39a76e7Sxw161283 		t1_fatal_err(adap);
623*d39a76e7Sxw161283 
624*d39a76e7Sxw161283 	t1_write_reg_4(adap, A_MC5_INT_CAUSE, cause);
625*d39a76e7Sxw161283 }
626*d39a76e7Sxw161283 
t1_mc5_get_intr_counts(struct pemc5 * mc5)627*d39a76e7Sxw161283 const struct pemc5_intr_counts *t1_mc5_get_intr_counts(struct pemc5 *mc5)
628*d39a76e7Sxw161283 {
629*d39a76e7Sxw161283 	return &mc5->intr_counts;
630*d39a76e7Sxw161283 }
631*d39a76e7Sxw161283 
t1_mc5_create(adapter_t * adapter,int mode)632*d39a76e7Sxw161283 struct pemc5 * __devinit t1_mc5_create(adapter_t *adapter, int mode)
633*d39a76e7Sxw161283 {
634*d39a76e7Sxw161283 	struct pemc5 *mc5;
635*d39a76e7Sxw161283 	u32 cfg, bits_per_entry;
636*d39a76e7Sxw161283 
637*d39a76e7Sxw161283 	if (mode != MC5_MODE_144_BIT && mode != MC5_MODE_72_BIT)
638*d39a76e7Sxw161283 		return NULL;
639*d39a76e7Sxw161283 
640*d39a76e7Sxw161283 	mc5 = t1_os_malloc_wait_zero(sizeof(*mc5));
641*d39a76e7Sxw161283 	if (!mc5) return NULL;
642*d39a76e7Sxw161283 
643*d39a76e7Sxw161283 	mc5->adapter = adapter;
644*d39a76e7Sxw161283 	mc5->mode = (unsigned char) mode;
645*d39a76e7Sxw161283 
646*d39a76e7Sxw161283 	cfg = t1_read_reg_4(adapter, A_MC5_CONFIG);
647*d39a76e7Sxw161283 	mc5->part_size = G_TCAM_PART_SIZE(cfg);
648*d39a76e7Sxw161283 	mc5->part_type = (unsigned char) G_TCAM_PART_TYPE(cfg);
649*d39a76e7Sxw161283 	if (cfg & F_TCAM_PART_TYPE_HI)
650*d39a76e7Sxw161283 		mc5->part_type |= 4;
651*d39a76e7Sxw161283 
652*d39a76e7Sxw161283 	/*
653*d39a76e7Sxw161283 	 * Calculate the size of the TCAM based on the total memory, mode, and
654*d39a76e7Sxw161283 	 * count information retrieved from the hardware.
655*d39a76e7Sxw161283 	 */
656*d39a76e7Sxw161283 	bits_per_entry = mode == MC5_MODE_144_BIT ? 144 : 72;
657*d39a76e7Sxw161283 	mc5->tcam_size = tcam_part_size[mc5->part_size] / bits_per_entry;
658*d39a76e7Sxw161283 
659*d39a76e7Sxw161283 	return mc5;
660*d39a76e7Sxw161283 }
661*d39a76e7Sxw161283 
t1_mc5_destroy(struct pemc5 * mc5)662*d39a76e7Sxw161283 void t1_mc5_destroy(struct pemc5 *mc5)
663*d39a76e7Sxw161283 {
664*d39a76e7Sxw161283 	t1_os_free((void *)mc5, sizeof(*mc5));
665*d39a76e7Sxw161283 }
666*d39a76e7Sxw161283 
667*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72
mc5_cmp(const void * pi,const void * pj)668*d39a76e7Sxw161283 static int mc5_cmp(const void *pi, const void *pj)
669*d39a76e7Sxw161283 {
670*d39a76e7Sxw161283 	const u32 *pii = (const u32 *)pi;
671*d39a76e7Sxw161283 	const u32 *pjj = (const u32 *)pj;
672*d39a76e7Sxw161283 
673*d39a76e7Sxw161283 	if (*pii < *pjj)
674*d39a76e7Sxw161283 		return -1;
675*d39a76e7Sxw161283 
676*d39a76e7Sxw161283 	return *pii > *pjj;
677*d39a76e7Sxw161283 }
678*d39a76e7Sxw161283 
679*d39a76e7Sxw161283 /*
680*d39a76e7Sxw161283  * DESC: Write local IP addresses to the TCAM
681*d39a76e7Sxw161283  *
682*d39a76e7Sxw161283  * NOTES: IP addresses should be in host byte order. So, an IP address:
683*d39a76e7Sxw161283  *        of 10.0.0.140 == (data = 0x0A00008C)
684*d39a76e7Sxw161283  */
mc5_set_lip_entries(struct pemc5 * mc5,u32 * p,int num_of_lip_addresses)685*d39a76e7Sxw161283 static int mc5_set_lip_entries(struct pemc5 *mc5, u32 *p,
686*d39a76e7Sxw161283 			       int num_of_lip_addresses)
687*d39a76e7Sxw161283 {
688*d39a76e7Sxw161283 	int i;
689*d39a76e7Sxw161283 
690*d39a76e7Sxw161283 	/*
691*d39a76e7Sxw161283 	 * Disable compression and M bus mode so that the TP core
692*d39a76e7Sxw161283 	 * doesn't access the TCAM  while we are writing.
693*d39a76e7Sxw161283 	 */
694*d39a76e7Sxw161283 	u32 cfg = t1_read_reg_4(mc5->adapter, A_MC5_CONFIG);
695*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_CONFIG,
696*d39a76e7Sxw161283 		       cfg & ~(F_M_BUS_ENABLE | F_COMPRESSION_ENABLE));
697*d39a76e7Sxw161283 
698*d39a76e7Sxw161283 	/* MC5 should now be ready to program the LIP addresses. */
699*d39a76e7Sxw161283 	for (i = 0; i < num_of_lip_addresses; i++) {
700*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_LIP_RAM_DATA, p[i]);
701*d39a76e7Sxw161283 		t1_write_reg_4(mc5->adapter, A_MC5_LIP_RAM_ADDR, 0x100 + i);
702*d39a76e7Sxw161283 	}
703*d39a76e7Sxw161283 
704*d39a76e7Sxw161283 	/* Restore MC5 mode. */
705*d39a76e7Sxw161283 	t1_write_reg_4(mc5->adapter, A_MC5_CONFIG, cfg | F_COMPRESSION_ENABLE);
706*d39a76e7Sxw161283 	return 0;
707*d39a76e7Sxw161283 }
708*d39a76e7Sxw161283 
709*d39a76e7Sxw161283 /*
710*d39a76e7Sxw161283  * The purpose of this routine is to write all of the local IP addresses
711*d39a76e7Sxw161283  * into the TCAM in sorted order. This is a requirement from the TCAM.
712*d39a76e7Sxw161283  */
t1_mc5_lip_write_entries(struct pemc5 * mc5)713*d39a76e7Sxw161283 void t1_mc5_lip_write_entries(struct pemc5 *mc5)
714*d39a76e7Sxw161283 {
715*d39a76e7Sxw161283 	u32 filler = 0;
716*d39a76e7Sxw161283 	int i;
717*d39a76e7Sxw161283 
718*d39a76e7Sxw161283 	if (mc5->lip_index) {
719*d39a76e7Sxw161283 		qsort(mc5->lip, mc5->lip_index, sizeof(u32), mc5_cmp);
720*d39a76e7Sxw161283 		filler = mc5->lip[mc5->lip_index - 1];
721*d39a76e7Sxw161283 	}
722*d39a76e7Sxw161283 	for (i = mc5->lip_index; i < MC5_LIP_NUM_OF_ENTRIES; i++)
723*d39a76e7Sxw161283 		mc5->lip[i] = filler;
724*d39a76e7Sxw161283 	mc5_set_lip_entries(mc5, mc5->lip, MC5_LIP_NUM_OF_ENTRIES);
725*d39a76e7Sxw161283 }
726*d39a76e7Sxw161283 
t1_mc5_lip_clear_entries(struct pemc5 * mc5)727*d39a76e7Sxw161283 void t1_mc5_lip_clear_entries(struct pemc5 *mc5)
728*d39a76e7Sxw161283 {
729*d39a76e7Sxw161283 	mc5->lip_index = 0;
730*d39a76e7Sxw161283 }
731*d39a76e7Sxw161283 
732*d39a76e7Sxw161283 /*
733*d39a76e7Sxw161283  * Add a local IP address to the LIP table.
734*d39a76e7Sxw161283  */
t1_mc5_lip_add_entry(struct pemc5 * mc5,u32 lip)735*d39a76e7Sxw161283 int t1_mc5_lip_add_entry(struct pemc5 *mc5, u32 lip)
736*d39a76e7Sxw161283 {
737*d39a76e7Sxw161283 	if (mc5->lip_index >= MC5_LIP_NUM_OF_ENTRIES) return 1;
738*d39a76e7Sxw161283 	mc5->lip[mc5->lip_index++] = lip;
739*d39a76e7Sxw161283 	return 0;
740*d39a76e7Sxw161283 }
741*d39a76e7Sxw161283 #endif
742