xref: /illumos-gate/usr/src/uts/common/io/chxge/com/mc4.c (revision fbd1c0dae6f4a2ccc2ce0527c7f19d3dd5ea90b8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * This file is part of the Chelsio T1 Ethernet driver.
24  *
25  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* mc4.c */
29 
30 #include "common.h"
31 #include "regs.h"
32 #include "mc4.h"
33 
34 struct pemc4 {
35 	adapter_t *adapter;
36 	unsigned int size;
37 	unsigned int nwords;           /* MC4 width in terms of 32-bit words */
38 	struct pemc4_intr_counts intr_cnt;
39 };
40 
41 void t1_mc4_destroy(struct pemc4 *mc4)
42 {
43 	t1_os_free((void *)mc4, sizeof(*mc4));
44 }
45 
46 #define is_MC4A(adapter) (!t1_is_T1B(adapter))
47 
48 /* Calculate amount of MC4 memory. */
49 static unsigned int __devinit mc4_calc_size(adapter_t *adapter)
50 {
51 	u32 mc4_cfg = t1_read_reg_4(adapter, A_MC4_CFG);
52 	unsigned int width = is_MC4A(adapter) ? G_MC4A_WIDTH(mc4_cfg) :
53 		                                !!(mc4_cfg & F_MC4_NARROW);
54 
55 	return (256 * 1024 * 1024) >> width;
56 }
57 
58 /*
59  * Write a value to a register and check that the write completed.  These
60  * writes normally complete in a cycle or two, so one read should suffice but
61  * just in case we give them a bit of grace period.  Note that the very first
62  * read exists to flush the posted write to the device.
63  */
64 static int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
65 {
66 	int attempts = 2;
67 
68 	t1_write_reg_4(adapter,	addr, val);
69 	val = t1_read_reg_4(adapter, addr);                   /* flush */
70 	while (attempts--) {
71 		if (!(t1_read_reg_4(adapter, addr) & F_BUSY))
72 			return 0;
73 		if (attempts)
74 			DELAY_US(1);
75 	}
76 	CH_ERR("%s: write to MC4 register 0x%x timed out\n",
77 	       adapter_name(adapter), addr);
78 	return -EIO;
79 }
80 
81 #define MC4_DLL_DONE (F_MASTER_DLL_LOCKED | F_MASTER_DLL_MAX_TAP_COUNT)
82 
83 int t1_mc4_init(struct pemc4 *mc4, unsigned int mc4_clock)
84 {
85 	int attempts;
86 	u32 val;
87 	unsigned int width, ext_mode, slow_mode;
88 	adapter_t *adapter = mc4->adapter;
89 
90 	/* Power up the FCRAMs. */
91 	val = t1_read_reg_4(adapter, A_MC4_CFG);
92 	t1_write_reg_4(adapter, A_MC4_CFG, val | F_POWER_UP);
93 	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */
94 
95 	if (is_MC4A(adapter)) {
96 		slow_mode = val & F_MC4A_SLOW;
97 		width = G_MC4A_WIDTH(val);
98 
99 		/* If we're not in slow mode, we are using the DLLs */
100 		if (!slow_mode) {
101 			/* Clear Reset */
102 			val = t1_read_reg_4(adapter, A_MC4_STROBE);
103 			t1_write_reg_4(adapter, A_MC4_STROBE,
104 				       val & ~F_SLAVE_DLL_RESET);
105 
106 			/* Wait for slave DLLs to lock */
107 			DELAY_US(2 * 512 / (mc4_clock / 1000000) + 1);
108 		}
109 	} else {
110 		slow_mode = val & F_MC4_SLOW;
111 		width = !!(val & F_MC4_NARROW);
112 
113 		/* Initializes the master DLL and slave delay lines. */
114 		if (t1_is_asic(adapter) && !slow_mode) {
115 			val = t1_read_reg_4(adapter, A_MC4_STROBE);
116 			t1_write_reg_4(adapter, A_MC4_STROBE,
117 				       val & ~F_MASTER_DLL_RESET);
118 
119 			/* Wait for the master DLL to lock. */
120 			attempts = 100;
121 			do {
122 				DELAY_US(1);
123 				val = t1_read_reg_4(adapter, A_MC4_STROBE);
124 			} while (!(val & MC4_DLL_DONE) && --attempts);
125 			if (!(val & MC4_DLL_DONE)) {
126 				CH_ERR("%s: MC4 DLL lock failed\n",
127 				       adapter_name(adapter));
128 				goto out_fail;
129 			}
130 		}
131 	}
132 
133 	mc4->nwords = 4 >> width;
134 
135 	/* Set the FCRAM output drive strength and enable DLLs if needed */
136 	ext_mode = t1_is_asic(adapter) && !slow_mode ? 0 : 1;
137 	if (wrreg_wait(adapter, A_MC4_EXT_MODE, ext_mode))
138 		goto out_fail;
139 
140 	/* Specify the FCRAM operating parameters */
141 	if (wrreg_wait(adapter, A_MC4_MODE, 0x32))
142 		goto out_fail;
143 
144 	/* Initiate an immediate refresh and wait for the write to complete. */
145 	val = t1_read_reg_4(adapter, A_MC4_REFRESH);
146 	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
147 		goto out_fail;
148 
149 	/* 2nd immediate refresh as before */
150 	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
151 		goto out_fail;
152 
153 	/* Convert to KHz first to avoid 64-bit division. */
154 	mc4_clock /= 1000;                            /* Hz->KHz */
155 	mc4_clock = mc4_clock * 7812 + mc4_clock / 2; /* ns */
156 	mc4_clock /= 1000000;                         /* KHz->MHz, ns->us */
157 
158 	/* Enable periodic refresh. */
159 	t1_write_reg_4(adapter, A_MC4_REFRESH,
160 		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc4_clock));
161 	(void) t1_read_reg_4(adapter, A_MC4_REFRESH);    /* flush */
162 
163 	t1_write_reg_4(adapter, A_MC4_ECC_CNTL,
164 		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);
165 
166 	/* Use the BIST engine to clear all of the MC4 memory. */
167 	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_BEG, 0);
168 	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_END, (mc4->size << width) - 1);
169 	t1_write_reg_4(adapter, A_MC4_BIST_DATA, 0);
170 	t1_write_reg_4(adapter, A_MC4_BIST_OP, V_OP(1) | 0x1f0);
171 	(void) t1_read_reg_4(adapter, A_MC4_BIST_OP);              /* flush */
172 
173 	attempts = 100;
174 	do {
175 		DELAY_MS(100);
176 		val = t1_read_reg_4(adapter, A_MC4_BIST_OP);
177 	} while ((val & F_BUSY) && --attempts);
178 	if (val & F_BUSY) {
179 		CH_ERR("%s: MC4 BIST timed out\n", adapter_name(adapter));
180 		goto out_fail;
181 	}
182 
183 	/* Enable normal memory accesses. */
184 	val = t1_read_reg_4(adapter, A_MC4_CFG);
185 	t1_write_reg_4(adapter, A_MC4_CFG, val | F_READY);
186 	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */
187 	return 0;
188 
189  out_fail:
190 	return -1;
191 }
192 
193 struct pemc4 * __devinit t1_mc4_create(adapter_t *adapter)
194 {
195 	struct pemc4 *mc4 = t1_os_malloc_wait_zero(sizeof(*mc4));
196 
197 	if (mc4) {
198 		mc4->adapter = adapter;
199 		mc4->size = mc4_calc_size(adapter);
200 	}
201 	return mc4;
202 }
203 
204 unsigned int t1_mc4_get_size(struct pemc4 *mc4)
205 {
206 	return mc4->size;
207 }
208 
209 #define MC4_INT_MASK (F_MC4_CORR_ERR | F_MC4_UNCORR_ERR | F_MC4_ADDR_ERR)
210 #define MC4_INT_FATAL (F_MC4_UNCORR_ERR | F_MC4_ADDR_ERR)
211 
212 void t1_mc4_intr_enable(struct pemc4 *mc4)
213 {
214 	u32 pl_intr;
215 
216 	if (t1_is_asic(mc4->adapter)) {
217 		t1_write_reg_4(mc4->adapter, A_MC4_INT_ENABLE, MC4_INT_MASK);
218 
219 		pl_intr = t1_read_reg_4(mc4->adapter, A_PL_ENABLE);
220 		t1_write_reg_4(mc4->adapter, A_PL_ENABLE,
221 			       pl_intr | F_PL_INTR_MC4);
222 	}
223 }
224 
225 void t1_mc4_intr_disable(struct pemc4 *mc4)
226 {
227 	u32 pl_intr;
228 
229 	if (t1_is_asic(mc4->adapter)) {
230 		t1_write_reg_4(mc4->adapter, A_MC4_INT_ENABLE, 0);
231 
232 		pl_intr = t1_read_reg_4(mc4->adapter, A_PL_ENABLE);
233 		t1_write_reg_4(mc4->adapter, A_PL_ENABLE,
234 			       pl_intr & ~F_PL_INTR_MC4);
235 	}
236 }
237 
238 void t1_mc4_intr_clear(struct pemc4 *mc4)
239 {
240 	if (t1_is_asic(mc4->adapter)) {
241 		t1_write_reg_4(mc4->adapter, A_MC4_INT_CAUSE, 0xffffffff);
242 		t1_write_reg_4(mc4->adapter, A_PL_CAUSE, F_PL_INTR_MC4);
243 	}
244 }
245 
246 int t1_mc4_intr_handler(struct pemc4 *mc4)
247 {
248 	adapter_t *adapter = mc4->adapter;
249 	u32 cause = t1_read_reg_4(adapter, A_MC4_INT_CAUSE);
250 
251 	if (cause & F_MC4_CORR_ERR) {
252 		mc4->intr_cnt.corr_err++;
253 		CH_WARN("%s: MC4 correctable error at addr 0x%x, "
254 			"data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
255 			adapter_name(adapter),
256 			G_MC4_CE_ADDR(t1_read_reg_4(adapter, A_MC4_CE_ADDR)),
257 			t1_read_reg_4(adapter, A_MC4_CE_DATA0),
258 			t1_read_reg_4(adapter, A_MC4_CE_DATA1),
259 			t1_read_reg_4(adapter, A_MC4_CE_DATA2),
260 			t1_read_reg_4(adapter, A_MC4_CE_DATA3),
261 			t1_read_reg_4(adapter, A_MC4_CE_DATA4));
262 	}
263 
264 	if (cause & F_MC4_UNCORR_ERR) {
265 		mc4->intr_cnt.uncorr_err++;
266 		CH_ALERT("%s: MC4 uncorrectable error at addr 0x%x, "
267 			 "data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
268 			 adapter_name(adapter),
269 			 G_MC4_UE_ADDR(t1_read_reg_4(adapter, A_MC4_UE_ADDR)),
270 			 t1_read_reg_4(adapter, A_MC4_UE_DATA0),
271 			 t1_read_reg_4(adapter, A_MC4_UE_DATA1),
272 			 t1_read_reg_4(adapter, A_MC4_UE_DATA2),
273 			 t1_read_reg_4(adapter, A_MC4_UE_DATA3),
274 			 t1_read_reg_4(adapter, A_MC4_UE_DATA4));
275 	}
276 
277 	if (cause & F_MC4_ADDR_ERR) {
278 		mc4->intr_cnt.addr_err++;
279 		CH_ALERT("%s: MC4 address error\n", adapter_name(adapter));
280 	}
281 
282 	if (cause & MC4_INT_FATAL)
283 		t1_fatal_err(adapter);
284 
285 	t1_write_reg_4(mc4->adapter, A_MC4_INT_CAUSE, cause);
286 	return 0;
287 }
288 
289 const struct pemc4_intr_counts *t1_mc4_get_intr_counts(struct pemc4 *mc4)
290 {
291 	return &mc4->intr_cnt;
292 }
293 
294 /*
295  * Read n 256-bit words from MC4 starting at word start, using backdoor
296  * accesses.
297  */
298 int t1_mc4_bd_read(struct pemc4 *mc4, unsigned int start, unsigned int n,
299 		   u32 *buf)
300 {
301 	adapter_t *adap = mc4->adapter;
302 	unsigned int size256 = mc4->size / 32, c = 8 / mc4->nwords, i;
303 
304 	if (start >= size256 || start + n > size256)
305 		return -EINVAL;
306 
307 	for (i = 8, start *= 16 * c, n *= c; n; --n, start += 16) {
308 		int attempts = 10;
309 		u32 val;
310 
311 		t1_write_reg_4(adap, A_MC4_BD_ADDR, start);
312 		t1_write_reg_4(adap, A_MC4_BD_OP, 0);
313 		val = t1_read_reg_4(adap, A_MC4_BD_OP);
314 		while ((val & F_BUSY) && attempts--)
315 			val = t1_read_reg_4(adap, A_MC4_BD_OP);
316 
317 		if (val & F_BUSY)
318 			return -EIO;
319 
320 		buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA3);
321 		if (mc4->nwords >= 2)
322 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA2);
323 		if (mc4->nwords == 4) {
324 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA1);
325 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA0);
326 		}
327 		if (i == 0) {
328 			i = 8;
329 			buf += 8;
330 		}
331 	}
332 	return 0;
333 }
334