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