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