xref: /netbsd/sys/dev/mvme/memc.c (revision 5f819ca3)
1*5f819ca3Schs /*	$NetBSD: memc.c,v 1.11 2012/10/27 17:18:27 chs Exp $	*/
208bde987Sscw 
308bde987Sscw /*-
408bde987Sscw  * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
508bde987Sscw  * All rights reserved.
608bde987Sscw  *
708bde987Sscw  * This code is derived from software contributed to The NetBSD Foundation
808bde987Sscw  * by Steve C. Woodford.
908bde987Sscw  *
1008bde987Sscw  * Redistribution and use in source and binary forms, with or without
1108bde987Sscw  * modification, are permitted provided that the following conditions
1208bde987Sscw  * are met:
1308bde987Sscw  * 1. Redistributions of source code must retain the above copyright
1408bde987Sscw  *    notice, this list of conditions and the following disclaimer.
1508bde987Sscw  * 2. Redistributions in binary form must reproduce the above copyright
1608bde987Sscw  *    notice, this list of conditions and the following disclaimer in the
1708bde987Sscw  *    documentation and/or other materials provided with the distribution.
1808bde987Sscw  *
1908bde987Sscw  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2008bde987Sscw  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2108bde987Sscw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2208bde987Sscw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2308bde987Sscw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2408bde987Sscw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2508bde987Sscw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2608bde987Sscw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2708bde987Sscw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2808bde987Sscw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2908bde987Sscw  * POSSIBILITY OF SUCH DAMAGE.
3008bde987Sscw  */
3108bde987Sscw 
3208bde987Sscw /*
3308bde987Sscw  * Support for the MEMECC and MEMC40 memory controllers on MVME68K
3408bde987Sscw  * and MVME88K boards.
3508bde987Sscw  */
3608bde987Sscw 
37365cbd94Slukem #include <sys/cdefs.h>
38*5f819ca3Schs __KERNEL_RCSID(0, "$NetBSD: memc.c,v 1.11 2012/10/27 17:18:27 chs Exp $");
39365cbd94Slukem 
4008bde987Sscw #include <sys/param.h>
4108bde987Sscw #include <sys/kernel.h>
4208bde987Sscw #include <sys/systm.h>
4308bde987Sscw #include <sys/device.h>
4408bde987Sscw #include <sys/malloc.h>
4508bde987Sscw 
46a2a38285Sad #include <sys/cpu.h>
47a2a38285Sad #include <sys/bus.h>
4808bde987Sscw 
4908bde987Sscw #include <dev/mvme/memcvar.h>
5008bde987Sscw #include <dev/mvme/memcreg.h>
5108bde987Sscw #include <dev/mvme/pcctwovar.h>
5208bde987Sscw #include <dev/mvme/pcctworeg.h>
5308bde987Sscw 
5408bde987Sscw #include <dev/vme/vmevar.h>
5508bde987Sscw #include <dev/mvme/mvmebus.h>
5608bde987Sscw #include <dev/mvme/vme_twovar.h>
5708bde987Sscw #include <dev/mvme/vme_tworeg.h>
5808bde987Sscw 
5908bde987Sscw 
6008bde987Sscw static struct memc_softc	*memc_softcs[MEMC_NDEVS];
6108bde987Sscw static int memc_softc_count;
6208bde987Sscw 
6308bde987Sscw static void memc040_attach(struct memc_softc *);
6408bde987Sscw static void memecc_attach(struct memc_softc *);
6508bde987Sscw static void memc_hook_error_intr(struct memc_softc *, int (*)(void *));
6608bde987Sscw 
6708bde987Sscw static int  memecc_err_intr(void *);
6808bde987Sscw static void memecc_log_error(struct memc_softc *, u_int8_t, int, int);
6908bde987Sscw 
7008bde987Sscw #define MEMECC_SCRUBBER_PERIOD	86400	/* ~24 hours */
7108bde987Sscw 
7208bde987Sscw /*
7308bde987Sscw  * The following stuff is used to decode the ECC syndrome code so
7408bde987Sscw  * that we can figure out exactly which address/bit needed to be
7508bde987Sscw  * corrected.
7608bde987Sscw  */
7708bde987Sscw #define MEMECC_SYN_BIT_MASK		0x0fu
7808bde987Sscw #define MEMECC_SYN_BANK_A		(0x00u << 4)
7908bde987Sscw #define MEMECC_SYN_BANK_B		(0x01u << 4)
8008bde987Sscw #define MEMECC_SYN_BANK_C		(0x02u << 4)
8108bde987Sscw #define MEMECC_SYN_BANK_D		(0x03u << 4)
8208bde987Sscw #define MEMECC_SYN_BANK_SHIFT		4
8308bde987Sscw #define MEMECC_SYN_BANK_MASK		0x03u
8408bde987Sscw #define MEMECC_SYN_CHECKBIT_ERR		0x80u
8508bde987Sscw #define MEMECC_SYN_INVALID		0xffu
8608bde987Sscw 
8708bde987Sscw static u_int8_t memc_syn_decode[256] = {
8808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x00 */
8908bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 0,		/* 0x01: Checkbit 0 */
9008bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 1,		/* 0x02: Checkbit 1 */
9108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x03 */
9208bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 2,		/* 0x04: Checkbit 2 */
9308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x05 */
9408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x06 */
9508bde987Sscw 	MEMECC_SYN_BANK_C | 10,			/* 0x07: Bank C 10/26 */
9608bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 3,		/* 0x08: Checkbit 3 */
9708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x09 */
9808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x0a */
9908bde987Sscw 	MEMECC_SYN_BANK_C | 13,			/* 0x0b: Bank C 13/29 */
10008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x0c */
10108bde987Sscw 	MEMECC_SYN_BANK_D | 1,			/* 0x0d: Bank D 1/17 */
10208bde987Sscw 	MEMECC_SYN_BANK_D | 2,			/* 0x0e: Bank D 2/18 */
10308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x0f */
10408bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 4,		/* 0x10: Checkbit 4 */
10508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x11 */
10608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x12 */
10708bde987Sscw 	MEMECC_SYN_BANK_C | 14,			/* 0x13: Bank C 14/30 */
10808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x14 */
10908bde987Sscw 	MEMECC_SYN_BANK_D | 4,			/* 0x15: Bank D 4/20 */
11008bde987Sscw 	MEMECC_SYN_BANK_D | 5,			/* 0x16: Bank D 5/21 */
11108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x17 */
11208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x18 */
11308bde987Sscw 	MEMECC_SYN_BANK_D | 8,			/* 0x19: Bank D 8/24 */
11408bde987Sscw 	MEMECC_SYN_BANK_D | 9,			/* 0x1a: Bank D 9/25 */
11508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x1b */
11608bde987Sscw 	MEMECC_SYN_BANK_D | 10,			/* 0x1c: Bank D 10/26 */
11708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x1d */
11808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x1e */
11908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x1f */
12008bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 5,		/* 0x20: Checkbit 5 */
12108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x21 */
12208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x22 */
12308bde987Sscw 	MEMECC_SYN_BANK_C | 0,			/* 0x23: Bank C 0/16 */
12408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x24 */
12508bde987Sscw 	MEMECC_SYN_BANK_D | 7,			/* 0x25: Bank D 7/23 */
12608bde987Sscw 	MEMECC_SYN_BANK_D | 6,			/* 0x26: Bank D 6/22 */
12708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x27 */
12808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x28 */
12908bde987Sscw 	MEMECC_SYN_BANK_A | 15,			/* 0x29: Bank A 15/31 */
13008bde987Sscw 	MEMECC_SYN_BANK_D | 12,			/* 0x2a: Bank D 12/28 */
13108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x2b */
13208bde987Sscw 	MEMECC_SYN_BANK_D | 13,			/* 0x2c: Bank D 13/29 */
13308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x2d */
13408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x2e */
13508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x2f */
13608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x30 */
13708bde987Sscw 	MEMECC_SYN_BANK_A | 14,			/* 0x31: Bank A 14/30 */
13808bde987Sscw 	MEMECC_SYN_BANK_A | 0,			/* 0x32: Bank A 0/16 */
13908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x33 */
14008bde987Sscw 	MEMECC_SYN_BANK_A | 1,			/* 0x34: Bank A 1/17 */
14108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x35 */
14208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x36 */
14308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x37 */
14408bde987Sscw 	MEMECC_SYN_BANK_A | 2,			/* 0x38: Bank A 2/18 */
14508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x39 */
14608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x3a */
14708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x3b */
14808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x3c */
14908bde987Sscw 	MEMECC_SYN_BANK_C | 3,			/* 0x3d: Bank C 3/19 */
15008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x3e */
15108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x3f */
15208bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 6,		/* 0x40: Checkbit 6 */
15308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x41 */
15408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x42 */
15508bde987Sscw 	MEMECC_SYN_BANK_C | 1,			/* 0x43: Bank C 1/17 */
15608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x44 */
15708bde987Sscw 	MEMECC_SYN_BANK_C | 4,			/* 0x45: Bank C 4/20 */
15808bde987Sscw 	MEMECC_SYN_BANK_C | 8,			/* 0x46: Bank C 8/24 */
15908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x47 */
16008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x48 */
16108bde987Sscw 	MEMECC_SYN_BANK_C | 7,			/* 0x49: Bank C 7/23 */
16208bde987Sscw 	MEMECC_SYN_BANK_D | 15,			/* 0x4a: Bank D 15/31 */
16308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x4b */
16408bde987Sscw 	MEMECC_SYN_BANK_D | 14,			/* 0x4c: Bank D 14/30 */
16508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x4d */
16608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x4e */
16708bde987Sscw 	MEMECC_SYN_BANK_B | 3,			/* 0x4f: Bank B 3/19 */
16808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x50 */
16908bde987Sscw 	MEMECC_SYN_BANK_B | 4,			/* 0x51: Bank B 4/20 */
17008bde987Sscw 	MEMECC_SYN_BANK_B | 7,			/* 0x52: Bank B 7/23 */
17108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x53 */
17208bde987Sscw 	MEMECC_SYN_BANK_A | 4,			/* 0x54: Bank A 4/20 */
17308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x55 */
17408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x56 */
17508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x57 */
17608bde987Sscw 	MEMECC_SYN_BANK_A | 5,			/* 0x58: Bank A 5/21 */
17708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x59 */
17808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5a */
17908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5b */
18008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5c */
18108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5d */
18208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5e */
18308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x5f */
18408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x60 */
18508bde987Sscw 	MEMECC_SYN_BANK_B | 5,			/* 0x61: Bank B 5/21 */
18608bde987Sscw 	MEMECC_SYN_BANK_B | 6,			/* 0x62: Bank B 6/22 */
18708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x63 */
18808bde987Sscw 	MEMECC_SYN_BANK_A | 8,			/* 0x64: Bank A 8/24 */
18908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x65 */
19008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x66 */
19108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x67 */
19208bde987Sscw 	MEMECC_SYN_BANK_A | 9,			/* 0x68: Bank A 9/25 */
19308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x69 */
19408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6a */
19508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6b */
19608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6c */
19708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6d */
19808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6e */
19908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x6f */
20008bde987Sscw 	MEMECC_SYN_BANK_A | 10,			/* 0x70: Bank A 10/26 */
20108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x71 */
20208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x72 */
20308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x73 */
20408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x74 */
20508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x75 */
20608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x76 */
20708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x77 */
20808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x78 */
20908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x79 */
21008bde987Sscw 	MEMECC_SYN_BANK_C | 11,			/* 0x7a: Bank C 11/27 */
21108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x7b */
21208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x7c */
21308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x7d */
21408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x7e */
21508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x7f */
21608bde987Sscw 	MEMECC_SYN_CHECKBIT_ERR | 7,		/* 0x80: Checkbit 7 */
21708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x81 */
21808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x82 */
21908bde987Sscw 	MEMECC_SYN_BANK_C | 2,			/* 0x83: Bank C 2/18 */
22008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x84 */
22108bde987Sscw 	MEMECC_SYN_BANK_C | 5,			/* 0x85: Bank C 5/21 */
22208bde987Sscw 	MEMECC_SYN_BANK_C | 9,			/* 0x86: Bank C 9/25 */
22308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x87 */
22408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x88 */
22508bde987Sscw 	MEMECC_SYN_BANK_C | 6,			/* 0x89: Bank C 6/22 */
22608bde987Sscw 	MEMECC_SYN_BANK_C | 12,			/* 0x8a: Bank C 12/28 */
22708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x8b */
22808bde987Sscw 	MEMECC_SYN_BANK_D | 0,			/* 0x8c: Bank D 0/16 */
22908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x8d */
23008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x8e */
23108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x8f */
23208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x90 */
23308bde987Sscw 	MEMECC_SYN_BANK_B | 8,			/* 0x91: Bank B 8/24 */
23408bde987Sscw 	MEMECC_SYN_BANK_C | 15,			/* 0x92: Bank C 15/31 */
23508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x93 */
23608bde987Sscw 	MEMECC_SYN_BANK_A | 7,			/* 0x94: Bank A 7/23 */
23708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x95 */
23808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x96 */
23908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x97 */
24008bde987Sscw 	MEMECC_SYN_BANK_A | 6,			/* 0x98: Bank A 6/22 */
24108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x99 */
24208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x9a */
24308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x9b */
24408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x9c */
24508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x9d */
24608bde987Sscw 	MEMECC_SYN_BANK_B | 11,			/* 0x9e: Bank B 11/27 */
24708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0x9f */
24808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xa0 */
24908bde987Sscw 	MEMECC_SYN_BANK_B | 9,			/* 0xa1: Bank B 9/25 */
25008bde987Sscw 	MEMECC_SYN_BANK_B | 12,			/* 0xa2: Bank B 12/28 */
25108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xa3 */
25208bde987Sscw 	MEMECC_SYN_BANK_B | 15,			/* 0xa4: Bank B 15/31 */
25308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xa5 */
25408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xa6 */
25508bde987Sscw 	MEMECC_SYN_BANK_A | 11,			/* 0xa7: Bank A 11/27 */
25608bde987Sscw 	MEMECC_SYN_BANK_A | 12,			/* 0xa8: Bank A 12/28 */
25708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xa9 */
25808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xaa */
25908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xab */
26008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xac */
26108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xad */
26208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xae */
26308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xaf */
26408bde987Sscw 	MEMECC_SYN_BANK_A | 13,			/* 0xb0: Bank A 13/29 */
26508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb1 */
26608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb2 */
26708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb3 */
26808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb4 */
26908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb5 */
27008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb6 */
27108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb7 */
27208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb8 */
27308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xb9 */
27408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xba */
27508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xbb */
27608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xbc */
27708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xbd */
27808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xbe */
27908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xbf */
28008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc0 */
28108bde987Sscw 	MEMECC_SYN_BANK_B | 10,			/* 0xc1: Bank B 10/26 */
28208bde987Sscw 	MEMECC_SYN_BANK_B | 13,			/* 0xc2: Bank B 13/29 */
28308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc3 */
28408bde987Sscw 	MEMECC_SYN_BANK_B | 14,			/* 0xc4: Bank B 14/30 */
28508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc5 */
28608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc6 */
28708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc7 */
28808bde987Sscw 	MEMECC_SYN_BANK_B | 0,			/* 0xc8: Bank B 0/16 */
28908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xc9 */
29008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xca */
29108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xcb */
29208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xcc */
29308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xcd */
29408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xce */
29508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xcf */
29608bde987Sscw 	MEMECC_SYN_BANK_B | 1,			/* 0xd0: Bank B 1/17 */
29708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd1 */
29808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd2 */
29908bde987Sscw 	MEMECC_SYN_BANK_A | 3,			/* 0xd3: Bank A 3/19 */
30008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd4 */
30108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd5 */
30208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd6 */
30308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd7 */
30408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd8 */
30508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xd9 */
30608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xda */
30708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xdb */
30808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xdc */
30908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xdd */
31008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xde */
31108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xdf */
31208bde987Sscw 	MEMECC_SYN_BANK_B | 2,			/* 0xe0: Bank B 2/18 */
31308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe1 */
31408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe2 */
31508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe3 */
31608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe4 */
31708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe5 */
31808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe6 */
31908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe7 */
32008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xe8 */
32108bde987Sscw 	MEMECC_SYN_BANK_D | 11,			/* 0xe9: Bank D 11/27 */
32208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xea */
32308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xeb */
32408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xec */
32508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xed */
32608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xee */
32708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xef */
32808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf0 */
32908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf1 */
33008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf2 */
33108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf3 */
33208bde987Sscw 	MEMECC_SYN_BANK_D | 3,			/* 0xf4: Bank D 3/19 */
33308bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf5 */
33408bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf6 */
33508bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf7 */
33608bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf8 */
33708bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xf9 */
33808bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xfa */
33908bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xfb */
34008bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xfc */
34108bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xfd */
34208bde987Sscw 	MEMECC_SYN_INVALID,			/* 0xfe */
34308bde987Sscw 	MEMECC_SYN_INVALID			/* 0xff */
34408bde987Sscw };
34508bde987Sscw 
34608bde987Sscw 
34708bde987Sscw /* ARGSUSED */
34808bde987Sscw void
memc_init(struct memc_softc * sc)349454af1c0Sdsl memc_init(struct memc_softc *sc)
35008bde987Sscw {
35108bde987Sscw 	u_int8_t chipid;
35208bde987Sscw 	u_int8_t memcfg;
35308bde987Sscw 
35408bde987Sscw 	if (memc_softc_count == MEMC_NDEVS)
35508bde987Sscw 		panic("memc_attach: too many memc devices!");
35608bde987Sscw 
35708bde987Sscw 	memc_softcs[memc_softc_count++] = sc;
35808bde987Sscw 
35908bde987Sscw 	chipid = memc_reg_read(sc, MEMC_REG_CHIP_ID);
36008bde987Sscw 	memcfg = memc_reg_read(sc, MEMC_REG_MEMORY_CONFIG);
36108bde987Sscw 
36208bde987Sscw 	printf(": %dMB %s Memory Controller Chip (Rev %d)\n",
36308bde987Sscw 	    MEMC_MEMORY_CONFIG_2_MB(memcfg),
36408bde987Sscw 	    (chipid == MEMC_CHIP_ID_MEMC040) ? "Parity" : "ECC",
36508bde987Sscw 	    memc_reg_read(sc, MEMC_REG_CHIP_REVISION));
36608bde987Sscw 
367*5f819ca3Schs 	printf("%s: Base Address: 0x%x, ", device_xname(sc->sc_dev),
36808bde987Sscw 	    MEMC_BASE_ADDRESS(memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_HI),
36908bde987Sscw 			      memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_LO)));
37008bde987Sscw 
37108bde987Sscw 	printf("Fast RAM Read %sabled\n", (memc_reg_read(sc,
37208bde987Sscw 	    MEMC_REG_MEMORY_CONFIG) & MEMC_MEMORY_CONFIG_FSTRD) ?
37308bde987Sscw 	    "En" : "Dis");
37408bde987Sscw 
37508bde987Sscw 	switch (chipid) {
37608bde987Sscw 	case MEMC_CHIP_ID_MEMC040:
37708bde987Sscw 		memc040_attach(sc);
37808bde987Sscw 		break;
37908bde987Sscw 	case MEMC_CHIP_ID_MEMECC:
38008bde987Sscw 		memecc_attach(sc);
38108bde987Sscw 		break;
38208bde987Sscw 	}
38308bde987Sscw }
38408bde987Sscw 
38508bde987Sscw static void
memc040_attach(struct memc_softc * sc)38608bde987Sscw memc040_attach(struct memc_softc *sc)
38708bde987Sscw {
38808bde987Sscw 
38908bde987Sscw 	/* XXX: TBD */
39008bde987Sscw }
39108bde987Sscw 
39208bde987Sscw static void
memecc_attach(struct memc_softc * sc)39308bde987Sscw memecc_attach(struct memc_softc *sc)
39408bde987Sscw {
39508bde987Sscw 	u_int8_t rv;
39608bde987Sscw 
39708bde987Sscw 	/*
39808bde987Sscw 	 * First, disable bus-error and interrupts on ECC errors.
39908bde987Sscw 	 * Also switch off SWAIT to enhance performance.
40008bde987Sscw 	 */
40108bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL);
40208bde987Sscw 	rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN |
40308bde987Sscw 	        MEMECC_DRAM_CONTROL_NCEIEN |
40408bde987Sscw 	        MEMECC_DRAM_CONTROL_SWAIT);
40508bde987Sscw 	rv |= MEMECC_DRAM_CONTROL_RAMEN;
40608bde987Sscw 	memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv);
40708bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL);
40808bde987Sscw 	rv &= ~(MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN);
40908bde987Sscw 	memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL, rv);
41008bde987Sscw 
41108bde987Sscw 	/*
41208bde987Sscw 	 * Ensure error correction is enabled
41308bde987Sscw 	 */
41408bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_DATA_CONTROL);
41508bde987Sscw 	rv &= ~MEMECC_DATA_CONTROL_DERC;
41608bde987Sscw 	memc_reg_write(sc, MEMECC_REG_DATA_CONTROL, rv);
41708bde987Sscw 
41808bde987Sscw 	/*
41908bde987Sscw 	 * Clear any error currently in the logs
42008bde987Sscw 	 */
42108bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER);
42208bde987Sscw #ifdef DIAGNOSTIC
42308bde987Sscw 	if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0)
42408bde987Sscw 		memecc_log_error(sc, rv, 0, 0);
42508bde987Sscw #endif
42608bde987Sscw 	memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER,
42708bde987Sscw 		    MEMECC_ERROR_LOGGER_ERRLOG);
42808bde987Sscw 
42908bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + 2);
43008bde987Sscw #ifdef DIAGNOSTIC
43108bde987Sscw 	if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0)
43208bde987Sscw 		memecc_log_error(sc, rv, 2, 0);
43308bde987Sscw #endif
43408bde987Sscw 	memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + 2,
43508bde987Sscw 		    MEMECC_ERROR_LOGGER_ERRLOG);
43608bde987Sscw 
43708bde987Sscw 	/*
43808bde987Sscw 	 * Now hook the ECC error interrupt
43908bde987Sscw 	 */
44008bde987Sscw 	if (memc_softc_count == 1)
44108bde987Sscw 		memc_hook_error_intr(sc, memecc_err_intr);
44208bde987Sscw 
44308bde987Sscw 	/*
44408bde987Sscw 	 * Enable bus-error and interrupt on uncorrectable ECC
44508bde987Sscw 	 */
44608bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL);
44708bde987Sscw 	rv |= MEMECC_DRAM_CONTROL_NCEBEN | MEMECC_DRAM_CONTROL_NCEIEN;
44808bde987Sscw 	memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv);
44908bde987Sscw 
45008bde987Sscw 	/*
45108bde987Sscw 	 * Set up the scrubber to run roughly once every 24 hours
45208bde987Sscw 	 * with minimal impact on the local bus. With these on/off
45308bde987Sscw 	 * time settings, a scrub of a 32MB DRAM board will take
45408bde987Sscw 	 * roughly half a minute.
45508bde987Sscw 	 */
45608bde987Sscw 	memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_HI,
45708bde987Sscw 	    MEMECC_SCRUB_PERIOD_HI(MEMECC_SCRUBBER_PERIOD));
45808bde987Sscw 	memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_LO,
45908bde987Sscw 	    MEMECC_SCRUB_PERIOD_LO(MEMECC_SCRUBBER_PERIOD));
46008bde987Sscw 	memc_reg_write(sc, MEMECC_REG_SCRUB_TIME_ONOFF,
46108bde987Sscw 	    MEMECC_SCRUB_TIME_ON_1 | MEMECC_SCRUB_TIME_OFF_16);
46208bde987Sscw 
46308bde987Sscw 	/*
46408bde987Sscw 	 * Start the scrubber, and enable interrupts on Correctable errors
46508bde987Sscw 	 */
46608bde987Sscw 	memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL,
46708bde987Sscw 	    memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL) |
46808bde987Sscw 	    MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN);
46908bde987Sscw 
470*5f819ca3Schs 	printf("%s: Logging ECC errors at ipl %d\n", device_xname(sc->sc_dev),
47108bde987Sscw 	    MEMC_IRQ_LEVEL);
47208bde987Sscw }
47308bde987Sscw 
47408bde987Sscw static void
memc_hook_error_intr(struct memc_softc * sc,int (* func)(void *))47508bde987Sscw memc_hook_error_intr(struct memc_softc *sc, int (*func)(void *))
47608bde987Sscw {
47708bde987Sscw 
47808bde987Sscw #if 0
47908bde987Sscw 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
48008bde987Sscw 	    (*sc->sc_isrevcnt)(sc->sc_isrcookie, MEMC_IRQ_LEVEL),
48108bde987Sscw 	    "memory", "ecc errors");
48208bde987Sscw #endif
48308bde987Sscw 
48408bde987Sscw 	/*
48508bde987Sscw 	 * On boards without a VMEChip2, the interrupt is routed
48608bde987Sscw 	 * via the MCChip (mvme162/mvme172).
48708bde987Sscw 	 */
48808bde987Sscw 	if (vmetwo_not_present)
48908bde987Sscw 		pcctwointr_establish(MCCHIPV_PARITY_ERR, func, MEMC_IRQ_LEVEL,
49008bde987Sscw 		    sc, &sc->sc_evcnt);
49108bde987Sscw 	else
49208bde987Sscw 		vmetwo_local_intr_establish(MEMC_IRQ_LEVEL,
49308bde987Sscw 		    VME2_VEC_PARITY_ERROR, func, sc, &sc->sc_evcnt);
49408bde987Sscw }
49508bde987Sscw 
49608bde987Sscw /* ARGSUSED */
49708bde987Sscw static int
memecc_err_intr(void * arg)49808bde987Sscw memecc_err_intr(void *arg)
49908bde987Sscw {
50008bde987Sscw 	struct memc_softc *sc;
50108bde987Sscw 	u_int8_t rv;
50208bde987Sscw 	int i, j, cnt = 0;
50308bde987Sscw 
50408bde987Sscw 	/*
50508bde987Sscw 	 * For each memory controller we found ...
50608bde987Sscw 	 */
50708bde987Sscw 	for (i = 0; i < memc_softc_count; i++) {
50808bde987Sscw 		sc = memc_softcs[i];
50908bde987Sscw 
51008bde987Sscw 		/*
51108bde987Sscw 		 * There are two error loggers per controller, the registers of
51208bde987Sscw 		 * the 2nd are offset from the 1st by 2 bytes.
51308bde987Sscw 		 */
51408bde987Sscw 		for (j = 0; j <= 2; j += 2) {
51508bde987Sscw 			rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + j);
51608bde987Sscw 			if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0) {
51708bde987Sscw 				memecc_log_error(sc, rv, j, 1);
51808bde987Sscw 				memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + j,
51908bde987Sscw 				    MEMECC_ERROR_LOGGER_ERRLOG);
52008bde987Sscw 				cnt++;
52108bde987Sscw 			}
52208bde987Sscw 		}
52308bde987Sscw 	}
52408bde987Sscw 
52508bde987Sscw 	return (cnt);
52608bde987Sscw }
52708bde987Sscw 
52808bde987Sscw /*
52908bde987Sscw  * Log an ECC error to the console.
53008bde987Sscw  * Note: Since this usually runs at an elevated ipl (above clock), we
53108bde987Sscw  * should probably schedule a soft interrupt to log the error details.
53208bde987Sscw  * (But only for errors where we would not normally panic.)
53308bde987Sscw  */
53408bde987Sscw static void
memecc_log_error(struct memc_softc * sc,u_int8_t errlog,int off,int mbepanic)53508bde987Sscw memecc_log_error(struct memc_softc *sc, u_int8_t errlog, int off, int mbepanic)
53608bde987Sscw {
53708bde987Sscw 	u_int32_t addr;
53808bde987Sscw 	u_int8_t rv, syndrome;
53908bde987Sscw 	const char *bm = "CPU";
54008bde987Sscw 	const char *rdwr;
54108bde987Sscw 	const char *etype;
54208bde987Sscw 	char syntext[32];
54308bde987Sscw 
54408bde987Sscw 	/*
54508bde987Sscw 	 * Get the address associated with the error.
54608bde987Sscw 	 */
54708bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HIHI + off);
54808bde987Sscw 	addr = (u_int32_t)rv;
54908bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HI + off);
55008bde987Sscw 	addr = (addr << 8) | (u_int32_t)rv;
55108bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_MID + off);
55208bde987Sscw 	addr = (addr << 8) | (u_int32_t)rv;
55308bde987Sscw 	rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_LO + off);
55408bde987Sscw 	addr = (addr << 8) | (u_int32_t)rv;
55508bde987Sscw 
55608bde987Sscw 	/*
55708bde987Sscw 	 * And the Syndrome bits
55808bde987Sscw 	 */
55908bde987Sscw 	syndrome = memc_reg_read(sc, MEMECC_REG_ERROR_SYNDROME + off);
56008bde987Sscw 
56108bde987Sscw 	rdwr = ((errlog & MEMECC_ERROR_LOGGER_ERD) != 0) ? " read" : " write";
56208bde987Sscw 
56308bde987Sscw 	if ((errlog & MEMECC_ERROR_LOGGER_EALT) != 0)
56408bde987Sscw 		bm = "Peripheral Device";
56508bde987Sscw 	else
56608bde987Sscw 	if ((errlog & MEMECC_ERROR_LOGGER_ESCRB) != 0) {
56708bde987Sscw 		bm = "Scrubber";
56808bde987Sscw 		rdwr = "";
56908bde987Sscw 	}
57008bde987Sscw 
57108bde987Sscw 	if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0) {
57208bde987Sscw 		int syncode, bank, bitnum;
57308bde987Sscw 
57408bde987Sscw 		etype = "Correctable";
57508bde987Sscw 		syncode = memc_syn_decode[syndrome];
57608bde987Sscw 		bitnum = (syncode & MEMECC_SYN_BIT_MASK) + (off ? 16 : 0);
57708bde987Sscw 		bank = (syncode >> MEMECC_SYN_BANK_SHIFT) &MEMECC_SYN_BANK_MASK;
57808bde987Sscw 
57908bde987Sscw 		if (syncode == MEMECC_SYN_INVALID)
58008bde987Sscw 			strcpy(syntext, "Invalid!");
58108bde987Sscw 		else
58208bde987Sscw 		if ((syncode & MEMECC_SYN_CHECKBIT_ERR) != 0)
583aca4c091Sitojun 			snprintf(syntext, sizeof(syntext),
584aca4c091Sitojun 			    "Checkbit#%d", bitnum);
58508bde987Sscw 		else {
58608bde987Sscw 			addr |= (u_int32_t) (bank << 2);
587aca4c091Sitojun 			snprintf(syntext, sizeof(syntext),
588aca4c091Sitojun 			    "DRAM Bank %c, Bit#%d", 'A' + bank, bitnum);
58908bde987Sscw 		}
59008bde987Sscw 	} else if ((errlog & MEMECC_ERROR_LOGGER_MBE) != 0)
59108bde987Sscw 		etype = "Uncorrectable";
59208bde987Sscw 	else
59308bde987Sscw 		etype = "Spurious";
59408bde987Sscw 
59508bde987Sscw 	printf("%s: %s error on %s%s access to 0x%08x.\n",
596*5f819ca3Schs 	    device_xname(sc->sc_dev), etype, bm, rdwr, addr);
59708bde987Sscw 
59808bde987Sscw 	if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0)
599*5f819ca3Schs 		printf("%s: ECC Syndrome 0x%02x (%s)\n", device_xname(sc->sc_dev),
60008bde987Sscw 		    syndrome, syntext);
60108bde987Sscw 
60208bde987Sscw 	/*
60308bde987Sscw 	 * If an uncorrectable error was detected by an alternate
60408bde987Sscw 	 * bus master or the scrubber, panic immediately.
60508bde987Sscw 	 * We can't rely on the contents of memory at this point.
60608bde987Sscw 	 *
60708bde987Sscw 	 * Uncorrectable errors detected when the CPU was accessing
60808bde987Sscw 	 * DRAM will cause the CPU to take a bus error trap. Depending
60908bde987Sscw 	 * on whether the error was in kernel or user mode, the system
61008bde987Sscw 	 * with either panic or kill the affected process. Basically,
61108bde987Sscw 	 * we don't have to deal with it here.
61208bde987Sscw 	 *
61308bde987Sscw 	 * XXX: I'm not sure whether it's our responsibility to
61408bde987Sscw 	 * perform some dummy writes to the offending address in this
61508bde987Sscw 	 * case to re-generate a good ECC. Note that we'd have to write
61608bde987Sscw 	 * an entire block of 4 words since we can only narrow down the
61708bde987Sscw 	 * faulty address for correctable errors...
61808bde987Sscw 	 */
61908bde987Sscw 	if (mbepanic && (errlog & MEMECC_ERROR_LOGGER_MBE) &&
62008bde987Sscw 	    (errlog & (MEMECC_ERROR_LOGGER_ESCRB|MEMECC_ERROR_LOGGER_EALT))) {
62108bde987Sscw 		/*
62212490842Swiz 		 * Ensure we don't get a Bus Error while panicking...
62308bde987Sscw 		 */
62408bde987Sscw 		rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL + off);
62508bde987Sscw 		rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN |
62608bde987Sscw 		        MEMECC_DRAM_CONTROL_NCEIEN);
62708bde987Sscw 		memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL + off, rv);
62808bde987Sscw 		rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL + off);
62908bde987Sscw 		rv &= ~(MEMECC_SCRUB_CONTROL_SBEIEN |
63008bde987Sscw 			MEMECC_SCRUB_CONTROL_SCRBEN);
63108bde987Sscw 		memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL + off, rv);
63208bde987Sscw 
63308bde987Sscw 		panic("%s: Halting system to preserve data integrity.",
634*5f819ca3Schs 		    device_xname(sc->sc_dev));
63508bde987Sscw 	}
63608bde987Sscw }
637