xref: /illumos-gate/usr/src/uts/common/io/chxge/com/mc3.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
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  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24  */
25 
26 #include "common.h"
27 #include "regs.h"
28 #include "mc3.h"
29 
30 #ifdef CONFIG_CHELSIO_T1_1G
31 # include "fpga_defs.h"
32 #endif
33 
34 struct pemc3 {
35 	adapter_t *adapter;
36 	unsigned int size;
37 	struct pemc3_intr_counts intr_cnt;
38 };
39 
40 #define MC3_INTR_MASK (F_MC3_CORR_ERR | F_MC3_UNCORR_ERR | \
41 		       V_MC3_PARITY_ERR(M_MC3_PARITY_ERR) | F_MC3_ADDR_ERR)
42 #define MC3_INTR_FATAL (F_MC3_UNCORR_ERR | V_MC3_PARITY_ERR(M_MC3_PARITY_ERR) | F_MC3_ADDR_ERR)
43 
t1_mc3_intr_enable(struct pemc3 * mc3)44 void t1_mc3_intr_enable(struct pemc3 *mc3)
45 {
46 	u32 en = t1_read_reg_4(mc3->adapter, A_PL_ENABLE);
47 
48 	if (t1_is_asic(mc3->adapter)) {
49 		t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK);
50 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE, en | F_PL_INTR_MC3);
51 #ifdef CONFIG_CHELSIO_T1_1G
52 	} else {
53 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRENABLE,
54 			       MC3_INTR_MASK);
55 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
56 			       en | FPGA_PCIX_INTERRUPT_MC3);
57 #endif
58 	}
59 }
60 
t1_mc3_intr_disable(struct pemc3 * mc3)61 void t1_mc3_intr_disable(struct pemc3 *mc3)
62 {
63 	u32 pl_intr = t1_read_reg_4(mc3->adapter, A_PL_ENABLE);
64 
65 	if (t1_is_asic(mc3->adapter)) {
66 		t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, 0);
67 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
68 			       pl_intr & ~F_PL_INTR_MC3);
69 #ifdef CONFIG_CHELSIO_T1_1G
70 	} else {
71 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRENABLE, 0);
72 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
73 			       pl_intr & ~FPGA_PCIX_INTERRUPT_MC3);
74 #endif
75 	}
76 }
77 
t1_mc3_intr_clear(struct pemc3 * mc3)78 void t1_mc3_intr_clear(struct pemc3 *mc3)
79 {
80 	if (t1_is_asic(mc3->adapter)) {
81 		if (t1_is_T1B(mc3->adapter)) {
82 			/*
83 			 * Workaround for T1B bug: we must write to enable
84 			 * register to clear interrupts.
85 			 */
86 			u32 old_en;
87 
88 			old_en = t1_read_reg_4(mc3->adapter, A_MC3_INT_ENABLE);
89 			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE,
90 				       0xffffffff);
91 			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, old_en);
92 		} else
93 			t1_write_reg_4(mc3->adapter, A_MC3_INT_CAUSE,
94 				       0xffffffff);
95 
96 		t1_write_reg_4(mc3->adapter, A_PL_CAUSE, F_PL_INTR_MC3);
97 #ifdef CONFIG_CHELSIO_T1_1G
98 	} else {
99 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRCAUSE,
100 			       0xffffffff);
101 		t1_write_reg_4(mc3->adapter, A_PL_CAUSE,
102 			       FPGA_PCIX_INTERRUPT_MC3);
103 #endif
104 	}
105 }
106 
t1_mc3_intr_handler(struct pemc3 * mc3)107 int t1_mc3_intr_handler(struct pemc3 *mc3)
108 {
109 	adapter_t *adapter = mc3->adapter;
110 	int cause_reg = A_MC3_INT_CAUSE;
111 	u32 cause;
112 
113 #ifdef CONFIG_CHELSIO_T1_1G
114 	if (!t1_is_asic(adapter))
115 		cause_reg = FPGA_MC3_REG_INTRCAUSE;
116 #endif
117 	cause = t1_read_reg_4(adapter, cause_reg);
118 
119 	if (cause & F_MC3_CORR_ERR) {
120 		mc3->intr_cnt.corr_err++;
121 		CH_WARN("%s: MC3 correctable error at addr 0x%x, "
122 			"data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
123 			adapter_name(adapter),
124 			G_MC3_CE_ADDR(t1_read_reg_4(adapter, A_MC3_CE_ADDR)),
125 			t1_read_reg_4(adapter, A_MC3_CE_DATA0),
126 			t1_read_reg_4(adapter, A_MC3_CE_DATA1),
127 			t1_read_reg_4(adapter, A_MC3_CE_DATA2),
128 			t1_read_reg_4(adapter, A_MC3_CE_DATA3),
129 			t1_read_reg_4(adapter, A_MC3_CE_DATA4));
130 	}
131 
132 	if (cause & F_MC3_UNCORR_ERR) {
133 		mc3->intr_cnt.uncorr_err++;
134 		CH_ALERT("%s: MC3 uncorrectable error at addr 0x%x, "
135 			 "data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
136 			 adapter_name(adapter),
137 			 G_MC3_UE_ADDR(t1_read_reg_4(adapter, A_MC3_UE_ADDR)),
138 			 t1_read_reg_4(adapter, A_MC3_UE_DATA0),
139 			 t1_read_reg_4(adapter, A_MC3_UE_DATA1),
140 			 t1_read_reg_4(adapter, A_MC3_UE_DATA2),
141 			 t1_read_reg_4(adapter, A_MC3_UE_DATA3),
142 			 t1_read_reg_4(adapter, A_MC3_UE_DATA4));
143 	}
144 
145 	if (G_MC3_PARITY_ERR(cause)) {
146 		mc3->intr_cnt.parity_err++;
147 		CH_ALERT("%s: MC3 parity error 0x%x\n", adapter_name(adapter),
148 			 G_MC3_PARITY_ERR(cause));
149 	}
150 
151 	if (cause & F_MC3_ADDR_ERR) {
152 		mc3->intr_cnt.addr_err++;
153 		CH_ALERT("%s: MC3 address error\n", adapter_name(adapter));
154 	}
155 
156 	if (cause & MC3_INTR_FATAL)
157 		t1_fatal_err(adapter);
158 
159 	if (t1_is_T1B(adapter)) {
160 		/*
161 		 * Workaround for T1B bug: we must write to enable register to
162 		 * clear interrupts.
163 		 */
164 		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, cause);
165 		/* restore enable */
166 		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK);
167 	} else
168 		t1_write_reg_4(adapter, cause_reg, cause);
169 
170 	return 0;
171 }
172 
173 #define is_MC3A(adapter) (!t1_is_T1B(adapter))
174 
175 /*
176  * Write a value to a register and check that the write completed.  These
177  * writes normally complete in a cycle or two, so one read should suffice.
178  * The very first read exists to flush the posted write to the device.
179  */
wrreg_wait(adapter_t * adapter,unsigned int addr,u32 val)180 static int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
181 {
182 	t1_write_reg_4(adapter,	addr, val);
183 	val = t1_read_reg_4(adapter, addr);                   /* flush */
184 	if (!(t1_read_reg_4(adapter, addr) & F_BUSY))
185 		return 0;
186 	CH_ERR("%s: write to MC3 register 0x%x timed out\n",
187 	       adapter_name(adapter), addr);
188 	return -EIO;
189 }
190 
191 #define MC3_DLL_DONE (F_MASTER_DLL_LOCKED | F_MASTER_DLL_MAX_TAP_COUNT)
192 
t1_mc3_init(struct pemc3 * mc3,unsigned int mc3_clock)193 int t1_mc3_init(struct pemc3 *mc3, unsigned int mc3_clock)
194 {
195 	u32 val;
196 	unsigned int width, fast_asic, attempts;
197 	adapter_t *adapter = mc3->adapter;
198 
199 	/* Check to see if ASIC is running in slow mode. */
200 	val = t1_read_reg_4(adapter, A_MC3_CFG);
201 	width = is_MC3A(adapter) ? G_MC3_WIDTH(val) : 0;
202 	fast_asic = t1_is_asic(adapter) && !(val & F_MC3_SLOW);
203 
204 	val &= ~(V_MC3_BANK_CYCLE(M_MC3_BANK_CYCLE) |
205 		 V_REFRESH_CYCLE(M_REFRESH_CYCLE) |
206 		 V_PRECHARGE_CYCLE(M_PRECHARGE_CYCLE) |
207 		 F_ACTIVE_TO_READ_WRITE_DELAY |
208 		 V_ACTIVE_TO_PRECHARGE_DELAY(M_ACTIVE_TO_PRECHARGE_DELAY) |
209 		 V_WRITE_RECOVERY_DELAY(M_WRITE_RECOVERY_DELAY));
210 
211 	if (mc3_clock <= 100000000)
212 		val |= V_MC3_BANK_CYCLE(7) | V_REFRESH_CYCLE(4) |
213 			V_PRECHARGE_CYCLE(2) | V_ACTIVE_TO_PRECHARGE_DELAY(5) |
214 			V_WRITE_RECOVERY_DELAY(2);
215 	else if (mc3_clock <= 133000000)
216 		val |= V_MC3_BANK_CYCLE(9) | V_REFRESH_CYCLE(5) |
217 			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
218 			V_ACTIVE_TO_PRECHARGE_DELAY(6) |
219 			V_WRITE_RECOVERY_DELAY(2);
220 	else
221 		val |= V_MC3_BANK_CYCLE(0xA) | V_REFRESH_CYCLE(6) |
222 			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
223 			V_ACTIVE_TO_PRECHARGE_DELAY(7) |
224 			V_WRITE_RECOVERY_DELAY(3);
225 	t1_write_reg_4(adapter, A_MC3_CFG, val);
226 
227 	val = t1_read_reg_4(adapter, A_MC3_CFG);
228 	t1_write_reg_4(adapter, A_MC3_CFG, val | F_CLK_ENABLE);
229 	val = t1_read_reg_4(adapter, A_MC3_CFG);                 /* flush */
230 
231 	if (fast_asic) {                                     /* setup DLLs */
232 		val = t1_read_reg_4(adapter, A_MC3_STROBE);
233 		if (is_MC3A(adapter)) {
234 			t1_write_reg_4(adapter, A_MC3_STROBE,
235 				       val & ~F_SLAVE_DLL_RESET);
236 
237 			/* Wait for slave DLLs to lock */
238 			DELAY_US(2 * 512 / (mc3_clock / 1000000) + 1);
239 		} else {
240 			/* Initialize the master DLL and slave delay lines. */
241 			t1_write_reg_4(adapter, A_MC3_STROBE,
242 				       val & ~F_MASTER_DLL_RESET);
243 
244 			/* Wait for the master DLL to lock. */
245 			attempts = 100;
246 			do {
247 				DELAY_US(1);
248 				val = t1_read_reg_4(adapter, A_MC3_STROBE);
249 			} while (!(val & MC3_DLL_DONE) && --attempts);
250 			if (!(val & MC3_DLL_DONE)) {
251 				CH_ERR("%s: MC3 DLL lock failed\n",
252 				       adapter_name(adapter));
253 				goto out_fail;
254 			}
255 		}
256 	}
257 
258 	/* Initiate a precharge and wait for the precharge to complete. */
259 	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
260 		goto out_fail;
261 
262 	/* Set the SDRAM output drive strength and enable DLLs if needed */
263 	if (wrreg_wait(adapter, A_MC3_EXT_MODE, fast_asic ? 0 : 1))
264 		goto out_fail;
265 
266 	/* Specify the SDRAM operating parameters. */
267 	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x161 : 0x21))
268 		goto out_fail;
269 
270 	/* Initiate a precharge and wait for the precharge to complete. */
271 	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
272 		goto out_fail;
273 
274 	/* Initiate an immediate refresh and wait for the write to complete. */
275 	val = t1_read_reg_4(adapter, A_MC3_REFRESH);
276 	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
277 		goto out_fail;
278 
279 	/* 2nd immediate refresh as before */
280 	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
281 		goto out_fail;
282 
283 	/* Specify the SDRAM operating parameters. */
284 	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x61 : 0x21))
285 		goto out_fail;
286 
287 	/* Convert to KHz first to avoid 64-bit division. */
288 	mc3_clock /=  1000;                            /* Hz->KHz */
289 	mc3_clock = mc3_clock * 7812 + mc3_clock / 2;  /* ns */
290 	mc3_clock /= 1000000;                          /* KHz->MHz, ns->us */
291 
292 	/* Enable periodic refresh. */
293 	t1_write_reg_4(adapter, A_MC3_REFRESH,
294 		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc3_clock));
295 	(void) t1_read_reg_4(adapter, A_MC3_REFRESH);    /* flush */
296 
297 	t1_write_reg_4(adapter, A_MC3_ECC_CNTL,
298 		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);
299 
300 	/* Use the BIST engine to clear MC3 memory and initialize ECC. */
301 	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_BEG, 0);
302 	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_END, (mc3->size << width) - 1);
303 	t1_write_reg_4(adapter, A_MC3_BIST_DATA, 0);
304 	t1_write_reg_4(adapter, A_MC3_BIST_OP, V_OP(1) | 0x1f0);
305 	(void) t1_read_reg_4(adapter, A_MC3_BIST_OP);              /* flush */
306 
307 	attempts = 100;
308 	do {
309 		DELAY_MS(100);
310 		val = t1_read_reg_4(adapter, A_MC3_BIST_OP);
311 	} while ((val & F_BUSY) && --attempts);
312 	if (val & F_BUSY) {
313 		CH_ERR("%s: MC3 BIST timed out\n", adapter_name(adapter));
314 		goto out_fail;
315 	}
316 
317 	/* Enable normal memory accesses. */
318 	val = t1_read_reg_4(adapter, A_MC3_CFG);
319 	t1_write_reg_4(adapter, A_MC3_CFG, val | F_READY);
320 	return 0;
321 
322  out_fail:
323 	return -1;
324 }
325 
mc3_calc_size(const adapter_t * adapter,u32 cfg)326 static unsigned int __devinit mc3_calc_size(const adapter_t *adapter, u32 cfg)
327 {
328 	unsigned int banks = !!(cfg & F_BANKS) + 1;
329 	unsigned int org = !!(cfg & F_ORGANIZATION) + 1;
330 	unsigned int density = G_DENSITY(cfg);
331 
332 	unsigned int capacity_in_MB = is_MC3A(adapter) ?
333 		((256 << density) * banks) / (org << G_MC3_WIDTH(cfg)) :
334 		((128 << density) * (16 / org) * banks) / 8;
335 
336 	return capacity_in_MB * 1024 * 1024;
337 }
338 
t1_mc3_create(adapter_t * adapter)339 struct pemc3 * __devinit t1_mc3_create(adapter_t *adapter)
340 {
341 	struct pemc3 *mc3 = t1_os_malloc_wait_zero(sizeof(*mc3));
342 
343 	if (mc3) {
344 		mc3->adapter = adapter;
345 		mc3->size = mc3_calc_size(adapter,
346 					  t1_read_reg_4(adapter, A_MC3_CFG));
347 	}
348 	return mc3;
349 }
350 
t1_mc3_destroy(struct pemc3 * mc3)351 void t1_mc3_destroy(struct pemc3 *mc3)
352 {
353 	t1_os_free((void *)mc3, sizeof(*mc3));
354 }
355 
t1_mc3_get_size(struct pemc3 * mc3)356 unsigned int t1_mc3_get_size(struct pemc3 *mc3)
357 {
358 	return mc3->size;
359 }
360 
t1_mc3_get_intr_counts(struct pemc3 * mc3)361 const struct pemc3_intr_counts *t1_mc3_get_intr_counts(struct pemc3 *mc3)
362 {
363 	return &mc3->intr_cnt;
364 }
365