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
t1_mc4_destroy(struct pemc4 * mc4)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. */
mc4_calc_size(adapter_t * adapter)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 */
wrreg_wait(adapter_t * adapter,unsigned int addr,u32 val)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
t1_mc4_init(struct pemc4 * mc4,unsigned int mc4_clock)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
t1_mc4_create(adapter_t * adapter)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
t1_mc4_get_size(struct pemc4 * mc4)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
t1_mc4_intr_enable(struct pemc4 * mc4)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
t1_mc4_intr_disable(struct pemc4 * mc4)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
t1_mc4_intr_clear(struct pemc4 * mc4)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
t1_mc4_intr_handler(struct pemc4 * mc4)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
t1_mc4_get_intr_counts(struct pemc4 * mc4)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 */
t1_mc4_bd_read(struct pemc4 * mc4,unsigned int start,unsigned int n,u32 * buf)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