xref: /illumos-gate/usr/src/cmd/mdb/intel/modules/amd_opteron/ao.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 #include <mdb/mdb_modapi.h>
26 #include <amd_opteron/ao.h>
27 
28 #define	ALLBITS	(u_longlong_t)-1
29 
30 static const mdb_bitmask_t ao_nbcfg_bits[] = {
31 	{ "SyncOnDramAdrParErrEn", ALLBITS, AMD_NB_CFG_SYNCONDRAMADRPARERREN },
32 	{ "NbMcaToMstCpuEn", ALLBITS, AMD_NB_CFG_NBMCATOMSTCPUEN },
33 	{ "ReservedBit26", ALLBITS, 0x4000000 },
34 	{ "DisPciCfgCpuErrRsp", ALLBITS, AMD_NB_CFG_DISPCICFGCPUERRRSP },
35 	{ "IoRdDatErrEn", ALLBITS, AMD_NB_CFG_IORDDATERREN },
36 	{ "ChipKillEccEn", ALLBITS, AMD_NB_CFG_CHIPKILLECCEN },
37 	{ "EccEn", ALLBITS, AMD_NB_CFG_ECCEN },
38 	{ "SyncOnAnyErrEn", ALLBITS, AMD_NB_CFG_SYNCONANYERREN },
39 	{ "SyncOnWdogEn", ALLBITS, AMD_NB_CFG_SYNCONWDOGEN },
40 	{ "GenCrcErrByte1", ALLBITS, AMD_NB_CFG_GENCRCERRBYTE1 },
41 	{ "GenCrcErrByte0", ALLBITS, AMD_NB_CFG_GENCRCERRBYTE0 },
42 	/* LdtLinkSel handled separately */
43 	/* WdogTmrBaseSel handled separately */
44 	/* WdogTmrCntSel handled separately */
45 	/* WdogTmrDis handled separately */
46 	{ "IoErrDis", ALLBITS, AMD_NB_CFG_IOERRDIS },
47 	{ "CpuErrDis", ALLBITS, AMD_NB_CFG_CPUERRDIS },
48 	{ "IoMstAbortDis", ALLBITS, AMD_NB_CFG_IOMSTABORTDIS },
49 	{ "SyncPktPropDis", ALLBITS, AMD_NB_CFG_SYNCPKTPROPDIS },
50 	{ "SyncPktGenDis", ALLBITS, AMD_NB_CFG_SYNCPKTGENDIS },
51 	{ "SyncOnUcEccEn", ALLBITS, AMD_NB_CFG_SYNCONUCECCEN },
52 	{ "CpuRdDatErrEn", ALLBITS, AMD_NB_CFG_CPURDDATERREN }
53 };
54 
55 /*ARGSUSED*/
56 static int
57 ao_nbcfg_describe(uintptr_t val, uint_t flags, int argc, const mdb_arg_t *argv)
58 {
59 	const mdb_bitmask_t *bm;
60 	uintptr_t field;
61 	int nbits, i;
62 
63 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
64 		return (DCMD_USAGE);
65 
66 	for (nbits = 0, bm = ao_nbcfg_bits, i = 0;
67 	    i < sizeof (ao_nbcfg_bits) / sizeof (mdb_bitmask_t); i++, bm++) {
68 		if (!(val & bm->bm_bits))
69 			continue;
70 
71 		mdb_printf("\t0x%08x  %s\n", bm->bm_bits, bm->bm_name);
72 
73 		val &= ~bm->bm_bits;
74 		nbits++;
75 	}
76 
77 	if ((field = (val & AMD_NB_CFG_LDTLINKSEL_MASK)) != 0) {
78 		mdb_printf("\tLdtLinkSel = %d", field >>
79 		    AMD_NB_CFG_LDTLINKSEL_SHIFT);
80 	}
81 
82 	if (val & AMD_NB_CFG_WDOGTMRDIS) {
83 		mdb_printf("\t0x%08x  %s\n", AMD_NB_CFG_WDOGTMRDIS,
84 		    "WdogTmrDis");
85 	} else {
86 		static const uint_t wdogcounts[] = {
87 			4095, 2047, 1023, 511, 255, 127, 63, 31
88 		};
89 
90 		uintptr_t cntfld = (val & AMD_NB_CFG_WDOGTMRCNTSEL_MASK);
91 		uintptr_t basefld = (val & AMD_NB_CFG_WDOGTMRBASESEL_MASK);
92 		uintptr_t count;
93 		int valid = 1;
94 		const char *units;
95 
96 		if (cntfld < sizeof (wdogcounts) / sizeof (uint_t))
97 			count = wdogcounts[cntfld];
98 		else
99 			valid = 0;
100 
101 		switch (basefld) {
102 		case AMD_NB_CFG_WDOGTMRBASESEL_1MS:
103 			units = "ms";
104 			break;
105 		case AMD_NB_CFG_WDOGTMRBASESEL_1US:
106 			units = "us";
107 			break;
108 		case AMD_NB_CFG_WDOGTMRBASESEL_5NS:
109 			count *= 5;
110 			units = "ns";
111 			break;
112 		default:
113 			units = " (unknown units)";
114 			break;
115 		}
116 
117 		if (valid) {
118 			mdb_printf("\tWatchdog timeout: %u%s\n", count,
119 			    units);
120 		} else {
121 			mdb_printf("\tInvalid Watchdog: Count %u, Base %u\n",
122 			    cntfld, basefld);
123 		}
124 	}
125 
126 	return (DCMD_OK);
127 }
128 
129 static const char *ao_scrub_rate[] = {
130 	"Do not scrub",		/* 0b00000 */
131 	"40.0 nanosec",		/* 0b00001 */
132 	"80.0 nanosec",		/* 0b00010 */
133 	"160.0 nanosec",	/* 0b00011 */
134 	"320.0 nanosec",	/* 0b00100 */
135 	"640.0 nanosec",	/* 0b00101 */
136 	"1.28 microsec",	/* 0b00110 */
137 	"2.56 microsec",	/* 0b00111 */
138 	"5.12 microsec",	/* 0b01000 */
139 	"10.2 microsec",	/* 0b01001 */
140 	"20.5 microsec",	/* 0b01010 */
141 	"41.0 microsec",	/* 0b01011 */
142 	"81.9 microsec",	/* 0b01100 */
143 	"163.8 microsec",	/* 0b01101 */
144 	"327.7 microsec",	/* 0b01110 */
145 	"655.4 microsec",	/* 0b01111 */
146 	"1.31 millsec",		/* 0b10000 */
147 	"2.62 millsec",		/* 0b10001 */
148 	"5.24 millsec",		/* 0b10010 */
149 	"10.49 millsec",	/* 0b10011 */
150 	"20.97 millsec",	/* 0b10100 */
151 	"42.00 millsec",	/* 0b10101 */
152 	"84.00 millsec",	/* 0b10110 */
153 };
154 
155 #define	SCRUBCODE(val, low) ((val) >> low & 0x1f)
156 
157 #define	SCRUBSTR(val, low) \
158 	(SCRUBCODE(val, low) < sizeof (ao_scrub_rate) / sizeof (char *) ? \
159 	ao_scrub_rate[SCRUBCODE(val, low)] : "reserved value!")
160 
161 /*ARGSUSED*/
162 static int
163 ao_scrubctl_describe(uintptr_t val, uint_t flags, int argc,
164     const mdb_arg_t *argv)
165 {
166 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
167 		return (DCMD_USAGE);
168 
169 	mdb_printf("\tDcacheScrub: %s\n\t    L2Scrub: %s\n\t  DramScrub: %s\n",
170 	    SCRUBSTR(val, 16), SCRUBSTR(val, 8), SCRUBSTR(val, 0));
171 
172 	return (DCMD_OK);
173 }
174 
175 /*ARGSUSED*/
176 static int
177 ao_sparectl_describe(uintptr_t val, uint_t flags, int argc,
178     const mdb_arg_t *argv)
179 {
180 	const char *itypes[] = {
181 		"No Interrupt",	/* 0b00 */
182 		"Reserved",	/* 0b01 */
183 		"SMI",		/* 0b10 */
184 		"Reserved",	/* 0b11 */
185 	};
186 
187 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
188 		return (DCMD_USAGE);
189 
190 	mdb_printf(
191 	    "\t  EccErrInt: %s\n"
192 	    "\tSwapDoneInt: %s\n"
193 	    "\t  BadDramCs: %d\n"
194 	    "\t   SwapDone: %s\n"
195 	    "\t     SwapEn: %s\n",
196 	    itypes[val >> 14 & 0x3],
197 	    itypes[val >> 12 & 0x3],
198 	    val >> 4 & 0x7,
199 	    val & 0x2 ? "Yes" : "No",
200 	    val & 0x1 ? "Yes" : "No");
201 
202 	return (DCMD_OK);
203 }
204 
205 static const char *ao_mcactl_dc[] = {
206 	"ECCI (Single-bit ECC Data Errors)",
207 	"ECCM (Multi-bit ECC Data Errors)",
208 	"DECC (Data Array ECC Errors)",
209 	"DMTP (Main Tag Array Parity Errors)",
210 	"DSTP (Snoop Tag Array Parity Errors)",
211 	"L1TP (L1 TLB Parity Errors)",
212 	"L2TP (L2 TLB Parity Errors)",
213 };
214 
215 static const char *ao_mcactl_ic[] = {
216 	"ECCI (Single-bit ECC data errors)",
217 	"ECCM (Multi-bit ECC data errors)",
218 	"IDP (Data array parity errors)",
219 	"IMTP (Main tag array parity errors)",
220 	"ISTP (Snoop tag array parity errors)",
221 	"L1TP (L1 TLB Parity Errors)",
222 	"L2TP (L2 TLB Parity Errors)",
223 	NULL,	/* reserved */
224 	NULL,	/* reserved */
225 	"RDDE (Read Data Errors)",
226 };
227 
228 static const char *ao_mcactl_bu[] = {
229 	"S_RDE_HP (System read data hardware prefetch)",
230 	"S_RDE_TLB (System read data TLB reload)",
231 	"S_RDE_ALL (All system read data)",
232 	"S_ECC1_TLB (System data 1-bit ECC TLB reload)",
233 	"S_ECC1_HP (System data 1-bit ECC hardware prefetch)",
234 	"S_ECCM_TLB (System data multi-bit ECC TLB reload)",
235 	"S_ECCM_HP (System data multi-bit ECC hardware prefetch)",
236 	"L2T_PAR_ICDC (L2 tag array parity IC or DC fetch)",
237 	"L2T_PAR_TLB (L2 tag array parity TLB reload)",
238 	"L2T_PAR_SNP (L2 tag array parity snoop)",
239 	"L2T_PAR_CPB (L2 tag array parity copyback)",
240 	"L2T_PAR_SCR (L2 tag array parity scrub)",
241 	"L2D_ECC1_TLB (L2 data array 1-bit ECC TLB reload)",
242 	"L2D_ECC1_SNP (L2 data array 1-bit ECC snoop)",
243 	"L2D_ECC1_CPB (L2 data array 1-bit ECC copyback)",
244 	"L2D_ECCM_TLB (L2 data array multi-bit ECC TLB reload)",
245 	"L2D_ECCM_SNP (L2 data array multi-bit ECC snoop)",
246 	"L2D_ECCM_CPB (L2 data array multi-bit ECC copyback)",
247 	"L2T_ECC1_SCR (L2 tag array 1-bit ECC Scrub)",
248 	"L2T_ECCM_SCR (L2 tag array multi-bit ECC Scrub)",
249 };
250 
251 static const char *ao_mcactl_ls[] = {
252 	"S_RDE_L (Read Data Errors on Load)",
253 	"S_RDE_S (Read Data Errors on Store)",
254 };
255 
256 static const char *ao_mcactl_nb[] = {
257 	"CorrEccEn (Correctable ECC Error Reporting Enable)",
258 	"UnCorrEccEn (Uncorrectable ECC Error Reporting Enable)",
259 	"CrcErr0En (HT Link 0 CRC Error Reporting Enable)",
260 	"CrcErr1En (HT Link 1 CRC Error Reporting Enable)",
261 	"CrcErr2En (HT Link 2 CRC Error Reporting Enable)",
262 	"SyncPkt0En (HT Link 0 Sync Packet Error Reporting Enable)",
263 	"SyncPkt1En (HT Link 1 Sync Packet Error Reporting Enable)",
264 	"SyncPkt2En (HT Link 2 Sync Packet Error Reporting Enable)",
265 	"MstrAbrtEn (Master Abort Error Reporting Enable)",
266 	"TgtAbrtEn (Target Abort Error Reporting Enable)",
267 	"GartTblWkEn (GART Table Walk Error Reporting Enable)",
268 	"AtomicRMWEn (Atomic Read-Modify-Write Error Reporting Enable)",
269 	"WchDogTmrEn (Watchdog Timer Error Reporting Enable)",
270 	NULL,	/* reserved */
271 	NULL,	/* reserved */
272 	NULL,	/* reserved */
273 	NULL,	/* reserved */
274 	NULL,	/* reserved */
275 	"DramParEn (DRAM Parity Error Reporting enable)",
276 };
277 
278 static const struct ao_mcactl {
279 	const char *bank_name;
280 	const char **bank_ctlbits;
281 	int bank_tblsz;
282 } ao_mcactls[] = {
283 	{ "dc", &ao_mcactl_dc[0], sizeof (ao_mcactl_dc) / sizeof (char *) },
284 	{ "ic", &ao_mcactl_ic[0], sizeof (ao_mcactl_ic) / sizeof (char *) },
285 	{ "bu", &ao_mcactl_bu[0], sizeof (ao_mcactl_bu) / sizeof (char *) },
286 	{ "ls", &ao_mcactl_ls[0], sizeof (ao_mcactl_ls) / sizeof (char *) },
287 	{ "nb", &ao_mcactl_nb[0], sizeof (ao_mcactl_nb) / sizeof (char *) }
288 };
289 
290 #define	AO_MCI_CTL	0x0
291 #define	AO_MCI_MASK	0x1
292 
293 static int
294 ao_mci_ctlmask_common(uintptr_t val, uint_t flags, int argc,
295     const mdb_arg_t *argv, int which)
296 {
297 	uint64_t bank;
298 	const char *bankname = NULL;
299 	int i;
300 
301 	if (argc != 2 || !(flags & DCMD_ADDRSPEC))
302 		return (DCMD_USAGE);
303 
304 	if (mdb_getopts(argc, argv,
305 	    't', MDB_OPT_STR, &bankname, NULL) != 2)
306 		return (DCMD_USAGE);
307 
308 	for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
309 		if (strncmp(bankname, ao_mcactls[i].bank_name,
310 		    2) == 0) {
311 			bank = i;
312 			break;
313 		}
314 	}
315 
316 	if (i == AMD_MCA_BANK_COUNT) {
317 		mdb_warn("Valid bank names: dc, ic, bu, ls, nb\n");
318 		return (DCMD_ERR);
319 	}
320 
321 	mdb_printf("Reporting %s for %s:\n", which == AO_MCI_CTL ? "enables" :
322 	    "masks", ao_mcactls[bank].bank_name);
323 	mdb_printf("%3s %4s %s\n", "Bit", "Set?", "Description");
324 
325 	for (i = 0; i < 63; i++) {
326 		int set = val & 0x1ULL << i;
327 		int inrange = i < ao_mcactls[bank].bank_tblsz;
328 		const char *desc = ao_mcactls[bank].bank_ctlbits[i];
329 
330 		if (inrange) {
331 			int known = desc != NULL;
332 
333 			mdb_printf("%2d  %4s ", i, set ? "Yes" : "- ");
334 			if (known)
335 				mdb_printf("%s\n", desc);
336 			else
337 				mdb_printf("reserved%s\n",
338 				    set ? " - but set!" : "");
339 		} else if (set) {
340 				mdb_printf("%2d  %4s Reserved - but set!\n",
341 				    i, "Yes");
342 		}
343 	}
344 
345 	return (DCMD_OK);
346 }
347 
348 /*ARGSUSED3*/
349 static int
350 ao_mci_ctl(uintptr_t val, uint_t flags, int argc, const mdb_arg_t *argv)
351 {
352 	return (ao_mci_ctlmask_common(val, flags, argc, argv, AO_MCI_CTL));
353 }
354 
355 /*ARGSUSED3*/
356 static int
357 ao_mci_mask(uintptr_t val, uint_t flags, int argc, const mdb_arg_t *argv)
358 {
359 	return (ao_mci_ctlmask_common(val, flags, argc, argv, AO_MCI_MASK));
360 }
361 
362 static const mdb_dcmd_t dcmds[] = {
363 	{ "ao_nbcfg", ":", "decode Northbridge config bits",
364 	    ao_nbcfg_describe },
365 	{ "ao_scrubctl", ":", "decode Scrub Control Register",
366 	    ao_scrubctl_describe },
367 	{ "ao_sparectl", ":", "decode Online Spare Control Register",
368 	    ao_sparectl_describe },
369 	{ "ao_mci_ctl", ":  -t <dc|ic|bu|ls|nb>",
370 	    "decode MCi_CTL", ao_mci_ctl },
371 	{ "ao_mci_mask", ":  -t <dc|ic|bu|ls|nb>",
372 	    "decode MCi_MASK", ao_mci_mask },
373 	{ NULL }
374 };
375 
376 static const mdb_walker_t walkers[] = {
377 	{ NULL }
378 };
379 
380 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
381 
382 const mdb_modinfo_t *
383 _mdb_init(void)
384 {
385 	return (&modinfo);
386 }
387