1 /* $NetBSD: memc.c,v 1.4 2004/05/16 15:44:11 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Steve C. Woodford. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Support for the MEMECC and MEMC40 memory controllers on MVME68K 41 * and MVME88K boards. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: memc.c,v 1.4 2004/05/16 15:44:11 wiz Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/kernel.h> 49 #include <sys/systm.h> 50 #include <sys/device.h> 51 #include <sys/malloc.h> 52 53 #include <machine/cpu.h> 54 #include <machine/bus.h> 55 56 #include <dev/mvme/memcvar.h> 57 #include <dev/mvme/memcreg.h> 58 #include <dev/mvme/pcctwovar.h> 59 #include <dev/mvme/pcctworeg.h> 60 61 #include <dev/vme/vmevar.h> 62 #include <dev/mvme/mvmebus.h> 63 #include <dev/mvme/vme_twovar.h> 64 #include <dev/mvme/vme_tworeg.h> 65 66 67 static struct memc_softc *memc_softcs[MEMC_NDEVS]; 68 static int memc_softc_count; 69 70 static void memc040_attach(struct memc_softc *); 71 static void memecc_attach(struct memc_softc *); 72 static void memc_hook_error_intr(struct memc_softc *, int (*)(void *)); 73 74 static int memecc_err_intr(void *); 75 static void memecc_log_error(struct memc_softc *, u_int8_t, int, int); 76 77 #define MEMECC_SCRUBBER_PERIOD 86400 /* ~24 hours */ 78 79 /* 80 * The following stuff is used to decode the ECC syndrome code so 81 * that we can figure out exactly which address/bit needed to be 82 * corrected. 83 */ 84 #define MEMECC_SYN_BIT_MASK 0x0fu 85 #define MEMECC_SYN_BANK_A (0x00u << 4) 86 #define MEMECC_SYN_BANK_B (0x01u << 4) 87 #define MEMECC_SYN_BANK_C (0x02u << 4) 88 #define MEMECC_SYN_BANK_D (0x03u << 4) 89 #define MEMECC_SYN_BANK_SHIFT 4 90 #define MEMECC_SYN_BANK_MASK 0x03u 91 #define MEMECC_SYN_CHECKBIT_ERR 0x80u 92 #define MEMECC_SYN_INVALID 0xffu 93 94 static u_int8_t memc_syn_decode[256] = { 95 MEMECC_SYN_INVALID, /* 0x00 */ 96 MEMECC_SYN_CHECKBIT_ERR | 0, /* 0x01: Checkbit 0 */ 97 MEMECC_SYN_CHECKBIT_ERR | 1, /* 0x02: Checkbit 1 */ 98 MEMECC_SYN_INVALID, /* 0x03 */ 99 MEMECC_SYN_CHECKBIT_ERR | 2, /* 0x04: Checkbit 2 */ 100 MEMECC_SYN_INVALID, /* 0x05 */ 101 MEMECC_SYN_INVALID, /* 0x06 */ 102 MEMECC_SYN_BANK_C | 10, /* 0x07: Bank C 10/26 */ 103 MEMECC_SYN_CHECKBIT_ERR | 3, /* 0x08: Checkbit 3 */ 104 MEMECC_SYN_INVALID, /* 0x09 */ 105 MEMECC_SYN_INVALID, /* 0x0a */ 106 MEMECC_SYN_BANK_C | 13, /* 0x0b: Bank C 13/29 */ 107 MEMECC_SYN_INVALID, /* 0x0c */ 108 MEMECC_SYN_BANK_D | 1, /* 0x0d: Bank D 1/17 */ 109 MEMECC_SYN_BANK_D | 2, /* 0x0e: Bank D 2/18 */ 110 MEMECC_SYN_INVALID, /* 0x0f */ 111 MEMECC_SYN_CHECKBIT_ERR | 4, /* 0x10: Checkbit 4 */ 112 MEMECC_SYN_INVALID, /* 0x11 */ 113 MEMECC_SYN_INVALID, /* 0x12 */ 114 MEMECC_SYN_BANK_C | 14, /* 0x13: Bank C 14/30 */ 115 MEMECC_SYN_INVALID, /* 0x14 */ 116 MEMECC_SYN_BANK_D | 4, /* 0x15: Bank D 4/20 */ 117 MEMECC_SYN_BANK_D | 5, /* 0x16: Bank D 5/21 */ 118 MEMECC_SYN_INVALID, /* 0x17 */ 119 MEMECC_SYN_INVALID, /* 0x18 */ 120 MEMECC_SYN_BANK_D | 8, /* 0x19: Bank D 8/24 */ 121 MEMECC_SYN_BANK_D | 9, /* 0x1a: Bank D 9/25 */ 122 MEMECC_SYN_INVALID, /* 0x1b */ 123 MEMECC_SYN_BANK_D | 10, /* 0x1c: Bank D 10/26 */ 124 MEMECC_SYN_INVALID, /* 0x1d */ 125 MEMECC_SYN_INVALID, /* 0x1e */ 126 MEMECC_SYN_INVALID, /* 0x1f */ 127 MEMECC_SYN_CHECKBIT_ERR | 5, /* 0x20: Checkbit 5 */ 128 MEMECC_SYN_INVALID, /* 0x21 */ 129 MEMECC_SYN_INVALID, /* 0x22 */ 130 MEMECC_SYN_BANK_C | 0, /* 0x23: Bank C 0/16 */ 131 MEMECC_SYN_INVALID, /* 0x24 */ 132 MEMECC_SYN_BANK_D | 7, /* 0x25: Bank D 7/23 */ 133 MEMECC_SYN_BANK_D | 6, /* 0x26: Bank D 6/22 */ 134 MEMECC_SYN_INVALID, /* 0x27 */ 135 MEMECC_SYN_INVALID, /* 0x28 */ 136 MEMECC_SYN_BANK_A | 15, /* 0x29: Bank A 15/31 */ 137 MEMECC_SYN_BANK_D | 12, /* 0x2a: Bank D 12/28 */ 138 MEMECC_SYN_INVALID, /* 0x2b */ 139 MEMECC_SYN_BANK_D | 13, /* 0x2c: Bank D 13/29 */ 140 MEMECC_SYN_INVALID, /* 0x2d */ 141 MEMECC_SYN_INVALID, /* 0x2e */ 142 MEMECC_SYN_INVALID, /* 0x2f */ 143 MEMECC_SYN_INVALID, /* 0x30 */ 144 MEMECC_SYN_BANK_A | 14, /* 0x31: Bank A 14/30 */ 145 MEMECC_SYN_BANK_A | 0, /* 0x32: Bank A 0/16 */ 146 MEMECC_SYN_INVALID, /* 0x33 */ 147 MEMECC_SYN_BANK_A | 1, /* 0x34: Bank A 1/17 */ 148 MEMECC_SYN_INVALID, /* 0x35 */ 149 MEMECC_SYN_INVALID, /* 0x36 */ 150 MEMECC_SYN_INVALID, /* 0x37 */ 151 MEMECC_SYN_BANK_A | 2, /* 0x38: Bank A 2/18 */ 152 MEMECC_SYN_INVALID, /* 0x39 */ 153 MEMECC_SYN_INVALID, /* 0x3a */ 154 MEMECC_SYN_INVALID, /* 0x3b */ 155 MEMECC_SYN_INVALID, /* 0x3c */ 156 MEMECC_SYN_BANK_C | 3, /* 0x3d: Bank C 3/19 */ 157 MEMECC_SYN_INVALID, /* 0x3e */ 158 MEMECC_SYN_INVALID, /* 0x3f */ 159 MEMECC_SYN_CHECKBIT_ERR | 6, /* 0x40: Checkbit 6 */ 160 MEMECC_SYN_INVALID, /* 0x41 */ 161 MEMECC_SYN_INVALID, /* 0x42 */ 162 MEMECC_SYN_BANK_C | 1, /* 0x43: Bank C 1/17 */ 163 MEMECC_SYN_INVALID, /* 0x44 */ 164 MEMECC_SYN_BANK_C | 4, /* 0x45: Bank C 4/20 */ 165 MEMECC_SYN_BANK_C | 8, /* 0x46: Bank C 8/24 */ 166 MEMECC_SYN_INVALID, /* 0x47 */ 167 MEMECC_SYN_INVALID, /* 0x48 */ 168 MEMECC_SYN_BANK_C | 7, /* 0x49: Bank C 7/23 */ 169 MEMECC_SYN_BANK_D | 15, /* 0x4a: Bank D 15/31 */ 170 MEMECC_SYN_INVALID, /* 0x4b */ 171 MEMECC_SYN_BANK_D | 14, /* 0x4c: Bank D 14/30 */ 172 MEMECC_SYN_INVALID, /* 0x4d */ 173 MEMECC_SYN_INVALID, /* 0x4e */ 174 MEMECC_SYN_BANK_B | 3, /* 0x4f: Bank B 3/19 */ 175 MEMECC_SYN_INVALID, /* 0x50 */ 176 MEMECC_SYN_BANK_B | 4, /* 0x51: Bank B 4/20 */ 177 MEMECC_SYN_BANK_B | 7, /* 0x52: Bank B 7/23 */ 178 MEMECC_SYN_INVALID, /* 0x53 */ 179 MEMECC_SYN_BANK_A | 4, /* 0x54: Bank A 4/20 */ 180 MEMECC_SYN_INVALID, /* 0x55 */ 181 MEMECC_SYN_INVALID, /* 0x56 */ 182 MEMECC_SYN_INVALID, /* 0x57 */ 183 MEMECC_SYN_BANK_A | 5, /* 0x58: Bank A 5/21 */ 184 MEMECC_SYN_INVALID, /* 0x59 */ 185 MEMECC_SYN_INVALID, /* 0x5a */ 186 MEMECC_SYN_INVALID, /* 0x5b */ 187 MEMECC_SYN_INVALID, /* 0x5c */ 188 MEMECC_SYN_INVALID, /* 0x5d */ 189 MEMECC_SYN_INVALID, /* 0x5e */ 190 MEMECC_SYN_INVALID, /* 0x5f */ 191 MEMECC_SYN_INVALID, /* 0x60 */ 192 MEMECC_SYN_BANK_B | 5, /* 0x61: Bank B 5/21 */ 193 MEMECC_SYN_BANK_B | 6, /* 0x62: Bank B 6/22 */ 194 MEMECC_SYN_INVALID, /* 0x63 */ 195 MEMECC_SYN_BANK_A | 8, /* 0x64: Bank A 8/24 */ 196 MEMECC_SYN_INVALID, /* 0x65 */ 197 MEMECC_SYN_INVALID, /* 0x66 */ 198 MEMECC_SYN_INVALID, /* 0x67 */ 199 MEMECC_SYN_BANK_A | 9, /* 0x68: Bank A 9/25 */ 200 MEMECC_SYN_INVALID, /* 0x69 */ 201 MEMECC_SYN_INVALID, /* 0x6a */ 202 MEMECC_SYN_INVALID, /* 0x6b */ 203 MEMECC_SYN_INVALID, /* 0x6c */ 204 MEMECC_SYN_INVALID, /* 0x6d */ 205 MEMECC_SYN_INVALID, /* 0x6e */ 206 MEMECC_SYN_INVALID, /* 0x6f */ 207 MEMECC_SYN_BANK_A | 10, /* 0x70: Bank A 10/26 */ 208 MEMECC_SYN_INVALID, /* 0x71 */ 209 MEMECC_SYN_INVALID, /* 0x72 */ 210 MEMECC_SYN_INVALID, /* 0x73 */ 211 MEMECC_SYN_INVALID, /* 0x74 */ 212 MEMECC_SYN_INVALID, /* 0x75 */ 213 MEMECC_SYN_INVALID, /* 0x76 */ 214 MEMECC_SYN_INVALID, /* 0x77 */ 215 MEMECC_SYN_INVALID, /* 0x78 */ 216 MEMECC_SYN_INVALID, /* 0x79 */ 217 MEMECC_SYN_BANK_C | 11, /* 0x7a: Bank C 11/27 */ 218 MEMECC_SYN_INVALID, /* 0x7b */ 219 MEMECC_SYN_INVALID, /* 0x7c */ 220 MEMECC_SYN_INVALID, /* 0x7d */ 221 MEMECC_SYN_INVALID, /* 0x7e */ 222 MEMECC_SYN_INVALID, /* 0x7f */ 223 MEMECC_SYN_CHECKBIT_ERR | 7, /* 0x80: Checkbit 7 */ 224 MEMECC_SYN_INVALID, /* 0x81 */ 225 MEMECC_SYN_INVALID, /* 0x82 */ 226 MEMECC_SYN_BANK_C | 2, /* 0x83: Bank C 2/18 */ 227 MEMECC_SYN_INVALID, /* 0x84 */ 228 MEMECC_SYN_BANK_C | 5, /* 0x85: Bank C 5/21 */ 229 MEMECC_SYN_BANK_C | 9, /* 0x86: Bank C 9/25 */ 230 MEMECC_SYN_INVALID, /* 0x87 */ 231 MEMECC_SYN_INVALID, /* 0x88 */ 232 MEMECC_SYN_BANK_C | 6, /* 0x89: Bank C 6/22 */ 233 MEMECC_SYN_BANK_C | 12, /* 0x8a: Bank C 12/28 */ 234 MEMECC_SYN_INVALID, /* 0x8b */ 235 MEMECC_SYN_BANK_D | 0, /* 0x8c: Bank D 0/16 */ 236 MEMECC_SYN_INVALID, /* 0x8d */ 237 MEMECC_SYN_INVALID, /* 0x8e */ 238 MEMECC_SYN_INVALID, /* 0x8f */ 239 MEMECC_SYN_INVALID, /* 0x90 */ 240 MEMECC_SYN_BANK_B | 8, /* 0x91: Bank B 8/24 */ 241 MEMECC_SYN_BANK_C | 15, /* 0x92: Bank C 15/31 */ 242 MEMECC_SYN_INVALID, /* 0x93 */ 243 MEMECC_SYN_BANK_A | 7, /* 0x94: Bank A 7/23 */ 244 MEMECC_SYN_INVALID, /* 0x95 */ 245 MEMECC_SYN_INVALID, /* 0x96 */ 246 MEMECC_SYN_INVALID, /* 0x97 */ 247 MEMECC_SYN_BANK_A | 6, /* 0x98: Bank A 6/22 */ 248 MEMECC_SYN_INVALID, /* 0x99 */ 249 MEMECC_SYN_INVALID, /* 0x9a */ 250 MEMECC_SYN_INVALID, /* 0x9b */ 251 MEMECC_SYN_INVALID, /* 0x9c */ 252 MEMECC_SYN_INVALID, /* 0x9d */ 253 MEMECC_SYN_BANK_B | 11, /* 0x9e: Bank B 11/27 */ 254 MEMECC_SYN_INVALID, /* 0x9f */ 255 MEMECC_SYN_INVALID, /* 0xa0 */ 256 MEMECC_SYN_BANK_B | 9, /* 0xa1: Bank B 9/25 */ 257 MEMECC_SYN_BANK_B | 12, /* 0xa2: Bank B 12/28 */ 258 MEMECC_SYN_INVALID, /* 0xa3 */ 259 MEMECC_SYN_BANK_B | 15, /* 0xa4: Bank B 15/31 */ 260 MEMECC_SYN_INVALID, /* 0xa5 */ 261 MEMECC_SYN_INVALID, /* 0xa6 */ 262 MEMECC_SYN_BANK_A | 11, /* 0xa7: Bank A 11/27 */ 263 MEMECC_SYN_BANK_A | 12, /* 0xa8: Bank A 12/28 */ 264 MEMECC_SYN_INVALID, /* 0xa9 */ 265 MEMECC_SYN_INVALID, /* 0xaa */ 266 MEMECC_SYN_INVALID, /* 0xab */ 267 MEMECC_SYN_INVALID, /* 0xac */ 268 MEMECC_SYN_INVALID, /* 0xad */ 269 MEMECC_SYN_INVALID, /* 0xae */ 270 MEMECC_SYN_INVALID, /* 0xaf */ 271 MEMECC_SYN_BANK_A | 13, /* 0xb0: Bank A 13/29 */ 272 MEMECC_SYN_INVALID, /* 0xb1 */ 273 MEMECC_SYN_INVALID, /* 0xb2 */ 274 MEMECC_SYN_INVALID, /* 0xb3 */ 275 MEMECC_SYN_INVALID, /* 0xb4 */ 276 MEMECC_SYN_INVALID, /* 0xb5 */ 277 MEMECC_SYN_INVALID, /* 0xb6 */ 278 MEMECC_SYN_INVALID, /* 0xb7 */ 279 MEMECC_SYN_INVALID, /* 0xb8 */ 280 MEMECC_SYN_INVALID, /* 0xb9 */ 281 MEMECC_SYN_INVALID, /* 0xba */ 282 MEMECC_SYN_INVALID, /* 0xbb */ 283 MEMECC_SYN_INVALID, /* 0xbc */ 284 MEMECC_SYN_INVALID, /* 0xbd */ 285 MEMECC_SYN_INVALID, /* 0xbe */ 286 MEMECC_SYN_INVALID, /* 0xbf */ 287 MEMECC_SYN_INVALID, /* 0xc0 */ 288 MEMECC_SYN_BANK_B | 10, /* 0xc1: Bank B 10/26 */ 289 MEMECC_SYN_BANK_B | 13, /* 0xc2: Bank B 13/29 */ 290 MEMECC_SYN_INVALID, /* 0xc3 */ 291 MEMECC_SYN_BANK_B | 14, /* 0xc4: Bank B 14/30 */ 292 MEMECC_SYN_INVALID, /* 0xc5 */ 293 MEMECC_SYN_INVALID, /* 0xc6 */ 294 MEMECC_SYN_INVALID, /* 0xc7 */ 295 MEMECC_SYN_BANK_B | 0, /* 0xc8: Bank B 0/16 */ 296 MEMECC_SYN_INVALID, /* 0xc9 */ 297 MEMECC_SYN_INVALID, /* 0xca */ 298 MEMECC_SYN_INVALID, /* 0xcb */ 299 MEMECC_SYN_INVALID, /* 0xcc */ 300 MEMECC_SYN_INVALID, /* 0xcd */ 301 MEMECC_SYN_INVALID, /* 0xce */ 302 MEMECC_SYN_INVALID, /* 0xcf */ 303 MEMECC_SYN_BANK_B | 1, /* 0xd0: Bank B 1/17 */ 304 MEMECC_SYN_INVALID, /* 0xd1 */ 305 MEMECC_SYN_INVALID, /* 0xd2 */ 306 MEMECC_SYN_BANK_A | 3, /* 0xd3: Bank A 3/19 */ 307 MEMECC_SYN_INVALID, /* 0xd4 */ 308 MEMECC_SYN_INVALID, /* 0xd5 */ 309 MEMECC_SYN_INVALID, /* 0xd6 */ 310 MEMECC_SYN_INVALID, /* 0xd7 */ 311 MEMECC_SYN_INVALID, /* 0xd8 */ 312 MEMECC_SYN_INVALID, /* 0xd9 */ 313 MEMECC_SYN_INVALID, /* 0xda */ 314 MEMECC_SYN_INVALID, /* 0xdb */ 315 MEMECC_SYN_INVALID, /* 0xdc */ 316 MEMECC_SYN_INVALID, /* 0xdd */ 317 MEMECC_SYN_INVALID, /* 0xde */ 318 MEMECC_SYN_INVALID, /* 0xdf */ 319 MEMECC_SYN_BANK_B | 2, /* 0xe0: Bank B 2/18 */ 320 MEMECC_SYN_INVALID, /* 0xe1 */ 321 MEMECC_SYN_INVALID, /* 0xe2 */ 322 MEMECC_SYN_INVALID, /* 0xe3 */ 323 MEMECC_SYN_INVALID, /* 0xe4 */ 324 MEMECC_SYN_INVALID, /* 0xe5 */ 325 MEMECC_SYN_INVALID, /* 0xe6 */ 326 MEMECC_SYN_INVALID, /* 0xe7 */ 327 MEMECC_SYN_INVALID, /* 0xe8 */ 328 MEMECC_SYN_BANK_D | 11, /* 0xe9: Bank D 11/27 */ 329 MEMECC_SYN_INVALID, /* 0xea */ 330 MEMECC_SYN_INVALID, /* 0xeb */ 331 MEMECC_SYN_INVALID, /* 0xec */ 332 MEMECC_SYN_INVALID, /* 0xed */ 333 MEMECC_SYN_INVALID, /* 0xee */ 334 MEMECC_SYN_INVALID, /* 0xef */ 335 MEMECC_SYN_INVALID, /* 0xf0 */ 336 MEMECC_SYN_INVALID, /* 0xf1 */ 337 MEMECC_SYN_INVALID, /* 0xf2 */ 338 MEMECC_SYN_INVALID, /* 0xf3 */ 339 MEMECC_SYN_BANK_D | 3, /* 0xf4: Bank D 3/19 */ 340 MEMECC_SYN_INVALID, /* 0xf5 */ 341 MEMECC_SYN_INVALID, /* 0xf6 */ 342 MEMECC_SYN_INVALID, /* 0xf7 */ 343 MEMECC_SYN_INVALID, /* 0xf8 */ 344 MEMECC_SYN_INVALID, /* 0xf9 */ 345 MEMECC_SYN_INVALID, /* 0xfa */ 346 MEMECC_SYN_INVALID, /* 0xfb */ 347 MEMECC_SYN_INVALID, /* 0xfc */ 348 MEMECC_SYN_INVALID, /* 0xfd */ 349 MEMECC_SYN_INVALID, /* 0xfe */ 350 MEMECC_SYN_INVALID /* 0xff */ 351 }; 352 353 354 /* ARGSUSED */ 355 void 356 memc_init(sc) 357 struct memc_softc *sc; 358 { 359 u_int8_t chipid; 360 u_int8_t memcfg; 361 362 if (memc_softc_count == MEMC_NDEVS) 363 panic("memc_attach: too many memc devices!"); 364 365 memc_softcs[memc_softc_count++] = sc; 366 367 chipid = memc_reg_read(sc, MEMC_REG_CHIP_ID); 368 memcfg = memc_reg_read(sc, MEMC_REG_MEMORY_CONFIG); 369 370 printf(": %dMB %s Memory Controller Chip (Rev %d)\n", 371 MEMC_MEMORY_CONFIG_2_MB(memcfg), 372 (chipid == MEMC_CHIP_ID_MEMC040) ? "Parity" : "ECC", 373 memc_reg_read(sc, MEMC_REG_CHIP_REVISION)); 374 375 printf("%s: Base Address: 0x%x, ", sc->sc_dev.dv_xname, 376 MEMC_BASE_ADDRESS(memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_HI), 377 memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_LO))); 378 379 printf("Fast RAM Read %sabled\n", (memc_reg_read(sc, 380 MEMC_REG_MEMORY_CONFIG) & MEMC_MEMORY_CONFIG_FSTRD) ? 381 "En" : "Dis"); 382 383 switch (chipid) { 384 case MEMC_CHIP_ID_MEMC040: 385 memc040_attach(sc); 386 break; 387 case MEMC_CHIP_ID_MEMECC: 388 memecc_attach(sc); 389 break; 390 } 391 } 392 393 static void 394 memc040_attach(struct memc_softc *sc) 395 { 396 397 /* XXX: TBD */ 398 } 399 400 static void 401 memecc_attach(struct memc_softc *sc) 402 { 403 u_int8_t rv; 404 405 /* 406 * First, disable bus-error and interrupts on ECC errors. 407 * Also switch off SWAIT to enhance performance. 408 */ 409 rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL); 410 rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN | 411 MEMECC_DRAM_CONTROL_NCEIEN | 412 MEMECC_DRAM_CONTROL_SWAIT); 413 rv |= MEMECC_DRAM_CONTROL_RAMEN; 414 memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv); 415 rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL); 416 rv &= ~(MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN); 417 memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL, rv); 418 419 /* 420 * Ensure error correction is enabled 421 */ 422 rv = memc_reg_read(sc, MEMECC_REG_DATA_CONTROL); 423 rv &= ~MEMECC_DATA_CONTROL_DERC; 424 memc_reg_write(sc, MEMECC_REG_DATA_CONTROL, rv); 425 426 /* 427 * Clear any error currently in the logs 428 */ 429 rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER); 430 #ifdef DIAGNOSTIC 431 if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0) 432 memecc_log_error(sc, rv, 0, 0); 433 #endif 434 memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER, 435 MEMECC_ERROR_LOGGER_ERRLOG); 436 437 rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + 2); 438 #ifdef DIAGNOSTIC 439 if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0) 440 memecc_log_error(sc, rv, 2, 0); 441 #endif 442 memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + 2, 443 MEMECC_ERROR_LOGGER_ERRLOG); 444 445 /* 446 * Now hook the ECC error interrupt 447 */ 448 if (memc_softc_count == 1) 449 memc_hook_error_intr(sc, memecc_err_intr); 450 451 /* 452 * Enable bus-error and interrupt on uncorrectable ECC 453 */ 454 rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL); 455 rv |= MEMECC_DRAM_CONTROL_NCEBEN | MEMECC_DRAM_CONTROL_NCEIEN; 456 memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv); 457 458 /* 459 * Set up the scrubber to run roughly once every 24 hours 460 * with minimal impact on the local bus. With these on/off 461 * time settings, a scrub of a 32MB DRAM board will take 462 * roughly half a minute. 463 */ 464 memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_HI, 465 MEMECC_SCRUB_PERIOD_HI(MEMECC_SCRUBBER_PERIOD)); 466 memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_LO, 467 MEMECC_SCRUB_PERIOD_LO(MEMECC_SCRUBBER_PERIOD)); 468 memc_reg_write(sc, MEMECC_REG_SCRUB_TIME_ONOFF, 469 MEMECC_SCRUB_TIME_ON_1 | MEMECC_SCRUB_TIME_OFF_16); 470 471 /* 472 * Start the scrubber, and enable interrupts on Correctable errors 473 */ 474 memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL, 475 memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL) | 476 MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN); 477 478 printf("%s: Logging ECC errors at ipl %d\n", sc->sc_dev.dv_xname, 479 MEMC_IRQ_LEVEL); 480 } 481 482 static void 483 memc_hook_error_intr(struct memc_softc *sc, int (*func)(void *)) 484 { 485 486 #if 0 487 evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR, 488 (*sc->sc_isrevcnt)(sc->sc_isrcookie, MEMC_IRQ_LEVEL), 489 "memory", "ecc errors"); 490 #endif 491 492 /* 493 * On boards without a VMEChip2, the interrupt is routed 494 * via the MCChip (mvme162/mvme172). 495 */ 496 if (vmetwo_not_present) 497 pcctwointr_establish(MCCHIPV_PARITY_ERR, func, MEMC_IRQ_LEVEL, 498 sc, &sc->sc_evcnt); 499 else 500 vmetwo_local_intr_establish(MEMC_IRQ_LEVEL, 501 VME2_VEC_PARITY_ERROR, func, sc, &sc->sc_evcnt); 502 } 503 504 /* ARGSUSED */ 505 static int 506 memecc_err_intr(void *arg) 507 { 508 struct memc_softc *sc; 509 u_int8_t rv; 510 int i, j, cnt = 0; 511 512 /* 513 * For each memory controller we found ... 514 */ 515 for (i = 0; i < memc_softc_count; i++) { 516 sc = memc_softcs[i]; 517 518 /* 519 * There are two error loggers per controller, the registers of 520 * the 2nd are offset from the 1st by 2 bytes. 521 */ 522 for (j = 0; j <= 2; j += 2) { 523 rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + j); 524 if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0) { 525 memecc_log_error(sc, rv, j, 1); 526 memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + j, 527 MEMECC_ERROR_LOGGER_ERRLOG); 528 cnt++; 529 } 530 } 531 } 532 533 return (cnt); 534 } 535 536 /* 537 * Log an ECC error to the console. 538 * Note: Since this usually runs at an elevated ipl (above clock), we 539 * should probably schedule a soft interrupt to log the error details. 540 * (But only for errors where we would not normally panic.) 541 */ 542 static void 543 memecc_log_error(struct memc_softc *sc, u_int8_t errlog, int off, int mbepanic) 544 { 545 u_int32_t addr; 546 u_int8_t rv, syndrome; 547 const char *bm = "CPU"; 548 const char *rdwr; 549 const char *etype; 550 char syntext[32]; 551 552 /* 553 * Get the address associated with the error. 554 */ 555 rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HIHI + off); 556 addr = (u_int32_t)rv; 557 rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HI + off); 558 addr = (addr << 8) | (u_int32_t)rv; 559 rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_MID + off); 560 addr = (addr << 8) | (u_int32_t)rv; 561 rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_LO + off); 562 addr = (addr << 8) | (u_int32_t)rv; 563 564 /* 565 * And the Syndrome bits 566 */ 567 syndrome = memc_reg_read(sc, MEMECC_REG_ERROR_SYNDROME + off); 568 569 rdwr = ((errlog & MEMECC_ERROR_LOGGER_ERD) != 0) ? " read" : " write"; 570 571 if ((errlog & MEMECC_ERROR_LOGGER_EALT) != 0) 572 bm = "Peripheral Device"; 573 else 574 if ((errlog & MEMECC_ERROR_LOGGER_ESCRB) != 0) { 575 bm = "Scrubber"; 576 rdwr = ""; 577 } 578 579 if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0) { 580 int syncode, bank, bitnum; 581 582 etype = "Correctable"; 583 syncode = memc_syn_decode[syndrome]; 584 bitnum = (syncode & MEMECC_SYN_BIT_MASK) + (off ? 16 : 0); 585 bank = (syncode >> MEMECC_SYN_BANK_SHIFT) &MEMECC_SYN_BANK_MASK; 586 587 if (syncode == MEMECC_SYN_INVALID) 588 strcpy(syntext, "Invalid!"); 589 else 590 if ((syncode & MEMECC_SYN_CHECKBIT_ERR) != 0) 591 snprintf(syntext, sizeof(syntext), 592 "Checkbit#%d", bitnum); 593 else { 594 addr |= (u_int32_t) (bank << 2); 595 snprintf(syntext, sizeof(syntext), 596 "DRAM Bank %c, Bit#%d", 'A' + bank, bitnum); 597 } 598 } else if ((errlog & MEMECC_ERROR_LOGGER_MBE) != 0) 599 etype = "Uncorrectable"; 600 else 601 etype = "Spurious"; 602 603 printf("%s: %s error on %s%s access to 0x%08x.\n", 604 sc->sc_dev.dv_xname, etype, bm, rdwr, addr); 605 606 if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0) 607 printf("%s: ECC Syndrome 0x%02x (%s)\n", sc->sc_dev.dv_xname, 608 syndrome, syntext); 609 610 /* 611 * If an uncorrectable error was detected by an alternate 612 * bus master or the scrubber, panic immediately. 613 * We can't rely on the contents of memory at this point. 614 * 615 * Uncorrectable errors detected when the CPU was accessing 616 * DRAM will cause the CPU to take a bus error trap. Depending 617 * on whether the error was in kernel or user mode, the system 618 * with either panic or kill the affected process. Basically, 619 * we don't have to deal with it here. 620 * 621 * XXX: I'm not sure whether it's our responsibility to 622 * perform some dummy writes to the offending address in this 623 * case to re-generate a good ECC. Note that we'd have to write 624 * an entire block of 4 words since we can only narrow down the 625 * faulty address for correctable errors... 626 */ 627 if (mbepanic && (errlog & MEMECC_ERROR_LOGGER_MBE) && 628 (errlog & (MEMECC_ERROR_LOGGER_ESCRB|MEMECC_ERROR_LOGGER_EALT))) { 629 /* 630 * Ensure we don't get a Bus Error while panicking... 631 */ 632 rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL + off); 633 rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN | 634 MEMECC_DRAM_CONTROL_NCEIEN); 635 memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL + off, rv); 636 rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL + off); 637 rv &= ~(MEMECC_SCRUB_CONTROL_SBEIEN | 638 MEMECC_SCRUB_CONTROL_SCRBEN); 639 memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL + off, rv); 640 641 panic("%s: Halting system to preserve data integrity.", 642 sc->sc_dev.dv_xname); 643 } 644 } 645