summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/Makefile.targ5
-rw-r--r--usr/src/uts/common/io/mem.c62
-rw-r--r--usr/src/uts/common/krtld/kobj.c4
-rw-r--r--usr/src/uts/common/krtld/kobj_stubs.c4
-rw-r--r--usr/src/uts/common/os/chip.c12
-rw-r--r--usr/src/uts/common/os/cpu.c52
-rw-r--r--usr/src/uts/common/os/ddifm.c29
-rw-r--r--usr/src/uts/common/os/fm.c184
-rw-r--r--usr/src/uts/common/os/kcpc.c44
-rw-r--r--usr/src/uts/common/os/modconf.c7
-rw-r--r--usr/src/uts/common/os/modctl.c97
-rw-r--r--usr/src/uts/common/os/panic.c3
-rw-r--r--usr/src/uts/common/os/policy.c8
-rw-r--r--usr/src/uts/common/sys/Makefile13
-rw-r--r--usr/src/uts/common/sys/chip.h1
-rw-r--r--usr/src/uts/common/sys/dumphdr.h3
-rw-r--r--usr/src/uts/common/sys/fm/protocol.h15
-rw-r--r--usr/src/uts/common/sys/fm/util.h10
-rw-r--r--usr/src/uts/common/sys/kobj.h4
-rw-r--r--usr/src/uts/common/sys/mem.h10
-rw-r--r--usr/src/uts/common/sys/modctl.h51
-rw-r--r--usr/src/uts/common/sys/policy.h3
-rw-r--r--usr/src/uts/i86pc/Makefile16
-rw-r--r--usr/src/uts/i86pc/Makefile.files9
-rw-r--r--usr/src/uts/i86pc/Makefile.i86pc.shared14
-rw-r--r--usr/src/uts/i86pc/Makefile.rules42
-rw-r--r--usr/src/uts/i86pc/Makefile.workarounds10
-rw-r--r--usr/src/uts/i86pc/amd_opteron/Makefile105
-rw-r--r--usr/src/uts/i86pc/cpu/Makefile.cpu28
-rw-r--r--usr/src/uts/i86pc/cpu/Makefile.files37
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao.h235
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c203
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c135
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c72
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c811
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h67
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in778
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c194
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h72
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c125
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c230
-rw-r--r--usr/src/uts/i86pc/cpu/scripts/Makefile50
-rw-r--r--usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl370
-rw-r--r--usr/src/uts/i86pc/generic_cpu/Makefile82
-rw-r--r--usr/src/uts/i86pc/io/mc/mc-amd.conf31
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd.h192
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_drv.c999
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_off.in55
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_subr.c442
-rw-r--r--usr/src/uts/i86pc/io/rootnex.c26
-rw-r--r--usr/src/uts/i86pc/mc-amd/Makefile97
-rw-r--r--usr/src/uts/i86pc/os/cmi.c299
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c5
-rw-r--r--usr/src/uts/i86pc/os/memscrub.c22
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c28
-rw-r--r--usr/src/uts/i86pc/os/startup.c106
-rw-r--r--usr/src/uts/i86pc/os/trap.c9
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module.h69
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module_impl.h74
-rw-r--r--usr/src/uts/i86pc/sys/machcpuvar.h5
-rw-r--r--usr/src/uts/i86pc/sys/machsystm.h2
-rw-r--r--usr/src/uts/i86pc/sys/rootnex.h19
-rw-r--r--usr/src/uts/i86pc/vm/hat_kdi.c4
-rw-r--r--usr/src/uts/intel/ia32/ml/exception.s41
-rw-r--r--usr/src/uts/intel/ia32/ml/i86_subr.s22
-rw-r--r--usr/src/uts/intel/ia32/sys/trap.h4
-rw-r--r--usr/src/uts/intel/mm/Makefile4
-rw-r--r--usr/src/uts/intel/os/driver_aliases2
-rw-r--r--usr/src/uts/intel/os/name_to_major1
-rw-r--r--usr/src/uts/intel/sys/Makefile7
-rw-r--r--usr/src/uts/intel/sys/archsystm.h4
-rw-r--r--usr/src/uts/intel/sys/controlregs.h5
-rw-r--r--usr/src/uts/intel/sys/fm/cpu/AMD.h223
-rw-r--r--usr/src/uts/intel/sys/mc.h80
-rw-r--r--usr/src/uts/intel/sys/mc_amd.h195
-rw-r--r--usr/src/uts/intel/sys/mca_amd.h418
-rw-r--r--usr/src/uts/intel/sys/mca_x86.h126
-rw-r--r--usr/src/uts/intel/sys/memtest.h126
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h51
-rw-r--r--usr/src/uts/sparc/sys/Makefile35
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h)0
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h)0
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h)0
-rw-r--r--usr/src/uts/sun4u/cpu/us3_common.c11
84 files changed, 7750 insertions, 395 deletions
diff --git a/usr/src/uts/Makefile.targ b/usr/src/uts/Makefile.targ
index aebc896db7..40526b3af2 100644
--- a/usr/src/uts/Makefile.targ
+++ b/usr/src/uts/Makefile.targ
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -146,6 +146,9 @@ $(USR_MOD_DIRS_32): $(USR_MOD_DIR)
$(ROOT_MOD_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) FRC
$(INS.file)
+$(ROOT_CPU_DIR)/%: $(OBJS_DIR)/% $(ROOT_CPU_DIR) FRC
+ $(INS.file)
+
$(ROOT_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_DRV_DIR) FRC
$(INS.file)
diff --git a/usr/src/uts/common/io/mem.c b/usr/src/uts/common/io/mem.c
index 0569b0ebae..11667e8c59 100644
--- a/usr/src/uts/common/io/mem.c
+++ b/usr/src/uts/common/io/mem.c
@@ -68,13 +68,15 @@
#include <sys/debug.h>
#include <sys/fm/protocol.h>
-#ifdef __sparc
+#if defined(__sparc)
extern int cpu_get_mem_name(uint64_t, uint64_t *, uint64_t, char *, int, int *);
extern int cpu_get_mem_info(uint64_t, uint64_t, uint64_t *, uint64_t *,
uint64_t *, int *, int *, int *);
extern size_t cpu_get_name_bufsize(void);
extern int cpu_get_mem_sid(char *, char *, int, int *);
extern int cpu_get_mem_addr(char *, char *, uint64_t, uint64_t *);
+#elif defined(__i386) || defined(__amd64)
+#include <sys/cpu_module.h>
#endif /* __sparc */
/*
@@ -415,6 +417,9 @@ mmwrite(dev_t dev, struct uio *uio, cred_t *cred)
static int
mmioctl_vtop(intptr_t data)
{
+#ifdef _SYSCALL32
+ mem_vtop32_t vtop32;
+#endif
mem_vtop_t mem_vtop;
proc_t *p;
pfn_t pfn = (pfn_t)PFN_INVALID;
@@ -422,13 +427,36 @@ mmioctl_vtop(intptr_t data)
struct as *as;
struct seg *seg;
- if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t)))
- return (EFAULT);
+ if (get_udatamodel() == DATAMODEL_NATIVE) {
+ if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t)))
+ return (EFAULT);
+ }
+#ifdef _SYSCALL32
+ else {
+ if (copyin((void *)data, &vtop32, sizeof (mem_vtop32_t)))
+ return (EFAULT);
+ mem_vtop.m_as = (struct as *)vtop32.m_as;
+ mem_vtop.m_va = (void *)vtop32.m_va;
+
+ if (mem_vtop.m_as != NULL)
+ return (EINVAL);
+ }
+#endif
+
if (mem_vtop.m_as == &kas) {
pfn = hat_getpfnum(kas.a_hat, mem_vtop.m_va);
- } else if (mem_vtop.m_as == NULL) {
- return (EIO);
} else {
+ if (mem_vtop.m_as == NULL) {
+ /*
+ * Assume the calling process's address space if the
+ * caller didn't specify one.
+ */
+ p = curthread->t_procp;
+ if (p == NULL)
+ return (EIO);
+ mem_vtop.m_as = p->p_as;
+ }
+
mutex_enter(&pidlock);
for (p = practive; p != NULL; p = p->p_next) {
if (p->p_as == mem_vtop.m_as) {
@@ -461,8 +489,18 @@ mmioctl_vtop(intptr_t data)
mem_vtop.m_pfn = pfn;
if (pfn == PFN_INVALID)
return (EIO);
- if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t)))
- return (EFAULT);
+
+ if (get_udatamodel() == DATAMODEL_NATIVE) {
+ if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t)))
+ return (EFAULT);
+ }
+#ifdef _SYSCALL32
+ else {
+ vtop32.m_pfn = mem_vtop.m_pfn;
+ if (copyout(&vtop32, (void *)data, sizeof (mem_vtop32_t)))
+ return (EFAULT);
+ }
+#endif
return (0);
}
@@ -533,7 +571,7 @@ mmioctl_page_fmri_retire(int cmd, intptr_t data)
if ((err = mm_get_mem_fmri(&mpage, &nvl)) < 0)
return (err);
- if ((err = mm_get_paddr(nvl, &pa)) < 0) {
+ if ((err = mm_get_paddr(nvl, &pa)) != 0) {
nvlist_free(nvl);
return (err);
}
@@ -1120,7 +1158,7 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr)
* If the "offset" member is not present, then the address is
* retrieved from the "physaddr" member.
*/
-#ifdef __sparc
+#if defined(__sparc)
if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0) {
if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) !=
0) {
@@ -1134,9 +1172,11 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr)
if ((err = cpu_get_mem_addr(unum, serids[0], offset, &pa)) != 0)
return (err);
}
-#else /* __i386, __amd64 */
- if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 0)
+#elif defined(__i386) || defined(__amd64)
+ if (cmi_mc_unumtopa(NULL, nvl, &pa) == 0)
return (EINVAL);
+#else
+#error "port me"
#endif /* __sparc */
*paddr = pa;
diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c
index 6df0916ea0..003022d104 100644
--- a/usr/src/uts/common/krtld/kobj.c
+++ b/usr/src/uts/common/krtld/kobj.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2970,7 +2970,7 @@ kobj_getelfsym(char *name, void *mp, int *size)
}
uintptr_t
-kobj_lookup(void *mod, char *name)
+kobj_lookup(struct module *mod, const char *name)
{
Sym *sp;
diff --git a/usr/src/uts/common/krtld/kobj_stubs.c b/usr/src/uts/common/krtld/kobj_stubs.c
index 7bc82c5139..3d972194bb 100644
--- a/usr/src/uts/common/krtld/kobj_stubs.c
+++ b/usr/src/uts/common/krtld/kobj_stubs.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -159,7 +159,7 @@ kobj_searchsym(struct module *mp, uintptr_t value, ulong_t *offset)
/*ARGSUSED*/
uintptr_t
-kobj_lookup(void *mod, char *name)
+kobj_lookup(struct module *mod, const char *name)
{
return (0);
}
diff --git a/usr/src/uts/common/os/chip.c b/usr/src/uts/common/os/chip.c
index b6fcbe89d2..8b0bfd765d 100644
--- a/usr/src/uts/common/os/chip.c
+++ b/usr/src/uts/common/os/chip.c
@@ -124,6 +124,18 @@ chip_find(chipid_t chipid)
return (NULL);
}
+chip_t *
+chip_lookup(chipid_t chipid)
+{
+ chip_t *chp;
+
+ mutex_enter(&cpu_lock);
+ chp = chip_find(chipid);
+ mutex_exit(&cpu_lock);
+
+ return (chp);
+}
+
#ifndef sun4v
/*
* Setup the kstats for this chip, if needed
diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c
index e9f4453f81..674f8bd6e5 100644
--- a/usr/src/uts/common/os/cpu.c
+++ b/usr/src/uts/common/os/cpu.c
@@ -59,6 +59,9 @@
#include <sys/msacct.h>
#include <sys/time.h>
#include <sys/archsystm.h>
+#if defined(__i386) || defined(__amd64)
+#include <sys/x86_archext.h>
+#endif
extern int mp_cpu_start(cpu_t *);
extern int mp_cpu_stop(cpu_t *);
@@ -2067,12 +2070,19 @@ static struct {
kstat_named_t ci_clock_MHz;
kstat_named_t ci_chip_id;
kstat_named_t ci_implementation;
-#ifdef __sparcv9
+ kstat_named_t ci_brandstr;
+ kstat_named_t ci_core_id;
+#if defined(__sparcv9)
kstat_named_t ci_device_ID;
kstat_named_t ci_cpu_fru;
#endif
- kstat_named_t ci_brandstr;
- kstat_named_t ci_core_id;
+#if defined(__i386) || defined(__amd64)
+ kstat_named_t ci_vendorstr;
+ kstat_named_t ci_family;
+ kstat_named_t ci_model;
+ kstat_named_t ci_step;
+ kstat_named_t ci_clogid;
+#endif
} cpu_info_template = {
{ "state", KSTAT_DATA_CHAR },
{ "state_begin", KSTAT_DATA_LONG },
@@ -2081,12 +2091,19 @@ static struct {
{ "clock_MHz", KSTAT_DATA_LONG },
{ "chip_id", KSTAT_DATA_LONG },
{ "implementation", KSTAT_DATA_STRING },
-#ifdef __sparcv9
+ { "brand", KSTAT_DATA_STRING },
+ { "core_id", KSTAT_DATA_LONG },
+#if defined(__sparcv9)
{ "device_ID", KSTAT_DATA_UINT64 },
{ "cpu_fru", KSTAT_DATA_STRING },
#endif
- { "brand", KSTAT_DATA_STRING },
- { "core_id", KSTAT_DATA_LONG },
+#if defined(__i386) || defined(__amd64)
+ { "vendor_id", KSTAT_DATA_STRING },
+ { "family", KSTAT_DATA_INT32 },
+ { "model", KSTAT_DATA_INT32 },
+ { "stepping", KSTAT_DATA_INT32 },
+ { "clog_id", KSTAT_DATA_INT32 },
+#endif
};
static kmutex_t cpu_info_template_lock;
@@ -2132,13 +2149,23 @@ cpu_info_kstat_update(kstat_t *ksp, int rw)
cpu_info_template.ci_chip_id.value.l = chip_plat_get_chipid(cp);
kstat_named_setstr(&cpu_info_template.ci_implementation,
cp->cpu_idstr);
-#ifdef __sparcv9
+ kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr);
+
+#if defined(__sparcv9)
cpu_info_template.ci_device_ID.value.ui64 =
cpunodes[cp->cpu_id].device_id;
kstat_named_setstr(&cpu_info_template.ci_cpu_fru, cpu_fru_fmri(cp));
#endif
- kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr);
+#if defined(__i386) || defined(__amd64)
cpu_info_template.ci_core_id.value.l = chip_plat_get_coreid(cp);
+ kstat_named_setstr(&cpu_info_template.ci_vendorstr,
+ cpuid_getvendorstr(cp));
+ cpu_info_template.ci_family.value.l = cpuid_getfamily(cp);
+ cpu_info_template.ci_model.value.l = cpuid_getmodel(cp);
+ cpu_info_template.ci_step.value.l = cpuid_getstep(cp);
+ cpu_info_template.ci_clogid.value.l = chip_plat_get_clogid(cp);
+#endif
+
return (0);
}
@@ -2155,13 +2182,16 @@ cpu_info_kstat_create(cpu_t *cp)
zoneid = ALL_ZONES;
if ((cp->cpu_info_kstat = kstat_create_zone("cpu_info", cp->cpu_id,
NULL, "misc", KSTAT_TYPE_NAMED,
- sizeof (cpu_info_template) / sizeof (kstat_named_t),
- KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) {
+ sizeof (cpu_info_template) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) {
cp->cpu_info_kstat->ks_data_size += 2 * CPU_IDSTRLEN;
-#ifdef __sparcv9
+#if defined(__sparcv9)
cp->cpu_info_kstat->ks_data_size +=
strlen(cpu_fru_fmri(cp)) + 1;
#endif
+#if defined(__i386) || defined(__amd64)
+ cp->cpu_info_kstat->ks_data_size += X86_VENDOR_STRLEN;
+#endif
cp->cpu_info_kstat->ks_lock = &cpu_info_template_lock;
cp->cpu_info_kstat->ks_data = &cpu_info_template;
cp->cpu_info_kstat->ks_private = cp;
diff --git a/usr/src/uts/common/os/ddifm.c b/usr/src/uts/common/os/ddifm.c
index 911a7d9a2f..6edd829ba8 100644
--- a/usr/src/uts/common/os/ddifm.c
+++ b/usr/src/uts/common/os/ddifm.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -477,7 +477,10 @@ ddi_fm_handler_register(dev_info_t *dip, ddi_err_func_t handler,
return;
}
- pdip = (dev_info_t *)DEVI(dip)->devi_parent;
+ if (dip == ddi_root_node())
+ pdip = dip;
+ else
+ pdip = (dev_info_t *)DEVI(dip)->devi_parent;
ASSERT(pdip);
@@ -529,7 +532,10 @@ ddi_fm_handler_unregister(dev_info_t *dip)
return;
}
- pdip = (dev_info_t *)DEVI(dip)->devi_parent;
+ if (dip == ddi_root_node())
+ pdip = dip;
+ else
+ pdip = (dev_info_t *)DEVI(dip)->devi_parent;
ASSERT(pdip);
@@ -581,10 +587,11 @@ ddi_fm_handler_unregister(dev_info_t *dip)
* This function must be called from a driver's attach(9E) entry point.
*/
void
-ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
+ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibcp)
{
struct dev_info *devi = DEVI(dip);
struct i_ddi_fmhdl *fmhdl;
+ ddi_iblock_cookie_t ibc;
int pcap, newcap = DDI_FM_NOT_CAPABLE;
if (!DEVI_IS_ATTACHING(dip)) {
@@ -606,11 +613,12 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
* Initialize the default ibc. The parent may change it
* depending upon its capabilities.
*/
- *ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL);
+ ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL);
- pcap = i_ndi_busop_fm_init(dip, *fmcap, ibc);
+ pcap = i_ndi_busop_fm_init(dip, *fmcap, &ibc);
} else {
pcap = *fmcap;
+ ibc = *ibcp;
}
/* Initialize the per-device instance FM handle */
@@ -636,7 +644,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
fmhdl->fh_acc_cache = NULL;
fmhdl->fh_tgts = NULL;
fmhdl->fh_dip = dip;
- fmhdl->fh_ibc = *ibc;
+ fmhdl->fh_ibc = ibc;
mutex_init(&fmhdl->fh_lock, NULL, MUTEX_DRIVER, fmhdl->fh_ibc);
devi->devi_fmhdl = fmhdl;
@@ -672,7 +680,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
*/
if (DDI_FM_DMA_ERR_CAP(*fmcap) && DDI_FM_DMA_ERR_CAP(pcap)) {
- i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, *ibc);
+ i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, ibc);
/* Set-up dma chk capability prop */
if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
@@ -684,7 +692,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
}
if (DDI_FM_ACC_ERR_CAP(*fmcap) && DDI_FM_ACC_ERR_CAP(pcap)) {
- i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, *ibc);
+ i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, ibc);
/* Set-up dma chk capability prop */
if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"fm-accchk-capable", 0) == 0)
@@ -700,6 +708,9 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc)
*/
fmhdl->fh_cap = newcap;
*fmcap = newcap;
+
+ if (ibcp != NULL)
+ *ibcp = ibc;
}
/*
diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c
index 33e8357a88..897697c2dc 100644
--- a/usr/src/uts/common/os/fm.c
+++ b/usr/src/uts/common/os/fm.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,7 +60,6 @@
#include <sys/sysevent.h>
#include <sys/sysevent_impl.h>
#include <sys/nvpair.h>
-#include <sys/nvpair_impl.h>
#include <sys/cmn_err.h>
#include <sys/cpuvar.h>
#include <sys/sysmacros.h>
@@ -73,6 +72,8 @@
#include <sys/cpuvar.h>
#include <sys/console.h>
#include <sys/panic.h>
+#include <sys/kobj.h>
+#include <sys/sunddi.h>
#include <sys/systeminfo.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/fm/util.h>
@@ -614,15 +615,13 @@ fm_nvlist_create(nv_alloc_t *nva)
void
fm_nvlist_destroy(nvlist_t *nvl, int flag)
{
- nv_alloc_t *nvhdl;
-
- nvhdl = ((nvpriv_t *)(uintptr_t)nvl->nvl_priv)->nvp_nva;
+ nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
nvlist_free(nvl);
- if (nvhdl != NULL) {
+ if (nva != NULL) {
if (flag == FM_NVA_FREE)
- fm_nva_xdestroy(nvhdl);
+ fm_nva_xdestroy(nva);
}
}
@@ -820,53 +819,88 @@ fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
}
+/*
+ * Set-up and validate the members of an hc fmri according to;
+ *
+ * Member name Type Value
+ * ===================================================
+ * version uint8_t 0
+ * auth nvlist_t <auth>
+ * hc-name string <name>
+ * hc-id string <id>
+ *
+ * Note that auth and hc-id are optional members.
+ */
+
+#define HC_MAXPAIRS 20
+#define HC_MAXNAMELEN 50
+
static int
-i_fm_fmri_hc_set_v0(nvlist_t *hc, uint32_t size, va_list ap)
+fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth)
{
- int i, ret;
- const char *name, *id;
- nvlist_t **hc_nvl;
+ if (version != FM_HC_SCHEME_VERSION) {
+ atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ return (0);
+ }
- if (size <= 0)
+ if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 ||
+ nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) {
+ atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
return (0);
+ }
- hc_nvl = kmem_zalloc(size * sizeof (nvlist_t *), KM_SLEEP);
+ if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
+ (nvlist_t *)auth) != 0) {
+ atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ return (0);
+ }
- for (i = 0; i < size; ++i) {
- name = va_arg(ap, const char *);
- if (name == NULL) {
- ret = EINVAL;
- goto fail;
- }
- id = va_arg(ap, const char *);
- if ((hc_nvl[i] = fm_nvlist_create(
- ((nvpriv_t *)(uintptr_t)hc->nvl_priv)->nvp_nva)) == NULL) {
- ret = ENOMEM;
- goto fail;
+ return (1);
+}
+
+void
+fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
+ nvlist_t *snvl, int npairs, ...)
+{
+ nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
+ nvlist_t *pairs[HC_MAXPAIRS];
+ va_list ap;
+ int i;
+
+ if (!fm_fmri_hc_set_common(fmri, version, auth))
+ return;
+
+ npairs = MIN(npairs, HC_MAXPAIRS);
+
+ va_start(ap, npairs);
+ for (i = 0; i < npairs; i++) {
+ const char *name = va_arg(ap, const char *);
+ uint32_t id = va_arg(ap, uint32_t);
+ char idstr[11];
+
+ (void) snprintf(idstr, sizeof (idstr), "%u", id);
+
+ pairs[i] = fm_nvlist_create(nva);
+ if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
+ nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
+ atomic_add_64(
+ &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
}
- if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME,
- name)) != 0)
- goto fail;
- if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID,
- id)) != 0)
- goto fail;
}
+ va_end(ap);
- if ((ret = nvlist_add_nvlist_array(hc, FM_FMRI_HC_LIST, hc_nvl,
- size)) != 0)
- goto fail;
+ if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0)
+ atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
- kmem_free(hc_nvl, size * sizeof (nvlist_t *));
- return (0);
+ for (i = 0; i < npairs; i++)
+ fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
-fail:
- for (i = 0; i < size; ++i) {
- if (hc_nvl[i] != NULL)
- fm_nvlist_destroy(hc_nvl[i], FM_NVA_RETAIN);
+ if (snvl != NULL) {
+ if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
+ atomic_add_64(
+ &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ }
}
-
- kmem_free(hc_nvl, size * sizeof (nvlist_t *));
- return (ret);
}
/*
@@ -930,47 +964,45 @@ fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
* cpumask uint8_t <cpu_mask>
* serial uint64_t <serial_id>
*
- * Note that auth is an optional member.
+ * Note that auth, cpumask, serial are optional members.
*
*/
void
fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
- uint32_t cpu_id, uint8_t cpu_mask, uint64_t serial_id)
+ uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp)
{
- if (version != CPU_SCHEME_VERSION0) {
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
+
+ if (version < CPU_SCHEME_VERSION1) {
+ atomic_add_64(failedp, 1);
return;
}
if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ atomic_add_64(failedp, 1);
return;
}
if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
FM_FMRI_SCHEME_CPU) != 0) {
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ atomic_add_64(failedp, 1);
return;
}
- if (auth != NULL)
- if (nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
- (nvlist_t *)auth) != 0) {
- atomic_add_64(
- &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
- }
+ if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
+ (nvlist_t *)auth) != 0)
+ atomic_add_64(failedp, 1);
- if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) {
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
- }
+ if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
+ atomic_add_64(failedp, 1);
- if (nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, cpu_mask) != 0) {
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
- }
+ if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
+ *cpu_maskp) != 0)
+ atomic_add_64(failedp, 1);
- if (nvlist_add_uint64(fmri_cpu, FM_FMRI_CPU_SERIAL_ID, serial_id)
- != 0)
- atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+ if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
+ FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
+ atomic_add_64(failedp, 1);
}
/*
@@ -1159,3 +1191,29 @@ fm_ena_time_get(uint64_t ena)
return (time);
}
+
+/*
+ * Convert a getpcstack() trace to symbolic name+offset, and add the resulting
+ * string array to a Fault Management ereport as FM_EREPORT_PAYLOAD_NAME_STACK.
+ */
+void
+fm_payload_stack_add(nvlist_t *payload, const pc_t *stack, int depth)
+{
+ int i;
+ char *sym;
+ ulong_t off;
+ char *stkpp[FM_STK_DEPTH];
+ char buf[FM_STK_DEPTH * FM_SYM_SZ];
+ char *stkp = buf;
+
+ for (i = 0; i < depth && i != FM_STK_DEPTH; i++, stkp += FM_SYM_SZ) {
+ if ((sym = kobj_getsymname(stack[i], &off)) != NULL)
+ (void) snprintf(stkp, FM_SYM_SZ, "%s+%lx", sym, off);
+ else
+ (void) snprintf(stkp, FM_SYM_SZ, "%lx", (long)stack[i]);
+ stkpp[i] = stkp;
+ }
+
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_STACK,
+ DATA_TYPE_STRING_ARRAY, FM_STK_DEPTH, stkpp, NULL);
+}
diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c
index f3bfd93d24..569344e8ca 100644
--- a/usr/src/uts/common/os/kcpc.c
+++ b/usr/src/uts/common/os/kcpc.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1515,41 +1516,12 @@ kcpc_invalidate(kthread_t *t)
int
kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third)
{
- char modname[PCBE_NAMELEN];
- char stub[PCBE_NAMELEN];
-
- if (prefix != NULL)
- (void) snprintf(stub, PCBE_NAMELEN, "pcbe.%s", prefix);
- else
- (void) snprintf(stub, PCBE_NAMELEN, "pcbe");
-
- (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u.%u",
- stub, first, second, third);
-
- DTRACE_PROBE1(kcpc__pcbe__spec, char *, modname);
-
- if (modload("pcbe", modname) >= 0)
- return (0);
-
- (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u",
- stub, first, second);
- if (modload("pcbe", modname) >= 0)
- return (0);
-
- (void) snprintf(modname, PCBE_NAMELEN, "%s.%u", stub, first);
- if (modload("pcbe", modname) >= 0)
- return (0);
-
- if (prefix == NULL)
- /*
- * If no prefix was given, we have tried all possible
- * PCBE names.
- */
- return (-1);
+ uint_t s[3];
- (void) snprintf(modname, PCBE_NAMELEN, "%s", stub);
- if (modload("pcbe", modname) >= 0)
- return (0);
+ s[0] = first;
+ s[1] = second;
+ s[2] = third;
- return (-1);
+ return (modload_qualified("pcbe",
+ "pcbe", prefix, ".", s, 3) < 0 ? -1 : 0);
}
diff --git a/usr/src/uts/common/os/modconf.c b/usr/src/uts/common/os/modconf.c
index 2c033495bc..f270cad2a0 100644
--- a/usr/src/uts/common/os/modconf.c
+++ b/usr/src/uts/common/os/modconf.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -101,6 +101,11 @@ struct mod_ops mod_miscops = {
mod_null, mod_null, mod_infonull
};
+/* CPU Modules */
+struct mod_ops mod_cpuops = {
+ mod_null, mod_null, mod_infonull
+};
+
/*
* Cryptographic Modules
*/
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index 73e0447ab1..e776a36310 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -19,6 +19,7 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -84,15 +85,14 @@ static int modinfo(modid_t, struct modinfo *);
static void mod_uninstall_all(void);
static int mod_getinfo(struct modctl *, struct modinfo *);
-static struct modctl *allocate_modp(char *, char *);
+static struct modctl *allocate_modp(const char *, const char *);
static int mod_load(struct modctl *, int);
static void mod_unload(struct modctl *);
static int modinstall(struct modctl *);
static int moduninstall(struct modctl *);
-static struct modctl *mod_hold_by_name_common(struct modctl *, char *);
-static struct modctl *mod_hold_by_id(modid_t);
+static struct modctl *mod_hold_by_name_common(struct modctl *, const char *);
static struct modctl *mod_hold_next_by_id(modid_t);
static struct modctl *mod_hold_loaded_mod(struct modctl *, char *, int *);
static struct modctl *mod_hold_installed_mod(char *, int, int *);
@@ -1943,6 +1943,71 @@ modload(char *subdir, char *filename)
}
/*
+ * Load a module using a series of qualified names from most specific to least
+ * specific, e.g. for subdir "foo", p1 "bar", p2 "baz", we might try:
+ *
+ * foo/bar.baz.1.2.3
+ * foo/bar.baz.1.2
+ * foo/bar.baz.1
+ *
+ * Return the module ID on success; -1 if no module was loaded.
+ */
+int
+modload_qualified(const char *subdir, const char *p1,
+ const char *p2, const char *delim, uint_t suffv[], int suffc)
+{
+ char path[MOD_MAXPATH];
+ size_t n, resid = sizeof (path);
+ char *p = path;
+
+ char **dotv;
+ int i, rc, id;
+ modctl_t *mp;
+
+ if (p2 != NULL)
+ n = snprintf(p, resid, "%s/%s%s%s", subdir, p1, delim, p2);
+ else
+ n = snprintf(p, resid, "%s/%s", subdir, p1);
+
+ if (n >= resid)
+ return (-1);
+
+ p += n;
+ resid -= n;
+ dotv = kmem_alloc(sizeof (char *) * (suffc + 1), KM_SLEEP);
+
+ for (i = 0; i < suffc; i++) {
+ dotv[i] = p;
+ n = snprintf(p, resid, "%s%u", delim, suffv[i]);
+
+ if (n >= resid) {
+ kmem_free(dotv, sizeof (char *) * (suffc + 1));
+ return (-1);
+ }
+
+ p += n;
+ resid -= n;
+ }
+
+ dotv[suffc] = p;
+
+ for (i = suffc; i >= 0; i--) {
+ dotv[i][0] = '\0';
+ mp = mod_hold_installed_mod(path, 1, &rc);
+
+ if (mp != NULL) {
+ kmem_free(dotv, sizeof (char *) * (suffc + 1));
+ id = mp->mod_id;
+ mod_release_mod(mp);
+ return (id);
+ }
+ }
+
+ kmem_free(dotv, sizeof (char *) * (suffc + 1));
+ return (-1);
+}
+
+/*
* Load a module.
*/
int
@@ -2440,7 +2505,7 @@ modadd(struct modctl *mp)
/*ARGSUSED*/
static struct modctl *
-allocate_modp(char *filename, char *modname)
+allocate_modp(const char *filename, const char *modname)
{
struct modctl *mp;
@@ -2473,12 +2538,12 @@ modgetsymname(uintptr_t value, ulong_t *offset)
}
/*
- * Lookup a symbol in a specified module. This is a wrapper routine that
- * calls kobj_lookup(). kobj_lookup() may go away but this
- * wrapper will prevent callers from noticing.
+ * Lookup a symbol in a specified module. These are wrapper routines that
+ * call kobj_lookup(). kobj_lookup() may go away but these wrappers will
+ * prevent callers from noticing.
*/
uintptr_t
-modlookup(char *modname, char *symname)
+modlookup(const char *modname, const char *symname)
{
struct modctl *modp;
uintptr_t val;
@@ -2490,6 +2555,14 @@ modlookup(char *modname, char *symname)
return (val);
}
+uintptr_t
+modlookup_by_modctl(modctl_t *modp, const char *symname)
+{
+ ASSERT(modp->mod_ref > 0 || modp->mod_busy);
+
+ return (kobj_lookup(modp->mod_mp, symname));
+}
+
/*
* Ask the user for the name of the system file and the default path
* for modules.
@@ -3149,9 +3222,9 @@ mod_hold_by_modctl(struct modctl *mp, int f)
}
static struct modctl *
-mod_hold_by_name_common(struct modctl *dep, char *filename)
+mod_hold_by_name_common(struct modctl *dep, const char *filename)
{
- char *modname;
+ const char *modname;
struct modctl *mp;
char *curname, *newname;
int found = 0;
@@ -3232,12 +3305,12 @@ mod_hold_by_name_requisite(struct modctl *dep, char *filename)
}
struct modctl *
-mod_hold_by_name(char *filename)
+mod_hold_by_name(const char *filename)
{
return (mod_hold_by_name_common(NULL, filename));
}
-static struct modctl *
+struct modctl *
mod_hold_by_id(modid_t modid)
{
struct modctl *mp;
diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c
index e085b0e586..87910574f5 100644
--- a/usr/src/uts/common/os/panic.c
+++ b/usr/src/uts/common/os/panic.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -143,6 +143,7 @@
#include <sys/spl.h>
#include <sys/errorq.h>
#include <sys/panic.h>
+#include <sys/fm/util.h>
/*
* Panic variables which are set once during the QUIESCE state by the
diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c
index 0dccc35dce..fe4a5c82df 100644
--- a/usr/src/uts/common/os/policy.c
+++ b/usr/src/uts/common/os/policy.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1279,6 +1279,12 @@ secpolicy_kmdb(const cred_t *scr)
return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL));
}
+int
+secpolicy_error_inject(const cred_t *scr)
+{
+ return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL));
+}
+
/*
* Processor sets, cpu configuration, resource pools.
*/
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index bb8e6e8d7a..f82a933903 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -20,7 +20,7 @@
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -657,12 +657,6 @@ FMHDRS= \
protocol.h \
util.h
-sparc_FMCPUHDRS= \
- UltraSPARC-II.h \
- UltraSPARC-III.h \
- UltraSPARC-T1.h
-FMCPUHDRS=$($(MACH)_FMCPUHDRS)
-
FMIOHDRS= \
ddi.h \
pci.h \
@@ -920,7 +914,6 @@ CHECKHDRS= \
$(TAVORHDRS:%.h=ib/adapters/tavor/%.check) \
$(ISOHDRS:%.h=iso/%.check) \
$(FMHDRS:%.h=fm/%.check) \
- $(FMCPUHDRS:%.h=fm/cpu/%.check) \
$(FMIOHDRS:%.h=fm/io/%.check) \
$(FSHDRS:%.h=fs/%.check) \
$(LVMHDRS:%.h=lvm/%.check) \
@@ -955,8 +948,7 @@ CHECKHDRS= \
$(ROOTDCAMHDRS) \
$(ROOTISOHDRS) \
$(ROOTFMHDRS) \
- $(ROOTFMCPUHDRS) \
- $(ROOTFMIOHDRS) \
+ $(ROOTFMIOHDRS) \
$(ROOTFSHDRS) \
$(ROOTIBDHDRS) \
$(ROOTIBHDRS) \
@@ -1000,7 +992,6 @@ install_h: \
$(ROOTDCAMHDRS) \
$(ROOTISOHDRS) \
$(ROOTFMHDRS) \
- $(ROOTFMCPUHDRS) \
$(ROOTFMIOHDRS) \
$(ROOTFSHDRS) \
$(ROOTIBDHDRS) \
diff --git a/usr/src/uts/common/sys/chip.h b/usr/src/uts/common/sys/chip.h
index e33b521783..80b9541d9a 100644
--- a/usr/src/uts/common/sys/chip.h
+++ b/usr/src/uts/common/sys/chip.h
@@ -172,6 +172,7 @@ void chip_cpu_fini(cpu_t *);
void chip_cpu_assign(cpu_t *);
void chip_cpu_unassign(cpu_t *);
void chip_cpu_startup(cpu_t *);
+chip_t *chip_lookup(chipid_t);
void chip_bootstrap_cpu(cpu_t *);
void chip_cpu_move_part(cpu_t *, struct cpupart *,
diff --git a/usr/src/uts/common/sys/dumphdr.h b/usr/src/uts/common/sys/dumphdr.h
index 7be14a40ed..5949b218c8 100644
--- a/usr/src/uts/common/sys/dumphdr.h
+++ b/usr/src/uts/common/sys/dumphdr.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,7 +33,6 @@
#include <sys/param.h>
#include <sys/utsname.h>
#include <sys/log.h>
-#include <sys/fm/util.h>
#ifdef __cplusplus
extern "C" {
diff --git a/usr/src/uts/common/sys/fm/protocol.h b/usr/src/uts/common/sys/fm/protocol.h
index 32f4d099f0..89b761ef6c 100644
--- a/usr/src/uts/common/sys/fm/protocol.h
+++ b/usr/src/uts/common/sys/fm/protocol.h
@@ -21,7 +21,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -177,7 +177,8 @@ extern "C" {
#define FM_HC_VERS0 0
#define FM_HC_SCHEME_VERSION FM_HC_VERS0
#define CPU_SCHEME_VERSION0 0
-#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION0
+#define CPU_SCHEME_VERSION1 1
+#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION1
#define MEM_SCHEME_VERSION0 0
#define FM_MEM_SCHEME_VERSION MEM_SCHEME_VERSION0
#define MOD_SCHEME_VERSION0 0
@@ -194,6 +195,7 @@ extern "C" {
#define FM_FMRI_HC_ROOT "hc-root"
#define FM_FMRI_HC_LIST_SZ "hc-list-sz"
#define FM_FMRI_HC_LIST "hc-list"
+#define FM_FMRI_HC_SPECIFIC "hc-specific"
/* hc-list version and member names */
#define FM_FMRI_HC_NAME "hc-name"
@@ -202,6 +204,9 @@ extern "C" {
#define HC_LIST_VERSION0 0
#define FM_HC_LIST_VERSION HC_LIST_VERSION0
+/* hc-specific member names */
+#define FM_FMRI_HC_SPECIFIC_OFFSET "offset"
+
/* fmd module scheme member names */
#define FM_FMRI_FMD_NAME "mod-name"
#define FM_FMRI_FMD_VERSION "mod-version"
@@ -261,13 +266,13 @@ extern void fm_ereport_set(nvlist_t *, int, const char *, uint64_t,
const nvlist_t *, ...);
extern void fm_payload_set(nvlist_t *, ...);
extern int i_fm_payload_set(nvlist_t *, const char *, va_list);
-extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, const char *,
- const char *, const char *, const char *, uint32_t, ...);
+extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, nvlist_t *,
+ int, ...);
extern void fm_fmri_dev_set(nvlist_t *, int, const nvlist_t *, const char *,
const char *);
extern void fm_fmri_de_set(nvlist_t *, int, const nvlist_t *, const char *);
extern void fm_fmri_cpu_set(nvlist_t *, int, const nvlist_t *, uint32_t,
- uint8_t, uint64_t);
+ uint8_t *, const char *);
extern void fm_fmri_mem_set(nvlist_t *, int, const nvlist_t *, const char *,
const char *, uint64_t);
extern void fm_authority_set(nvlist_t *, int, const char *, const char *,
diff --git a/usr/src/uts/common/sys/fm/util.h b/usr/src/uts/common/sys/fm/util.h
index c0dc908ddc..33f5876cab 100644
--- a/usr/src/uts/common/sys/fm/util.h
+++ b/usr/src/uts/common/sys/fm/util.h
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,9 +75,14 @@ typedef struct erpt_dump {
} erpt_dump_t;
#ifdef _KERNEL
+#include <sys/systm.h>
+#define FM_STK_DEPTH 20 /* maximum stack depth */
+#define FM_SYM_SZ 64 /* maximum symbol size */
#define FM_ERR_PIL 2 /* PIL for ereport_errorq drain processing */
+#define FM_EREPORT_PAYLOAD_NAME_STACK "stack"
+
extern errorq_t *ereport_errorq;
extern void *ereport_dumpbuf;
extern size_t ereport_dumplen;
@@ -89,6 +95,8 @@ extern void fm_banner(void);
extern void fm_ereport_dump(void);
extern void fm_ereport_post(nvlist_t *, int);
+extern void fm_payload_stack_add(nvlist_t *, const pc_t *, int);
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/kobj.h b/usr/src/uts/common/sys/kobj.h
index c2f8b2f9cb..7d2bd0922e 100644
--- a/usr/src/uts/common/sys/kobj.h
+++ b/usr/src/uts/common/sys/kobj.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -152,7 +152,7 @@ typedef struct {
extern int kobj_load_module(struct modctl *, int);
extern void kobj_unload_module(struct modctl *);
-extern uintptr_t kobj_lookup(void *, char *);
+extern uintptr_t kobj_lookup(struct module *, const char *);
extern Sym *kobj_lookup_all(struct module *, char *, int);
extern int kobj_addrcheck(void *, caddr_t);
extern int kobj_module_to_id(void *);
diff --git a/usr/src/uts/common/sys/mem.h b/usr/src/uts/common/sys/mem.h
index f6f749ef0e..d1307589a1 100644
--- a/usr/src/uts/common/sys/mem.h
+++ b/usr/src/uts/common/sys/mem.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -55,6 +55,14 @@ typedef struct mem_vtop {
pfn_t m_pfn;
} mem_vtop_t;
+#if defined(_SYSCALL32)
+typedef struct mem_vtop32 {
+ uint32_t m_as;
+ uint32_t m_va;
+ uint32_t m_pfn;
+} mem_vtop32_t;
+#endif
+
/*
* Private ioctls for fmd(1M). These interfaces are Sun Private. Applications
* and drivers should not make use of these interfaces: they can change without
diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h
index 06019d5f0f..d2f4cfd803 100644
--- a/usr/src/uts/common/sys/modctl.h
+++ b/usr/src/uts/common/sys/modctl.h
@@ -62,6 +62,9 @@ struct mod_ops {
* The defined set of mod_ops structures for each loadable module type
* Defined in modctl.c
*/
+#if defined(__i386) || defined(__amd64)
+extern struct mod_ops mod_cpuops;
+#endif
extern struct mod_ops mod_cryptoops;
extern struct mod_ops mod_driverops;
extern struct mod_ops mod_execops;
@@ -107,6 +110,17 @@ struct modlfs {
struct vfsdef_v3 *fs_vfsdef; /* version may actually vary */
};
+#if defined(__i386) || defined(__amd64)
+struct cmi_ops;
+
+/* For CPU modules */
+struct modlcpu {
+ struct mod_ops *cpu_modops;
+ char *cpu_linkinfo;
+ struct cmi_ops *cpu_cmiops;
+};
+#endif
+
/* For cryptographic providers */
struct modlcrypto {
struct mod_ops *crypto_modops;
@@ -417,7 +431,7 @@ struct modctl_list {
* are replicated in the modctl structure so that mod_containing_pc()
* doesn't have to grab any locks (modctls are persistent; modules are not.)
*/
-struct modctl {
+typedef struct modctl {
struct modctl *mod_next; /* &modules based list */
struct modctl *mod_prev;
int mod_id;
@@ -449,7 +463,7 @@ struct modctl {
int mod_gencount; /* # times loaded/unloaded */
struct modctl *mod_requisite_loading; /* mod circular dependency */
-};
+} modctl_t;
/*
* mod_loadflags
@@ -479,7 +493,10 @@ extern int moddebug;
* this is the head of a doubly linked list. Only the next and prev
* pointers are used
*/
-extern struct modctl modules;
+extern modctl_t modules;
+
+extern int modload_qualified(const char *,
+ const char *, const char *, const char *, uint_t[], int);
extern void mod_setup(void);
extern int modload(char *, char *);
@@ -494,7 +511,7 @@ extern int mod_remove_by_name(char *);
extern int mod_sysvar(const char *, const char *, u_longlong_t *);
extern int mod_sysctl(int, void *);
struct sysparam;
-extern int mod_hold_by_modctl(struct modctl *, int);
+extern int mod_hold_by_modctl(modctl_t *, int);
#define MOD_WAIT_ONCE 0x01
#define MOD_WAIT_FOREVER 0x02
#define MOD_LOCK_HELD 0x04
@@ -506,13 +523,15 @@ extern void mod_release_stub(struct mod_stub_info *);
extern void mod_askparams(void);
extern void mod_uninstall_daemon(void);
extern void modreap(void);
-extern struct modctl *mod_hold_by_name(char *);
-extern void mod_release_mod(struct modctl *);
-extern uintptr_t modlookup(char *, char *);
+extern modctl_t *mod_hold_by_id(modid_t);
+extern modctl_t *mod_hold_by_name(const char *);
+extern void mod_release_mod(modctl_t *);
+extern uintptr_t modlookup(const char *, const char *);
+extern uintptr_t modlookup_by_modctl(modctl_t *, const char *);
extern char *modgetsymname(uintptr_t, unsigned long *);
-extern void mod_release_requisites(struct modctl *);
-extern struct modctl *mod_load_requisite(struct modctl *, char *);
-extern struct modctl *mod_find_by_filename(char *, char *);
+extern void mod_release_requisites(modctl_t *);
+extern modctl_t *mod_load_requisite(modctl_t *, char *);
+extern modctl_t *mod_find_by_filename(char *, char *);
extern uintptr_t modgetsymvalue(char *, int);
extern void mod_rele_dev_by_major(major_t);
@@ -532,11 +551,11 @@ extern void read_class_file(void);
extern void setbootpath(char *);
extern void setbootfstype(char *);
-extern int install_stubs_by_name(struct modctl *, char *);
-extern void install_stubs(struct modctl *);
-extern void uninstall_stubs(struct modctl *);
-extern void reset_stubs(struct modctl *);
-extern struct modctl *mod_getctl(struct modlinkage *);
+extern int install_stubs_by_name(modctl_t *, char *);
+extern void install_stubs(modctl_t *);
+extern void uninstall_stubs(modctl_t *);
+extern void reset_stubs(modctl_t *);
+extern modctl_t *mod_getctl(struct modlinkage *);
extern major_t mod_name_to_major(char *);
extern modid_t mod_name_to_modid(char *);
extern char *mod_major_to_name(major_t);
@@ -550,7 +569,7 @@ extern char *mod_containing_pc(caddr_t);
extern int mod_in_autounload(void);
extern char *mod_modname(struct modlinkage *);
-extern int dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp);
+extern int dev_minorperm(dev_info_t *, char *, mperm_t *);
/*
* Declarations used for dynamic linking support routines. Interfaces
diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h
index 3e1b260c1e..9653a58b0e 100644
--- a/usr/src/uts/common/sys/policy.h
+++ b/usr/src/uts/common/sys/policy.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -88,6 +88,7 @@ boolean_t secpolicy_contract_event_choice(const cred_t *);
int secpolicy_coreadm(const cred_t *);
int secpolicy_cpc_cpu(const cred_t *);
int secpolicy_dispadm(const cred_t *);
+int secpolicy_error_inject(const cred_t *);
int secpolicy_excl_open(const cred_t *);
int secpolicy_fs_mount(cred_t *, vnode_t *, struct vfs *);
int secpolicy_fs_unmount(cred_t *, struct vfs *);
diff --git a/usr/src/uts/i86pc/Makefile b/usr/src/uts/i86pc/Makefile
index 90cc8f9dd2..a4bafb16ff 100644
--- a/usr/src/uts/i86pc/Makefile
+++ b/usr/src/uts/i86pc/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -69,11 +69,16 @@ check := TARGET= check
.PARALLEL: $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) \
modlist modlist.intel
-def all clean clobber clean.lint: genassym unix .WAIT \
+INITIAL_TARGETS = \
+ genassym \
+ unix \
+ cpu/scripts
+
+def all clean clobber clean.lint: setup genassym unix .WAIT \
$(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS)
-install: install_platforms genassym unix .WAIT $(KMODS) $(CLOSED_KMODS) \
- $(XMODS) $(CLOSED_XMODS)
+install: install_platforms setup genassym unix .WAIT \
+ $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS)
# list the modules under i86pc.
modlist: unix $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS)
@@ -91,6 +96,9 @@ modlintlib: $(KMODS) $(CLOSED_KMODS)
genassym unix $(KMODS): FRC
@cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET)
+setup: FRC
+ @cd cpu/scripts; pwd; $(MAKE) setup
+
$(XMODS): FRC
@if [ -f $@/Makefile ]; then \
cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET); \
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index ff2999c94c..d9195b54ac 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -20,7 +20,7 @@
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -37,6 +37,7 @@ CORE_OBJS += \
beeper.o \
biosdisk.o \
cbe.o \
+ cmi.o \
confunix.o \
cpuid.o \
dis_tables.o \
@@ -127,6 +128,12 @@ AGPGART_OBJS += agpgart.o \
AGPTARGET_OBJS += agptarget.o
AMD64GART_OBJS += amd64_gart.o
+include $(SRC)/common/mc/mc-amd/Makefile.mcamd
+MCAMD_OBJS += \
+ $(MCAMD_CMN_OBJS) \
+ mcamd_drv.o \
+ mcamd_subr.o
+
#
# PCI-Express driver modules
#
diff --git a/usr/src/uts/i86pc/Makefile.i86pc.shared b/usr/src/uts/i86pc/Makefile.i86pc.shared
index c983d2a6ca..fcbd150bb8 100644
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared
@@ -21,7 +21,7 @@
#
# uts/i86pc/Makefile.i86pc
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -260,16 +260,18 @@ DRV_KMODS += agptarget
DRV_KMODS += amd64_gart
DRV_KMODS += cpc
+DRV_KMODS += mc-amd
DRV_KMODS += power
-$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata
-$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x
+$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata
+$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x
$(CLOSED_BUILD)CLOSED_DRV_KMODS += audioens
$(CLOSED_BUILD)CLOSED_DRV_KMODS += bmc
$(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscbus
$(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscv
$(CLOSED_BUILD)CLOSED_DRV_KMODS += elxl
$(CLOSED_BUILD)CLOSED_DRV_KMODS += iprb
+$(CLOSED_BUILD)CLOSED_DRV_KMODS += memtest
$(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += ncrs
$(CLOSED_BUILD)CLOSED_DRV_KMODS += pcic
$(CLOSED_BUILD)CLOSED_DRV_KMODS += pcn
@@ -277,6 +279,12 @@ $(CLOSED_BUILD)CLOSED_DRV_KMODS += rtls
$(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += sbpro
#
+# CPU Modules
+#
+CPU_KMODS += amd_opteron
+CPU_KMODS += generic_cpu
+
+#
# Exec Class Modules (/kernel/exec):
#
EXEC_KMODS +=
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index a272f48bf5..772db5ece7 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -20,7 +20,7 @@
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -45,10 +45,28 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/conf/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s
+ $(COMPILE.s) -o $@ $<
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s
+ $(COMPILE.s) -o $@ $<
+
$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/mc/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/pci/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -118,6 +136,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/power/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(SRC)/common/mc/mc-amd/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/acpica/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -179,9 +201,24 @@ $(DTRACESTUBS): $(DTRACESTUBS_O)
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/conf/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s
+ @($(LHEAD) $(LINT.s) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s
+ @($(LHEAD) $(LINT.s) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/mc/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/pci/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
@@ -227,6 +264,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/agpgart/%.c
$(LINTS_DIR)/%.ln: $(SRC)/common/atomic/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(SRC)/common/mc/mc-amd/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/acpica/%.s
@($(LHEAD) $(LINT.s) $< $(LTAIL))
diff --git a/usr/src/uts/i86pc/Makefile.workarounds b/usr/src/uts/i86pc/Makefile.workarounds
index f6f79bde49..ffd5a20e69 100644
--- a/usr/src/uts/i86pc/Makefile.workarounds
+++ b/usr/src/uts/i86pc/Makefile.workarounds
@@ -19,10 +19,7 @@
#
# CDDL HEADER END
#
-#
-# uts/i86pc/Makefile.workarounds
-#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -57,6 +54,11 @@ WORKAROUND_DEFS += -DOPTERON_ERRATUM_95
WORKAROUND_DEFS += -DOPTERON_ERRATUM_100
#
+# DRAM Scrubber May Cause Data Corruption When Using Node-Interleaved Memory
+#
+WORKAROUND_DEFS += -DOPTERON_ERRATUM_101
+
+#
# CPUID Instruction May Return Incorrect Model Number in Some Processors
#
WORKAROUND_DEFS += -DOPTERON_ERRATUM_108
diff --git a/usr/src/uts/i86pc/amd_opteron/Makefile b/usr/src/uts/i86pc/amd_opteron/Makefile
new file mode 100644
index 0000000000..50db5b7db0
--- /dev/null
+++ b/usr/src/uts/i86pc/amd_opteron/Makefile
@@ -0,0 +1,105 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = cpu.AuthenticAMD.15
+#
+OBJECTS = $(CPU_AO_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(CPU_AO_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE)
+
+SRCDIR = ../cpu/amd_opteron
+
+AO_MCA_DISP_C = $(OBJS_DIR)/ao_mca_disp.c
+AO_MCA_DISP_SRC = $(SRCDIR)/ao_mca_disp.in
+AO_GENDISP = ../cpu/scripts/ao_gendisp
+
+#
+# Include common rules.
+#
+include ../cpu/Makefile.cpu
+
+#
+# Our lint library has a different name from that of the module we build.
+#
+LINT_MODULE = amd_opteron
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(LINT_MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Overrides and additions
+#
+CLEANFILES += $(AO_MCA_DISP_C)
+CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR)
+ASFLAGS += -I$(SRCDIR) -I$(OBJS_DIR)
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Create ao_mca_disp.c
+#
+$(AO_MCA_DISP_C): $(AO_MCA_DISP_SRC) $(AO_GENDISP)
+ $(AO_GENDISP) $(AO_MCA_DISP_SRC) >$@
+
+$(OBJS_DIR)/%.o: $(OBJS_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+#
+# Include common targets.
+#
+include ../Makefile.targ
diff --git a/usr/src/uts/i86pc/cpu/Makefile.cpu b/usr/src/uts/i86pc/cpu/Makefile.cpu
new file mode 100644
index 0000000000..c73344de87
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/Makefile.cpu
@@ -0,0 +1,28 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(UTSBASE)/i86pc/Makefile.i86pc
+include $(UTSBASE)/i86pc/cpu/Makefile.files
diff --git a/usr/src/uts/i86pc/cpu/Makefile.files b/usr/src/uts/i86pc/cpu/Makefile.files
new file mode 100644
index 0000000000..3252058682
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/Makefile.files
@@ -0,0 +1,37 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+CPU_AO_OBJS = \
+ ao_cpu.o \
+ ao_main.o \
+ ao_mc.o \
+ ao_mca.o \
+ ao_mca_disp.o \
+ ao_poll.o
+
+CPU_GCPU_OBJS = \
+ gcpu_main.o \
+ gcpu_mca.o
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h
new file mode 100644
index 0000000000..e5f6c518a8
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h
@@ -0,0 +1,235 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _AO_H
+#define _AO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/mc.h>
+#include <sys/mca_amd.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/nvpair.h>
+#include <sys/cyclic.h>
+#include <sys/errorq.h>
+#include <sys/kobj.h>
+#include <sys/fm/util.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AO_MCA_MAX_ERRORS 10
+
+typedef struct ao_data ao_data_t;
+
+typedef struct ao_bank_regs {
+ uint32_t abr_status;
+ uint32_t abr_addr;
+} ao_bank_regs_t;
+
+extern ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT];
+
+/*
+ * Rather than using torturous conditionals, we match errors using a table of
+ * ao_error_disp_t's. The members in the ao_error_disp_t are matched against
+ * the value of MCi_STATUS, with a successful match indicating that the given
+ * error occurred.
+ *
+ * While aed_stat_code will match most of the status code bits, a few of the
+ * status code fields are either/or, and are treated separately so as to
+ * minimize the number of ao_error_disp_t structures that must be created.
+ * For example, the dc.tag_par error can have r4 values drd or dwr. Rather
+ * than creating two ao_error_disp_t's, we use the separate aed_stat_r4_bits
+ * field to indicate both AO_MCA_R4_BIT_DRD and AO_MCA_R4_BIT_DWD. As the
+ * matching r4 values are drawn from aed_stat_r4_bits, we don't use the r4
+ * bits in aed_stat_code for matching. Similar reasoning lies behind the
+ * creation of the pp and ii fields.
+ */
+#define AO_AED_PANIC_NEVER 0x00000000
+#define AO_AED_PANIC_PRIV 0x00000001
+#define AO_AED_PANIC_USER 0x00000002
+#define AO_AED_PANIC_ALWAYS 0x00000003
+
+#define AO_AED_F_CORRECTABLE 0x00000001
+#define AO_AED_F_LOFAULT_OK 0x00000002
+
+typedef struct ao_error_disp {
+ const char *aed_class; /* ereport class for use if match */
+ uint64_t aed_ereport_members; /* ereport contents flags if match */
+ uint64_t aed_stat_mask; /* status msr bits for match */
+ uint64_t aed_stat_mask_res; /* status mask result for match */
+ uint16_t aed_stat_code; /* status code for match */
+ uint8_t aed_stat_extcode; /* extended status code for match */
+ uint8_t aed_stat_pp_bits:4; /* AO_MCA_PP_BIT_* for pp matching */
+ uint8_t aed_stat_ii_bits:4; /* AO_MCA_II_BIT_* for ii matching */
+ uint16_t aed_stat_r4_bits; /* AO_MCA_R4_BIT_* for r4 matching */
+ uint8_t aed_panic_when; /* extra conditions for panic */
+ uint8_t aed_flags; /* AO_AED_F_* */
+} ao_error_disp_t;
+
+/*
+ * The poller has two parts. First is the omni cyclic, which runs on all
+ * CPUs, and which polls the error MSRs at some fixed (long) interval. This
+ * cyclic will run on all machines, all the time, and thus must have minimal
+ * runtime impact. The second portion of the poller is manually-initiated, and
+ * is used by the error injector/synthesizer to request an immediate poll of the
+ * error state registers.
+ *
+ * With this number of moving parts, it is essential that we have some sort of
+ * audit log for post-mortem analysis. A circular array of trace buffers
+ * (ao_mca_poll_trace_t structures) is kept to record this activity. Whenever
+ * an event occurs that is of interest to the poller, an entry is made in
+ * the trace array describing that event.
+ */
+#define AO_MPT_WHAT_CYC_ERR 0 /* cyclic-induced poll */
+#define AO_MPT_WHAT_POKE_ERR 1 /* manually-induced poll */
+#define AO_MPT_WHAT_UNFAULTING 2 /* discarded error state */
+
+typedef struct ao_mca_poll_trace {
+ hrtime_t mpt_when; /* timestamp of event */
+ uint8_t mpt_what; /* AO_MPT_WHAT_* (which event?) */
+ uint8_t mpt_nerr; /* number of errors discovered */
+ uint16_t mpt_pad1;
+ uint32_t mpt_pad2;
+} ao_mca_poll_trace_t;
+
+/*
+ * Processor error state is saved in logout areas. There are three separate
+ * logout areas, each used for a different purpose. The logout areas are stored
+ * in an array (ao_mca_logout), indexed by the AO_MCA_LOGOUT_* macros.
+ *
+ * The save areas are:
+ *
+ * 1. Exception handler MSR save - Written to by the initial portion of the #mc
+ * handler. Read from by the main body of the exception handler.
+ *
+ * 3. Poller MSR save - Used by the poller to store error state MSR values.
+ * While this logout area doesn't necessarily have to live in the ao_mca_t,
+ * it does so to enhance observability.
+ *
+ * The logout areas contain both global error state (acl_ip, acl_timestamp,
+ * etc.), as well as a bank array. The bank array contains one ao_bank_logout_t
+ * per error reporting bank.
+ */
+
+typedef struct ao_bank_logout {
+ uint64_t abl_status; /* Saved MCi_STATUS register */
+ uint64_t abl_addr; /* Saved MCi_ADDR register */
+} ao_bank_logout_t;
+
+#define AO_ACL_F_PRIV 0x1 /* #mc in kernel mode (else user) */
+#define AO_ACL_F_FATAL 0x2 /* logout detected fatal error(s) */
+
+typedef struct ao_cpu_logout {
+ ao_data_t *acl_ao; /* pointer to per-cpu ao_data_t */
+ uintptr_t acl_ip; /* instruction pointer if #mc trap */
+ uint64_t acl_timestamp; /* gethrtime() at time of logout */
+ uint64_t acl_mcg_status; /* MCG_STATUS register value */
+ ao_bank_logout_t acl_banks[AMD_MCA_BANK_COUNT]; /* bank state saves */
+ pc_t acl_stack[FM_STK_DEPTH]; /* saved stack trace (if any) */
+ int acl_stackdepth; /* saved stack trace depth */
+ uint_t acl_flags; /* flags (see AO_ACL_F_* above) */
+} ao_cpu_logout_t;
+
+/* Index for ao_mca_logout, below */
+#define AO_MCA_LOGOUT_EXCEPTION 0
+#define AO_MCA_LOGOUT_POLLER 1
+#define AO_MCA_LOGOUT_NUM 2
+
+#define AO_MCA_F_UNFAULTING 0x1 /* CPU exiting faulted state */
+
+/*
+ * We store config as inherited from the BIOS to assist in troubleshooting.
+ */
+typedef struct ao_bios_cfg {
+ uint64_t bcfg_bank_ctl[AMD_MCA_BANK_COUNT];
+ uint64_t bcfg_bank_mask[AMD_MCA_BANK_COUNT];
+ uint32_t bcfg_nb_cfg;
+} ao_bios_cfg_t;
+
+/*
+ * The master data structure used to hold MCA-related state.
+ */
+typedef struct ao_mca {
+ ao_bios_cfg_t ao_mca_bios_cfg; /* Bank and NB config before our init */
+ ao_cpu_logout_t ao_mca_logout[AO_MCA_LOGOUT_NUM]; /* save areas */
+ kmutex_t ao_mca_poll_lock; /* keep pollers from colliding */
+ ao_mca_poll_trace_t *ao_mca_poll_trace; /* trace buffers for this cpu */
+ uint_t ao_mca_poll_curtrace; /* most recently-filled trace buffer */
+ uint_t ao_mca_flags; /* AO_MCA_F_* */
+} ao_mca_t;
+
+/*
+ * Per-CPU state
+ */
+struct ao_data {
+ ao_mca_t ao_mca; /* MCA state for this CPU */
+ cpu_t *ao_cpu; /* link to CPU's cpu_t */
+ const cmi_mc_ops_t *ao_mc_ops; /* memory controller ops */
+ void *ao_mc_data; /* argument for memory controller ops */
+};
+
+#ifdef _KERNEL
+
+struct regs;
+
+extern errorq_t *ao_mca_queue;
+extern const cmi_ops_t _cmi_ops;
+
+extern void ao_faulted_enter(void *);
+extern void ao_faulted_exit(void *);
+extern int ao_scrubber_enable(void *, uint64_t, uint64_t);
+
+extern void ao_mca_post_init(void *);
+extern void ao_mca_init(void *);
+extern int ao_mca_trap(void *, struct regs *);
+extern int ao_mca_inject(void *, cmi_mca_regs_t *, uint_t);
+extern void ao_mca_poke(void *);
+extern void ao_mca_poll_init(ao_mca_t *);
+extern void ao_mca_poll_start(void);
+
+extern int ao_mca_logout(ao_cpu_logout_t *, struct regs *, int *);
+extern void ao_mca_drain(void *, const void *, const errorq_elem_t *);
+extern nvlist_t *ao_fmri_create(ao_data_t *, nv_alloc_t *);
+
+extern void ao_mc_register(void *, const cmi_mc_ops_t *, void *);
+extern const struct cmi_mc_ops *ao_mc_getops(void *);
+extern int ao_mc_patounum(ao_data_t *, uint64_t, uint32_t, int, mc_unum_t *);
+extern int ao_mc_unumtopa(ao_data_t *, mc_unum_t *, nvlist_t *, uint64_t *);
+
+extern void ao_pcicfg_write(uint_t, uint_t, uint_t, uint32_t);
+extern uint32_t ao_pcicfg_read(uint_t, uint_t, uint_t);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AO_H */
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c
new file mode 100644
index 0000000000..e13c672fac
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/chip.h>
+#include <sys/cmn_err.h>
+#include <sys/sysmacros.h>
+#include <sys/fm/protocol.h>
+
+#include "ao.h"
+
+/*
+ * AMD Opteron CPU Subroutines
+ *
+ * The following three tunables are used to determine the scrubbing rates for
+ * the D$, L2$, and DRAM hardware scrubbers. The values range from 0x00-0x16
+ * as described in BKDG 3.6.6 Scrub Control Register. A value of zero disables
+ * the scrubber. Values above zero indicate rates in descending order.
+ *
+ * The current default values are used on several Sun systems. In the future
+ * this code should assign values dynamically based on memory sizing. If you
+ * tune these values manually be aware of the following architectural issue:
+ * At present, Opteron can only survive certain kinds of multi-bit errors if
+ * they are detected by the scrubbers. Therefore in general we want these
+ * values tuned as high as possible without impacting workload performance.
+ */
+uint32_t ao_scrub_rate_dcache = 8; /* 64B every 5.12 us */
+uint32_t ao_scrub_rate_l2cache = 9; /* 64B every 10.2 us */
+uint32_t ao_scrub_rate_dram = 0xd; /* 64B every 163.8 us */
+
+uint32_t ao_scrub_system; /* debug stash for system's value */
+uint32_t ao_scrub_bios; /* debug stash for bios's value */
+uint32_t ao_scrub_lo; /* debug stash for system low addr */
+uint32_t ao_scrub_hi; /* debug stash for system high addr */
+
+enum {
+ AO_SCRUB_DEFAULT, /* retain system default values */
+ AO_SCRUB_FIXED, /* assign ao_scrub_rate_* values */
+ AO_SCRUB_MAX /* assign max of system and tunables */
+} ao_scrub_policy = AO_SCRUB_MAX;
+
+nvlist_t *
+ao_fmri_create(ao_data_t *ao, nv_alloc_t *nva)
+{
+ nvlist_t *nvl = fm_nvlist_create(nva);
+
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
+ "motherboard", 0,
+ "chip", ao->ao_cpu->cpu_chip->chip_id,
+ "cpu", chip_plat_get_clogid(ao->ao_cpu));
+
+ return (nvl);
+}
+
+/*
+ * Return the maximum scrubbing rate between r1 and r2, where r2 is extracted
+ * from the specified 'cfg' register value using 'mask' and 'shift'. If a
+ * value is zero, scrubbing is off so return the opposite value. Otherwise
+ * the maximum rate is the smallest non-zero value of the two values.
+ */
+static uint32_t
+ao_scrubber_max(uint32_t r1, uint32_t cfg, uint32_t mask, uint32_t shift)
+{
+ uint32_t r2 = (cfg & mask) >> shift;
+
+ if (r1 != 0 && r2 != 0)
+ return (MIN(r1, r2));
+
+ return (r1 ? r1 : r2);
+}
+
+/*
+ * Enable the chip-specific hardware scrubbers for the D$, L2$, and DRAM, and
+ * return a boolean value indicating if we enabled the DRAM scrubber. We set
+ * the scrubber rate based on a set of tunables defined at the top of the file.
+ * The 'base' parameter is the DRAM Base Address for this chip and is used to
+ * determine where the scrubber starts. The 'ilen' value is the IntvlEn field
+ * from the DRAM configuration indicating the node-interleaving configuration.
+ */
+int
+ao_scrubber_enable(void *data, uint64_t base, uint64_t ilen)
+{
+ ao_data_t *ao = data;
+ chipid_t chipid = chip_plat_get_chipid(ao->ao_cpu);
+ uint32_t scrubctl, lo, hi;
+ int rv = 1;
+
+ /*
+ * Read the initial scrubber configuration and save it for debugging.
+ * If ao_scrub_policy is DEFAULT, return immediately. Otherwise we
+ * disable scrubbing activity while we fiddle with the configuration.
+ */
+ scrubctl = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL);
+ cas32(&ao_scrub_bios, 0, scrubctl);
+
+ if (ao_scrub_policy == AO_SCRUB_DEFAULT)
+ return ((scrubctl & AMD_NB_SCRUBCTL_DRAM_MASK) != 0);
+
+ scrubctl &= ~AMD_NB_SCRUBCTL_DRAM_MASK;
+ scrubctl &= ~AMD_NB_SCRUBCTL_L2_MASK;
+ scrubctl &= ~AMD_NB_SCRUBCTL_DC_MASK;
+
+ ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl);
+
+ /*
+ * Read the DRAM Scrub Address Low and High registers, clear their
+ * address fields, enable sequential-redirect mode, and update the
+ * address fields using the specified DRAM Base Address.
+ */
+ lo = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO);
+ hi = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI);
+
+ lo &= ~AMD_NB_SCRUBADDR_LO_MASK;
+ hi &= ~AMD_NB_SCRUBADDR_HI_MASK;
+
+ lo |= AMD_NB_SCRUBADDR_MKLO(base) | AMD_NB_SCRUBADDR_LO_SCRUBREDIREN;
+ hi |= AMD_NB_SCRUBADDR_MKHI(base);
+
+ ao_scrub_lo = lo;
+ ao_scrub_hi = hi;
+
+ ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO, lo);
+ ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI, hi);
+
+ if (ao_scrub_rate_dcache > AMD_NB_SCRUBCTL_RATE_MAX) {
+ cmn_err(CE_WARN, "ao_scrub_rate_dcache is too large; "
+ "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX);
+ ao_scrub_rate_dcache = AMD_NB_SCRUBCTL_RATE_MAX;
+ }
+
+ if (ao_scrub_rate_l2cache > AMD_NB_SCRUBCTL_RATE_MAX) {
+ cmn_err(CE_WARN, "ao_scrub_rate_l2cache is too large; "
+ "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX);
+ ao_scrub_rate_l2cache = AMD_NB_SCRUBCTL_RATE_MAX;
+ }
+
+ if (ao_scrub_rate_dram > AMD_NB_SCRUBCTL_RATE_MAX) {
+ cmn_err(CE_WARN, "ao_scrub_rate_dram is too large; "
+ "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX);
+ ao_scrub_rate_dram = AMD_NB_SCRUBCTL_RATE_MAX;
+ }
+
+ if (ao_scrub_policy == AO_SCRUB_MAX) {
+ ao_scrub_rate_dcache =
+ ao_scrubber_max(ao_scrub_rate_dcache, ao_scrub_bios,
+ AMD_NB_SCRUBCTL_DC_MASK, AMD_NB_SCRUBCTL_DC_SHIFT);
+
+ ao_scrub_rate_l2cache =
+ ao_scrubber_max(ao_scrub_rate_l2cache, ao_scrub_bios,
+ AMD_NB_SCRUBCTL_L2_MASK, AMD_NB_SCRUBCTL_L2_SHIFT);
+
+ ao_scrub_rate_dram =
+ ao_scrubber_max(ao_scrub_rate_dram, ao_scrub_bios,
+ AMD_NB_SCRUBCTL_DRAM_MASK, AMD_NB_SCRUBCTL_DRAM_SHIFT);
+ }
+
+#ifdef OPTERON_ERRATUM_101
+ /*
+ * If the DRAM Base Address register's IntlvEn field indicates that
+ * node interleaving is enabled, we must disable the DRAM scrubber
+ * and return zero to indicate that Solaris should use s/w instead.
+ */
+ if (ilen != 0) {
+ cmn_err(CE_CONT, "?Opteron DRAM scrubber disabled because "
+ "DRAM memory is node-interleaved");
+ ao_scrub_rate_dram = 0;
+ rv = 0;
+ }
+#endif
+ scrubctl |= AMD_NB_MKSCRUBCTL(ao_scrub_rate_dcache,
+ ao_scrub_rate_l2cache, ao_scrub_rate_dram);
+
+ ao_scrub_system = scrubctl;
+ ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl);
+
+ return (rv);
+}
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c
new file mode 100644
index 0000000000..777538adf0
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c
@@ -0,0 +1,135 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The CPU module for the AMD Athlon64 and Opteron processors
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/sunddi.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/cpuvar.h>
+#include <sys/x86_archext.h>
+#include <sys/kmem.h>
+#include <sys/modctl.h>
+#include <sys/mc.h>
+
+#include "ao.h"
+
+/*
+ * At present this CPU module only supports the features for Athlon64 and
+ * Opteron up to and including the Rev E processor. If we detect Rev F or
+ * later, return ENOTSUP and let the generic x86 CPU module load instead.
+ * Opteron Rev F is currently defined as Family 0xF Model [0x40 .. 0x5F].
+ */
+static uint_t ao_model_limit = 0x40;
+
+static int
+ao_init(cpu_t *cp, void **datap)
+{
+ ao_data_t *ao;
+
+ if (cpuid_getmodel(cp) >= ao_model_limit)
+ return (ENOTSUP);
+
+ ao = *datap = kmem_zalloc(sizeof (ao_data_t), KM_SLEEP);
+ ao->ao_cpu = cp;
+
+ return (0);
+}
+
+static void
+ao_fini(void *data)
+{
+ kmem_free(data, sizeof (ao_data_t));
+}
+
+const cmi_ops_t _cmi_ops = {
+ ao_init,
+ ao_mca_post_init,
+ ao_fini,
+ ao_faulted_enter,
+ ao_faulted_exit,
+ ao_scrubber_enable,
+ ao_mca_init,
+ ao_mca_trap,
+ ao_mca_inject,
+ ao_mca_poke,
+ ao_mc_register,
+ ao_mc_getops
+};
+
+static struct modlcpu modlcpu = {
+ &mod_cpuops,
+ "AMD Athlon64/Opteron CPU Module"
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modlcpu,
+ NULL
+};
+
+int
+_init(void)
+{
+ int err;
+
+ ao_mca_queue = errorq_create("ao_mca_queue",
+ ao_mca_drain, NULL, AO_MCA_MAX_ERRORS * (max_ncpus + 1),
+ sizeof (ao_cpu_logout_t), 1, ERRORQ_VITAL);
+
+ if (ao_mca_queue == NULL)
+ return (EAGAIN); /* errorq_create() logs a message for us */
+
+ if ((err = mod_install(&modlinkage)) != 0) {
+ errorq_destroy(ao_mca_queue);
+ ao_mca_queue = NULL;
+ }
+
+ return (err);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int err;
+
+ if ((err = mod_remove(&modlinkage)) == 0)
+ errorq_destroy(ao_mca_queue);
+
+ return (err);
+}
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c
new file mode 100644
index 0000000000..b2fd0ca82f
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c
@@ -0,0 +1,72 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cpu_module_impl.h>
+
+#include "ao.h"
+
+void
+ao_mc_register(void *data, const cmi_mc_ops_t *mcops, void *mcdata)
+{
+ ao_data_t *ao = data;
+
+ ASSERT(ao->ao_mc_ops == NULL);
+
+ ao->ao_mc_ops = mcops;
+ ao->ao_mc_data = mcdata;
+}
+
+const struct cmi_mc_ops *
+ao_mc_getops(void *data)
+{
+ ao_data_t *ao = data;
+
+ return (ao->ao_mc_ops);
+}
+
+int
+ao_mc_patounum(ao_data_t *ao, uint64_t pa, uint32_t synd, int syndtype,
+ mc_unum_t *unump)
+{
+ if (ao->ao_mc_ops == NULL)
+ return (0); /* mc not registered, or failed to load */
+
+ return (ao->ao_mc_ops->cmi_mc_patounum(ao->ao_mc_data, pa, synd,
+ syndtype, unump));
+}
+
+int
+ao_mc_unumtopa(ao_data_t *ao, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap)
+{
+ if (ao->ao_mc_ops == NULL)
+ return (0); /* mc not registered, or failed to load */
+
+ return (ao->ao_mc_ops->cmi_mc_unumtopa(ao->ao_mc_data, unump, nvl,
+ pap));
+}
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c
new file mode 100644
index 0000000000..e8884f212d
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c
@@ -0,0 +1,811 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/regset.h>
+#include <sys/privregs.h>
+#include <sys/pci_impl.h>
+#include <sys/cpuvar.h>
+#include <sys/x86_archext.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/chip.h>
+#include <sys/cyclic.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/pci_cfgspace_impl.h>
+#include <sys/sysevent.h>
+#include <sys/smbios.h>
+#include <sys/mca_x86.h>
+#include <sys/mca_amd.h>
+#include <sys/mc.h>
+#include <sys/psw.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sdt.h>
+#include <sys/fm/util.h>
+#include <sys/fm/protocol.h>
+#include <sys/fm/cpu/AMD.h>
+
+#include "ao.h"
+#include "ao_mca_disp.h"
+
+errorq_t *ao_mca_queue; /* machine-check ereport queue */
+int ao_mca_stack_flag = 1; /* record stack trace in ereports */
+int ao_mca_smi_disable = 1; /* attempt to disable SMI polling */
+
+ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT] = {
+ { AMD_MSR_DC_STATUS, AMD_MSR_DC_ADDR },
+ { AMD_MSR_IC_STATUS, AMD_MSR_IC_ADDR },
+ { AMD_MSR_BU_STATUS, AMD_MSR_BU_ADDR },
+ { AMD_MSR_LS_STATUS, AMD_MSR_LS_ADDR },
+ { AMD_MSR_NB_STATUS, AMD_MSR_NB_ADDR }
+};
+
+typedef struct ao_bank_cfg {
+ uint_t bank_ctl;
+ uint_t bank_ctl_mask;
+ uint64_t bank_ctl_init;
+ uint_t bank_status;
+ uint_t bank_addr;
+} ao_bank_cfg_t;
+
+static const ao_bank_cfg_t ao_bank_cfgs[] = {
+ { AMD_MSR_DC_CTL, AMD_MSR_DC_MASK, AMD_DC_CTL_INIT, AMD_MSR_DC_STATUS,
+ AMD_MSR_DC_ADDR },
+ { AMD_MSR_IC_CTL, AMD_MSR_IC_MASK, AMD_IC_CTL_INIT, AMD_MSR_IC_STATUS,
+ AMD_MSR_IC_ADDR },
+ { AMD_MSR_BU_CTL, AMD_MSR_BU_MASK, AMD_BU_CTL_INIT, AMD_MSR_BU_STATUS,
+ AMD_MSR_BU_ADDR },
+ { AMD_MSR_LS_CTL, AMD_MSR_LS_MASK, AMD_LS_CTL_INIT, AMD_MSR_LS_STATUS,
+ AMD_MSR_LS_ADDR },
+ { AMD_MSR_NB_CTL, AMD_MSR_NB_MASK, AMD_NB_CTL_INIT, AMD_MSR_NB_STATUS,
+ AMD_MSR_NB_ADDR }
+};
+
+static const ao_error_disp_t ao_disp_unknown = {
+ FM_EREPORT_CPU_AMD_UNKNOWN,
+ FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN
+};
+
+/*
+ * This is quite awful but necessary to work around x86 system vendor's view of
+ * the world. Other operating systems (you know who you are) don't understand
+ * Opteron-specific error handling, so BIOS and system vendors often hide these
+ * conditions from them by using SMI polling to copy out any errors from the
+ * machine-check registers. When Solaris runs on a system with this feature,
+ * we want to disable the SMI polling so we can use FMA instead. Sadly, there
+ * isn't even a standard self-describing way to express the whole situation,
+ * so we have to resort to hard-coded values. This should all be changed to
+ * be a self-describing vendor-specific SMBIOS structure in the future.
+ */
+static const struct ao_smi_disable {
+ const char *asd_sys_vendor; /* SMB_TYPE_SYSTEM vendor prefix */
+ const char *asd_bios_vendor; /* SMB_TYPE_BIOS vendor prefix */
+ uint32_t asd_port; /* output port for SMI disable */
+ uint32_t asd_code; /* output code for SMI disable */
+} ao_smi_disable[] = {
+ { "Sun Microsystems", "American Megatrends", 0x502F, 0x59 },
+ { NULL, NULL, 0, 0 }
+};
+
+static int
+ao_disp_match_r4(uint16_t ref, uint8_t r4)
+{
+ static const uint16_t ao_r4_map[] = {
+ AO_MCA_R4_BIT_GEN, /* AMD_ERRCODE_R4_GEN */
+ AO_MCA_R4_BIT_RD, /* AMD_ERRCODE_R4_RD */
+ AO_MCA_R4_BIT_WR, /* AMD_ERRCODE_R4_WR */
+ AO_MCA_R4_BIT_DRD, /* AMD_ERRCODE_R4_DRD */
+ AO_MCA_R4_BIT_DWR, /* AMD_ERRCODE_R4_DWR */
+ AO_MCA_R4_BIT_IRD, /* AMD_ERRCODE_R4_IRD */
+ AO_MCA_R4_BIT_PREFETCH, /* AMD_ERRCODE_R4_PREFETCH */
+ AO_MCA_R4_BIT_EVICT, /* AMD_ERRCODE_R4_EVICT */
+ AO_MCA_R4_BIT_SNOOP /* AMD_ERRCODE_R4_SNOOP */
+ };
+
+ ASSERT(r4 < sizeof (ao_r4_map) / sizeof (uint16_t));
+
+ return ((ref & ao_r4_map[r4]) != 0);
+}
+
+static int
+ao_disp_match_pp(uint8_t ref, uint8_t pp)
+{
+ static const uint8_t ao_pp_map[] = {
+ AO_MCA_PP_BIT_SRC, /* AMD_ERRCODE_PP_SRC */
+ AO_MCA_PP_BIT_RSP, /* AMD_ERRCODE_PP_RSP */
+ AO_MCA_PP_BIT_OBS, /* AMD_ERRCODE_PP_OBS */
+ AO_MCA_PP_BIT_GEN /* AMD_ERRCODE_PP_GEN */
+ };
+
+ ASSERT(pp < sizeof (ao_pp_map) / sizeof (uint8_t));
+
+ return ((ref & ao_pp_map[pp]) != 0);
+}
+
+static int
+ao_disp_match_ii(uint8_t ref, uint8_t ii)
+{
+ static const uint8_t ao_ii_map[] = {
+ AO_MCA_II_BIT_MEM, /* AMD_ERRCODE_II_MEM */
+ 0,
+ AO_MCA_II_BIT_IO, /* AMD_ERRCODE_II_IO */
+ AO_MCA_II_BIT_GEN /* AMD_ERRCODE_II_GEN */
+ };
+
+ ASSERT(ii < sizeof (ao_ii_map) / sizeof (uint8_t));
+
+ return ((ref & ao_ii_map[ii]) != 0);
+}
+
+static uint8_t
+bit_strip(uint16_t *codep, uint16_t mask, uint16_t shift)
+{
+ uint8_t val = (*codep & mask) >> shift;
+ *codep &= ~mask;
+ return (val);
+}
+
+#define BIT_STRIP(codep, name) \
+ bit_strip(codep, AMD_ERRCODE_##name##_MASK, AMD_ERRCODE_##name##_SHIFT)
+
+static int
+ao_disp_match_one(const ao_error_disp_t *aed, uint64_t status)
+{
+ uint16_t code = status & AMD_ERRCODE_MASK;
+ uint8_t extcode = (status & AMD_ERREXT_MASK) >> AMD_ERREXT_SHIFT;
+ uint64_t stat_mask = aed->aed_stat_mask;
+ uint64_t stat_mask_res = aed->aed_stat_mask_res;
+
+ /*
+ * If the bank's status register indicates overflow, then we can no
+ * longer rely on the value of CECC: our experience with actual fault
+ * injection has shown that multiple CE's overwriting each other shows
+ * AMD_BANK_STAT_CECC and AMD_BANK_STAT_UECC both set to zero. This
+ * should be clarified in a future BKDG or by the Revision Guide.
+ */
+ if (status & AMD_BANK_STAT_OVER) {
+ stat_mask &= ~AMD_BANK_STAT_CECC;
+ stat_mask_res &= ~AMD_BANK_STAT_CECC;
+ }
+
+ if ((status & stat_mask) != stat_mask_res)
+ return (0);
+
+ /*
+ * r4 and pp bits are stored separately, so we mask off and compare them
+ * for the code types that use them. Once we've taken the r4 and pp
+ * bits out of the equation, we can directly compare the resulting code
+ * with the one stored in the ao_error_disp_t.
+ */
+ if (AMD_ERRCODE_ISMEM(code)) {
+ uint8_t r4 = BIT_STRIP(&code, R4);
+
+ if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4))
+ return (0);
+
+ } else if (AMD_ERRCODE_ISBUS(code)) {
+ uint8_t r4 = BIT_STRIP(&code, R4);
+ uint8_t pp = BIT_STRIP(&code, PP);
+ uint8_t ii = BIT_STRIP(&code, II);
+
+ if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4) ||
+ !ao_disp_match_pp(aed->aed_stat_pp_bits, pp) ||
+ !ao_disp_match_ii(aed->aed_stat_ii_bits, ii))
+ return (0);
+ }
+
+ return (code == aed->aed_stat_code && extcode == aed->aed_stat_extcode);
+}
+
+static const ao_error_disp_t *
+ao_disp_match(uint_t bankno, uint64_t status)
+{
+ const ao_error_disp_t *aed;
+
+ for (aed = ao_error_disp[bankno]; aed->aed_stat_mask != 0; aed++) {
+ if (ao_disp_match_one(aed, status))
+ return (aed);
+ }
+
+ return (&ao_disp_unknown);
+}
+
+void
+ao_pcicfg_write(uint_t chipid, uint_t func, uint_t reg, uint32_t val)
+{
+ ASSERT(chipid + 24 <= 31);
+ ASSERT((func & 7) == func);
+ ASSERT((reg & 3) == 0 && reg < 256);
+
+ pci_mech1_putl(0, chipid + 24, func, reg, val);
+}
+
+uint32_t
+ao_pcicfg_read(uint_t chipid, uint_t func, uint_t reg)
+{
+ ASSERT(chipid + 24 <= 31);
+ ASSERT((func & 7) == func);
+ ASSERT((reg & 3) == 0 && reg < 256);
+
+ return (pci_mech1_getl(0, chipid + 24, func, reg));
+}
+
+/*
+ * Setup individual bank detectors after stashing their bios settings.
+ */
+static void
+ao_bank_cfg(ao_mca_t *mca)
+{
+ ao_bios_cfg_t *bioscfg = &mca->ao_mca_bios_cfg;
+ const ao_bank_cfg_t *bankcfg = ao_bank_cfgs;
+ int i;
+
+ for (i = 0; i < AMD_MCA_BANK_COUNT; i++, bankcfg++) {
+ bioscfg->bcfg_bank_ctl[i] = rdmsr(bankcfg->bank_ctl);
+ bioscfg->bcfg_bank_mask[i] = rdmsr(bankcfg->bank_ctl_mask);
+ wrmsr(bankcfg->bank_ctl, bankcfg->bank_ctl_init);
+ }
+}
+
+/*
+ * Bits to be added to the NorthBridge (NB) configuration register.
+ * See BKDG 3.29 Section 3.6.4.2 for more information.
+ */
+uint32_t ao_nb_cfg_add =
+ AMD_NB_CFG_NBMCATOMSTCPUEN |
+ AMD_NB_CFG_DISPCICFGCPUERRRSP |
+ AMD_NB_CFG_SYNCONUCECCEN |
+ AMD_NB_CFG_CPUECCERREN;
+
+/*
+ * Bits to be cleared from the NorthBridge (NB) configuration register.
+ * See BKDG 3.29 Section 3.6.4.2 for more information.
+ */
+uint32_t ao_nb_cfg_remove =
+ AMD_NB_CFG_IORDDATERREN |
+ AMD_NB_CFG_SYNCONANYERREN |
+ AMD_NB_CFG_SYNCONWDOGEN |
+ AMD_NB_CFG_IOERRDIS |
+ AMD_NB_CFG_IOMSTABORTDIS |
+ AMD_NB_CFG_SYNCPKTPROPDIS |
+ AMD_NB_CFG_SYNCPKTGENDIS;
+
+/*
+ * Bits to be used if we configure the NorthBridge (NB) Watchdog. The watchdog
+ * triggers a machine check exception when no response to an NB system access
+ * occurs within a specified time interval. If the BIOS (i.e. platform design)
+ * has enabled the watchdog, we leave its rate alone. If the BIOS has not
+ * enabled the watchdog, we enable it and set the rate to one specified below.
+ * To disable the watchdog, add the AMD_NB_CFG_WDOGTMRDIS bit to ao_nb_cfg_add.
+ */
+uint32_t ao_nb_cfg_wdog =
+ AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
+ AMD_NB_CFG_WDOGTMRBASESEL_1MS;
+
+static void
+ao_nb_cfg(ao_mca_t *mca)
+{
+ uint_t chipid = chip_plat_get_chipid(CPU);
+ uint32_t val;
+
+ if (chip_plat_get_clogid(CPU) != 0)
+ return; /* only configure NB once per CPU */
+
+ /*
+ * Read the NorthBridge (NB) configuration register in PCI space,
+ * modify the settings accordingly, and store the new value back.
+ */
+ mca->ao_mca_bios_cfg.bcfg_nb_cfg = val =
+ ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG);
+
+ /*
+ * If the watchdog was disabled, enable it according to the policy
+ * described above. Then apply the ao_nb_cfg_[add|remove] masks.
+ */
+ if (val & AMD_NB_CFG_WDOGTMRDIS) {
+ val &= ~AMD_NB_CFG_WDOGTMRBASESEL_MASK;
+ val &= ~AMD_NB_CFG_WDOGTMRCNTSEL_MASK;
+ val &= ~AMD_NB_CFG_WDOGTMRDIS;
+ val |= ao_nb_cfg_wdog;
+ }
+
+ val &= ~ao_nb_cfg_remove;
+ val |= ao_nb_cfg_add;
+
+ ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG, val);
+}
+
+/*
+ * Capture the machine-check exception state into our per-CPU logout area, and
+ * dispatch a copy of the logout area to our error queue for ereport creation.
+ * If 'rp' is non-NULL, we're being called from trap context; otherwise we're
+ * being polled or poked by the injector. We return the number of errors
+ * found through 'np', and a boolean indicating whether the error is fatal.
+ * The caller is expected to call fm_panic() if we return fatal (non-zero).
+ */
+int
+ao_mca_logout(ao_cpu_logout_t *acl, struct regs *rp, int *np)
+{
+ int i, fatal, n = 0;
+
+ acl->acl_timestamp = gethrtime_waitfree();
+ acl->acl_mcg_status = rdmsr(IA32_MSR_MCG_STATUS);
+ acl->acl_ip = rp ? rp->r_pc : 0;
+ acl->acl_flags = 0;
+
+ /*
+ * Iterate over the banks of machine-check registers, read the address
+ * and status registers into the logout area, and clear them as we go.
+ */
+ for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
+ ao_bank_logout_t *abl = &acl->acl_banks[i];
+
+ abl->abl_addr = rdmsr(ao_bank_regs[i].abr_addr);
+ abl->abl_status = rdmsr(ao_bank_regs[i].abr_status);
+
+ if (abl->abl_status & AMD_BANK_STAT_VALID)
+ wrmsr(ao_bank_regs[i].abr_status, 0);
+ }
+
+ if (rp == NULL || !USERMODE(rp->r_cs))
+ acl->acl_flags |= AO_ACL_F_PRIV;
+
+ if (ao_mca_stack_flag)
+ acl->acl_stackdepth = getpcstack(acl->acl_stack, FM_STK_DEPTH);
+ else
+ acl->acl_stackdepth = 0;
+
+ /*
+ * Clear MCG_STATUS, indicating that machine-check trap processing is
+ * complete. Once we do this, another machine-check trap can occur.
+ */
+ wrmsr(IA32_MSR_MCG_STATUS, 0);
+
+ /*
+ * If we took a machine-check trap, then the error is fatal if the
+ * return instruction pointer is not valid in the global register.
+ */
+ fatal = rp != NULL && !(acl->acl_mcg_status & MCG_STATUS_RIPV);
+
+ /*
+ * Now iterate over the saved logout area, determining whether the
+ * error that we saw is fatal or not based upon our dispositions
+ * and the hardware's indicators of whether or not we can resume.
+ */
+ for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
+ ao_bank_logout_t *abl = &acl->acl_banks[i];
+ const ao_error_disp_t *aed;
+
+ if (!(abl->abl_status & AMD_BANK_STAT_VALID))
+ continue;
+
+ aed = ao_disp_match(i, abl->abl_status);
+ fatal |= (aed->aed_panic_when != AO_AED_PANIC_NEVER);
+
+ /*
+ * If we are taking a machine-check exception and the overflow
+ * bit is set or our context is corrupt, then we must die.
+ * NOTE: This code assumes that if the overflow bit is set and
+ * we didn't take a #mc exception (i.e. the poller found it),
+ * then multiple correctable errors overwrote each other.
+ * This will need to change if we eventually use the Opteron
+ * Rev E exception mechanism for detecting correctable errors.
+ */
+ if (rp != NULL && (abl->abl_status &
+ (AMD_BANK_STAT_OVER | AMD_BANK_STAT_PCC)))
+ fatal = 1;
+
+ /*
+ * If we are taking a machine-check exception and we don't
+ * recognize the error case at all, then assume it's fatal.
+ * This will need to change if we eventually use the Opteron
+ * Rev E exception mechanism for detecting correctable errors.
+ */
+ if (rp != NULL && aed == &ao_disp_unknown)
+ fatal = 1;
+
+ n++;
+ }
+
+ if (n > 0) {
+ errorq_dispatch(ao_mca_queue, acl, sizeof (ao_cpu_logout_t),
+ fatal && cmi_panic_on_uncorrectable_error ?
+ ERRORQ_SYNC : ERRORQ_ASYNC);
+ }
+
+ if (np != NULL)
+ *np = n; /* return number of errors found to caller */
+
+ return (fatal);
+}
+
+static uint_t
+ao_ereport_synd(ao_mca_t *mca,
+ const ao_bank_logout_t *abl, uint_t *typep, int is_nb)
+{
+ if (is_nb) {
+ if ((mca->ao_mca_bios_cfg.bcfg_nb_cfg &
+ AMD_NB_CFG_CHIPKILLECCEN) != 0) {
+ *typep = AMD_SYNDTYPE_CHIPKILL;
+ return (AMD_NB_STAT_CKSYND(abl->abl_status));
+ } else {
+ *typep = AMD_SYNDTYPE_ECC;
+ return (AMD_BANK_SYND(abl->abl_status));
+ }
+ } else {
+ *typep = AMD_SYNDTYPE_ECC;
+ return (AMD_BANK_SYND(abl->abl_status));
+ }
+}
+
+static void
+ao_ereport_create_resource_elem(nvlist_t **nvlp, nv_alloc_t *nva,
+ mc_unum_t *unump, int dimmnum)
+{
+ nvlist_t *snvl;
+ *nvlp = fm_nvlist_create(nva); /* freed by caller */
+
+ snvl = fm_nvlist_create(nva);
+
+ (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
+ unump->unum_offset);
+
+ fm_fmri_hc_set(*nvlp, FM_HC_SCHEME_VERSION, NULL, snvl, 4,
+ "motherboard", unump->unum_board,
+ "chip", unump->unum_chip,
+ "memory-controller", unump->unum_mc,
+ "dimm", unump->unum_dimms[dimmnum]);
+
+ fm_nvlist_destroy(snvl, FM_NVA_FREE);
+}
+
+static void
+ao_ereport_add_resource(nvlist_t *payload, nv_alloc_t *nva, mc_unum_t *unump)
+{
+
+ nvlist_t *elems[MC_UNUM_NDIMM];
+ int nelems = 0;
+ int i;
+
+ for (i = 0; i < MC_UNUM_NDIMM; i++) {
+ if (unump->unum_dimms[i] == -1)
+ break;
+ ao_ereport_create_resource_elem(&elems[nelems++], nva,
+ unump, i);
+ }
+
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
+ DATA_TYPE_NVLIST_ARRAY, nelems, elems);
+
+ for (i = 0; i < nelems; i++)
+ fm_nvlist_destroy(elems[i], FM_NVA_FREE);
+}
+
+static void
+ao_ereport_add_logout(ao_data_t *ao, nvlist_t *payload, nv_alloc_t *nva,
+ const ao_cpu_logout_t *acl, uint_t bankno, const ao_error_disp_t *aed)
+{
+ uint64_t members = aed->aed_ereport_members;
+ ao_mca_t *mca = &ao->ao_mca;
+ const ao_bank_logout_t *abl = &acl->acl_banks[bankno];
+ uint_t synd, syndtype;
+
+ synd = ao_ereport_synd(mca, abl, &syndtype, bankno == AMD_MCA_BANK_NB);
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_STAT) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_STAT,
+ DATA_TYPE_UINT64, abl->abl_status, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_NUM,
+ DATA_TYPE_UINT8, bankno, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR,
+ DATA_TYPE_UINT64, abl->abl_addr, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR_VALID,
+ DATA_TYPE_BOOLEAN_VALUE, (abl->abl_status &
+ AMD_BANK_STAT_ADDRV) ? B_TRUE : B_FALSE);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_SYND) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND,
+ DATA_TYPE_UINT16, synd, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND_TYPE,
+ DATA_TYPE_STRING, (syndtype == AMD_SYNDTYPE_CHIPKILL ?
+ "C" : "E"), NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_IP) {
+ uint64_t ip = (acl->acl_mcg_status & MCG_STATUS_EIPV) ?
+ acl->acl_ip : 0;
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_IP,
+ DATA_TYPE_UINT64, ip, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_PRIV) {
+ fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PRIV,
+ DATA_TYPE_BOOLEAN_VALUE, (acl->acl_flags & AO_ACL_F_PRIV) ?
+ B_TRUE : B_FALSE, NULL);
+ }
+
+ if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE) {
+ mc_unum_t unum;
+ int addrvalid;
+
+ addrvalid = (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) &&
+ (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) &&
+ (abl->abl_status & AMD_BANK_STAT_ADDRV);
+
+ if (addrvalid && ao_mc_patounum(ao, abl->abl_addr, synd,
+ syndtype, &unum))
+ ao_ereport_add_resource(payload, nva, &unum);
+ }
+
+ if (ao_mca_stack_flag && members & FM_EREPORT_PAYLOAD_FLAG_STACK) {
+ fm_payload_stack_add(payload, acl->acl_stack,
+ acl->acl_stackdepth);
+ }
+}
+
+static void
+ao_ereport_post(const ao_cpu_logout_t *acl,
+ int bankno, const ao_error_disp_t *aed)
+{
+ ao_data_t *ao = acl->acl_ao;
+ errorq_elem_t *eqep;
+ nvlist_t *ereport, *detector;
+ nv_alloc_t *nva = NULL;
+ char buf[FM_MAX_CLASS];
+
+ if (panicstr) {
+ if ((eqep = errorq_reserve(ereport_errorq)) == NULL)
+ return;
+ ereport = errorq_elem_nvl(ereport_errorq, eqep);
+ nva = errorq_elem_nva(ereport_errorq, eqep);
+ } else {
+ ereport = fm_nvlist_create(nva);
+ }
+
+ /*
+ * Create the scheme "cpu" FMRI
+ */
+ detector = ao_fmri_create(ao, nva);
+
+ /*
+ * Encode all the common data into the ereport.
+ */
+ (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s",
+ FM_ERROR_CPU, "amd", aed->aed_class);
+
+ fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
+ fm_ena_generate_cpu(acl->acl_timestamp, ao->ao_cpu->cpu_id,
+ FM_ENA_FMT1), detector, NULL);
+
+ /*
+ * Encode the error-specific data that was saved in the logout area.
+ */
+ ao_ereport_add_logout(ao, ereport, nva, acl, bankno, aed);
+
+ if (panicstr) {
+ errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
+ } else {
+ (void) fm_ereport_post(ereport, EVCH_TRYHARD);
+ fm_nvlist_destroy(ereport, FM_NVA_FREE);
+ fm_nvlist_destroy(detector, FM_NVA_FREE);
+ }
+}
+
+/*ARGSUSED*/
+void
+ao_mca_drain(void *ignored, const void *data, const errorq_elem_t *eqe)
+{
+ const ao_cpu_logout_t *acl = data;
+ int i;
+
+ for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
+ const ao_bank_logout_t *abl = &acl->acl_banks[i];
+ const ao_error_disp_t *aed;
+
+ if (abl->abl_status & AMD_BANK_STAT_VALID) {
+ aed = ao_disp_match(i, abl->abl_status);
+ ao_ereport_post(acl, i, aed);
+ }
+ }
+}
+
+int
+ao_mca_trap(void *data, struct regs *rp)
+{
+ ao_data_t *ao = data;
+ ao_mca_t *mca = &ao->ao_mca;
+ ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_EXCEPTION];
+ return (ao_mca_logout(acl, rp, NULL));
+}
+
+/*ARGSUSED*/
+int
+ao_mca_inject(void *data, cmi_mca_regs_t *regs, uint_t nregs)
+{
+ uint64_t hwcr, oldhwcr;
+ int i;
+
+ oldhwcr = rdmsr(MSR_AMD_HWCR);
+ hwcr = oldhwcr | AMD_HWCR_MCI_STATUS_WREN;
+ wrmsr(MSR_AMD_HWCR, hwcr);
+
+ for (i = 0; i < nregs; i++)
+ wrmsr(regs[i].cmr_msrnum, regs[i].cmr_msrval);
+
+ wrmsr(MSR_AMD_HWCR, oldhwcr);
+ return (0);
+}
+
+void
+ao_mca_init(void *data)
+{
+ ao_data_t *ao = data;
+ ao_mca_t *mca = &ao->ao_mca;
+ uint64_t cap;
+ int i;
+
+ ao_mca_poll_init(mca);
+
+ ASSERT(x86_feature & X86_MCA);
+ cap = rdmsr(IA32_MSR_MCG_CAP);
+ ASSERT(cap & MCG_CAP_CTL_P);
+
+ /*
+ * If the hardware's bank count is different than what we expect, then
+ * we're running on some Opteron variant that we don't understand yet.
+ */
+ if ((cap & MCG_CAP_COUNT_MASK) != AMD_MCA_BANK_COUNT) {
+ cmn_err(CE_WARN, "CPU %d has %llu MCA banks; expected %u: "
+ "disabling MCA on this CPU", ao->ao_cpu->cpu_id,
+ (u_longlong_t)cap & MCG_CAP_COUNT_MASK, AMD_MCA_BANK_COUNT);
+ return;
+ }
+
+ /*
+ * Configure the logout areas. We preset every logout area's acl_ao
+ * pointer to refer back to our per-CPU state for errorq drain usage.
+ */
+ for (i = 0; i < AO_MCA_LOGOUT_NUM; i++)
+ mca->ao_mca_logout[i].acl_ao = ao;
+
+ ao_bank_cfg(mca);
+ ao_nb_cfg(mca);
+
+ wrmsr(IA32_MSR_MCG_CTL, AMD_MCG_EN_ALL);
+
+ /*
+ * Throw away all existing bank state. We do this because some BIOSes,
+ * perhaps during POST, do things to the machine that cause MCA state
+ * to be updated. If we interpret this state as an actual error, we
+ * may end up indicting something that's not actually broken.
+ */
+ for (i = 0; i < sizeof (ao_bank_cfgs) / sizeof (ao_bank_cfg_t); i++)
+ wrmsr(ao_bank_cfgs[i].bank_status, 0ULL);
+
+ wrmsr(IA32_MSR_MCG_STATUS, 0ULL);
+ membar_producer();
+
+ setcr4(getcr4() | CR4_MCE); /* enable #mc exceptions */
+}
+
+/*ARGSUSED*/
+void
+ao_mca_post_init(void *data)
+{
+ const struct ao_smi_disable *asd;
+ id_t id;
+
+ smbios_system_t sy;
+ smbios_bios_t sb;
+ smbios_info_t si;
+
+ /*
+ * Fetch the System and BIOS vendor strings from SMBIOS and see if they
+ * match a value in our table. If so, disable SMI error polling. This
+ * is grotesque and should be replaced by self-describing vendor-
+ * specific SMBIOS data or a specification enhancement instead.
+ */
+ if (ao_mca_smi_disable && ksmbios != NULL &&
+ smbios_info_bios(ksmbios, &sb) != SMB_ERR &&
+ (id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
+ smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
+
+ for (asd = ao_smi_disable; asd->asd_sys_vendor != NULL; asd++) {
+ if (strncmp(asd->asd_sys_vendor, si.smbi_manufacturer,
+ strlen(asd->asd_sys_vendor)) != 0 ||
+ strncmp(asd->asd_bios_vendor, sb.smbb_vendor,
+ strlen(asd->asd_bios_vendor)) != 0)
+ continue;
+
+ cmn_err(CE_CONT, "?SMI polling disabled in favor of "
+ "Solaris Fault Management for AMD Processors");
+
+ outl(asd->asd_port, asd->asd_code);
+ break;
+ }
+ }
+
+ ao_mca_poll_start();
+}
+
+/*
+ * Called after a CPU has been marked with CPU_FAULTED. Not called on the
+ * faulted CPU. cpu_lock is held.
+ */
+/*ARGSUSED*/
+void
+ao_faulted_enter(void *data)
+{
+ /*
+ * Nothing to do here. We'd like to turn off the faulted CPU's
+ * correctable error detectors, but that can only be done by the
+ * faulted CPU itself. cpu_get_state() will now return P_FAULTED,
+ * allowing the poller to skip this CPU until it is re-enabled.
+ */
+}
+
+/*
+ * Called after the CPU_FAULTED bit has been cleared from a previously-faulted
+ * CPU. Not called on the faulted CPU. cpu_lock is held.
+ */
+void
+ao_faulted_exit(void *data)
+{
+ ao_data_t *ao = data;
+
+ /*
+ * We'd like to clear the faulted CPU's MCi_STATUS registers so as to
+ * avoid generating ereports for errors which occurred while the CPU was
+ * officially faulted. Unfortunately, those registers can only be
+ * cleared by the CPU itself, so we can't do it here.
+ *
+ * We're going to set the UNFAULTING bit on the formerly-faulted CPU's
+ * MCA state. This will tell the poller that the MCi_STATUS registers
+ * can't yet be trusted. The poller, which is the first thing we
+ * control that'll execute on that CPU, will clear the registers, and
+ * will then clear the bit.
+ */
+
+ ao->ao_mca.ao_mca_flags |= AO_MCA_F_UNFAULTING;
+}
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h
new file mode 100644
index 0000000000..ccb1c01bce
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _AO_MCA_DISP_H
+#define _AO_MCA_DISP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/mca_amd.h>
+#include <sys/fm/cpu/AMD.h>
+
+#include "ao.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AO_MCA_PP_BIT_SRC 0x1
+#define AO_MCA_PP_BIT_RSP 0x2
+#define AO_MCA_PP_BIT_OBS 0x4
+#define AO_MCA_PP_BIT_GEN 0x8
+
+#define AO_MCA_II_BIT_MEM 0x1
+#define AO_MCA_II_BIT_IO 0x2
+#define AO_MCA_II_BIT_GEN 0x4
+
+#define AO_MCA_R4_BIT_GEN 0x001
+#define AO_MCA_R4_BIT_RD 0x002
+#define AO_MCA_R4_BIT_WR 0x004
+#define AO_MCA_R4_BIT_DRD 0x008
+#define AO_MCA_R4_BIT_DWD 0x010
+#define AO_MCA_R4_BIT_DWR 0x020
+#define AO_MCA_R4_BIT_IRD 0x040
+#define AO_MCA_R4_BIT_PREFETCH 0x080
+#define AO_MCA_R4_BIT_EVICT 0x100
+#define AO_MCA_R4_BIT_SNOOP 0x200
+
+extern const ao_error_disp_t *ao_error_disp[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AO_MCA_DISP_H */
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in
new file mode 100644
index 0000000000..b8d88e71a5
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in
@@ -0,0 +1,778 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+funcunit = dc
+
+desc = Correctable D$ data infill from system memory
+error = ereport.cpu.amd.dc.inf_sys_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 drd mem/io lg -
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Correctable D$ data infill from L2$
+error = ereport.cpu.amd.dc.inf_l2_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - drd - l2 data
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Uncorrectable D$ data infill from system memory
+error = ereport.cpu.amd.dc.inf_sys_eccm
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 drd mem/io lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Uncorrectable D$ data infill from L2$
+error = ereport.cpu.amd.dc.inf_l2_eccm
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - drd - l2 data
+
+panic = always
+flags = correctable
+
+# ---
+
+desc = Correctable single-bit error in Data Array from scrub
+error = ereport.cpu.amd.dc.data_ecc1
+
+mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - gen - l1 data
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Uncorrectable single-bit error in Data Array
+error = ereport.cpu.amd.dc.data_ecc1_uc
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_SCRUB
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - drd/dwr/ev/snp - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = Uncorrectable multi-bit error in Data Array
+error = ereport.cpu.amd.dc.data_eccm
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - drd/dwr/ev/snp - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = Uncorrectable multi-bit error in Data Array from scrub
+error = ereport.cpu.amd.dc.data_eccm
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_SCRUB
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - gen - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = Main Tag Array Parity Error
+error = ereport.cpu.amd.dc.tag_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - drd/dwr - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = Snoop Tag Array Parity Error
+error = ereport.cpu.amd.dc.stag_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - snp/ev - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = L1 DTLB Parity Error
+error = ereport.cpu.amd.dc.l1tlb_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 tlb - - - - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = L1 DTLB Parity Error (multimatch)
+error = ereport.cpu.amd.dc.l1tlb_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0001 tlb - - - - l1 data
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 DTLB Parity Error
+error = ereport.cpu.amd.dc.l2tlb_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 tlb - - - - l2 data
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 DTLB Parity Error (multimatch)
+error = ereport.cpu.amd.dc.l2tlb_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0001 tlb - - - - l2 data
+
+panic = always
+flags =
+
+#
+# Instruction Cache Functional Unit
+#
+
+funcunit = ic
+
+desc = Correctable I$ data infill from system memory
+error = ereport.cpu.amd.ic.inf_sys_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 ird mem lg -
+
+panic = never
+flags = correctable
+
+# ----
+
+desc = Correctable I$ data infill from L2$
+error = ereport.cpu.amd.ic.inf_l2_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - ird - l2 instr
+
+panic = never
+flags = correctable
+
+# ----
+
+desc = Uncorrectable I$ data infill from system memory
+error = ereport.cpu.amd.ic.inf_sys_eccm
+
+mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 ird mem lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Uncorrectable I$ data infill from L2$
+error = ereport.cpu.amd.ic.inf_l2_eccm
+
+mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - ird - l2 instr
+
+panic = always
+flags =
+
+# ---
+
+desc = Data Array Parity Error
+error = ereport.cpu.amd.ic.data_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - ird - l1 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Main Tag Array Parity Error
+error = ereport.cpu.amd.ic.tag_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - ird/ev - l1 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Snoop Tag Array Parity Error
+error = ereport.cpu.amd.ic.stag_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - snp/ev - l1 instr
+
+panic = always
+flags =
+
+# ---
+
+desc = L1 ITLB Parity Error
+error = ereport.cpu.amd.ic.l1tlb_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 tlb - - - - l1 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = L1 ITLB Parity Error (multimatch)
+error = ereport.cpu.amd.ic.l1tlb_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0001 tlb - - - - l1 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = L2 ITLB Parity Error
+error = ereport.cpu.amd.ic.l2tlb_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 tlb - - - - l2 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = L2 ITLB Parity Error (multimatch)
+error = ereport.cpu.amd.ic.l2tlb_par
+
+mask on =
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0001 tlb - - - - l2 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = System Data Read Error
+error = ereport.cpu.amd.ic.rdde
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 ird mem lg -
+
+panic = always
+flags =
+
+#
+# ---
+#
+
+funcunit = bu
+
+# ---
+
+desc = L2 data array single-bit ECC during TLB reload, snoop, or copyback
+error = ereport.cpu.amd.bu.l2d_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - rd/snp/ev - l2 gen
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = L2 data array multi-bit ECC during TLB reload, snoop, or copyback
+error = ereport.cpu.amd.bu.l2d_eccm
+
+mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 mem - - rd/snp/ev - l2 gen
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 main tag array single-bit ECC error on scrubber access
+error = ereport.cpu.amd.bu.l2t_ecc1
+
+mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB
+mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - gen - l2 instr
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = L2 main tag array multi-bit ECC error on scrubber access
+error = ereport.cpu.amd.bu.l2t_eccm
+
+mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - gen - l2 instr
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 main tag array parity error on I$ fetch
+error = ereport.cpu.amd.bu.l2t_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - ird - l2 instr
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 main tag array parity error on D$ fetch
+error = ereport.cpu.amd.bu.l2t_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - drd - l2 data
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 main tag array parity error on TLB reload, snoop, or copyback
+error = ereport.cpu.amd.bu.l2t_par
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - rd/snp/ev - l2 gen
+
+panic = always
+flags =
+
+# ---
+
+desc = L2 main tag array parity error on scrubber access
+error = ereport.cpu.amd.bu.l2t_par
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 mem - - gen - l2 instr
+
+panic = always
+flags =
+
+# ---
+
+desc = System data single-bit ECC for hardware prefetch or TLB reload
+error = ereport.cpu.amd.bu.s_ecc1
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 rd/pf mem/io lg -
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = System data multi-bit ECC for hardware prefetch or TLB reload
+error = ereport.cpu.amd.bu.s_eccm
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 rd/pf mem/io lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = System data read error for TLB reload or hardware prefetch
+error = ereport.cpu.amd.bu.s_rde
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 rd/pf mem/io lg -
+
+panic = always
+flags =
+
+#
+# ---
+#
+
+funcunit = ls
+
+desc = System data read error
+error = ereport.cpu.amd.ls.s_rde
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src 0 rd/wr mem/io lg -
+
+panic = always
+flags =
+
+#
+# ---
+#
+
+funcunit = nb
+
+desc = Correctable ECC error from Normal ECC
+error = ereport.cpu.amd.nb.mem_ce
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src/rsp 0 rd/wr mem lg -
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Uncorrectable ECC error from Normal ECC
+error = ereport.cpu.amd.nb.mem_ue
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0000 bus src/rsp 0 rd/wr mem lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Correctable ECC error from ChipKill ECC
+error = ereport.cpu.amd.nb.mem_ce
+
+mask on = AMD_BANK_STAT_CECC
+mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 1000 bus src/rsp 0 rd/wr mem lg -
+
+panic = never
+flags = correctable
+
+# ---
+
+desc = Uncorrectable ECC error from ChipKill ECC
+error = ereport.cpu.amd.nb.mem_ue
+
+mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC
+mask off = AMD_BANK_STAT_CECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 1000 bus src/rsp 0 rd/wr mem lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Hypertransport CRC error
+error = ereport.cpu.amd.nb.ht_crc
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0001 bus obs 0 gen gen lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Hypertransport Sync packet error
+error = ereport.cpu.amd.nb.ht_sync
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0010 bus obs 0 gen gen lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Master Abort
+error = ereport.cpu.amd.nb.ma
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0011 bus src/obs 0 rd/wr mem/io lg -
+
+panic = never
+flags =
+
+# ---
+
+desc = Target Abort
+error = ereport.cpu.amd.nb.ta
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0100 bus src/obs 0 rd/wr mem/io lg -
+
+panic = never
+flags =
+
+# ---
+
+desc = GART Table Walk Error
+error = ereport.cpu.amd.nb.gart_walk
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0101 tlb - - - - lg gen
+
+panic = always
+flags =
+
+# ---
+
+desc = Atomic Read/Modify/Write error
+error = ereport.cpu.amd.nb.rmw
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0110 bus obs 0 gen io lg -
+
+panic = always
+flags =
+
+# ---
+
+desc = Watchdog error (timeout)
+error = ereport.cpu.amd.nb.wdog
+
+mask on = AMD_BANK_STAT_UC
+mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC
+
+# ext type pp t rrrr ii ll tt
+# ------- ------- ------- ------- --------------- ------- ------- -----
+code = 0111 bus gen 1 gen gen lg -
+
+panic = always
+flags =
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c
new file mode 100644
index 0000000000..e083351d12
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c
@@ -0,0 +1,194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * AMD Athlon64/Opteron CPU Module Machine-Check Poller
+ *
+ * The AMD Opteron processor doesn't yet report correctable errors via #mc's.
+ * Instead, it fixes the problem, silently updates the error state MSRs, and
+ * resumes operation. In order to discover occurrances of correctable errors,
+ * we have to poll in the background using the omni cyclics mechanism. The
+ * error injector also has the ability to manually request an immediate poll.
+ * Locking is fairly simple within the poller: the per-CPU mutex
+ * ao->ao_mca.ao_mca_poll_lock ensures that only one poll request is active.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/x86_archext.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+#include <sys/sdt.h>
+
+#include "ao.h"
+
+static uint_t ao_mca_poll_trace_nent = 100;
+#ifdef DEBUG
+static uint_t ao_mca_poll_trace_always = 1;
+#else
+static uint_t ao_mca_poll_trace_always = 0;
+#endif
+
+static cyclic_id_t ao_mca_poll_cycid;
+static hrtime_t ao_mca_poll_interval = NANOSEC * 10ULL;
+
+static void
+ao_mca_poll_trace(ao_mca_t *mca, uint32_t what, uint32_t nerr)
+{
+ uint_t next;
+ ao_mca_poll_trace_t *pt;
+
+ ASSERT(MUTEX_HELD(&mca->ao_mca_poll_lock));
+ DTRACE_PROBE2(ao__poll__trace, uint32_t, what, uint32_t, nerr);
+
+ if (mca->ao_mca_poll_trace == NULL)
+ return; /* poll trace buffer is disabled */
+
+ next = (mca->ao_mca_poll_curtrace + 1) % ao_mca_poll_trace_nent;
+ pt = &mca->ao_mca_poll_trace[next];
+
+ pt->mpt_when = 0;
+ pt->mpt_what = what;
+
+ if (what == AO_MPT_WHAT_CYC_ERR)
+ pt->mpt_nerr = MIN(nerr, UINT8_MAX);
+
+ pt->mpt_when = gethrtime();
+ mca->ao_mca_poll_curtrace = next;
+}
+
+static void
+ao_mca_poll_common(ao_mca_t *mca, int what)
+{
+ ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_POLLER];
+ int i, n, fatal;
+
+ if (mca->ao_mca_flags & AO_MCA_F_UNFAULTING) {
+ mca->ao_mca_flags &= ~AO_MCA_F_UNFAULTING;
+ ao_mca_poll_trace(mca, AO_MPT_WHAT_UNFAULTING, 0);
+
+ /*
+ * On the first poll after re-enabling a faulty CPU we clear
+ * the status registers; see ao_faulted_exit() for more info.
+ */
+ if (what == AO_MPT_WHAT_CYC_ERR) {
+ for (i = 0; i < AMD_MCA_BANK_COUNT; i++)
+ wrmsr(ao_bank_regs[i].abr_status, 0);
+ return;
+ }
+ }
+
+ fatal = ao_mca_logout(acl, NULL, &n);
+ ao_mca_poll_trace(mca, what, n);
+
+ if (fatal && cmi_panic_on_uncorrectable_error)
+ fm_panic("Unrecoverable Machine-Check Exception");
+}
+
+static void
+ao_mca_poll_cyclic(void *arg)
+{
+ ao_data_t *ao = arg;
+
+ if (ao != NULL && mutex_tryenter(&ao->ao_mca.ao_mca_poll_lock)) {
+ ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_CYC_ERR);
+ mutex_exit(&ao->ao_mca.ao_mca_poll_lock);
+ }
+}
+
+void
+ao_mca_poke(void *arg)
+{
+ ao_data_t *ao = arg;
+
+ mutex_enter(&ao->ao_mca.ao_mca_poll_lock);
+ ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_POKE_ERR);
+ mutex_exit(&ao->ao_mca.ao_mca_poll_lock);
+}
+
+/*ARGSUSED*/
+static void
+ao_mca_poll_online(void *arg, cpu_t *cpu, cyc_handler_t *cyh, cyc_time_t *cyt)
+{
+ cyt->cyt_when = 0;
+ cyh->cyh_level = CY_LOW_LEVEL;
+
+ /*
+ * If the CPU coming on-line isn't supported by this CPU module, then
+ * disable the cylic by cranking cyt_interval and setting arg to NULL.
+ */
+ if (cpu->cpu_m.mcpu_cmi != NULL &&
+ cpu->cpu_m.mcpu_cmi->cmi_ops != &_cmi_ops) {
+ cyt->cyt_interval = INT64_MAX;
+ cyh->cyh_func = ao_mca_poll_cyclic;
+ cyh->cyh_arg = NULL;
+ } else {
+ cyt->cyt_interval = ao_mca_poll_interval;
+ cyh->cyh_func = ao_mca_poll_cyclic;
+ cyh->cyh_arg = cpu->cpu_m.mcpu_cmidata;
+ }
+}
+
+/*ARGSUSED*/
+static void
+ao_mca_poll_offline(void *arg, cpu_t *cpu, void *cyh_arg)
+{
+ /* nothing to do here */
+}
+
+void
+ao_mca_poll_init(ao_mca_t *mca)
+{
+ mutex_init(&mca->ao_mca_poll_lock, NULL, MUTEX_DRIVER, NULL);
+
+ if (ao_mca_poll_trace_always) {
+ mca->ao_mca_poll_trace =
+ kmem_zalloc(sizeof (ao_mca_poll_trace_t) *
+ ao_mca_poll_trace_nent, KM_SLEEP);
+ mca->ao_mca_poll_curtrace = 0;
+ }
+}
+
+void
+ao_mca_poll_start(void)
+{
+ cyc_omni_handler_t cyo;
+
+ if (ao_mca_poll_interval == 0)
+ return; /* if manually tuned to zero, disable polling */
+
+ cyo.cyo_online = ao_mca_poll_online;
+ cyo.cyo_offline = ao_mca_poll_offline;
+ cyo.cyo_arg = NULL;
+
+ mutex_enter(&cpu_lock);
+ ao_mca_poll_cycid = cyclic_add_omni(&cyo);
+ mutex_exit(&cpu_lock);
+}
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h
new file mode 100644
index 0000000000..f330920591
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h
@@ -0,0 +1,72 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _GCPU_H
+#define _GCPU_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/cpu_module.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct gcpu_mca_bank {
+ uint_t bank_ctl; /* MCi_CTL MSR */
+ uint_t bank_status; /* MCi_STATUS MSR */
+ uint_t bank_addr; /* MCi_ADDR MSR */
+ uint_t bank_misc; /* MCi_MISC MSR */
+} gcpu_mca_bank_t;
+
+typedef struct gcpu_mca_data {
+ uint64_t bank_status_data; /* MCi_STATUS value from exception */
+ uint64_t bank_addr_data; /* MCi_ADDR value from exception */
+ uint64_t bank_misc_data; /* MCi_MISC value from exception */
+} gcpu_mca_data_t;
+
+typedef struct gcpu_mca {
+ const gcpu_mca_bank_t *gcpu_mca_banks;
+ gcpu_mca_data_t *gcpu_mca_data;
+ uint_t gcpu_mca_nbanks;
+} gcpu_mca_t;
+
+typedef struct gcpu_data {
+ gcpu_mca_t gcpu_mca;
+} gcpu_data_t;
+
+struct regs;
+
+extern void gcpu_mca_init(void *);
+extern int gcpu_mca_trap(void *, struct regs *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCPU_H */
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c
new file mode 100644
index 0000000000..68b3d8221a
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c
@@ -0,0 +1,125 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Generic x86 CPU Module
+ *
+ * This CPU module is used for generic x86 CPUs when Solaris has no other
+ * CPU-specific support module available. Code in this module should be the
+ * absolute bare-bones support and must be cognizant of both Intel and AMD etc.
+ */
+
+#include <sys/types.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/cpuvar.h>
+#include <sys/kmem.h>
+#include <sys/modctl.h>
+
+#include "gcpu.h"
+
+/*ARGSUSED*/
+static void
+gcpu_nop(void *data)
+{
+}
+
+static int
+gcpu_notsup(void)
+{
+ return (ENOTSUP);
+}
+
+static int
+gcpu_nil(void)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+gcpu_init(cpu_t *cpu, void **datap)
+{
+ *datap = kmem_zalloc(sizeof (gcpu_data_t), KM_SLEEP);
+ return (0);
+}
+
+static void
+gcpu_fini(void *data)
+{
+ gcpu_data_t *dp = data;
+
+ kmem_free(dp->gcpu_mca.gcpu_mca_data,
+ dp->gcpu_mca.gcpu_mca_nbanks * sizeof (gcpu_mca_data_t));
+
+ kmem_free(dp, sizeof (gcpu_data_t));
+}
+
+const cmi_ops_t _cmi_ops = {
+ gcpu_init, /* cmi_init */
+ gcpu_nop, /* cmi_post_init */
+ gcpu_fini, /* cmi_fini */
+ gcpu_nop, /* cmi_faulted_enter */
+ gcpu_nop, /* cmi_faulted_exit */
+ (int (*)())gcpu_nil, /* cmi_scrubber_enable */
+ gcpu_mca_init, /* cmi_mca_init */
+ gcpu_mca_trap, /* cmi_mca_trap */
+ (int (*)())gcpu_notsup, /* cmi_mca_inject */
+ gcpu_nop, /* cmi_mca_poke */
+ (void (*)())gcpu_nop, /* cmi_mc_register */
+ (const cmi_mc_ops_t *(*)())gcpu_nop /* cmi_mc_getops */
+};
+
+static struct modlcpu modlcpu = {
+ &mod_cpuops,
+ "Generic x86 CPU Module"
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modlcpu,
+ NULL
+};
+
+int
+_init(void)
+{
+ return (mod_install(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ return (mod_remove(&modlinkage));
+}
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
new file mode 100644
index 0000000000..3793ff1087
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/mca_x86.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/cmn_err.h>
+#include <sys/cpuvar.h>
+#include <sys/x86_archext.h>
+#include <sys/controlregs.h>
+#include <sys/sysmacros.h>
+#include <sys/regset.h>
+#include <sys/privregs.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/log.h>
+#include <sys/psw.h>
+
+#include "gcpu.h"
+
+/*
+ * x86 architecture standard banks for IA32 and compatible processors. These
+ * are effectively the lowest common denominators for the MCA architecture.
+ */
+static const gcpu_mca_bank_t gcpu_mca_banks_ia32[] = {
+{ IA32_MSR_MC0_CTL, IA32_MSR_MC0_STATUS, IA32_MSR_MC0_ADDR, IA32_MSR_MC0_MISC },
+{ IA32_MSR_MC1_CTL, IA32_MSR_MC1_STATUS, IA32_MSR_MC1_ADDR, IA32_MSR_MC1_MISC },
+{ IA32_MSR_MC2_CTL, IA32_MSR_MC2_STATUS, IA32_MSR_MC2_ADDR, IA32_MSR_MC2_MISC },
+{ IA32_MSR_MC3_CTL, IA32_MSR_MC3_STATUS, IA32_MSR_MC3_ADDR, IA32_MSR_MC3_MISC },
+};
+
+/*
+ * The P6-family processors have a different layout for their banks. Note that
+ * MC4 comes *before* MC3 by design here (Intel's design that is, not ours).
+ */
+static const gcpu_mca_bank_t gcpu_mca_banks_p6[] = {
+{ P6_MSR_MC0_CTL, P6_MSR_MC0_STATUS, P6_MSR_MC0_ADDR, P6_MSR_MC0_MISC },
+{ P6_MSR_MC1_CTL, P6_MSR_MC1_STATUS, P6_MSR_MC1_ADDR, P6_MSR_MC1_MISC },
+{ P6_MSR_MC2_CTL, P6_MSR_MC2_STATUS, P6_MSR_MC2_ADDR, P6_MSR_MC2_MISC },
+{ P6_MSR_MC4_CTL, P6_MSR_MC4_STATUS, P6_MSR_MC4_ADDR, P6_MSR_MC4_MISC },
+{ P6_MSR_MC3_CTL, P6_MSR_MC3_STATUS, P6_MSR_MC3_ADDR, P6_MSR_MC3_MISC },
+};
+
+/*
+ * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU.
+ * Refer to the IA-32 Intel Architecture Software Developer's Manual,
+ * Volume 3: System Programming Guide, Section 14.5 for more information.
+ */
+void
+gcpu_mca_init(void *data)
+{
+ gcpu_data_t *gcpu = data;
+ gcpu_mca_t *mca = &gcpu->gcpu_mca;
+ cpu_t *cp = CPU;
+
+ uint64_t cap;
+ uint_t nbanks;
+ int i;
+
+ /*
+ * We're only prepared to handle processors that have an MCG_CAP
+ * register. P5, K6, and earlier processors, which have their own
+ * more primitive way of doing machine checks, are not supported.
+ */
+ ASSERT(x86_feature & X86_MCA);
+ cap = rdmsr(IA32_MSR_MCG_CAP);
+
+ if (!(cap & MCG_CAP_CTL_P))
+ return; /* do nothing if IA32_MCG_CTL register is missing */
+
+ if (strcmp(cpuid_getvendorstr(cp), "GenuineIntel") == 0 &&
+ cpuid_getfamily(cp) == 6) {
+ mca->gcpu_mca_banks = gcpu_mca_banks_p6;
+ mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_p6) /
+ sizeof (gcpu_mca_bank_t);
+ } else {
+ mca->gcpu_mca_banks = gcpu_mca_banks_ia32;
+ mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_ia32) /
+ sizeof (gcpu_mca_bank_t);
+ }
+
+ mca->gcpu_mca_data = kmem_alloc(
+ mca->gcpu_mca_nbanks * sizeof (gcpu_mca_data_t), KM_SLEEP);
+
+ /*
+ * Unlike AMD's approach of assigning one MCG_CTL bit to each machine
+ * check register bank, Intel doesn't describe the layout of MCG_CTL or
+ * promise that each bit corresponds to a bank. The generic guidance
+ * is simply to write all ones to MCG_CTL, enabling everything that is
+ * present (h/w ignores writes to the undefined bit positions). The
+ * code right now only handles the original four banks or the P6 banks,
+ * so we may enable more than we know how to read on a future CPU.
+ * This code can be enhanced to dynamically allocate bank state based
+ * upon MCG_CAP.Count if RAS ever becomes important on non-AMD CPUs.
+ */
+ nbanks = cap & MCG_CAP_COUNT_MASK;
+ mca->gcpu_mca_nbanks = MIN(nbanks, mca->gcpu_mca_nbanks);
+ wrmsr(IA32_MSR_MCG_CTL, 0ULL); /* disable features while we configure */
+
+ for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
+ const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i];
+ wrmsr(bank->bank_ctl, -1ULL);
+ wrmsr(bank->bank_status, 0ULL);
+ }
+
+ wrmsr(IA32_MSR_MCG_CTL, -1ULL); /* enable all machine-check features */
+ setcr4(getcr4() | CR4_MCE); /* enable machine-check exceptions */
+}
+
+/*
+ * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU.
+ * Refer to the IA-32 Intel Architecture Software Developer's Manual,
+ * Volume 3: System Programming Guide, Section 14.7 for more information.
+ */
+int
+gcpu_mca_trap(void *data, struct regs *rp)
+{
+ gcpu_data_t *gcpu = data;
+ gcpu_mca_t *mca = &gcpu->gcpu_mca;
+ uint64_t gstatus = rdmsr(IA32_MSR_MCG_STATUS);
+ int i, fatal = !(gstatus & MCG_STATUS_RIPV);
+
+ if (!(gstatus & MCG_STATUS_MCIP))
+ return (0); /* spurious machine check trap */
+
+ /*
+ * Read out the bank status values, and the address and misc registers
+ * if they are valid. Update our fatal status based on each bank.
+ * Clear the MCG_STATUS register when we're done reading the h/w state.
+ */
+ for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
+ const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i];
+ gcpu_mca_data_t *data = &mca->gcpu_mca_data[i];
+ uint64_t bstatus = rdmsr(bank->bank_status);
+
+ data->bank_status_data = bstatus;
+ data->bank_addr_data = 0;
+ data->bank_misc_data = 0;
+
+ if (!(bstatus & MSR_MC_STATUS_VAL))
+ continue;
+
+ if (bstatus & MSR_MC_STATUS_ADDRV)
+ data->bank_addr_data = rdmsr(bank->bank_addr);
+ if (bstatus & MSR_MC_STATUS_MISCV)
+ data->bank_misc_data = rdmsr(bank->bank_misc);
+
+ if (bstatus & (MSR_MC_STATUS_PCC | MSR_MC_STATUS_O))
+ fatal = 1; /* context corrupt or overflow */
+
+ wrmsr(bank->bank_status, 0ULL);
+ }
+
+ wrmsr(IA32_MSR_MCG_STATUS, 0);
+
+ log_enter();
+
+ if (gstatus & MCG_STATUS_EIPV) {
+ cmn_err(CE_WARN, "Machine-Check Exception at 0x%lx in %s mode",
+ (ulong_t)rp->r_pc, USERMODE(rp->r_cs) ? "user" : "kernel");
+ } else {
+ cmn_err(CE_WARN, "Machine-Check Exception in %s mode",
+ USERMODE(rp->r_cs) ? "user" : "kernel");
+ }
+
+ /*
+ * Now go back through our saved state and report it using cmn_err().
+ * We don't bother attempting any kind of decoding here as the actual
+ * values are entirely specific to the actual processor in use. We
+ * could break out the generic bit-fields, but you're only here if
+ * we didn't care enough to implement FMA support for this processor.
+ */
+ for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
+ gcpu_mca_data_t *bank = &mca->gcpu_mca_data[i];
+ uint64_t bstatus = bank->bank_status_data;
+
+ if (!(bstatus & MSR_MC_STATUS_VAL))
+ continue;
+
+ switch (bstatus & (MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV)) {
+ case MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV:
+ cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx "
+ "MISC 0x%016llx", i, (u_longlong_t)bstatus,
+ (u_longlong_t)bank->bank_addr_data,
+ (u_longlong_t)bank->bank_misc_data);
+ break;
+ case MSR_MC_STATUS_ADDRV:
+ cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx",
+ i, (u_longlong_t)bstatus,
+ (u_longlong_t)bank->bank_addr_data);
+ break;
+ case MSR_MC_STATUS_MISCV:
+ cmn_err(CE_WARN, "%d STAT 0x%016llx MISC 0x%016llx",
+ i, (u_longlong_t)bstatus,
+ (u_longlong_t)bank->bank_misc_data);
+ break;
+ default:
+ cmn_err(CE_WARN, "%d STAT 0x%016llx",
+ i, (u_longlong_t)bstatus);
+ }
+ }
+
+ log_exit();
+ return (fatal);
+}
diff --git a/usr/src/uts/i86pc/cpu/scripts/Makefile b/usr/src/uts/i86pc/cpu/scripts/Makefile
new file mode 100644
index 0000000000..f3509aa90e
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/scripts/Makefile
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PERLFILES= \
+ ao_gendisp
+
+include ../../../Makefile.uts
+
+OWNER= root
+GROUP= bin
+
+.KEEP_STATE:
+
+all install setup: $(PERLFILES)
+
+clean:
+ $(RM) $(PERLFILES)
+
+include ../../../Makefile.targ
+
+%: %.pl
+ $(RM) $@
+ cat $< > $@
+ chmod +x $@
diff --git a/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl
new file mode 100644
index 0000000000..9d8b24e539
--- /dev/null
+++ b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl
@@ -0,0 +1,370 @@
+#!/bin/perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+use strict;
+use File::Basename;
+
+my $PROGNAME = basename($0);
+
+my ($funcunit, $error);
+my @funcunits = ();
+
+my $state = "initial";
+
+sub usage() {
+ print STDERR "Usage: $PROGNAME inputfile\n";
+ exit(2);
+}
+
+sub bail() {
+ print STDERR "$PROGNAME: ", join(" ", @_), "\n";
+ exit(1);
+}
+
+sub parsebail() {
+ print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n";
+ exit(1);
+}
+
+sub print_header() {
+ print "#include \"ao_mca_disp.h\"\n\n";
+}
+
+sub print_footer() {
+ print "const ao_error_disp_t *ao_error_disp[] = {\n";
+
+ foreach my $name (@funcunits) {
+ print "\t$name,\n";
+ }
+
+ print "};\n";
+}
+
+sub funcunit_begin() {
+ my $arrnm = "ao_error_disp_" . $_[0];
+ print "static const ao_error_disp_t " . $arrnm . "[] = {\n";
+
+ @funcunits = (@funcunits, $arrnm);
+}
+
+sub funcunit_end() {
+ print "\tNULL\n};\n\n";
+}
+
+sub error_begin() {
+ my ($ereport_name) = @_;
+
+ $ereport_name =~ tr/[a-z]./[A-Z]_/;
+ my $flags_name = $ereport_name;
+ $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/;
+
+ print "\tFM_$ereport_name,\n\tFM_$flags_name,\n";
+}
+
+sub error_end() {
+ print "\t},\n\n";
+}
+
+sub print_bits() {
+ my $name = $_[0];
+ my @bits = @_[1..$#_];
+
+ if (@bits == 0) {
+ print "\t0,";
+ } elsif (@bits == 1) {
+ print "\t$bits[0],";
+ } else {
+ print "\t( ", join(" | ", @bits), " ),";
+ }
+
+ print " /* $name */\n";
+}
+
+sub field_burst() {
+ my ($field, $valuesref, $name, $prefix) = @_;
+
+ if ($field eq "-") {
+ return ();
+ }
+
+ map {
+ if (!defined ${$valuesref}{$_}) {
+ &parsebail("unknown $name value `$_'");
+ }
+ $_ = ${$valuesref}{$_};
+ tr/[a-z]/[A-Z]/;
+ $prefix . "_" . $_;
+ } split(/\//, $field);
+}
+
+sub bin2dec() {
+ my $bin = $_[0];
+ my $dec = 0;
+
+ foreach my $bit (split(//, $bin)) {
+ $dec = $dec * 2 + ($bit eq "1" ? 1 : 0);
+ }
+
+ $dec;
+}
+
+sub state_funcunit() {
+ my $val = $_[0];
+
+ if (defined $::funcunit) {
+ &funcunit_end();
+ }
+
+ $::funcunit = $val;
+ undef $::error;
+ &funcunit_begin($::funcunit);
+}
+
+sub state_desc() {
+ my $desc = $_[0];
+
+ print "\t/* $desc */\n\t{\n";
+}
+
+sub state_error() {
+ $::error = $_[0];
+ &error_begin($::error);
+}
+
+sub state_mask_on() {
+ @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
+}
+
+sub state_mask_off() {
+ my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
+
+ &print_bits("mask", @::mask_on, @mask_off);
+ &print_bits("mask_res", @::mask_on);
+}
+
+sub state_code() {
+ my ($ext, $type, $pp, $t, $r4, $ii, $ll, $tt) = split(/\s+/, $_[0]);
+
+ my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 );
+ my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 );
+
+ my %r4_values = (
+ gen => 'gen',
+ rd => 'rd',
+ wr => 'wr',
+ drd => 'drd',
+ dwr => 'dwr',
+ ird => 'ird',
+ pf => 'prefetch',
+ ev => 'evict',
+ snp => 'snoop',
+ '-' => '-');
+
+ my %pp_values = (
+ src => 'src',
+ rsp => 'rsp',
+ obs => 'obs',
+ gen => 'gen',
+ '-' => '-' );
+
+ my %t_values = ( 0 => 1, 1 => 1, '-' => 1 );
+
+ my %ii_values = (
+ mem => 'mem',
+ io => 'io',
+ gen => 'gen',
+ '-' => '-' );
+
+ if (!defined $tt_values{$tt}) {
+ &parsebail("unknown tt value `$tt'");
+ }
+
+ if (!defined $ll_values{$ll}) {
+ &parsebail("unknown ll value `$ll'");
+ }
+
+ my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT");
+
+ my @pp = ($pp eq '-') ? () :
+ &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT");
+
+ if (!defined $t_values{$t}) {
+ &parsebail("unknown t value `$t'");
+ }
+
+ my @ii = ($ii eq '-') ? () :
+ &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT");
+
+ map {
+ tr/[a-z]/[A-Z]/;
+ } ($ii, $ll, $tt);
+
+ if ($type eq "bus") {
+ if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" ||
+ $ll eq "-" ||
+ $tt ne "-") {
+ &parsebail("invalid members for bus code type");
+ }
+
+ print "\tAMD_ERRCODE_MKBUS(" .
+ "0, " . # pp
+ "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " .
+ "0, " . # r4
+ "0, " . # ii
+ "AMD_ERRCODE_LL_$ll),\n";
+
+ } elsif ($type eq "mem") {
+ if ($r4 eq "-" || $tt eq "-" || $ll eq "-" ||
+ $pp ne "-" || $t ne "-" || $ii ne "-") {
+ &parsebail("invalid members for mem code type");
+ }
+
+ print "\tAMD_ERRCODE_MKMEM(" .
+ "0, " . # r4
+ "AMD_ERRCODE_TT_$tt, " .
+ "AMD_ERRCODE_LL_$ll),\n";
+
+ } elsif ($type eq "tlb") {
+ if ($tt eq "-" || $ll eq "-" ||
+ $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") {
+ &parsebail("invalid members for tlb code type");
+ }
+
+ print "\tAMD_ERRCODE_MKTLB(" .
+ "AMD_ERRCODE_TT_$tt, " .
+ "AMD_ERRCODE_LL_$ll),\n";
+ } else {
+ &parsebail("unknown code type `$type'");
+ }
+
+ print "\t" . &bin2dec($ext) . ", /* ext code $ext */\n";
+
+ &print_bits("pp_bits", @pp);
+ &print_bits("ii_bits", @ii);
+ &print_bits("r4_bits", @r4);
+}
+
+sub state_panic() {
+ my $val = $_[0];
+
+ if ($val eq "") {
+ print "\t0, /* panic_when */\n";
+ } else {
+ $val =~ tr/[a-z]/[A-Z]/;
+ print "\tAO_AED_PANIC_$val,\n";
+ }
+}
+
+sub state_flags() {
+ my @flags = split(/,\s*/, $_[0]);
+
+ @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags;
+
+ &print_bits("flags", @flags);
+}
+
+my %stateparse = (
+ funcunit => [ \&state_funcunit, "desc" ],
+ desc => [ \&state_desc, "error" ],
+ error => [ \&state_error, "mask on" ],
+ 'mask on' => [ \&state_mask_on, "mask off" ],
+ 'mask off' => [ \&state_mask_off, "code" ],
+ code => [ \&state_code, "panic" ],
+ panic => [ \&state_panic, "flags" ],
+ flags => [ \&state_flags, "initial" ]
+);
+
+usage unless (@ARGV == 1);
+
+my $infile = $ARGV[0];
+open(INFILE, "<$infile") || &bail("failed to open $infile: $!");
+
+&print_header();
+
+while (<INFILE>) {
+ chop;
+
+ /^#/ && next;
+ /^$/ && next;
+
+ if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) {
+ &parsebail("failed to parse");
+ }
+
+ my ($keyword, $val) = ($1, $2);
+
+ if ($state eq "initial") {
+ if ($keyword eq "funcunit") {
+ $state = "funcunit";
+ } elsif ($keyword eq "desc") {
+ $state = "desc";
+ } else {
+ &parsebail("unexpected keyword $keyword between " .
+ "errors");
+ }
+
+ } elsif ($state eq "desc") {
+ if ($keyword eq "funcunit") {
+ $state = "funcunit";
+ }
+ }
+
+ if ($keyword ne $state) {
+ &parsebail("keyword `$keyword' invalid here; expected `$state'");
+ }
+
+ if (!defined $stateparse{$state}) {
+ &parsebail("attempt to transition to invalid state `$state'");
+ }
+
+ my ($handler, $next) = @{$stateparse{$state}};
+
+ &{$handler}($val);
+
+ $state = $next;
+
+ if ($state eq "initial") {
+ &error_end();
+ }
+}
+
+close(INFILE);
+
+if ($state ne "initial" && $state ne "desc") {
+ &bail("input file ended prematurely");
+}
+
+if (defined $::funcunit) {
+ &funcunit_end();
+} else {
+ &bail("no functional units defined");
+}
+
+&print_footer;
diff --git a/usr/src/uts/i86pc/generic_cpu/Makefile b/usr/src/uts/i86pc/generic_cpu/Makefile
new file mode 100644
index 0000000000..f23d9dd369
--- /dev/null
+++ b/usr/src/uts/i86pc/generic_cpu/Makefile
@@ -0,0 +1,82 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = cpu.generic
+#
+OBJECTS = $(CPU_GCPU_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(CPU_GCPU_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include ../cpu/Makefile.cpu
+
+#
+# Our lint library has a different name from that of the module we build.
+#
+LINT_MODULE = generic_cpu
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(LINT_MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include ../Makefile.targ
diff --git a/usr/src/uts/i86pc/io/mc/mc-amd.conf b/usr/src/uts/i86pc/io/mc/mc-amd.conf
new file mode 100644
index 0000000000..066b704525
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mc-amd.conf
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+name="mc-amd" parent="pseudo";
+
+ddi-forceattach=1;
diff --git a/usr/src/uts/i86pc/io/mc/mcamd.h b/usr/src/uts/i86pc/io/mc/mcamd.h
new file mode 100644
index 0000000000..330ecfa5b5
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mcamd.h
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MCAMD_H
+#define _MCAMD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/chip.h>
+#include <sys/ksynch.h>
+#include <sys/mc_amd.h>
+#include <mcamd_api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * PCI configuration space functions for the memory controller. Note that
+ * the function numbers here also serve as the mc_func indices in the mc_t.
+ */
+#define MC_FUNC_HTCONFIG 0 /* unused */
+#define MC_FUNC_HTCONFIG_BINDNM "pci1022,1100" /* unused */
+#define MC_FUNC_ADDRMAP 1
+#define MC_FUNC_ADDRMAP_BINDNM "pci1022,1101"
+#define MC_FUNC_DRAMCTL 2
+#define MC_FUNC_DRAMCTL_BINDNM "pci1022,1102"
+
+/*
+ * The memory controller driver attaches to several device nodes, but publishes
+ * a single minor node. We need to ensure that the minor node can be
+ * consistently mapped back to a single (and the same) device node, so we need
+ * to pick one to be used. We'll use the DRAM Controller device node, as it'll
+ * be the last to be attached.
+ */
+#define MC_FUNC_DEVIMAP MC_FUNC_DRAMCTL
+
+#define MC_FUNC_NUM 3
+
+/*
+ * The following define the offsets at which various MC registers are
+ * accessed in PCI config space. For defines describing the register
+ * structure see mc_amd.h.
+ */
+
+/*
+ * BKDG 3.29 section 3.4 - MC DRAM base and limit addresses, hole offset.
+ */
+#define MC_AM_REG_NODE_NUM 8 /* Number of DRAM nodes */
+#define MC_AM_REG_DRAMBASE_0 0x40 /* Offset for DRAM Base 0 */
+#define MC_AM_REG_DRAMLIM_0 0x44 /* Offset for DRAM Limit 0 */
+#define MC_AM_REG_DRAM_INCR 8 /* incr between base/limit pairs */
+#define MC_AM_REG_HOLEADDR 0xf0 /* DRAM Hole Address Register */
+
+/*
+ * BKDG 3.29 section 3.5 - DRAM contoller chip-select base, mask,
+ * DRAM bank address mapping, DRAM configuration.
+ */
+#define MC_DC_REG_CS_INCR 4 /* incr for CS base and mask */
+#define MC_DC_REG_CSBASE_0 0x40 /* 0x40 - 0x5c */
+#define MC_DC_REG_CSMASK_0 0x60 /* 0x60 - 0x7c */
+#define MC_DC_REG_BANKADDRMAP 0x80
+#define MC_DC_REG_DRAMCFGLO 0x90
+#define MC_DC_REG_DRAMCFGHI 0x94
+
+typedef struct mc_func {
+ uint_t mcf_instance;
+ dev_info_t *mcf_devi;
+} mc_func_t;
+
+typedef struct mc_dimm mc_dimm_t;
+typedef struct mc_cs mc_cs_t;
+typedef struct mc mc_t;
+
+typedef uint64_t mc_prop_t; /* see mcamd_get_numprop */
+
+/*
+ * Node types for mch_type below. These are used in array indexing.
+ */
+#define MC_NT_MC 0
+#define MC_NT_CS 1
+#define MC_NT_DIMM 2
+#define MC_NT_NTYPES 3
+
+typedef struct mc_hdr {
+ uint_t mch_type;
+ union {
+ mc_t *_mch_mc;
+ mc_cs_t *_mch_cs;
+ } _mch_ptr;
+} mc_hdr_t;
+
+#define mch_mc _mch_ptr._mch_mc
+
+struct mc_dimm {
+ mc_hdr_t mcd_hdr; /* id, pointer to parent */
+ mc_dimm_t *mcd_next; /* next dimm for this MC */
+ mc_cs_t *mcd_cs[MC_CHIP_DIMMRANKMAX]; /* associated chip-selects */
+ mc_prop_t mcd_num; /* dimm number */
+};
+
+#define mcd_mc mcd_hdr.mch_mc
+
+struct mc_cs {
+ mc_hdr_t mccs_hdr; /* id, pointer to parent */
+ mc_cs_t *mccs_next; /* Next chip-select of MC */
+ mc_dimm_t *mccs_dimm[MC_CHIP_DIMMPERCS]; /* dimms for this cs */
+ mc_prop_t mccs_num; /* Chip-select number */
+ mc_prop_t mccs_base; /* DRAM CS Base */
+ mc_prop_t mccs_mask; /* DRAM CS Mask */
+ mc_prop_t mccs_size; /* Chip-select bank size */
+ mc_prop_t mccs_dimmnums[MC_CHIP_DIMMPERCS];
+};
+
+#define mccs_mc mccs_hdr.mch_mc
+
+typedef struct mc_props {
+ mc_dimm_t *mcp_dimmlist; /* List of all logical DIMMs, */
+ mc_dimm_t *mcp_dimmlast; /* linked via mcd_mcnext */
+ mc_prop_t mcp_num; /* Associated *chip* number */
+ mc_prop_t mcp_rev; /* Chip revision (MC_REV_*) */
+ mc_prop_t mcp_base; /* base address for mc's drams */
+ mc_prop_t mcp_lim; /* limit address for mc's drams */
+ mc_prop_t mcp_dramcfg; /* DRAM config hi, DRAM config lo */
+ mc_prop_t mcp_dramhole; /* DRAM Hole Address Register */
+ mc_prop_t mcp_ilen; /* interleave enable */
+ mc_prop_t mcp_ilsel; /* interleave select */
+ mc_prop_t mcp_csbankmap; /* chip-select bank mapping reg */
+ mc_prop_t mcp_accwidth; /* dram access width (64 or 128) */
+ mc_prop_t mcp_csbank_intlv; /* cs bank interleave factor */
+ mc_prop_t mcp_disabled_cs; /* # banks with CSBE clear */
+} mc_props_t;
+
+struct mc {
+ mc_hdr_t mc_hdr; /* id */
+ struct mc *mc_next; /* linear, doubly-linked list */
+ const char *mc_revname; /* revision name string */
+ uint_t mc_ref; /* reference (attach) count */
+ mc_func_t mc_funcs[MC_FUNC_NUM]; /* Instance, devinfo, ... */
+ chip_t *mc_chip; /* Associated chip */
+ mc_cs_t *mc_cslist; /* All active chip-selects */
+ mc_cs_t *mc_cslast; /* End of chip-select list */
+ mc_props_t mc_props; /* Properties */
+ nvlist_t *mc_nvl; /* nvlist for export */
+ char *mc_snapshot; /* packed nvlist for libmc */
+ size_t mc_snapshotsz; /* packed nvlist buffer size */
+ uint_t mc_snapshotgen; /* snapshot generation number */
+};
+
+typedef struct mcamd_hdl {
+ int mcamd_errno;
+ int mcamd_debug;
+} mcamd_hdl_t;
+
+extern mc_t *mc_list;
+extern krwlock_t mc_lock;
+
+extern void mcamd_mkhdl(mcamd_hdl_t *);
+extern void mcamd_mc_register(struct cpu *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MCAMD_H */
diff --git a/usr/src/uts/i86pc/io/mc/mcamd_drv.c b/usr/src/uts/i86pc/io/mc/mcamd_drv.c
new file mode 100644
index 0000000000..0b0c04a1d4
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mcamd_drv.c
@@ -0,0 +1,999 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/ddifm.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/stat.h>
+#include <sys/modctl.h>
+#include <sys/types.h>
+#include <sys/mc.h>
+#include <sys/cpuvar.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/cred.h>
+#include <sys/ksynch.h>
+#include <sys/rwlock.h>
+#include <sys/chip.h>
+#include <sys/open.h>
+#include <sys/policy.h>
+#include <sys/machsystm.h>
+#include <sys/x86_archext.h>
+#include <sys/cpu_module.h>
+#include <sys/mc_amd.h>
+
+#include <mcamd.h>
+#include <mcamd_api.h>
+
+int mc_quadranksupport = 0; /* set to 1 for a MB with quad rank support */
+
+mc_t *mc_list;
+krwlock_t mc_lock;
+int mc_hold_attached = 1;
+
+static void
+mc_snapshot_destroy(mc_t *mc)
+{
+ ASSERT(RW_LOCK_HELD(&mc_lock));
+
+ if (mc->mc_snapshot == NULL)
+ return;
+
+ kmem_free(mc->mc_snapshot, mc->mc_snapshotsz);
+ mc->mc_snapshot = NULL;
+ mc->mc_snapshotgen++;
+}
+
+static int
+mc_snapshot_update(mc_t *mc)
+{
+ ASSERT(RW_LOCK_HELD(&mc_lock));
+
+ if (mc->mc_snapshot != NULL)
+ return (0);
+
+ if (nvlist_pack(mc->mc_nvl, &mc->mc_snapshot, &mc->mc_snapshotsz,
+ NV_ENCODE_XDR, KM_SLEEP) != 0)
+ return (-1);
+
+ return (0);
+}
+
+static mc_t *
+mc_lookup_func(dev_info_t *dip, int instance, mc_func_t **funcp)
+{
+ mc_t *mc;
+ int i;
+
+ ASSERT(RW_LOCK_HELD(&mc_lock));
+
+ for (mc = mc_list; mc != NULL; mc = mc->mc_next) {
+ for (i = 0; i < MC_FUNC_NUM; i++) {
+ mc_func_t *func = &mc->mc_funcs[i];
+ if ((dip != NULL && func->mcf_devi == dip) ||
+ (dip == NULL && func->mcf_instance == instance)) {
+ if (funcp != NULL)
+ *funcp = func;
+ return (mc);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+static mc_t *
+mc_lookup_by_devi(dev_info_t *dip, mc_func_t **funcp)
+{
+ return (mc_lookup_func(dip, 0, funcp));
+}
+
+static mc_t *
+mc_lookup_by_instance(int instance, mc_func_t **funcp)
+{
+ return (mc_lookup_func(NULL, instance, funcp));
+}
+
+static mc_t *
+mc_lookup_by_chipid(int chipid)
+{
+ mc_t *mc;
+
+ ASSERT(RW_LOCK_HELD(&mc_lock));
+
+ for (mc = mc_list; mc != NULL; mc = mc->mc_next) {
+ if (mc->mc_chip->chip_id == chipid)
+ return (mc);
+ }
+
+ return (NULL);
+}
+
+typedef struct mc_rev_map {
+ uint_t rm_family;
+ uint_t rm_modello;
+ uint_t rm_modelhi;
+ uint_t rm_rev;
+ const char *rm_name;
+} mc_rev_map_t;
+
+static const mc_rev_map_t mc_rev_map[] = {
+ { 0xf, 0x00, 0x0f, MC_REV_PRE_D, "B/C/CG" },
+ { 0xf, 0x10, 0x1f, MC_REV_D_E, "D" },
+ { 0xf, 0x20, 0x3f, MC_REV_D_E, "E" },
+ { 0xf, 0x40, 0x5f, MC_REV_F, "F" },
+ { 0, 0, 0, MC_REV_UNKNOWN, NULL }
+};
+
+static const mc_rev_map_t *
+mc_revision(chip_t *chp)
+{
+ int rmn = sizeof (mc_rev_map) / sizeof (mc_rev_map[0]);
+ const mc_rev_map_t *rm;
+ uint8_t family, model;
+
+ if (chp == NULL)
+ return (&mc_rev_map[rmn - 1]);
+
+ /*
+ * For the moment, we assume that both cores in multi-core chips will
+ * be of the same revision, so we'll confine our revision check to
+ * the first CPU pointed to by this chip.
+ */
+ family = cpuid_getfamily(chp->chip_cpus);
+ model = cpuid_getmodel(chp->chip_cpus);
+
+ for (rm = mc_rev_map; rm->rm_rev != MC_REV_UNKNOWN; rm++) {
+ if (family == rm->rm_family && model >= rm->rm_modello &&
+ model <= rm->rm_modelhi)
+ break;
+ }
+
+ return (rm);
+}
+
+static void
+mc_prop_read_pair(ddi_acc_handle_t cfghdl, uint32_t *r1, off_t r1addr,
+ uint32_t *r2, off_t r2addr, int n, off_t incr)
+{
+ int i;
+
+ for (i = 0; i < n; i++, r1addr += incr, r2addr += incr) {
+ r1[i] = pci_config_get32(cfghdl, r1addr);
+ r2[i] = pci_config_get32(cfghdl, r2addr);
+ }
+}
+
+static void
+mc_nvl_add_prop(nvlist_t *nvl, void *node, uint_t code)
+{
+ int valfound;
+ uint64_t value;
+ const char *name = mcamd_get_propname(code);
+
+ valfound = mcamd_get_numprop(NULL, (mcamd_node_t *)node, code, &value);
+
+ ASSERT(name != NULL && valfound);
+ if (name != NULL && valfound)
+ (void) nvlist_add_uint64(nvl, name, value);
+}
+
+static nvlist_t *
+mc_nvl_create(mc_t *mc)
+{
+ mc_cs_t *mccs = mc->mc_cslist;
+ nvlist_t *cslist[MC_CHIP_NCS], *dimmlist[MC_CHIP_NDIMM];
+ nvlist_t *mcnvl;
+ mc_dimm_t *mcd;
+ int nelem, i;
+
+ (void) nvlist_alloc(&mcnvl, NV_UNIQUE_NAME, KM_SLEEP);
+ (void) nvlist_add_string(mcnvl, "revname", mc->mc_revname);
+
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_NUM);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_REV);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_BASE_ADDR);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_LIM_ADDR);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_CONFIG);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_HOLE);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILEN);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILSEL);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANKMAP);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_ACCESS_WIDTH);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANK_INTLV);
+ mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DISABLED_CS);
+
+ for (nelem = 0; mccs != NULL; mccs = mccs->mccs_next, nelem++) {
+ nvlist_t **csp = &cslist[nelem];
+
+ (void) nvlist_alloc(csp, NV_UNIQUE_NAME, KM_SLEEP);
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_NUM);
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_BASE_ADDR);
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_MASK);
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_SIZE);
+
+ if (mccs->mccs_dimmnums[0] != -1)
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_LODIMM);
+ if (mccs->mccs_dimmnums[1] != -1)
+ mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_UPDIMM);
+ }
+
+ (void) nvlist_add_nvlist_array(mcnvl, "cslist", cslist, nelem);
+ for (i = 0; i < nelem; i++)
+ nvlist_free(cslist[i]);
+
+ for (nelem = 0, mcd = mc->mc_props.mcp_dimmlist; mcd != NULL;
+ mcd = mcd->mcd_next, nelem++) {
+ nvlist_t **dimmp = &dimmlist[nelem];
+ int ncs = 0;
+ uint64_t csnums[MC_CHIP_DIMMRANKMAX];
+
+ (void) nvlist_alloc(dimmp, NV_UNIQUE_NAME, KM_SLEEP);
+
+ mc_nvl_add_prop(*dimmp, mcd, MCAMD_PROP_NUM);
+
+ for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) {
+ if (mcd->mcd_cs[i] != NULL)
+ csnums[ncs++] = mcd->mcd_cs[i]->mccs_num;
+ }
+
+ (void) nvlist_add_uint64_array(*dimmp, "csnums", csnums, ncs);
+ }
+
+ (void) nvlist_add_nvlist_array(mcnvl, "dimmlist", dimmlist, nelem);
+ for (i = 0; i < nelem; i++)
+ nvlist_free(dimmlist[i]);
+
+ return (mcnvl);
+}
+
+static void
+mc_dimm_csadd(mc_dimm_t *mcd, mc_cs_t *mccs)
+{
+ int i;
+
+ for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) {
+ if (mcd->mcd_cs[i] == NULL) {
+ mcd->mcd_cs[i] = mccs;
+ break;
+ }
+ }
+ ASSERT(i != MC_CHIP_DIMMRANKMAX);
+}
+
+static mc_dimm_t *
+mc_dimm_create(mc_t *mc, mc_cs_t *mccs, uint_t num)
+{
+ mc_dimm_t *mcd = kmem_zalloc(sizeof (mc_dimm_t), KM_SLEEP);
+
+ mcd->mcd_hdr.mch_type = MC_NT_DIMM;
+ mcd->mcd_mc = mc;
+ mcd->mcd_num = num;
+ mc_dimm_csadd(mcd, mccs);
+
+ return (mcd);
+}
+
+/*
+ * A chip-select is associated with up to 2 dimms, and a single dimm may
+ * have up to 4 associated chip-selects (in the presence of quad-rank support
+ * on the motherboard). How we number our dimms is determined by the MC
+ * config. This function may be called by multiple chip-selects for the
+ * same dimm(s).
+ */
+static void
+mc_cs_dimmlist_create(mc_t *mc, mc_cs_t *mccs, uint_t *dimm_nums, int ndimm)
+{
+ mc_dimm_t *mcd;
+ mc_props_t *mcp = &mc->mc_props;
+ int i;
+ int nfound = 0;
+
+ /*
+ * Has some other chip-select already created this dimm or dimms?
+ */
+ for (mcd = mcp->mcp_dimmlist; mcd != NULL; mcd = mcd->mcd_next) {
+ for (i = 0; i < ndimm; i++) {
+ if (mcd->mcd_num == dimm_nums[i]) {
+ mccs->mccs_dimm[i] = mcd;
+ mccs->mccs_dimmnums[i] = mcd->mcd_num;
+ mc_dimm_csadd(mcd, mccs);
+ nfound++;
+ }
+ }
+ }
+ ASSERT(nfound == 0 || nfound == ndimm);
+ if (nfound == ndimm)
+ return;
+
+ for (i = 0; i < ndimm; i++) {
+ mcd = mccs->mccs_dimm[i] =
+ mc_dimm_create(mc, mccs, dimm_nums[i]);
+
+ mccs->mccs_dimmnums[i] = mcd->mcd_num;
+
+ if (mcp->mcp_dimmlist == NULL)
+ mcp->mcp_dimmlist = mcd;
+ else
+ mcp->mcp_dimmlast->mcd_next = mcd;
+ mcp->mcp_dimmlast = mcd;
+ }
+
+}
+
+/*
+ * A placeholder for a future implementation that works this out from
+ * smbios or SPD information. For now we will return a value that
+ * can be tuned in /etc/system, and the default will cover current Sun systems.
+ */
+/*ARGSUSED*/
+static int
+mc_config_quadranksupport(mc_t *mc)
+{
+ return (mc_quadranksupport != 0);
+}
+
+/*
+ * Create the DIMM structure for this MC. There are a number of unkowns,
+ * such as the number of DIMM slots for this MC, the number of chip-select
+ * ranks supported for each DIMM, how the slots are labelled etc.
+ *
+ * SMBIOS information can help with some of this (if the bios implementation is
+ * complete and accurate, which is often not the case):
+ *
+ * . A record is required for each SMB_TYPE_MEMDEVICE slot, whether populated
+ * or not. The record should reference the associated SMB_TYPE_MEMARRAY,
+ * so we can figure out the number of slots for each MC. In practice some
+ * smbios implementations attribute all slots (from multiple chips) to
+ * a single memory array.
+ *
+ * . SMB_TYPE_MEMDEVICEMAP records indicate how a particular SMB_TYPE_MEMDEVICE
+ * has been mapped. Some smbios implementation produce rubbish here, or get
+ * confused when cs bank interleaving is enabled or disabled, but we can
+ * perform some validation of the information before using it. The record
+ * information is not well suited to handling cs bank interleaving since
+ * it really only provides for a device to have a few contiguos mappings
+ * and with cs interleave we have lots of little chunks interleaved across
+ * the devices. If we assume that the bios has followed the BKDG algorithm
+ * for setting up cs interleaving (which involves assinging contiguous
+ * and adjacent ranges to the chip selects and then swapping some
+ * base and mask hi and lo bits) then we can attempt to interpret the
+ * DEVICEMAP records as being the addresses prior to swapping address/mask
+ * bits to establish the interleave - that seems to cover at least some
+ * smbios implementations. Even if that assumption appears good it is
+ * also not clear which MEMDEVICE records correspond to LODIMMs and which
+ * to UPDIMMs in a DIMM pair (128 bit MC mode) - we have to interpret the
+ * Device Locator and Bank Locator labels.
+ *
+ * We also do not know how many chip-select banks reside on individual
+ * DIMMs. For instance we cannot distinguish a system that supports 8
+ * DIMMs slots per chip (one CS line each, thereby supporting only single-rank
+ * DIMMs) vs a system that has just 4 slots per chip and which routes
+ * 2 CS lines to each pair (thereby supporting dual rank DIMMs). In each
+ * we would discover 8 active chip-selects.
+ *
+ * So the task of establishing the real DIMM configuration is complex, likely
+ * requiring some combination of good SMBIOS data and perhaps our own access
+ * to SPD information. Instead we opt for a canonical numbering scheme,
+ * derived from the 'AMD Athlon (TM) 64 FX and AMD Opteron (TM) Processors
+ * Motherboard Design Guide' (AMD publication #25180).
+ */
+static void
+mc_dimmlist_create(mc_t *mc)
+{
+ int mcmode;
+ mc_cs_t *mccs;
+ int quadrank = mc_config_quadranksupport(mc);
+ uint_t dimm_nums[MC_CHIP_DIMMPERCS];
+ int ldimmno; /* logical DIMM pair number, 0 .. 3 */
+
+ mcmode = mc->mc_props.mcp_dramcfg & MC_DC_DCFG_128 ? 128 : 64;
+
+ for (mccs = mc->mc_cslist; mccs != NULL; mccs = mccs->mccs_next) {
+ if (quadrank) {
+ /*
+ * Quad-rank support. We assume that any of cs#
+ * 4/5/6/6 that we have discovered active are routed
+ * for quad rank support as described in the MB
+ * design guide:
+ * DIMM0: CS# 0, 1, 4 and 5
+ * DIMM1: CS# 2, 3, 6 and 7
+ */
+ ldimmno = (mccs->mccs_num % 4) /2;
+ } else {
+ /*
+ * DIMM0: CS# 0 and 1
+ * DIMM1: CS# 2 and 3
+ * DIMM2: CS# 4 and 5
+ * DIMM3: CS# 6 and 7
+ */
+ ldimmno = mccs->mccs_num / 2;
+ }
+
+ if (mcmode == 128) {
+ /* 128-bit data width mode - dimms present in pairs */
+ dimm_nums[0] = ldimmno * 2; /* LODIMM */
+ dimm_nums[1] = ldimmno * 2 + 1; /* UPDIMM */
+ } else {
+ /* 64-bit data width mode - only even numbered dimms */
+ dimm_nums[0] = ldimmno * 2; /* LODIMM */
+ }
+ mc_cs_dimmlist_create(mc, mccs, dimm_nums,
+ mcmode == 128 ? 2 : 1);
+ }
+}
+
+static mc_cs_t *
+mc_cs_create(mc_t *mc, uint_t num, uint64_t base, uint64_t mask, size_t sz)
+{
+ mc_cs_t *mccs = kmem_zalloc(sizeof (mc_cs_t), KM_SLEEP);
+
+ mccs->mccs_hdr.mch_type = MC_NT_CS;
+ mccs->mccs_mc = mc;
+ mccs->mccs_num = num;
+ mccs->mccs_base = base;
+ mccs->mccs_mask = mask;
+ mccs->mccs_size = sz;
+
+ return (mccs);
+}
+
+/*
+ * Function 1 Configuration - Address Map (see BKDG 3.4.4 DRAM Address Map)
+ *
+ * Read the Function 1 Address Map for each potential DRAM node. The Base
+ * Address for a node gives the starting system address mapped at that node,
+ * and the limit gives the last valid address mapped at that node. Regions for
+ * different nodes should not overlap, unless node-interleaving is enabled.
+ * The base register also indicates the node-interleaving settings (IntlvEn).
+ * The limit register includes IntlvSel which determines which 4K blocks will
+ * be routed to this node and the destination node ID for addresses that fall
+ * within the [base, limit] range - this must match the pair number.
+ */
+static void
+mc_mkprops_addrmap(ddi_acc_handle_t cfghdl, mc_t *mc)
+{
+ uint32_t base[MC_AM_REG_NODE_NUM], lim[MC_AM_REG_NODE_NUM];
+ mc_props_t *mcp = &mc->mc_props;
+ int i;
+
+ mc_prop_read_pair(cfghdl, base, MC_AM_REG_DRAMBASE_0, lim,
+ MC_AM_REG_DRAMLIM_0, MC_AM_REG_NODE_NUM, MC_AM_REG_DRAM_INCR);
+
+ for (i = 0; i < MC_AM_REG_NODE_NUM; i++) {
+ /*
+ * Don't create properties for empty nodes.
+ */
+ if ((lim[i] & MC_AM_DL_DRAMLIM_MASK) == 0)
+ continue;
+
+ /*
+ * Don't create properties for DIMM ranges that aren't local
+ * to this node.
+ */
+ if ((lim[i] & MC_AM_DL_DSTNODE_MASK) != mc->mc_chip->chip_id)
+ continue;
+
+ mcp->mcp_base = MC_AM_DB_DRAMBASE(base[i]);
+ mcp->mcp_lim = MC_AM_DL_DRAMLIM(lim[i]);
+ mcp->mcp_ilen = (base[i] & MC_AM_DB_INTLVEN_MASK) >>
+ MC_AM_DB_INTLVEN_SHIFT;
+ mcp->mcp_ilsel = (lim[i] & MC_AM_DL_INTLVSEL_MASK) >>
+ MC_AM_DL_INTLVSEL_SHIFT;
+ }
+
+ /*
+ * The Function 1 DRAM Hole Address Register tells us which node(s)
+ * own the DRAM space that is hoisted above 4GB, together with the
+ * hole base and offset for this node.
+ */
+ mcp->mcp_dramhole = pci_config_get32(cfghdl, MC_AM_REG_HOLEADDR);
+}
+
+/*
+ * Function 2 configuration - DRAM Controller
+ */
+static void
+mc_mkprops_dramctl(ddi_acc_handle_t cfghdl, mc_t *mc)
+{
+ uint32_t base[MC_CHIP_NCS], mask[MC_CHIP_NCS];
+ uint64_t dramcfg;
+ mc_props_t *mcp = &mc->mc_props;
+ int wide = 0; /* 128-bit access mode? */
+ int i;
+ mcamd_hdl_t hdl;
+
+ mcamd_mkhdl(&hdl); /* to call into common code */
+
+ /*
+ * Read Function 2 DRAM Configuration High and Low registers and
+ * weld them together into a 64-bit value. The High component
+ * is mostly concerned with memory clocks etc and we'll not have
+ * any use for that. The Low component tells us if ECC is enabled,
+ * if we're in 64- or 128-bit MC mode, how the upper chip-selects
+ * are mapped, which chip-select pairs are using x4 parts, etc.
+ */
+ dramcfg = pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGLO) |
+ ((uint64_t)pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGHI) << 32);
+ wide = dramcfg & MC_DC_DCFG_128;
+
+ mcp->mcp_dramcfg = dramcfg;
+ mcp->mcp_accwidth = wide ? 128 : 64;
+
+ /*
+ * Read Function 2 DRAM Bank Address Mapping. This tells us
+ * whether bank swizzle mode is enabled, and also encodes
+ * the type of DIMM module in use for each chip-select pair.
+ */
+ mcp->mcp_csbankmap = pci_config_get32(cfghdl, MC_DC_REG_BANKADDRMAP);
+
+ /*
+ * Read Function 2 Configuration Registers for DRAM CS Base 0 thru 7
+ * and DRAM CS Mask 0 thru 7. The Base registers give us the
+ * BaseAddrHi and BaseAddrLo from which the base can be constructed,
+ * and whether this chip-select bank is enabled (CSBE). The
+ * Mask registers give us AddrMaskHi and AddrMaskLo from which
+ * a full mask can be constructed.
+ */
+ mc_prop_read_pair(cfghdl, base, MC_DC_REG_CSBASE_0, mask,
+ MC_DC_REG_CSMASK_0, MC_CHIP_NCS, MC_DC_REG_CS_INCR);
+
+ /*
+ * Create a cs node for each enabled chip-select
+ */
+ for (i = 0; i < MC_CHIP_NCS; i++) {
+ mc_cs_t *mccs;
+ uint64_t csmask;
+ size_t sz;
+
+ if (!(base[i] & MC_DC_CSB_CSBE)) {
+ mcp->mcp_disabled_cs++;
+ continue;
+ }
+
+ if (mcamd_cs_size(&hdl, (mcamd_node_t *)mc, i, &sz) < 0)
+ continue;
+
+ csmask = MC_DC_CSM_CSMASK(mask[i]);
+ mccs = mc_cs_create(mc, i, MC_DC_CSB_CSBASE(base[i]), csmask,
+ sz);
+
+ if (mc->mc_cslist == NULL)
+ mc->mc_cslist = mccs;
+ else
+ mc->mc_cslast->mccs_next = mccs;
+ mc->mc_cslast = mccs;
+
+ /*
+ * Check for cs bank interleaving - some bits clear in the
+ * lower mask. All banks must/will have the same lomask bits
+ * if cs interleaving is active.
+ */
+ if (!mcp->mcp_csbank_intlv) {
+ int bitno, ibits = 0;
+ for (bitno = MC_DC_CSM_MASKLO_LOBIT;
+ bitno <= MC_DC_CSM_MASKLO_HIBIT; bitno++) {
+ if (!(csmask & (1 << bitno)))
+ ibits++;
+ }
+ if (ibits > 0)
+ mcp->mcp_csbank_intlv = 1 << ibits;
+ }
+ }
+
+ /*
+ * Now that we have discovered all active chip-selects we attempt
+ * to divine the associated DIMM configuration.
+ */
+ mc_dimmlist_create(mc);
+}
+
+typedef struct mc_bind_map {
+ const char *bm_bindnm; /* attachment binding name */
+ uint_t bm_func; /* PCI config space function number for bind */
+ const char *bm_model; /* value for device node model property */
+ void (*bm_mkprops)(ddi_acc_handle_t, mc_t *);
+} mc_bind_map_t;
+
+static const mc_bind_map_t mc_bind_map[] = {
+ { MC_FUNC_HTCONFIG_BINDNM, MC_FUNC_HTCONFIG,
+ "AMD Memory Controller (HT Configuration)", NULL },
+ { MC_FUNC_ADDRMAP_BINDNM, MC_FUNC_ADDRMAP,
+ "AMD Memory Controller (Address Map)", mc_mkprops_addrmap },
+ { MC_FUNC_DRAMCTL_BINDNM, MC_FUNC_DRAMCTL,
+ "AMD Memory Controller (DRAM Controller & HT Trace)",
+ mc_mkprops_dramctl },
+ NULL
+};
+
+/*ARGSUSED*/
+static int
+mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ rw_enter(&mc_lock, RW_READER);
+ if (mc_lookup_by_chipid(getminor(*devp)) == NULL) {
+ rw_exit(&mc_lock);
+ return (EINVAL);
+ }
+ rw_exit(&mc_lock);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+mc_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
+{
+ int rc = 0;
+ mc_t *mc;
+
+ if (cmd != MC_IOC_SNAPSHOT_INFO && cmd != MC_IOC_SNAPSHOT)
+ return (EINVAL);
+
+ rw_enter(&mc_lock, RW_READER);
+
+ if ((mc = mc_lookup_by_chipid(getminor(dev))) == NULL) {
+ rw_exit(&mc_lock);
+ return (EINVAL);
+ }
+
+ if (mc_snapshot_update(mc) < 0) {
+ rw_exit(&mc_lock);
+ return (EIO);
+ }
+
+ switch (cmd) {
+ case MC_IOC_SNAPSHOT_INFO: {
+ mc_snapshot_info_t mcs;
+
+ mcs.mcs_size = mc->mc_snapshotsz;
+ mcs.mcs_gen = mc->mc_snapshotgen;
+
+ if (ddi_copyout(&mcs, (void *)arg, sizeof (mc_snapshot_info_t),
+ mode) < 0)
+ rc = EFAULT;
+ break;
+ }
+
+ case MC_IOC_SNAPSHOT:
+ if (ddi_copyout(mc->mc_snapshot, (void *)arg, mc->mc_snapshotsz,
+ mode) < 0)
+ rc = EFAULT;
+ break;
+ }
+
+ rw_exit(&mc_lock);
+
+ return (rc);
+}
+
+static struct cb_ops mc_cb_ops = {
+ mc_open,
+ mc_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ nodev, /* no read routine */
+ nodev, /* no write routine */
+ mc_ioctl,
+ nodev, /* no devmap routine */
+ nodev, /* no mmap routine */
+ nodev, /* no segmap routine */
+ nochpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP, /* safe for multi-thread/multi-processor */
+};
+
+/*ARGSUSED*/
+static int
+mc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+ int rc = DDI_SUCCESS;
+ mc_t *mc;
+
+ if (infocmd != DDI_INFO_DEVT2DEVINFO &&
+ infocmd != DDI_INFO_DEVT2INSTANCE) {
+ *result = NULL;
+ return (DDI_FAILURE);
+ }
+
+ rw_enter(&mc_lock, RW_READER);
+
+ if ((mc = mc_lookup_by_chipid(getminor((dev_t)arg))) == NULL ||
+ mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi == NULL) {
+ rc = DDI_FAILURE;
+ } else if (infocmd == DDI_INFO_DEVT2DEVINFO) {
+ *result = mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi;
+ } else {
+ *result = (void *)(uintptr_t)
+ mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_instance;
+ }
+
+ rw_exit(&mc_lock);
+
+ return (rc);
+}
+
+/*ARGSUSED2*/
+static int
+mc_fm_handle(dev_info_t *dip, ddi_fm_error_t *fmerr, const void *arg)
+{
+ pci_ereport_post(dip, fmerr, NULL);
+ return (DDI_FM_NONFATAL);
+}
+
+static void
+mc_fm_init(dev_info_t *dip)
+{
+ int fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE;
+ ddi_fm_init(dip, &fmcap, NULL);
+ pci_ereport_setup(dip);
+ ddi_fm_handler_register(dip, mc_fm_handle, NULL);
+}
+
+static void
+mc_fm_fini(dev_info_t *dip)
+{
+ pci_ereport_teardown(dip);
+ ddi_fm_fini(dip);
+}
+
+static mc_t *
+mc_create(chipid_t chipid)
+{
+ chip_t *chp = chip_lookup(chipid);
+ const mc_rev_map_t *rmp = mc_revision(chp);
+ mc_t *mc;
+
+ ASSERT(RW_WRITE_HELD(&mc_lock));
+
+ if (chp == NULL || rmp->rm_rev == MC_REV_UNKNOWN)
+ return (NULL);
+
+ mc = kmem_zalloc(sizeof (mc_t), KM_SLEEP);
+ mc->mc_hdr.mch_type = MC_NT_MC;
+ mc->mc_chip = chp;
+ mc->mc_props.mcp_rev = rmp->rm_rev;
+ mc->mc_revname = rmp->rm_name;
+ mc->mc_props.mcp_num = mc->mc_chip->chip_id;
+
+ mc->mc_next = mc_list;
+ mc_list = mc;
+
+ return (mc);
+}
+
+static int
+mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ ddi_acc_handle_t hdl;
+ const mc_bind_map_t *bm;
+ const char *bindnm;
+ char *unitstr = NULL;
+ long unitaddr;
+ int chipid, func, rc;
+ cpu_t *cpu;
+ mc_t *mc;
+
+ if (cmd != DDI_ATTACH)
+ return (DDI_FAILURE);
+
+ bindnm = ddi_binding_name(dip);
+ for (bm = mc_bind_map; bm->bm_bindnm != NULL; bm++) {
+ if (strcmp(bindnm, bm->bm_bindnm) == 0) {
+ func = bm->bm_func;
+ break;
+ }
+ }
+
+ if (bm->bm_bindnm == NULL)
+ return (DDI_FAILURE);
+
+ /*
+ * We need the device number, which corresponds to the processor node
+ * number plus 24. The node number can then be used to associate this
+ * memory controller device with a given processor chip.
+ */
+ (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "unit-address", &unitstr);
+ rc = ddi_strtol(unitstr, NULL, 16, &unitaddr);
+ ASSERT(rc == 0 && unitaddr >= MC_AMD_DEV_OFFSET);
+ if (rc != 0 || unitaddr < MC_AMD_DEV_OFFSET) {
+ cmn_err(CE_WARN, "failed to parse unit address %s for %s\n",
+ unitstr, bindnm);
+ return (DDI_FAILURE);
+ }
+
+ chipid = unitaddr - MC_AMD_DEV_OFFSET;
+
+ rw_enter(&mc_lock, RW_WRITER);
+
+ for (mc = mc_list; mc != NULL; mc = mc->mc_next) {
+ if (mc->mc_chip->chip_id == chipid)
+ break;
+ }
+
+ /* Integrate this memory controller device into existing set */
+ if (mc == NULL) {
+ mc = mc_create(chipid);
+
+ if (mc == NULL) {
+ /*
+ * We don't complain here because this is a legitimate
+ * path for MP systems. On those machines, we'll attach
+ * before all CPUs have been initialized, and thus the
+ * chip verification in mc_create will fail. We'll be
+ * reattached later for those CPUs.
+ */
+ rw_exit(&mc_lock);
+ return (DDI_FAILURE);
+ }
+ } else {
+ mc_snapshot_destroy(mc);
+ }
+
+ /* Beyond this point, we're committed to creating this node */
+
+ mc_fm_init(dip);
+
+ ASSERT(mc->mc_funcs[func].mcf_devi == NULL);
+ mc->mc_funcs[func].mcf_devi = dip;
+ mc->mc_funcs[func].mcf_instance = ddi_get_instance(dip);
+
+ mc->mc_ref++;
+
+ rw_downgrade(&mc_lock);
+
+ /*
+ * Add the common properties to this node, and then add any properties
+ * that are specific to this node based upon its configuration space.
+ */
+ (void) ddi_prop_update_string(DDI_DEV_T_NONE,
+ dip, "model", (char *)bm->bm_model);
+
+ (void) ddi_prop_update_int(DDI_DEV_T_NONE,
+ dip, "chip-id", mc->mc_chip->chip_id);
+
+ if (bm->bm_mkprops != NULL &&
+ pci_config_setup(dip, &hdl) == DDI_SUCCESS) {
+ bm->bm_mkprops(hdl, mc);
+ pci_config_teardown(&hdl);
+ }
+
+ /*
+ * If this is the last node to be attached for this memory controller,
+ * so create the minor node and set up the properties.
+ */
+ if (func == MC_FUNC_DEVIMAP) {
+ mc_props_t *mcp = &mc->mc_props;
+
+ if (ddi_create_minor_node(dip, "mc-amd", S_IFCHR,
+ mc->mc_chip->chip_id, "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "failed to create minor node for chip "
+ "%u memory controller\n", mc->mc_chip->chip_id);
+ }
+
+ /*
+ * Register the memory controller for every CPU of this chip.
+ * Then attempt to enable h/w memory scrubbers for this node.
+ * If we are successful, disable the software memory scrubber.
+ */
+ mutex_enter(&cpu_lock);
+
+ cpu = mc->mc_chip->chip_cpus;
+ rc = cmi_scrubber_enable(cpu, mcp->mcp_base, mcp->mcp_ilen);
+
+ do {
+ mcamd_mc_register(cpu);
+ cpu = cpu->cpu_next_chip;
+ } while (cpu != mc->mc_chip->chip_cpus);
+
+ mutex_exit(&cpu_lock);
+
+ if (rc)
+ memscrub_disable();
+ }
+
+ nvlist_free(mc->mc_nvl);
+ mc->mc_nvl = mc_nvl_create(mc);
+
+ rw_exit(&mc_lock);
+ return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ return (DDI_FAILURE);
+}
+
+static struct dev_ops mc_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ mc_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ mc_attach, /* devo_attach */
+ mc_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &mc_cb_ops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "Memory Controller for AMD processors",
+ &mc_ops
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ rw_init(&mc_lock, NULL, RW_DRIVER, NULL);
+ return (mod_install(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int rc;
+
+ if ((rc = mod_remove(&modlinkage)) != 0)
+ return (rc);
+
+ rw_destroy(&mc_lock);
+ return (0);
+}
diff --git a/usr/src/uts/i86pc/io/mc/mcamd_off.in b/usr/src/uts/i86pc/io/mc/mcamd_off.in
new file mode 100644
index 0000000000..8e6a8dbc5e
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mcamd_off.in
@@ -0,0 +1,55 @@
+\
+\ CDDL HEADER START
+\
+\ The contents of this file are subject to the terms of the
+\ Common Development and Distribution License, Version 1.0 only
+\ (the "License"). You may not use this file except in compliance
+\ with the License.
+\
+\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+\ or http://www.opensolaris.org/os/licensing.
+\ See the License for the specific language governing permissions
+\ and limitations under the License.
+\
+\ When distributing Covered Code, include this CDDL HEADER in each
+\ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+\ If applicable, add the following below this CDDL HEADER, with the
+\ fields enclosed by brackets "[]" replaced with your own identifying
+\ information: Portions Copyright [yyyy] [name of copyright owner]
+\
+\ CDDL HEADER END
+\
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+\
+\ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+\ Use is subject to license terms.
+\
+
+#include <mcamd.h>
+
+mc_t
+ mc_props.mcp_num MCAMD_MC_OFF_NUM
+ mc_props.mcp_rev MCAMD_MC_OFF_REV
+ mc_props.mcp_base MCAMD_MC_OFF_BASE_ADDR
+ mc_props.mcp_lim MCAMD_MC_OFF_LIM_ADDR
+ mc_props.mcp_dramcfg MCAMD_MC_OFF_DRAMCFG
+ mc_props.mcp_dramhole MCAMD_MC_OFF_DRAMHOLE
+ mc_props.mcp_ilen MCAMD_MC_OFF_DRAM_ILEN
+ mc_props.mcp_ilsel MCAMD_MC_OFF_DRAM_ILSEL
+ mc_props.mcp_csbankmap MCAMD_MC_OFF_CSBANKMAP
+ mc_props.mcp_accwidth MCAMD_MC_OFF_ACCWIDTH
+ mc_props.mcp_csbank_intlv MCAMD_MC_OFF_CSBANK_INTLV
+ mc_props.mcp_disabled_cs MCAMD_MC_OFF_DISABLED_CS
+
+mc_cs_t
+ mccs_num MCAMD_CS_OFF_NUM
+ mccs_base MCAMD_CS_OFF_BASE_ADDR
+ mccs_mask MCAMD_CS_OFF_MASK
+ mccs_size MCAMD_CS_OFF_SIZE
+ mccs_dimmnums MCAMD_CS_OFF_DIMMNUMS
+
+mc_dimm_t
+ mcd_num MCAMD_DIMM_OFF_NUM
+
diff --git a/usr/src/uts/i86pc/io/mc/mcamd_subr.c b/usr/src/uts/i86pc/io/mc/mcamd_subr.c
new file mode 100644
index 0000000000..4537de771b
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mcamd_subr.c
@@ -0,0 +1,442 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Stub routines used to link in files from $SRC/common/mc
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/varargs.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/fm/protocol.h>
+#include <sys/mc.h>
+
+#include <mcamd.h>
+#include <mcamd_off.h>
+
+int mcamd_debug = 0; /* see mcamd_api.h for MCAMD_DBG_* values */
+
+struct mc_propmap {
+ uint_t mcpm_code;
+ uint_t mcpm_offset;
+};
+
+static uint_t
+nodetype(mcamd_node_t *node)
+{
+ mc_hdr_t *mch = (mc_hdr_t *)node;
+ return (mch->mch_type);
+}
+
+static void *
+node2type(mcamd_node_t *node, int type)
+{
+ mc_hdr_t *mch = (mc_hdr_t *)node;
+ ASSERT(mch->mch_type == type);
+ return (mch);
+}
+
+/*
+ * Iterate over all memory controllers.
+ */
+/*ARGSUSED*/
+mcamd_node_t *
+mcamd_mc_next(mcamd_hdl_t *hdl, mcamd_node_t *root, mcamd_node_t *last)
+{
+ mc_t *mc;
+
+ ASSERT(RW_LOCK_HELD(&mc_lock));
+
+ if (last == NULL)
+ return ((mcamd_node_t *)mc_list);
+
+ mc = node2type(last, MC_NT_MC);
+
+ return ((mcamd_node_t *)mc->mc_next);
+}
+
+/*
+ * Iterate over all chip-selects of a MC or all chip-selects of a DIMM
+ * depending on the node type of 'node'. In the DIMM case we do not
+ * have a linked list of associated chip-selects but an array of pointer
+ * to them.
+ */
+/*ARGSUSED*/
+mcamd_node_t *
+mcamd_cs_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last)
+{
+ uint_t nt = nodetype(node);
+ mc_t *mc;
+ mc_cs_t *mccs;
+ mc_dimm_t *mcd;
+ int i;
+ void *retval;
+
+ ASSERT(nt == MC_NT_MC || nt == MC_NT_DIMM);
+
+ if (last == NULL) {
+ switch (nt) {
+ case MC_NT_MC:
+ mc = node2type(node, MC_NT_MC);
+ retval = mc->mc_cslist;
+ break;
+ case MC_NT_DIMM:
+ mcd = node2type(node, MC_NT_DIMM);
+ retval = mcd->mcd_cs[0];
+ break;
+ }
+ } else {
+ mccs = node2type(last, MC_NT_CS);
+
+ switch (nt) {
+ case MC_NT_MC:
+ retval = mccs->mccs_next;
+ break;
+ case MC_NT_DIMM:
+ mcd = node2type(node, MC_NT_DIMM);
+ for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) {
+ if (mcd->mcd_cs[i] == mccs)
+ break;
+ }
+ if (i == MC_CHIP_DIMMRANKMAX)
+ cmn_err(CE_PANIC, "Bad last value for "
+ "mcamd_cs_next");
+
+ if (i == MC_CHIP_DIMMRANKMAX - 1)
+ retval = NULL;
+ else
+ retval = mcd->mcd_cs[i + 1];
+ break;
+ }
+ }
+
+ return ((mcamd_node_t *)retval);
+}
+
+/*
+ * Iterate over all DIMMs of an MC or all DIMMs of a chip-select depending
+ * on the node type of 'node'. In the chip-select case we don not have
+ * a linked list of associated DIMMs but an array of pointers to them.
+ */
+/*ARGSUSED*/
+mcamd_node_t *
+mcamd_dimm_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last)
+{
+ uint_t nt = nodetype(node);
+ mc_t *mc;
+ mc_cs_t *mccs;
+ mc_dimm_t *mcd;
+ int i;
+ void *retval;
+
+ ASSERT(nt == MC_NT_MC || nt == MC_NT_CS);
+
+ if (last == NULL) {
+ switch (nt) {
+ case MC_NT_MC:
+ mc = node2type(node, MC_NT_MC);
+ retval = mc->mc_props.mcp_dimmlist;
+ break;
+ case MC_NT_CS:
+ mccs = node2type(node, MC_NT_CS);
+ retval = mccs->mccs_dimm[0];
+ break;
+ }
+ } else {
+ mcd = node2type(last, MC_NT_DIMM);
+
+ switch (nt) {
+ case MC_NT_MC:
+ retval = mcd->mcd_next;
+ break;
+ case MC_NT_CS:
+ mccs = node2type(node, MC_NT_CS);
+ for (i = 0; i < MC_CHIP_DIMMPERCS; i++) {
+ if (mccs->mccs_dimm[i] == mcd)
+ break;
+ }
+ if (i == MC_CHIP_DIMMPERCS)
+ cmn_err(CE_PANIC, "Bad last value for "
+ "mcamd_dimm_next");
+
+ if (i == MC_CHIP_DIMMPERCS - 1)
+ retval = NULL;
+ else
+ retval = mccs->mccs_dimm[i + 1];
+ break;
+ }
+ }
+
+ return ((mcamd_node_t *)retval);
+}
+
+/*ARGSUSED*/
+mcamd_node_t *
+mcamd_cs_mc(mcamd_hdl_t *hdl, mcamd_node_t *csnode)
+{
+ mc_cs_t *mccs = node2type(csnode, MC_NT_CS);
+ return ((mcamd_node_t *)mccs->mccs_mc);
+}
+
+/*ARGSUSED*/
+mcamd_node_t *
+mcamd_dimm_mc(mcamd_hdl_t *hdl, mcamd_node_t *dnode)
+{
+ mc_dimm_t *mcd = node2type(dnode, MC_NT_DIMM);
+ return ((mcamd_node_t *)mcd->mcd_mc);
+}
+
+/*
+ * Node properties. A property is accessed through a property number code;
+ * we search these tables for a match (choosing table from node type) and
+ * return the uint64_t property at the indicated offset into the node
+ * structure. All properties must be of type uint64_t. It is assumed that
+ * property lookup does not have to be super-fast - we search linearly
+ * down the (small) lists.
+ */
+static const struct mc_propmap mcamd_mc_propmap[] = {
+ { MCAMD_PROP_NUM, MCAMD_MC_OFF_NUM },
+ { MCAMD_PROP_REV, MCAMD_MC_OFF_REV },
+ { MCAMD_PROP_BASE_ADDR, MCAMD_MC_OFF_BASE_ADDR },
+ { MCAMD_PROP_LIM_ADDR, MCAMD_MC_OFF_LIM_ADDR },
+ { MCAMD_PROP_DRAM_CONFIG, MCAMD_MC_OFF_DRAMCFG },
+ { MCAMD_PROP_DRAM_HOLE, MCAMD_MC_OFF_DRAMHOLE },
+ { MCAMD_PROP_DRAM_ILEN, MCAMD_MC_OFF_DRAM_ILEN },
+ { MCAMD_PROP_DRAM_ILSEL, MCAMD_MC_OFF_DRAM_ILSEL },
+ { MCAMD_PROP_CSBANKMAP, MCAMD_MC_OFF_CSBANKMAP },
+ { MCAMD_PROP_ACCESS_WIDTH, MCAMD_MC_OFF_ACCWIDTH },
+ { MCAMD_PROP_CSBANK_INTLV, MCAMD_MC_OFF_CSBANK_INTLV },
+ { MCAMD_PROP_DISABLED_CS, MCAMD_MC_OFF_DISABLED_CS }
+};
+
+static const struct mc_propmap mcamd_cs_propmap[] = {
+ { MCAMD_PROP_NUM, MCAMD_CS_OFF_NUM },
+ { MCAMD_PROP_BASE_ADDR, MCAMD_CS_OFF_BASE_ADDR },
+ { MCAMD_PROP_MASK, MCAMD_CS_OFF_MASK },
+ { MCAMD_PROP_SIZE, MCAMD_CS_OFF_SIZE },
+ { MCAMD_PROP_LODIMM, MCAMD_CS_OFF_DIMMNUMS },
+ { MCAMD_PROP_UPDIMM, MCAMD_CS_OFF_DIMMNUMS +
+ MCAMD_CS_OFF_DIMMNUMS_INCR }
+};
+
+static const struct mc_propmap mcamd_dimm_propmap[] = {
+ { MCAMD_PROP_NUM, MCAMD_DIMM_OFF_NUM },
+};
+
+/*ARGSUSED*/
+int
+mcamd_get_numprop(mcamd_hdl_t *hdl, mcamd_node_t *node, uint_t code,
+ uint64_t *valp)
+{
+ int i;
+ mc_hdr_t *mch = (mc_hdr_t *)node;
+ int nt = mch->mch_type;
+ int found = 0;
+ const struct mc_propmap *pmp;
+ struct mcamd_nt_props {
+ const struct mc_propmap *props;
+ int numprops;
+ } props[] = {
+ { mcamd_mc_propmap, /* MC_NT_MC */
+ sizeof (mcamd_mc_propmap) / sizeof (struct mc_propmap) },
+ { mcamd_cs_propmap, /* MC_NT_CS */
+ sizeof (mcamd_cs_propmap) / sizeof (struct mc_propmap) },
+ { mcamd_dimm_propmap, /* MC_NT_DIMM */
+ sizeof (mcamd_dimm_propmap) / sizeof (struct mc_propmap) },
+ };
+
+ if (mch->mch_type < MC_NT_NTYPES) {
+ for (i = 0, pmp = props[nt].props; i < props[nt].numprops;
+ i++, pmp++) {
+ if (pmp->mcpm_code == code) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ ASSERT(found);
+ if (found) {
+ *valp = *(uint64_t *)((uintptr_t)node + pmp->mcpm_offset);
+ }
+
+ return (found == 1);
+}
+
+int
+mcamd_errno(mcamd_hdl_t *mcamd)
+{
+ return (mcamd->mcamd_errno);
+}
+
+int
+mcamd_set_errno(mcamd_hdl_t *mcamd, int err)
+{
+ mcamd->mcamd_errno = err;
+ return (-1);
+}
+
+void
+mcamd_dprintf(mcamd_hdl_t *mcamd, int mask, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!(mcamd->mcamd_debug & mask))
+ return;
+
+ va_start(ap, fmt);
+ vcmn_err(mask & MCAMD_DBG_ERR ? CE_WARN : CE_NOTE, fmt, ap);
+ va_end(ap);
+}
+
+void
+mcamd_mkhdl(mcamd_hdl_t *hdl)
+{
+ hdl->mcamd_errno = 0;
+ hdl->mcamd_debug = mcamd_debug;
+}
+
+/*ARGSUSED*/
+static int
+mcamd_patounum_wrap(void *arg, uint64_t pa, uint32_t synd, int syndtype,
+ mc_unum_t *unump)
+{
+ mcamd_hdl_t mcamd;
+ int rc;
+
+ mcamd_mkhdl(&mcamd);
+
+ rw_enter(&mc_lock, RW_READER);
+
+ rc = mcamd_patounum(&mcamd,
+ (mcamd_node_t *)mc_list, pa, synd, syndtype, unump);
+
+#ifdef DEBUG
+ /*
+ * Apply the reverse operation to verify the result. If there is
+ * a problem complain but continue.
+ */
+ if (rc == 0 && MCAMD_RC_OFFSET_VALID(unump->unum_offset)) {
+ uint64_t rpa;
+ if (mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump,
+ &rpa) != 0 || rpa != pa) {
+ mcamd_dprintf(&mcamd, MCAMD_DBG_ERR,
+ "mcamd_patounum_wrap: offset calculation "
+ "verification for PA 0x%llx failed\n", pa);
+ }
+ }
+#endif
+ rw_exit(&mc_lock);
+
+ return (rc == 0);
+}
+
+static int
+fmri2unum(nvlist_t *nvl, mc_unum_t *unump)
+{
+ int i;
+ uint64_t offset;
+ nvlist_t *fu, **hcl;
+ uint_t npr;
+
+ if (nvlist_lookup_nvlist(nvl, FM_FMRI_MEM_UNUM "-fmri", &fu) != 0 ||
+ nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0||
+ nvlist_lookup_nvlist_array(fu, FM_FMRI_HC_LIST, &hcl, &npr) != 0)
+ return (0);
+
+
+ bzero(unump, sizeof (mc_unum_t));
+ for (i = 0; i < MC_UNUM_NDIMM; i++)
+ unump->unum_dimms[i] = -1;
+
+ for (i = 0; i < npr; i++) {
+ char *hcnm, *hcid;
+ long v;
+
+ if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &hcnm) != 0 ||
+ nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0 ||
+ ddi_strtol(hcid, NULL, 0, &v) != 0)
+ return (0);
+
+ if (strcmp(hcnm, "motherboard") == 0)
+ unump->unum_board = (int)v;
+ else if (strcmp(hcnm, "chip") == 0)
+ unump->unum_chip = (int)v;
+ else if (strcmp(hcnm, "memory-controller") == 0)
+ unump->unum_mc = (int)v;
+ else if (strcmp(hcnm, "chip-select") == 0)
+ unump->unum_cs = (int)v;
+ else if (strcmp(hcnm, "dimm") == 0)
+ unump->unum_dimms[0] = (int)v;
+ }
+
+ unump->unum_offset = offset;
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static int
+mcamd_unumtopa_wrap(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap)
+{
+ mcamd_hdl_t mcamd;
+ int rc;
+ mc_unum_t unum;
+
+ if (unump != NULL && nvl != NULL)
+ return (0);
+
+ if (unump == NULL) {
+ if (!fmri2unum(nvl, &unum))
+ return (0);
+ unump = &unum;
+ }
+
+ mcamd_mkhdl(&mcamd);
+
+ rw_enter(&mc_lock, RW_READER);
+ rc = mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, pap);
+ rw_exit(&mc_lock);
+
+ return (rc == 0);
+}
+
+static const cmi_mc_ops_t mcamd_mc_ops = {
+ mcamd_patounum_wrap,
+ mcamd_unumtopa_wrap
+};
+
+void
+mcamd_mc_register(cpu_t *cp)
+{
+ cmi_mc_register(cp, &mcamd_mc_ops, NULL);
+}
diff --git a/usr/src/uts/i86pc/io/rootnex.c b/usr/src/uts/i86pc/io/rootnex.c
index 69789f49a7..741b405669 100644
--- a/usr/src/uts/i86pc/io/rootnex.c
+++ b/usr/src/uts/i86pc/io/rootnex.c
@@ -63,7 +63,6 @@
#include <sys/rootnex.h>
#include <vm/hat_i86.h>
-
/*
* enable/disable extra checking of function parameters. Useful for debugging
* drivers.
@@ -82,6 +81,9 @@ int rootnex_unbind_verify_buffer = 0;
int rootnex_sync_check_parms = 0;
#endif
+/* Master Abort and Target Abort panic flag */
+int rootnex_fm_ma_ta_panic_flag = 0;
+
/* Semi-temporary patchables to phase in bug fixes, test drivers, etc. */
int rootnex_bind_fail = 1;
int rootnex_bind_warn = 1;
@@ -321,6 +323,8 @@ static int rootnex_maxxfer_window_boundary(ddi_dma_impl_t *hp,
static int rootnex_valid_sync_parms(ddi_dma_impl_t *hp, rootnex_window_t *win,
off_t offset, size_t size, uint_t cache_flags);
static int rootnex_verify_buffer(rootnex_dma_t *dma);
+static int rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr,
+ const void *no_used);
/*
@@ -365,6 +369,7 @@ _fini(void)
static int
rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ int fmcap;
int e;
@@ -385,12 +390,24 @@ rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
rootnex_state = kmem_zalloc(sizeof (rootnex_state_t), KM_SLEEP);
rootnex_state->r_dip = dip;
+ rootnex_state->r_err_ibc = (ddi_iblock_cookie_t)ipltospl(15);
rootnex_state->r_reserved_msg_printed = B_FALSE;
rootnex_cnt = &rootnex_state->r_counters[0];
mutex_init(&rootnex_state->r_peekpoke_mutex, NULL, MUTEX_SPIN,
(void *)ipltospl(15));
+ /*
+ * Set minimum fm capability level for i86pc platforms and then
+ * initialize error handling. Since we're the rootnex, we don't
+ * care what's returned in the fmcap field.
+ */
+ ddi_system_fmcap = DDI_FM_ERRCB_CAPABLE;
+ fmcap = ddi_system_fmcap;
+ ddi_fm_init(dip, &fmcap, &rootnex_state->r_err_ibc);
+ if (fmcap & DDI_FM_ERRCB_CAPABLE)
+ ddi_fm_handler_register(dip, rootnex_fm_callback, NULL);
+
/* initialize DMA related state */
e = rootnex_dma_init();
if (e != DDI_SUCCESS) {
@@ -4407,3 +4424,10 @@ rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
return (DDI_FAILURE);
#endif /* defined(__amd64) */
}
+
+/*ARGSUSED*/
+static int
+rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
+{
+ return (rootnex_fm_ma_ta_panic_flag ? DDI_FM_FATAL : DDI_FM_NONFATAL);
+}
diff --git a/usr/src/uts/i86pc/mc-amd/Makefile b/usr/src/uts/i86pc/mc-amd/Makefile
new file mode 100644
index 0000000000..d7c876fa41
--- /dev/null
+++ b/usr/src/uts/i86pc/mc-amd/Makefile
@@ -0,0 +1,97 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = mc-amd
+#
+OBJECTS = $(MCAMD_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(MCAMD_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE)
+SRCDIR = $(UTSBASE)/i86pc/io/mc
+CONF_SRCDIR = $(UTSBASE)/i86pc/io/mc
+
+MCAMD_OFF_H = $(OBJS_DIR)/mcamd_off.h
+MCAMD_OFF_SRC = $(SRCDIR)/mcamd_off.in
+
+#
+# Include common rules.
+#
+include ../cpu/Makefile.cpu
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(SRC_CONFFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# Overrides and additions
+#
+CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) -I$(SRC)/common/mc/mc-amd
+CLEANFILES += $(MCAMD_OFF_H)
+CLOBBERFILES += $(MCAMD_OFF_H)
+
+$(OBJECTS): $(MCAMD_OFF_H)
+
+#
+# Create mcamd_off.h
+#
+$(MCAMD_OFF_H): $(MCAMD_OFF_SRC)
+ $(OFFSETS_CREATE) <$(MCAMD_OFF_SRC) >$@
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include ../Makefile.targ
diff --git a/usr/src/uts/i86pc/os/cmi.c b/usr/src/uts/i86pc/os/cmi.c
new file mode 100644
index 0000000000..236b3c44a8
--- /dev/null
+++ b/usr/src/uts/i86pc/os/cmi.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Public interface to routines implemented by CPU modules
+ */
+
+#include <sys/x86_archext.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/fm/util.h>
+#include <sys/reboot.h>
+#include <sys/modctl.h>
+#include <sys/param.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#define CPUMOD_SUBDIR "cpu"
+#define CPUMOD_PREFIX "cpu"
+
+#define CMI_OPS(cpu) \
+ (cpu)->cpu_m.mcpu_cmi->cmi_ops
+#define CMI_DATA(cpu) \
+ (cpu)->cpu_m.mcpu_cmidata
+
+/*
+ * If cleared for debugging, we will suppress panicking on fatal hardware
+ * errors. This should *only* be used for debugging; it use can and will
+ * cause data corruption if actual hardware errors are detected by the system.
+ */
+int cmi_panic_on_uncorrectable_error = 1;
+
+static cmi_t *cmi_list;
+static kmutex_t cmi_load_lock;
+
+static int
+cmi_cpu_match(cpu_t *c1, cpu_t *c2)
+{
+ return (cpuid_getfamily(c1) == cpuid_getfamily(c2) &&
+ cpuid_getmodel(c1) == cpuid_getmodel(c2) &&
+ cpuid_getstep(c1) == cpuid_getstep(c2) &&
+ strcmp(cpuid_getvendorstr(c1), cpuid_getvendorstr(c2)) == 0);
+}
+
+static cmi_t *
+cmi_load_modctl(modctl_t *modp)
+{
+ uintptr_t ops;
+ cmi_t *cmi;
+
+ ASSERT(MUTEX_HELD(&cmi_load_lock));
+
+ for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
+ if (cmi->cmi_modp == modp)
+ return (cmi);
+ }
+
+ if ((ops = modlookup_by_modctl(modp, "_cmi_ops")) == NULL) {
+ cmn_err(CE_WARN, "CPU module %s is invalid: no _cmi_ops "
+ "found\n", modp->mod_modname);
+ return (NULL);
+ }
+
+ /*
+ * Hold the module in memory. We call to CPU modules without using the
+ * stubs mechanism, so these modules must be manually held in memory.
+ * The mod_ref acts as if another loaded module has a dependency on us.
+ */
+ mutex_enter(&mod_lock);
+ modp->mod_ref++;
+ mutex_exit(&mod_lock);
+
+ cmi = kmem_zalloc(sizeof (cmi_t), KM_SLEEP);
+ cmi->cmi_ops = (const cmi_ops_t *)ops;
+ cmi->cmi_modp = modp;
+
+ cmi->cmi_next = cmi_list;
+ cmi_list = cmi;
+
+ return (cmi);
+}
+
+static cmi_t *
+cmi_load_module(cpu_t *cp)
+{
+ modctl_t *modp;
+ cmi_t *cmi;
+ int i, modid;
+ uint_t s[3];
+
+ /*
+ * Look to see if we've already got a module loaded for a CPU just
+ * like this one. If we do, then we'll re-use it.
+ */
+ ASSERT(MUTEX_HELD(&cmi_load_lock));
+ mutex_enter(&cpu_lock);
+
+ for (i = 0; i < NCPU; i++) {
+ cpu_t *cp2 = cpu[i];
+
+ if (cp2 != NULL && cp2 != cp &&
+ cp2->cpu_m.mcpu_cmi != NULL && cmi_cpu_match(cp, cp2)) {
+ mutex_exit(&cpu_lock);
+ return (cp2->cpu_m.mcpu_cmi);
+ }
+ }
+
+ mutex_exit(&cpu_lock);
+
+ /*
+ * If we can't find a match, attempt to load the appropriate module.
+ * If that also fails, try to load the generic CPU module.
+ */
+ s[0] = cpuid_getfamily(cp);
+ s[1] = cpuid_getmodel(cp);
+ s[2] = cpuid_getstep(cp);
+
+ modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
+ cpuid_getvendorstr(cp), ".", s, sizeof (s) / sizeof (s[0]));
+
+ if (modid == -1)
+ modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic");
+
+ if (modid == -1)
+ return (NULL);
+
+ modp = mod_hold_by_id(modid);
+ cmi = cmi_load_modctl(modp);
+ mod_release_mod(modp);
+
+ return (cmi);
+}
+
+static cmi_t *
+cmi_load_generic(void)
+{
+ modctl_t *modp;
+ cmi_t *cmi;
+ int modid;
+
+ if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
+ return (NULL);
+
+ modp = mod_hold_by_id(modid);
+ cmi = cmi_load_modctl(modp);
+ mod_release_mod(modp);
+
+ return (cmi);
+}
+
+/*
+ * Load a CPU module for the specified CPU, and then call its cmi_init routine.
+ * If the module returns ENOTSUP, try using the generic CPU module instead.
+ * If all else fails, we return -1 and the caller will panic or halt.
+ */
+int
+cmi_load(cpu_t *cp)
+{
+ int err = ENOENT;
+ cmi_t *cmi;
+ void *data;
+
+ mutex_enter(&cmi_load_lock);
+
+ if ((cmi = cmi_load_module(cp)) == NULL || (
+ (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0 && err != ENOTSUP)) {
+ cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d",
+ cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err);
+ mutex_exit(&cmi_load_lock);
+ return (-1);
+ }
+
+ if (err != 0 && ((cmi = cmi_load_generic()) == NULL ||
+ (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0)) {
+ cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d",
+ cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err);
+ mutex_exit(&cmi_load_lock);
+ return (-1);
+ }
+
+ ASSERT(cp->cpu_m.mcpu_cmi == NULL);
+ cp->cpu_m.mcpu_cmi = cmi;
+ cp->cpu_m.mcpu_cmidata = data;
+
+ cmi->cmi_refcnt++;
+ mutex_exit(&cmi_load_lock);
+
+ if (boothowto & RB_VERBOSE) {
+ printf("cpuid %d: initialized cpumod: %s\n",
+ cp->cpu_id, cmi->cmi_modp->mod_modname);
+ }
+
+ return (0);
+}
+
+void
+cmi_init(void)
+{
+ if (cmi_load(CPU) < 0)
+ panic("failed to load module for CPU %u", CPU->cpu_id);
+}
+
+void
+cmi_post_init(void)
+{
+ CMI_OPS(CPU)->cmi_post_init(CMI_DATA(CPU));
+}
+
+void
+cmi_faulted_enter(cpu_t *cp)
+{
+ CMI_OPS(cp)->cmi_faulted_enter(CMI_DATA(cp));
+}
+
+void
+cmi_faulted_exit(cpu_t *cp)
+{
+ CMI_OPS(cp)->cmi_faulted_exit(CMI_DATA(cp));
+}
+
+int
+cmi_scrubber_enable(cpu_t *cp, uint64_t base, uint64_t ilen)
+{
+ return (CMI_OPS(cp)->cmi_scrubber_enable(CMI_DATA(cp), base, ilen));
+}
+
+void
+cmi_mca_init(void)
+{
+ CMI_OPS(CPU)->cmi_mca_init(CMI_DATA(CPU));
+}
+
+void
+cmi_mca_trap(struct regs *rp)
+{
+ if (CMI_OPS(CPU)->cmi_mca_trap(CMI_DATA(CPU), rp)) {
+ if (cmi_panic_on_uncorrectable_error)
+ fm_panic("Unrecoverable Machine-Check Exception");
+ else
+ cmn_err(CE_WARN, "suppressing panic from fatal #mc");
+ }
+}
+
+int
+cmi_mca_inject(cmi_mca_regs_t *regs, uint_t nregs)
+{
+ int err;
+
+ kpreempt_disable();
+ err = CMI_OPS(CPU)->cmi_mca_inject(CMI_DATA(CPU), regs, nregs);
+ kpreempt_enable();
+
+ return (err);
+}
+
+void
+cmi_mca_poke(void)
+{
+ CMI_OPS(CPU)->cmi_mca_poke(CMI_DATA(CPU));
+}
+
+void
+cmi_mc_register(cpu_t *cp, const cmi_mc_ops_t *mcops, void *mcdata)
+{
+ CMI_OPS(cp)->cmi_mc_register(CMI_DATA(cp), mcops, mcdata);
+}
+
+int
+cmi_mc_patounum(uint64_t pa, uint32_t synd, int syndtype, mc_unum_t *up)
+{
+ const struct cmi_mc_ops *mcops;
+ cpu_t *cp = CPU;
+
+ if (CMI_OPS(cp) == NULL ||
+ (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL)
+ return (-1); /* not registered yet */
+
+ return (mcops->cmi_mc_patounum(CMI_DATA(cp), pa, synd, syndtype, up));
+}
+
+int
+cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
+{
+ const struct cmi_mc_ops *mcops;
+ cpu_t *cp = CPU;
+
+ if (up != NULL && nvl != NULL)
+ return (-1); /* only convert from one or the other form */
+
+ if (CMI_OPS(cp) == NULL ||
+ (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL)
+ return (-1); /* not registered yet */
+
+ return (mcops->cmi_mc_unumtopa(CMI_DATA(cp), up, nvl, pap));
+}
diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c
index a16c5a6298..739700125a 100644
--- a/usr/src/uts/i86pc/os/cpuid.c
+++ b/usr/src/uts/i86pc/os/cpuid.c
@@ -2628,9 +2628,12 @@ add_cpunode2devtree(processorid_t cpu_id, struct cpuid_info *cpi)
"chunks", CPI_CHUNKS(cpi));
(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
"apic-id", CPI_APIC_ID(cpi));
- if (cpi->cpi_chipid >= 0)
+ if (cpi->cpi_chipid >= 0) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
"chip#", cpi->cpi_chipid);
+ (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
+ "clog#", cpi->cpi_clogid);
+ }
}
/* cpuid-features */
diff --git a/usr/src/uts/i86pc/os/memscrub.c b/usr/src/uts/i86pc/os/memscrub.c
index 6dd21e302f..2e73a2a694 100644
--- a/usr/src/uts/i86pc/os/memscrub.c
+++ b/usr/src/uts/i86pc/os/memscrub.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -129,6 +130,7 @@ static void *memscrub_pte;
* we can patch these defaults in /etc/system if necessary
*/
uint_t disable_memscrub = 0;
+static uint_t disable_memscrub_quietly = 0;
pgcnt_t memscrub_min_pages = MEMSCRUB_MIN_PAGES;
pgcnt_t memscrub_span_pages = MEMSCRUB_DFL_SPAN_PAGES;
time_t memscrub_period_sec = MEMSCRUB_DFL_PERIOD_SEC;
@@ -150,6 +152,7 @@ static uint_t memscrub_phys_pages;
static kcondvar_t memscrub_cv;
static kmutex_t memscrub_lock;
+
/*
* memscrub_lock protects memscrub_memlist
*/
@@ -199,6 +202,16 @@ memscrub_init()
TS_RUN, memscrub_thread_pri);
}
+/*
+ * Function to cause the software memscrubber to exit quietly if the
+ * platform support has located a hardware scrubber and enabled it.
+ */
+void
+memscrub_disable(void)
+{
+ disable_memscrub_quietly = 1;
+}
+
#ifdef MEMSCRUB_DEBUG
void
memscrub_printmemlist(char *title, struct memlist *listp)
@@ -267,7 +280,7 @@ memscrubber()
deadline = gethrestime_sec() + memscrub_delay_start_sec;
for (;;) {
- if (disable_memscrub)
+ if (disable_memscrub || disable_memscrub_quietly)
break;
mutex_enter(&memscrub_lock);
@@ -317,7 +330,7 @@ memscrubber()
pgcnt_t pages = memscrub_span_pages;
uint64_t address = mlp_next_addr;
- if (disable_memscrub)
+ if (disable_memscrub || disable_memscrub_quietly)
break;
mutex_enter(&memscrub_lock);
@@ -379,7 +392,8 @@ memscrubber()
memscrub_exit:
- cmn_err(CE_NOTE, "memory scrubber exiting.");
+ if (!disable_memscrub_quietly)
+ cmn_err(CE_NOTE, "memory scrubber exiting.");
cv_destroy(&memscrub_cv);
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index f98a787266..a0809d99fe 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -64,6 +64,7 @@
#include <vm/hat_i86.h>
#include <sys/memnode.h>
#include <sys/pci_cfgspace.h>
+#include <sys/cpu_module.h>
struct cpu cpus[1]; /* CPU data */
struct cpu *cpu[NCPU] = {&cpus[0]}; /* pointers to all CPUs */
@@ -1024,11 +1025,6 @@ mp_startup(void)
*/
if (x86_feature & X86_MTRR)
mtrr_sync();
- /*
- * Enable machine check architecture
- */
- if (x86_feature & X86_MCA)
- setup_mca();
/*
* Initialize this CPU's syscall handlers
@@ -1102,6 +1098,18 @@ mp_startup(void)
(void) spl0(); /* enable interrupts */
+ /*
+ * Set up the CPU module for this CPU. This can't be done before
+ * this CPU is made CPU_READY, because we may (in heterogeneous systems)
+ * need to go load another CPU module. The act of attempting to load
+ * a module may trigger a cross-call, which will ASSERT unless this
+ * cpu is CPU_READY.
+ */
+ cmi_init();
+
+ if (x86_feature & X86_MCA)
+ cmi_mca_init();
+
if (boothowto & RB_DEBUG)
kdi_dvec_cpu_init(cp);
@@ -1238,15 +1246,17 @@ mp_unmap_warm_reset_vector(ushort_t *warm_reset_vector)
psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *));
}
-/*ARGSUSED*/
void
mp_cpu_faulted_enter(struct cpu *cp)
-{}
+{
+ cmi_faulted_enter(cp);
+}
-/*ARGSUSED*/
void
mp_cpu_faulted_exit(struct cpu *cp)
-{}
+{
+ cmi_faulted_exit(cp);
+}
/*
* The following two routines are used as context operators on threads belonging
diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c
index 091fb331e3..1766aa0d81 100644
--- a/usr/src/uts/i86pc/os/startup.c
+++ b/usr/src/uts/i86pc/os/startup.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -123,6 +123,7 @@
#include <sys/cpc_impl.h>
#include <sys/chip.h>
#include <sys/x86_archext.h>
+#include <sys/cpu_module.h>
#include <sys/smbios.h>
extern void progressbar_init(void);
@@ -1289,11 +1290,6 @@ startup_modules(void)
mod_setup();
/*
- * Setup machine check architecture on P6
- */
- setup_mca();
-
- /*
* Initialize system parameters.
*/
param_init();
@@ -1337,6 +1333,19 @@ startup_modules(void)
* then invoke bus specific code to probe devices.
*/
setup_ddi();
+
+ /*
+ * Set up the CPU module subsystem. Modifies the device tree, so it
+ * must be done after setup_ddi().
+ */
+ cmi_init();
+
+ /*
+ * Initialize the MCA handlers
+ */
+ if (x86_feature & X86_MCA)
+ cmi_mca_init();
+
/*
* Fake a prom tree such that /dev/openprom continues to work
*/
@@ -1879,6 +1888,11 @@ post_startup(void)
memscrub_init();
/*
+ * Complete CPU module initialization
+ */
+ cmi_post_init();
+
+ /*
* Perform forceloading tasks for /etc/system.
*/
(void) mod_sysctl(SYS_FORCELOAD, NULL);
@@ -2379,86 +2393,6 @@ uint64_t mtrrdef, pat_attr_reg;
*/
int enable_relaxed_mtrr = 0;
-/*
- * These must serve for Pentium, Pentium Pro (P6/Pentium II/Pentium III)
- * and Pentium 4, and yes, they are named 0, 1, 2, 4, 3 in ascending
- * address order (starting from 0x400). The Pentium 4 only implements
- * 4 sets, and while they are named 0-3 in the doc, the corresponding
- * names for P6 are 0,1,2,4. So define these arrays in address order
- * so that they work for both pre-Pentium4 and Pentium 4 processors.
- */
-
-static uint_t mci_ctl[] = {REG_MC0_CTL, REG_MC1_CTL, REG_MC2_CTL,
- REG_MC4_CTL, REG_MC3_CTL};
-static uint_t mci_status[] = {REG_MC0_STATUS, REG_MC1_STATUS, REG_MC2_STATUS,
- REG_MC4_STATUS, REG_MC3_STATUS};
-static uint_t mci_addr[] = {REG_MC0_ADDR, REG_MC1_ADDR, REG_MC2_ADDR,
- REG_MC4_ADDR, REG_MC3_ADDR};
-static int mca_cnt;
-
-
-void
-setup_mca()
-{
- int i;
- uint64_t mca_cap;
-
- if (!(x86_feature & X86_MCA))
- return;
- mca_cap = rdmsr(REG_MCG_CAP);
- if (mca_cap & MCG_CAP_CTL_P)
- wrmsr(REG_MCG_CTL, -1ULL); /* all ones */
- mca_cnt = mca_cap & MCG_CAP_COUNT_MASK;
- if (mca_cnt > P6_MCG_CAP_COUNT)
- mca_cnt = P6_MCG_CAP_COUNT;
- for (i = 1; i < mca_cnt; i++)
- wrmsr(mci_ctl[i], -1ULL); /* all ones */
- for (i = 0; i < mca_cnt; i++)
- wrmsr(mci_status[i], 0ULL);
- setcr4(getcr4() | CR4_MCE);
-
-}
-
-int
-mca_exception(struct regs *rp)
-{
- uint64_t status, addr;
- int i, ret = 1, errcode, mserrcode;
-
- status = rdmsr(REG_MCG_STATUS);
- if (status & MCG_STATUS_RIPV)
- ret = 0;
- if (status & MCG_STATUS_EIPV)
- cmn_err(CE_WARN, "MCE at 0x%lx", rp->r_pc);
- wrmsr(REG_MCG_STATUS, 0ULL);
- for (i = 0; i < mca_cnt; i++) {
- status = rdmsr(mci_status[i]);
- /*
- * If status register not valid skip this bank
- */
- if (!(status & MCI_STATUS_VAL))
- continue;
- errcode = status & MCI_STATUS_ERRCODE;
- mserrcode = (status >> MSERRCODE_SHFT) & MCI_STATUS_ERRCODE;
- if (status & MCI_STATUS_ADDRV) {
- /*
- * If mci_addr contains the address where
- * error occurred, display the address
- */
- addr = rdmsr(mci_addr[i]);
- cmn_err(CE_WARN, "MCE: Bank %d: error code 0x%x:"\
- "addr = 0x%" PRIx64 ", model errcode = 0x%x", i,
- errcode, addr, mserrcode);
- } else {
- cmn_err(CE_WARN,
- "MCE: Bank %d: error code 0x%x, mserrcode = 0x%x",
- i, errcode, mserrcode);
- }
- wrmsr(mci_status[i], 0ULL);
- }
- return (ret);
-}
-
void
setup_mtrr()
{
diff --git a/usr/src/uts/i86pc/os/trap.c b/usr/src/uts/i86pc/os/trap.c
index da416edeea..37a38b9a80 100644
--- a/usr/src/uts/i86pc/os/trap.c
+++ b/usr/src/uts/i86pc/os/trap.c
@@ -497,15 +497,6 @@ trap(struct regs *rp, caddr_t addr, processorid_t cpuid)
}
switch (type) {
-
- case T_MCE: /* Machine check exception */
- case T_MCE + USER:
- if (x86_feature & X86_MCA) {
- if (mca_exception(rp))
- (void) die(type, rp, addr, cpuid);
- type &= ~USER;
- goto cleanup;
- }
default:
if (type & USER) {
if (tudebug)
diff --git a/usr/src/uts/i86pc/sys/cpu_module.h b/usr/src/uts/i86pc/sys/cpu_module.h
new file mode 100644
index 0000000000..8bd9c488a7
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/cpu_module.h
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_CPU_MODULE_H
+#define _SYS_CPU_MODULE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/cpuvar.h>
+#include <sys/nvpair.h>
+#include <sys/mc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct regs;
+struct cmi_mc_ops;
+
+typedef struct cmi_mca_regs {
+ uint_t cmr_msrnum;
+ uint64_t cmr_msrval;
+} cmi_mca_regs_t;
+
+extern void cmi_init(void);
+extern void cmi_post_init(void);
+
+extern void cmi_faulted_enter(struct cpu *);
+extern void cmi_faulted_exit(struct cpu *);
+extern int cmi_scrubber_enable(struct cpu *, uint64_t, uint64_t);
+
+extern void cmi_mca_init(void);
+extern int cmi_mca_inject(cmi_mca_regs_t *, uint_t);
+extern void cmi_mca_poke(void);
+
+extern void cmi_mc_register(struct cpu *, const struct cmi_mc_ops *, void *);
+extern int cmi_mc_patounum(uint64_t, uint32_t, int, mc_unum_t *);
+extern int cmi_mc_unumtopa(mc_unum_t *, nvlist_t *, uint64_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CPU_MODULE_H */
diff --git a/usr/src/uts/i86pc/sys/cpu_module_impl.h b/usr/src/uts/i86pc/sys/cpu_module_impl.h
new file mode 100644
index 0000000000..7bdd6de7ce
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/cpu_module_impl.h
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_CPU_MODULE_IMPL_H
+#define _SYS_CPU_MODULE_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/cpu_module.h>
+#include <sys/cpuvar.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct cmi_mc_ops {
+ int (*cmi_mc_patounum)(void *, uint64_t, uint32_t, int, mc_unum_t *);
+ int (*cmi_mc_unumtopa)(void *, mc_unum_t *, nvlist_t *, uint64_t *);
+} cmi_mc_ops_t;
+
+typedef struct cmi_ops {
+ int (*cmi_init)(cpu_t *, void **);
+ void (*cmi_post_init)(void *);
+ void (*cmi_fini)(void *);
+ void (*cmi_faulted_enter)(void *);
+ void (*cmi_faulted_exit)(void *);
+ int (*cmi_scrubber_enable)(void *, uint64_t, uint64_t);
+ void (*cmi_mca_init)(void *);
+ int (*cmi_mca_trap)(void *, struct regs *);
+ int (*cmi_mca_inject)(void *, cmi_mca_regs_t *, uint_t);
+ void (*cmi_mca_poke)(void *);
+ void (*cmi_mc_register)(void *, const cmi_mc_ops_t *, void *);
+ const struct cmi_mc_ops *(*cmi_mc_getops)(void *);
+} cmi_ops_t;
+
+typedef struct cmi {
+ struct cmi *cmi_next;
+ const cmi_ops_t *cmi_ops;
+ struct modctl *cmi_modp;
+ uint_t cmi_refcnt;
+} cmi_t;
+
+extern int cmi_panic_on_uncorrectable_error;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CPU_MODULE_IMPL_H */
diff --git a/usr/src/uts/i86pc/sys/machcpuvar.h b/usr/src/uts/i86pc/sys/machcpuvar.h
index 9e355d4b49..f339b97951 100644
--- a/usr/src/uts/i86pc/sys/machcpuvar.h
+++ b/usr/src/uts/i86pc/sys/machcpuvar.h
@@ -52,7 +52,8 @@ extern "C" {
*/
typedef void *cpu_pri_lev_t;
-struct cpuid_info; /* (deliberately not visible here) */
+struct cpuid_info;
+struct cmi;
struct machcpu {
/* define all the x_call stuff */
@@ -91,6 +92,8 @@ struct machcpu {
uint64_t pil_high_start[HIGH_LEVELS];
uint64_t intrstat[PIL_MAX + 1][2];
struct cpuid_info *mcpu_cpi;
+ struct cmi *mcpu_cmi; /* CPU module state */
+ void *mcpu_cmidata;
#if defined(__amd64)
greg_t mcpu_rtmp_rsp; /* syscall: temporary %rsp stash */
greg_t mcpu_rtmp_r15; /* syscall: temporary %r15 stash */
diff --git a/usr/src/uts/i86pc/sys/machsystm.h b/usr/src/uts/i86pc/sys/machsystm.h
index 0732c4fde2..8dc5c5414b 100644
--- a/usr/src/uts/i86pc/sys/machsystm.h
+++ b/usr/src/uts/i86pc/sys/machsystm.h
@@ -86,7 +86,9 @@ extern void get_system_configuration(void);
extern void mmu_init(void);
extern int cpuid2nodeid(int);
extern void map_kaddr(caddr_t, pfn_t, int, int);
+
extern void memscrub_init(void);
+extern void memscrub_disable(void);
extern unsigned int microdata;
extern int use_mp;
diff --git a/usr/src/uts/i86pc/sys/rootnex.h b/usr/src/uts/i86pc/sys/rootnex.h
index 4236730776..96600248eb 100644
--- a/usr/src/uts/i86pc/sys/rootnex.h
+++ b/usr/src/uts/i86pc/sys/rootnex.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -325,14 +325,15 @@ typedef enum {
* r_counters - profile/performance counters
*/
typedef struct rootnex_state_s {
- uint_t r_prealloc_cookies;
- uint_t r_prealloc_size;
- kmem_cache_t *r_dmahdl_cache;
- uintptr_t r_dvma_call_list_id;
- kmutex_t r_peekpoke_mutex;
- dev_info_t *r_dip;
- boolean_t r_reserved_msg_printed;
- uint64_t r_counters[ROOTNEX_CNT_LAST];
+ uint_t r_prealloc_cookies;
+ uint_t r_prealloc_size;
+ kmem_cache_t *r_dmahdl_cache;
+ uintptr_t r_dvma_call_list_id;
+ kmutex_t r_peekpoke_mutex;
+ dev_info_t *r_dip;
+ ddi_iblock_cookie_t r_err_ibc;
+ boolean_t r_reserved_msg_printed;
+ uint64_t r_counters[ROOTNEX_CNT_LAST];
} rootnex_state_t;
diff --git a/usr/src/uts/i86pc/vm/hat_kdi.c b/usr/src/uts/i86pc/vm/hat_kdi.c
index 61d26bb28f..acdc2ddbb9 100644
--- a/usr/src/uts/i86pc/vm/hat_kdi.c
+++ b/usr/src/uts/i86pc/vm/hat_kdi.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,6 +33,7 @@
* operations may be performed.
*/
+#include <sys/cpuvar.h>
#include <sys/kdi_impl.h>
#include <sys/errno.h>
#include <sys/systm.h>
diff --git a/usr/src/uts/intel/ia32/ml/exception.s b/usr/src/uts/intel/ia32/ml/exception.s
index fce42f797b..5886ab532c 100644
--- a/usr/src/uts/intel/ia32/ml/exception.s
+++ b/usr/src/uts/intel/ia32/ml/exception.s
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -943,14 +943,47 @@ check_for_user_address:
/*
* #MC
*/
+ .globl cmi_mca_trap /* see uts/i86pc/os/cmi.c */
+
+#if defined(__amd64)
+
ENTRY_NP(mcetrap)
TRAP_NOERR(T_MCE) /* $18 */
-#if defined(__amd64)
SET_CPU_GSBASE
-#endif
- jmp cmninttrap
+ INTR_PUSH
+
+ TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP)
+ TRACE_REGS(%rdi, %rsp, %rbx, %rcx)
+ TRACE_STAMP(%rdi)
+
+ DISABLE_INTR_FLAGS
+ movq %rsp, %rbp
+
+ movq %rsp, %rdi /* arg0 = struct regs *rp */
+ call cmi_mca_trap /* cmi_mca_trap(rp); */
+
+ jmp _sys_rtt
SET_SIZE(mcetrap)
+#else
+
+ ENTRY_NP(mcetrap)
+ TRAP_NOERR(T_MCE) /* $18 */
+ INTR_PUSH
+
+ DISABLE_INTR_FLAGS
+ movl %esp, %ebp
+
+ movl %esp, %ecx
+ pushl %ecx /* arg0 = struct regs *rp */
+ call cmi_mca_trap /* cmi_mca_trap(rp) */
+ addl $4, %esp /* pop arg0 */
+
+ jmp _sys_rtt
+ SET_SIZE(mcetrap)
+
+#endif
+
/*
* #XF
*/
diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s
index 4c75164e50..5a164b1088 100644
--- a/usr/src/uts/intel/ia32/ml/i86_subr.s
+++ b/usr/src/uts/intel/ia32/ml/i86_subr.s
@@ -1999,23 +1999,43 @@ repoutsd(int port, uint32_t *addr, int count)
#endif /* __lint */
/*
+ * void int3(void)
+ * void int18(void)
* void int20(void)
*/
#if defined(__lint)
void
+int3(void)
+{}
+
+void
+int18(void)
+{}
+
+void
int20(void)
{}
#else /* __lint */
+ ENTRY(int3)
+ int $T_BPTFLT
+ ret
+ SET_SIZE(int3)
+
+ ENTRY(int18)
+ int $T_MCE
+ ret
+ SET_SIZE(int18)
+
ENTRY(int20)
movl boothowto, %eax
andl $RB_DEBUG, %eax
jz 1f
- int $20
+ int $T_DBGENTR
1:
rep; ret /* use 2 byte return instruction when branch target */
/* AMD Software Optimization Guide - Section 6.2 */
diff --git a/usr/src/uts/intel/ia32/sys/trap.h b/usr/src/uts/intel/ia32/sys/trap.h
index 44a22bcd51..9eafa6b197 100644
--- a/usr/src/uts/intel/ia32/sys/trap.h
+++ b/usr/src/uts/intel/ia32/sys/trap.h
@@ -24,7 +24,7 @@
/* All Rights Reserved */
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,7 +58,7 @@ extern "C" {
#define T_PGFLT 0xe /* #pf page fault */
#define T_EXTERRFLT 0x10 /* #mf x87 FPU error fault */
#define T_ALIGNMENT 0x11 /* #ac alignment check error */
-#define T_MCE 0x12 /* #mc machine check exception (P6 only) */
+#define T_MCE 0x12 /* #mc machine check exception */
#define T_SIMDFPE 0x13 /* #xm SSE/SSE exception */
#define T_DBGENTR 0x14 /* debugger entry */
#define T_ENDPERR 0x21 /* emulated extension error flt */
diff --git a/usr/src/uts/intel/mm/Makefile b/usr/src/uts/intel/mm/Makefile
index 729ed50b4d..8efea6da29 100644
--- a/usr/src/uts/intel/mm/Makefile
+++ b/usr/src/uts/intel/mm/Makefile
@@ -22,7 +22,7 @@
#
# uts/intel/mm/Makefile
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -51,6 +51,8 @@ CONF_SRCDIR = $(UTSBASE)/common/io
#
include $(UTSBASE)/intel/Makefile.intel
+CPPFLAGS += -I$(UTSBASE)/i86pc
+
#
# Define targets
#
diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases
index d5b27e5095..0e95977131 100644
--- a/usr/src/uts/intel/os/driver_aliases
+++ b/usr/src/uts/intel/os/driver_aliases
@@ -26,3 +26,5 @@ mpt "pci1000,50"
mpt "pci1000,56"
mpt "pci1000,58"
ibd "ib.ipib"
+mc-amd "pci1022,1101"
+mc-amd "pci1022,1102"
diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major
index 72b3a3ab6f..6ee2d75b26 100644
--- a/usr/src/uts/intel/os/name_to_major
+++ b/usr/src/uts/intel/os/name_to_major
@@ -119,4 +119,5 @@ zfs 182
npe 183
pcie_pci 184
kssl 185
+mc-amd 186
did 239
diff --git a/usr/src/uts/intel/sys/Makefile b/usr/src/uts/intel/sys/Makefile
index 31cb0ddb03..de2867be84 100644
--- a/usr/src/uts/intel/sys/Makefile
+++ b/usr/src/uts/intel/sys/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -55,6 +55,11 @@ HDRS = \
machlock.h \
machsig.h \
machtypes.h \
+ mc.h \
+ mc_amd.h \
+ mca_amd.h \
+ mca_x86.h \
+ memtest.h \
mii.h \
miipriv.h \
mmu.h \
diff --git a/usr/src/uts/intel/sys/archsystm.h b/usr/src/uts/intel/sys/archsystm.h
index 76c33e8c05..5ed70f0cb2 100644
--- a/usr/src/uts/intel/sys/archsystm.h
+++ b/usr/src/uts/intel/sys/archsystm.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,6 +60,8 @@ extern void tenmicrosec(void);
extern void restore_int_flag(int);
extern int clear_int_flag(void);
+extern void int3(void);
+extern void int18(void);
extern void int20(void);
#if defined(__amd64)
diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h
index b0001c62be..5863b0c201 100644
--- a/usr/src/uts/intel/sys/controlregs.h
+++ b/usr/src/uts/intel/sys/controlregs.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -145,7 +145,8 @@ extern "C" {
#define MSR_AMD_HWCR 0xc0010015
-#define AMD_HWCR_FFDIS 0x40 /* set to disable TLB Flush Filter */
+#define AMD_HWCR_FFDIS 0x00040 /* disable TLB Flush Filter */
+#define AMD_HWCR_MCI_STATUS_WREN 0x40000 /* enable write of MCi_STATUS */
/* AMD's NorthBridge Config MSR, SHOULD ONLY BE WRITTEN TO BY BIOS */
diff --git a/usr/src/uts/intel/sys/fm/cpu/AMD.h b/usr/src/uts/intel/sys/fm/cpu/AMD.h
new file mode 100644
index 0000000000..bb7aa427e5
--- /dev/null
+++ b/usr/src/uts/intel/sys/fm/cpu/AMD.h
@@ -0,0 +1,223 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_FM_CPU_AMD_H
+#define _SYS_FM_CPU_AMD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ereport class subcategory for AMD processors */
+#define FM_EREPORT_CPU_AMD "amd"
+
+/*
+ * Ereport payload definitions
+ */
+#define FM_EREPORT_PAYLOAD_NAME_BANK_STAT "bank-status"
+#define FM_EREPORT_PAYLOAD_NAME_BANK_NUM "bank-number"
+#define FM_EREPORT_PAYLOAD_NAME_ADDR "addr"
+#define FM_EREPORT_PAYLOAD_NAME_ADDR_VALID "addr-valid"
+#define FM_EREPORT_PAYLOAD_NAME_SYND "syndrome"
+#define FM_EREPORT_PAYLOAD_NAME_SYND_TYPE "syndrome-type"
+#define FM_EREPORT_PAYLOAD_NAME_IP "ip"
+#define FM_EREPORT_PAYLOAD_NAME_PRIV "privileged"
+#define FM_EREPORT_PAYLOAD_NAME_RESOURCE "resource"
+
+#define FM_EREPORT_PAYLOAD_FLAG_BANK_STAT 0x0000000000000001
+#define FM_EREPORT_PAYLOAD_FLAG_BANK_NUM 0x0000000000000002
+#define FM_EREPORT_PAYLOAD_FLAG_ADDR 0x0000000000000004
+#define FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID 0x0000000000000008
+#define FM_EREPORT_PAYLOAD_FLAG_SYND 0x0000000000000010
+#define FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE 0x0000000000000020
+#define FM_EREPORT_PAYLOAD_FLAG_IP 0x0000000000000040
+#define FM_EREPORT_PAYLOAD_FLAG_PRIV 0x0000000000000080
+#define FM_EREPORT_PAYLOAD_FLAG_RESOURCE 0x0000000000000100
+#define FM_EREPORT_PAYLOAD_FLAG_STACK 0x0000000000000200
+
+#define FM_EREPORT_PAYLOAD_FLAGS_BANK \
+ (FM_EREPORT_PAYLOAD_FLAG_BANK_STAT | FM_EREPORT_PAYLOAD_FLAG_BANK_NUM)
+#define FM_EREPORT_PAYLOAD_FLAGS_ADDR \
+ (FM_EREPORT_PAYLOAD_FLAG_ADDR | FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID)
+#define FM_EREPORT_PAYLOAD_FLAGS_SYND \
+ (FM_EREPORT_PAYLOAD_FLAG_SYND | FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE)
+#define FM_EREPORT_PAYLOAD_FLAGS_RESOURCE \
+ (FM_EREPORT_PAYLOAD_FLAG_RESOURCE)
+#define FM_EREPORT_PAYLOAD_FLAGS_COMMON \
+ (FM_EREPORT_PAYLOAD_FLAGS_BANK | FM_EREPORT_PAYLOAD_FLAG_IP | \
+ FM_EREPORT_PAYLOAD_FLAG_PRIV)
+#define FM_EREPORT_PAYLOAD_FLAGS_NB \
+ (FM_EREPORT_PAYLOAD_FLAG_STACK)
+
+#define FM_EREPORT_PAYLOAD_FLAGS_1(f1) \
+ (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1)
+#define FM_EREPORT_PAYLOAD_FLAGS_2(f1, f2) \
+ (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \
+ FM_EREPORT_PAYLOAD_FLAGS_##f2)
+#define FM_EREPORT_PAYLOAD_FLAGS_3(f1, f2, f3) \
+ (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \
+ FM_EREPORT_PAYLOAD_FLAGS_##f2 | FM_EREPORT_PAYLOAD_FLAGS_##f3)
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1_UC \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_TAG_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_STAG_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L1TLB_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L2TLB_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_DATA_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_TAG_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_STAG_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L1TLB_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L2TLB_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_RDDE \
+ FM_EREPORT_PAYLOAD_FLAGS_COMMON
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_PAR \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_RDE \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECC1 \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECCM \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND)
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_LS_S_RDE \
+ FM_EREPORT_PAYLOAD_FLAGS_COMMON
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_CE \
+ FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_UE \
+ FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_CRC \
+ FM_EREPORT_PAYLOAD_FLAGS_COMMON
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_SYNC \
+ FM_EREPORT_PAYLOAD_FLAGS_COMMON
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MA \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_TA \
+ FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_GART_WALK \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_RMW \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_WDOG \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+
+#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN \
+ FM_EREPORT_PAYLOAD_FLAGS_1(ADDR)
+
+#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECC1 "dc.inf_sys_ecc1"
+#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECCM "dc.inf_sys_eccm"
+#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECC1 "dc.inf_l2_ecc1"
+#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECCM "dc.inf_l2_eccm"
+#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1 "dc.data_ecc1"
+#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1_UC "dc.data_ecc1_uc"
+#define FM_EREPORT_CPU_AMD_DC_DATA_ECCM "dc.data_eccm"
+#define FM_EREPORT_CPU_AMD_DC_TAG_PAR "dc.tag_par"
+#define FM_EREPORT_CPU_AMD_DC_STAG_PAR "dc.stag_par"
+#define FM_EREPORT_CPU_AMD_DC_L1TLB_PAR "dc.l1tlb_par"
+#define FM_EREPORT_CPU_AMD_DC_L2TLB_PAR "dc.l2tlb_par"
+
+#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECC1 "ic.inf_sys_ecc1"
+#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECCM "ic.inf_sys_eccm"
+#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECC1 "ic.inf_l2_ecc1"
+#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECCM "ic.inf_l2_eccm"
+#define FM_EREPORT_CPU_AMD_IC_DATA_PAR "ic.data_par"
+#define FM_EREPORT_CPU_AMD_IC_TAG_PAR "ic.tag_par"
+#define FM_EREPORT_CPU_AMD_IC_STAG_PAR "ic.stag_par"
+#define FM_EREPORT_CPU_AMD_IC_L1TLB_PAR "ic.l1tlb_par"
+#define FM_EREPORT_CPU_AMD_IC_L2TLB_PAR "ic.l2tlb_par"
+#define FM_EREPORT_CPU_AMD_IC_RDDE "ic.rdde"
+
+#define FM_EREPORT_CPU_AMD_BU_L2D_ECC1 "bu.l2d_ecc1"
+#define FM_EREPORT_CPU_AMD_BU_L2D_ECCM "bu.l2d_eccm"
+#define FM_EREPORT_CPU_AMD_BU_L2T_PAR "bu.l2t_par"
+#define FM_EREPORT_CPU_AMD_BU_L2T_ECC1 "bu.l2t_ecc1"
+#define FM_EREPORT_CPU_AMD_BU_L2T_ECCM "bu.l2t_eccm"
+#define FM_EREPORT_CPU_AMD_BU_S_RDE "bu.s_rde"
+#define FM_EREPORT_CPU_AMD_BU_S_ECC1 "bu.s_ecc1"
+#define FM_EREPORT_CPU_AMD_BU_S_ECCM "bu.s_eccm"
+
+#define FM_EREPORT_CPU_AMD_LS_S_RDE "ls.s_rde"
+
+#define FM_EREPORT_CPU_AMD_NB_MEM_CE "nb.mem_ce"
+#define FM_EREPORT_CPU_AMD_NB_MEM_UE "nb.mem_ue"
+#define FM_EREPORT_CPU_AMD_NB_HT_CRC "nb.ht_crc"
+#define FM_EREPORT_CPU_AMD_NB_HT_SYNC "nb.ht_sync"
+#define FM_EREPORT_CPU_AMD_NB_MA "nb.ma"
+#define FM_EREPORT_CPU_AMD_NB_TA "nb.ta"
+#define FM_EREPORT_CPU_AMD_NB_GART_WALK "nb.gart_walk"
+#define FM_EREPORT_CPU_AMD_NB_RMW "nb.rmw"
+#define FM_EREPORT_CPU_AMD_NB_WDOG "nb.wdog"
+
+#define FM_EREPORT_CPU_AMD_UNKNOWN "unknown"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FM_CPU_AMD_H */
diff --git a/usr/src/uts/intel/sys/mc.h b/usr/src/uts/intel/sys/mc.h
new file mode 100644
index 0000000000..416f323c86
--- /dev/null
+++ b/usr/src/uts/intel/sys/mc.h
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_MC_H
+#define _SYS_MC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Public interfaces exposed by the memory controller driver
+ */
+
+#include <sys/cpuvar.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MC_UNUM_NAMLEN 192
+#define MC_UNUM_NDIMM 8
+
+typedef struct mc_unum {
+ int unum_board;
+ int unum_chip;
+ int unum_mc;
+ int unum_cs;
+ uint64_t unum_offset;
+ int unum_dimms[MC_UNUM_NDIMM];
+} mc_unum_t;
+
+#define MC_AMD_DEV_OFFSET 24 /* node ID + offset == PCI dev num */
+
+#define MC_IOC (0x4d43 << 16)
+#define MC_IOC_SNAPSHOT_INFO (MC_IOC | 1)
+#define MC_IOC_SNAPSHOT (MC_IOC | 2)
+
+/*
+ * Prior to requesting a copy of the snapshot, consumers are advised to request
+ * information regarding the snapshot. An mc_snapshot_info_t will be returned,
+ * containing the snapshot size as well as the snapshot generation number. Note
+ * that, due to the potentially dynamic nature of the system, the snapshot may
+ * change at any time. As such, the information in the mc_snapshot_info_t may
+ * be out of date by the time it is used. The generation number is used to
+ * track snapshot changes. That is, the generation number will be updated each
+ * time the source data for the snapshot is updated. The consumer should not
+ * attach any meaning to the magnitude of a generation number change, and pay
+ * attention only to the fact that the number has changed.
+ */
+typedef struct mc_snapshot_info {
+ uint32_t mcs_size; /* snapshot size */
+ uint_t mcs_gen; /* snapshot generation number */
+} mc_snapshot_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MC_H */
diff --git a/usr/src/uts/intel/sys/mc_amd.h b/usr/src/uts/intel/sys/mc_amd.h
new file mode 100644
index 0000000000..fba266b14f
--- /dev/null
+++ b/usr/src/uts/intel/sys/mc_amd.h
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MC_AMD_H
+#define _MC_AMD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Definitions describing various memory controller constant properties and
+ * the structure of configuration registers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Configuration constants
+ */
+#define MC_CHIP_NDIMM 8 /* max dimms per MC */
+#define MC_CHIP_NCS 8 /* number of chip-selects per MC */
+#define MC_CHIP_DIMMRANKMAX 4 /* largest number of ranks per dimm */
+#define MC_CHIP_DIMMPERCS 2 /* max number of dimms per cs */
+#define MC_CHIP_DIMMPAIR(csnum) (csnum / MC_CHIP_DIMMPERCS)
+
+/*
+ * Encoding of chip version variations that we need to distinguish
+ */
+#define MC_REV_UNKNOWN -1u /* unknown AMD revision */
+#define MC_REV_PRE_D 0 /* B/C/CG */
+#define MC_REV_D_E 1 /* D or E */
+#define MC_REV_F 2 /* F */
+
+/*
+ * BKDG 3.29 section 3.4.4.1 - DRAM base i registers
+ */
+#define MC_AM_DB_DRAMBASE_MASK 0xffff0000
+#define MC_AM_DB_DRAMBASE_LSHFT 8
+#define MC_AM_DB_DRAMBASE(regval) \
+ (((uint64_t)(regval) & MC_AM_DB_DRAMBASE_MASK) << \
+ MC_AM_DB_DRAMBASE_LSHFT)
+#define MC_AM_DB_INTLVEN_MASK 0x00000700
+#define MC_AM_DB_INTLVEN_SHIFT 8
+#define MC_AM_DB_WE 0x00000002
+#define MC_AM_DB_RE 0x00000001
+
+/*
+ * BKDG 3.29 section 3.4.4.2 - DRAM limit i registers
+ */
+#define MC_AM_DL_DRAMLIM_MASK 0xffff0000
+#define MC_AM_DL_DRAMLIM_SHIFT 16
+#define MC_AM_DL_DRAMLIM_LSHFT 8
+#define MC_AM_DL_DRAMLIM(regval) \
+ ((((uint64_t)(regval) & MC_AM_DL_DRAMLIM_MASK) << \
+ MC_AM_DL_DRAMLIM_LSHFT) | ((regval) ? \
+ ((1 << (MC_AM_DL_DRAMLIM_SHIFT + MC_AM_DL_DRAMLIM_LSHFT)) - 1) : 0))
+#define MC_AM_DL_INTLVSEL_MASK 0x00000700
+#define MC_AM_DL_INTLVSEL_SHIFT 8
+#define MC_AM_DL_DSTNODE_MASK 0x00000007
+
+/*
+ * BKDG 3.29 section 3.5.4 - DRAM CS Base Address Registers.
+ *
+ * MC_DC_CSB_CSBASE combines the BaseAddrHi and BaseAddrLo into a single
+ * uint64_t, shifting them into the dram address bits they describe.
+ */
+#define MC_DC_CSB_BASEHI_MASK 0xffe00000
+#define MC_DC_CSB_BASEHI_LSHFT 4
+
+#define MC_DC_CSB_BASELO_MASK 0x0000fe00
+#define MC_DC_CSB_BASELO_LSHFT 4
+
+#define MC_DC_CSB_CSBASE(regval) \
+ ((((uint64_t)(regval) & MC_DC_CSB_BASEHI_MASK) << \
+ MC_DC_CSB_BASEHI_LSHFT) | (((uint64_t)(regval) & \
+ MC_DC_CSB_BASELO_MASK) << MC_DC_CSB_BASELO_LSHFT))
+
+#define MC_DC_CSB_CSBE 0x00000001
+
+/*
+ * BKDG 3.29 section 3.5.5 - DRAM CS Mask Registers.
+ *
+ * MC_DC_CSM_CSMASK combines the AddrMaskHi and AddrMaskLo into a single
+ * uint64_t, shifting them into the dram address bit positions they mask.
+ * It also fills the gaps between high and low mask and below the low mask.
+ * MC_DC_CSM_UNMASKED_BITS indicates the number of high dram address bits
+ * above MC_DC_CSM_MASKHI_HIBIT that cannot be masked.
+ */
+#define MC_DC_CSM_MASKHI_MASK 0x3fe00000
+#define MC_DC_CSM_MASKHI_LSHFT 4
+#define MC_DC_CSM_MASKHI_LOBIT 25
+#define MC_DC_CSM_MASKHI_HIBIT 33
+
+#define MC_DC_CSM_MASKLO_MASK 0x0000fe00
+#define MC_DC_CSM_MASKLO_LOBIT 13
+#define MC_DC_CSM_MASKLO_HIBIT 19
+#define MC_DC_CSM_MASKLO_LSHFT 4
+
+#define MC_DC_CSM_MASKFILL 0x1f01fff /* [24:20] and [12:0] */
+
+#define MC_DC_CSM_UNMASKED_BITS 2
+
+#define MC_DC_CSM_CSMASK(regval) \
+ ((((uint64_t)(regval) & MC_DC_CSM_MASKHI_MASK) << \
+ MC_DC_CSM_MASKHI_LSHFT) | (((uint64_t)(regval) & \
+ MC_DC_CSM_MASKLO_MASK) << MC_DC_CSM_MASKLO_LSHFT) | \
+ MC_DC_CSM_MASKFILL)
+
+/*
+ * BKDG 3.29 section 3.5.6 - DRAM Bank Address Mapping Register
+ */
+#define MC_DC_BAM_CSBANK_MASK 0x0000000f
+#define MC_DC_BAM_CSBANK_SHIFT 4
+#define MC_DC_BAM_CSBANK_SWIZZLE 0x40000000
+
+/*
+ * BKDG 3.29 section 3.4.8 - DRAM Hole register, revs E and later
+ */
+#define MC_DC_HOLE_VALID 0x00000001
+#define MC_DC_HOLE_OFFSET_MASK 0x0000ff00
+#define MC_DC_HOLE_OFFSET_LSHIFT 16
+
+/*
+ * BKDG 3.29 section 3.5.11 - DRAM configuration high and low registers.
+ * The following defines may be applied to a uint64_t made by
+ * concatenating those two 32-bit registers.
+ */
+#define MC_DC_DCFG_DLL_DIS 0x0000000000000001
+#define MC_DC_DCFG_D_DRV 0x0000000000000002
+#define MC_DC_DCFG_QFC_EN 0x0000000000000004
+#define MC_DC_DCFG_DISDQSYS 0x0000000000000008
+#define MC_DC_DCFG_BURST2OPT 0x0000000000000020
+#define MC_DC_DCFG_MOD64BITMUX 0x0000000000000040
+#define MC_DC_DCFG_PWRDWNTRIEN 0x0000000000000080 /* >= rev E */
+#define MC_DC_DCFG_SCRATCHBIT 0x0000000000000080 /* <= rev D */
+#define MC_DC_DCFG_DRAMINIT 0x0000000000000100
+#define MC_DC_DCFG_DUALDIMMEN 0x0000000000000200
+#define MC_DC_DCFG_DRAMENABLE 0x0000000000000400
+#define MC_DC_DCFG_MEMCLRSTATUS 0x0000000000000800
+#define MC_DC_DCFG_ESR 0x0000000000001000
+#define MC_DC_DCFG_SR_S 0x0000000000002000
+#define MC_DC_DCFG_RDWRQBYP_MASK 0x000000000000c000
+#define MC_DC_DCFG_128 0x0000000000010000
+#define MC_DC_DCFG_DIMMECEN 0x0000000000020000
+#define MC_DC_DCFG_UNBUFFDIMM 0x0000000000040000
+#define MC_DC_DCFG_32BYTEEN 0x0000000000080000
+#define MC_DC_DCFG_X4DIMMS_MASK 0x0000000000f00000
+#define MC_DC_DCFG_X4DIMMS_SHIFT 20
+#define MC_DC_DCFG_DISINRCVRS 0x0000000001000000
+#define MC_DC_DCFG_BYPMAX_MASK 0x000000000e000000
+#define MC_DC_DCFG_EN2T 0x0000000010000000
+#define MC_DC_DCFG_UPPERCSMAP 0x0000000020000000
+#define MC_DC_DCFG_PWRDOWNCTL_MASK 0x00000000c0000000
+#define MC_DC_DCFG_ASYNCLAT_MASK 0x0000000f00000000
+#define MC_DC_DCFG_RDPREAMBLE_MASK 0x00000f0000000000
+#define MC_DC_DCFG_MEMDQDRVSTREN_MASK 0x0000600000000000
+#define MC_DC_DCFG_DISABLEJITTER 0x0000800000000000
+#define MC_DC_DCFG_ILD_LMT_MASK 0x0007000000000000
+#define MC_DC_DCFG_ECC_EN 0x0008000000000000
+#define MC_DC_DCFG_MEMCLK_MASK 0x0070000000000000
+#define MC_DC_DCFG_MCR 0x0200000000000000
+#define MC_DC_DCFG_MC0_EN 0x0400000000000000
+#define MC_DC_DCFG_MC1_EN 0x0800000000000000
+#define MC_DC_DCFG_MC2_EN 0x1000000000000000
+#define MC_DC_DCFG_MC3_EN 0x2000000000000000
+#define MC_DC_DCFG_ODDDIVISORCORRECT 0x8000000000000000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MC_AMD_H */
diff --git a/usr/src/uts/intel/sys/mca_amd.h b/usr/src/uts/intel/sys/mca_amd.h
new file mode 100644
index 0000000000..21524f8713
--- /dev/null
+++ b/usr/src/uts/intel/sys/mca_amd.h
@@ -0,0 +1,418 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_MCA_AMD_H
+#define _SYS_MCA_AMD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Constants the Memory Check Architecture as implemented on AMD CPUs.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AMD_MSR_MCG_CAP 0x179
+#define AMD_MSR_MCG_STATUS 0x17a
+#define AMD_MSR_MCG_CTL 0x17b
+
+#define AMD_MCA_BANK_DC 0 /* Data Cache */
+#define AMD_MCA_BANK_IC 1 /* Instruction Cache */
+#define AMD_MCA_BANK_BU 2 /* Bus Unit */
+#define AMD_MCA_BANK_LS 3 /* Load/Store Unit */
+#define AMD_MCA_BANK_NB 4 /* Northbridge */
+#define AMD_MCA_BANK_COUNT 5
+
+#define AMD_MSR_DC_CTL 0x400
+#define AMD_MSR_DC_MASK 0xc0010044
+#define AMD_MSR_DC_STATUS 0x401
+#define AMD_MSR_DC_ADDR 0x402
+
+#define AMD_MSR_IC_CTL 0x404
+#define AMD_MSR_IC_MASK 0xc0010045
+#define AMD_MSR_IC_STATUS 0x405
+#define AMD_MSR_IC_ADDR 0x406
+
+#define AMD_MSR_BU_CTL 0x408
+#define AMD_MSR_BU_MASK 0xc0010046
+#define AMD_MSR_BU_STATUS 0x409
+#define AMD_MSR_BU_ADDR 0x40a
+
+#define AMD_MSR_LS_CTL 0x40c
+#define AMD_MSR_LS_MASK 0xc0010047
+#define AMD_MSR_LS_STATUS 0x40d
+#define AMD_MSR_LS_ADDR 0x40e
+
+#define AMD_MSR_NB_CTL 0x410
+#define AMD_MSR_NB_MASK 0xc0010048
+#define AMD_MSR_NB_STATUS 0x411
+#define AMD_MSR_NB_ADDR 0x412
+
+#define AMD_MCG_EN_DC 0x01
+#define AMD_MCG_EN_IC 0x02
+#define AMD_MCG_EN_BU 0x04
+#define AMD_MCG_EN_LS 0x08
+#define AMD_MCG_EN_NB 0x10
+#define AMD_MCG_EN_ALL \
+ (AMD_MCG_EN_DC | AMD_MCG_EN_IC | AMD_MCG_EN_BU | AMD_MCG_EN_LS | \
+ AMD_MCG_EN_NB)
+
+/*
+ * Data Cache (DC) bank error-detection enabling bits and CTL register
+ * initializer value.
+ */
+
+#define AMD_DC_EN_ECCI 0x00000001ULL
+#define AMD_DC_EN_ECCM 0x00000002ULL
+#define AMD_DC_EN_DECC 0x00000004ULL
+#define AMD_DC_EN_DMTP 0x00000008ULL
+#define AMD_DC_EN_DSTP 0x00000010ULL
+#define AMD_DC_EN_L1TP 0x00000020ULL
+#define AMD_DC_EN_L2TP 0x00000040ULL
+
+#define AMD_DC_CTL_INIT \
+ (AMD_DC_EN_ECCI | AMD_DC_EN_ECCM | AMD_DC_EN_DECC | AMD_DC_EN_DMTP | \
+ AMD_DC_EN_DSTP | AMD_DC_EN_L1TP | AMD_DC_EN_L2TP)
+
+/*
+ * Instruction Cache (IC) bank error-detection enabling bits and CTL register
+ * initializer value.
+ *
+ * The Northbridge will handle Read Data errors. Our initializer will enable
+ * all but the RDDE detector.
+ */
+
+#define AMD_IC_EN_ECCI 0x00000001ULL
+#define AMD_IC_EN_ECCM 0x00000002ULL
+#define AMD_IC_EN_IDP 0x00000004ULL
+#define AMD_IC_EN_IMTP 0x00000008ULL
+#define AMD_IC_EN_ISTP 0x00000010ULL
+#define AMD_IC_EN_L1TP 0x00000020ULL
+#define AMD_IC_EN_L2TP 0x00000040ULL
+#define AMD_IC_EN_RDDE 0x00000200ULL
+
+#define AMD_IC_CTL_INIT \
+ (AMD_IC_EN_ECCI | AMD_IC_EN_ECCM | AMD_IC_EN_IDP | AMD_IC_EN_IMTP | \
+ AMD_IC_EN_ISTP | AMD_IC_EN_L1TP | AMD_IC_EN_L2TP)
+
+/*
+ * Bus Unit (BU) bank error-detection enabling bits and CTL register
+ * initializer value.
+ *
+ * The Northbridge will handle Read Data errors. Our initializer will enable
+ * all but the S_RDE_* detectors.
+ */
+
+#define AMD_BU_EN_S_RDE_HP 0x00000001ULL
+#define AMD_BU_EN_S_RDE_TLB 0x00000002ULL
+#define AMD_BU_EN_S_RDE_ALL 0x00000004ULL
+#define AMD_BU_EN_S_ECC1_TLB 0x00000008ULL
+#define AMD_BU_EN_S_ECC1_HP 0x00000010ULL
+#define AMD_BU_EN_S_ECCM_TLB 0x00000020ULL
+#define AMD_BU_EN_S_ECCM_HP 0x00000040ULL
+#define AMD_BU_EN_L2T_PAR_ICDC 0x00000080ULL
+#define AMD_BU_EN_L2T_PAR_TLB 0x00000100ULL
+#define AMD_BU_EN_L2T_PAR_SNP 0x00000200ULL
+#define AMD_BU_EN_L2T_PAR_CPB 0x00000400ULL
+#define AMD_BU_EN_L2T_PAR_SCR 0x00000800ULL
+#define AMD_BU_EN_L2D_ECC1_TLB 0x00001000ULL
+#define AMD_BU_EN_L2D_ECC1_SNP 0x00002000ULL
+#define AMD_BU_EN_L2D_ECC1_CPB 0x00004000ULL
+#define AMD_BU_EN_L2D_ECCM_TLB 0x00008000ULL
+#define AMD_BU_EN_L2D_ECCM_SNP 0x00010000ULL
+#define AMD_BU_EN_L2D_ECCM_CPB 0x00020000ULL
+#define AMD_BU_EN_L2T_ECC1_SCR 0x00040000ULL
+#define AMD_BU_EN_L2T_ECCM_SCR 0x00080000ULL
+
+#define AMD_BU_CTL_INIT \
+ (AMD_BU_EN_S_ECC1_TLB | AMD_BU_EN_S_ECC1_HP | \
+ AMD_BU_EN_S_ECCM_TLB | AMD_BU_EN_S_ECCM_HP | \
+ AMD_BU_EN_L2T_PAR_ICDC | AMD_BU_EN_L2T_PAR_TLB | \
+ AMD_BU_EN_L2T_PAR_SNP | AMD_BU_EN_L2T_PAR_CPB | \
+ AMD_BU_EN_L2T_PAR_SCR | AMD_BU_EN_L2D_ECC1_TLB | \
+ AMD_BU_EN_L2D_ECC1_SNP | AMD_BU_EN_L2D_ECC1_CPB | \
+ AMD_BU_EN_L2D_ECCM_TLB | AMD_BU_EN_L2D_ECCM_SNP | \
+ AMD_BU_EN_L2D_ECCM_CPB | AMD_BU_EN_L2T_ECC1_SCR | \
+ AMD_BU_EN_L2T_ECCM_SCR)
+
+/*
+ * Load/Store (LS) bank error-detection enabling bits and CTL register
+ * initializer value.
+ *
+ * The Northbridge will handle Read Data errors. That's the only type of
+ * error the LS unit can detect at present, so we won't be enabling any
+ * LS detectors.
+ */
+
+#define AMD_LS_EN_S_RDE_S 0x00000001ULL
+#define AMD_LS_EN_S_RDE_L 0x00000002ULL
+
+#define AMD_LS_CTL_INIT 0ULL
+
+/*
+ * The Northbridge (NB) is configured using both the standard MCA CTL register
+ * and a NB-specific configuration register (NB CFG). The AMD_NB_EN_* macros
+ * are the detector enabling bits for the NB MCA CTL register. The
+ * AMD_NB_CFG_* bits are for the NB CFG register.
+ *
+ * The CTL register can be initialized statically, but portions of the NB CFG
+ * register must be initialized based on the current machine's configuration.
+ *
+ * The MCA NB Control Register maps to MC4_CTL[31:0].
+ *
+ */
+#define AMD_NB_EN_CORRECC 0x00000001
+#define AMD_NB_EN_UNCORRECC 0x00000002
+#define AMD_NB_EN_CRCERR0 0x00000004
+#define AMD_NB_EN_CRCERR1 0x00000008
+#define AMD_NB_EN_CRCERR2 0x00000010
+#define AMD_NB_EN_SYNCPKT0 0x00000020
+#define AMD_NB_EN_SYNCPKT1 0x00000040
+#define AMD_NB_EN_SYNCPKT2 0x00000080
+#define AMD_NB_EN_MSTRABRT 0x00000100
+#define AMD_NB_EN_TGTABRT 0x00000200
+#define AMD_NB_EN_GARTTBLWK 0x00000400
+#define AMD_NB_EN_ATOMICRMW 0x00000800
+#define AMD_NB_EN_WCHDOGTMR 0x00001000
+
+#define AMD_NB_CTL_INIT /* All but GARTTBLWK */ \
+ (AMD_NB_EN_CORRECC | AMD_NB_EN_UNCORRECC | \
+ AMD_NB_EN_CRCERR0 | AMD_NB_EN_CRCERR1 | AMD_NB_EN_CRCERR2 | \
+ AMD_NB_EN_SYNCPKT0 | AMD_NB_EN_SYNCPKT1 | AMD_NB_EN_SYNCPKT2 | \
+ AMD_NB_EN_MSTRABRT | AMD_NB_EN_TGTABRT | \
+ AMD_NB_EN_ATOMICRMW | AMD_NB_EN_WCHDOGTMR)
+
+#define AMD_NB_CFG_CPUECCERREN 0x00000001
+#define AMD_NB_CFG_CPURDDATERREN 0x00000002
+#define AMD_NB_CFG_SYNCONUCECCEN 0x00000004
+#define AMD_NB_CFG_SYNCPKTGENDIS 0x00000008
+#define AMD_NB_CFG_SYNCPKTPROPDIS 0x00000010
+#define AMD_NB_CFG_IOMSTABORTDIS 0x00000020
+#define AMD_NB_CFG_CPUERRDIS 0x00000040
+#define AMD_NB_CFG_IOERRDIS 0x00000080
+#define AMD_NB_CFG_WDOGTMRDIS 0x00000100
+#define AMD_NB_CFG_SYNCONWDOGEN 0x00100000
+#define AMD_NB_CFG_SYNCONANYERREN 0x00200000
+#define AMD_NB_CFG_ECCEN 0x00400000
+#define AMD_NB_CFG_CHIPKILLECCEN 0x00800000
+#define AMD_NB_CFG_IORDDATERREN 0x01000000
+#define AMD_NB_CFG_DISPCICFGCPUERRRSP 0x02000000
+#define AMD_NB_CFG_NBMCATOMSTCPUEN 0x08000000
+
+#define AMD_NB_CFG_WDOGTMRCNTSEL_4095 0x00000000
+#define AMD_NB_CFG_WDOGTMRCNTSEL_2047 0x00000200
+#define AMD_NB_CFG_WDOGTMRCNTSEL_1023 0x00000400
+#define AMD_NB_CFG_WDOGTMRCNTSEL_511 0x00000600
+#define AMD_NB_CFG_WDOGTMRCNTSEL_255 0x00000800
+#define AMD_NB_CFG_WDOGTMRCNTSEL_127 0x00000a00
+#define AMD_NB_CFG_WDOGTMRCNTSEL_63 0x00000c00
+#define AMD_NB_CFG_WDOGTMRCNTSEL_31 0x00000e00
+#define AMD_NB_CFG_WDOGTMRCNTSEL_MASK 0x00000e00
+#define AMD_NB_CFG_WDOGTMRCNTSEL_SHIFT 9
+
+#define AMD_NB_CFG_WDOGTMRBASESEL_1MS 0x00000000
+#define AMD_NB_CFG_WDOGTMRBASESEL_1US 0x00001000
+#define AMD_NB_CFG_WDOGTMRBASESEL_5NS 0x00002000
+#define AMD_NB_CFG_WDOGTMRBASESEL_MASK 0x00003000
+#define AMD_NB_CFG_WDOGTMRBASESEL_SHIFT 12
+
+#define AMD_NB_CFG_LDTLINKSEL_MASK 0x0000c000
+#define AMD_NB_CFG_LDTLINKSEL_SHIFT 14
+
+#define AMD_NB_CFG_GENCRCERRBYTE0 0x00010000
+#define AMD_NB_CFG_GENCRCERRBYTE1 0x00020000
+
+/* Generic bank status register bits */
+#define AMD_BANK_STAT_VALID 0x8000000000000000
+#define AMD_BANK_STAT_OVER 0x4000000000000000
+#define AMD_BANK_STAT_UC 0x2000000000000000
+#define AMD_BANK_STAT_EN 0x1000000000000000
+#define AMD_BANK_STAT_MISCV 0x0800000000000000
+#define AMD_BANK_STAT_ADDRV 0x0400000000000000
+#define AMD_BANK_STAT_PCC 0x0200000000000000
+
+#define AMD_BANK_STAT_CECC 0x0000400000000000
+#define AMD_BANK_STAT_UECC 0x0000200000000000
+#define AMD_BANK_STAT_SCRUB 0x0000010000000000
+
+#define AMD_BANK_STAT_SYND_MASK 0x007f800000000000 /* syndrome[7:0] */
+#define AMD_BANK_STAT_SYND_SHIFT 47
+
+#define AMD_BANK_SYND(stat) \
+ (((stat) & AMD_BANK_STAT_SYND_MASK) >> AMD_BANK_STAT_SYND_SHIFT)
+#define AMD_BANK_MKSYND(synd) \
+ (((uint64_t)(synd) << AMD_BANK_STAT_SYND_SHIFT) & \
+ AMD_BANK_STAT_SYND_MASK)
+
+/* northbridge (NB) status registers */
+
+#define AMD_NB_FUNC 3
+#define AMD_NB_REG_CFG 0x44
+#define AMD_NB_REG_STLO 0x48 /* alias: NB_STATUS[0:31] */
+#define AMD_NB_REG_STHI 0x4c /* alias: NB_STATUS[32:63] */
+#define AMD_NB_REG_ADDRLO 0x50 /* alias: NB_ADDR[0:31] */
+#define AMD_NB_REG_ADDRHI 0x54 /* alias: NB_ADDR[32:63] */
+
+#define AMD_NB_REG_SCRUBCTL 0x58
+#define AMD_NB_REG_SCRUBADDR_LO 0x5c
+#define AMD_NB_REG_SCRUBADDR_HI 0x60
+
+#define AMD_NB_STAT_LDTLINK_MASK 0x0000007000000000
+#define AMD_NB_STAT_LDTLINK_SHIFT 4
+#define AMD_NB_STAT_ERRCPU1 0x0000000200000000
+#define AMD_NB_STAT_ERRCPU0 0x0000000100000000
+#define AMD_NB_STAT_CKSYND_MASK 0x00000000ff000000 /* syndrome[15:8] */
+#define AMD_NB_STAT_CKSYND_SHIFT (24 - 8) /* shift [31:24] to [15:8] */
+
+#define AMD_NB_STAT_CKSYND(stat) \
+ ((((stat) & AMD_NB_STAT_CKSYND_MASK) >> AMD_NB_STAT_CKSYND_SHIFT) | \
+ AMD_BANK_SYND((stat)))
+
+#define AMD_NB_STAT_MKCKSYND(synd) \
+ ((((uint64_t)(synd) << AMD_NB_STAT_CKSYND_SHIFT) & \
+ AMD_NB_STAT_CKSYND_MASK) | AMD_BANK_MKSYND(synd))
+
+#define AMD_ERRCODE_MASK 0x000000000000ffff
+#define AMD_ERREXT_MASK 0x00000000000f0000
+#define AMD_ERREXT_SHIFT 16
+
+#define AMD_ERRCODE_TT_MASK 0x000c
+#define AMD_ERRCODE_TT_SHIFT 2
+#define AMD_ERRCODE_TT_INSTR 0x0
+#define AMD_ERRCODE_TT_DATA 0x1
+#define AMD_ERRCODE_TT_GEN 0x2
+
+#define AMD_ERRCODE_LL_MASK 0x0003
+#define AMD_ERRCODE_LL_L0 0x0
+#define AMD_ERRCODE_LL_L1 0x1
+#define AMD_ERRCODE_LL_L2 0x2
+#define AMD_ERRCODE_LL_LG 0x3
+
+#define AMD_ERRCODE_R4_MASK 0x00f0
+#define AMD_ERRCODE_R4_SHIFT 4
+#define AMD_ERRCODE_R4_GEN 0x0
+#define AMD_ERRCODE_R4_RD 0x1
+#define AMD_ERRCODE_R4_WR 0x2
+#define AMD_ERRCODE_R4_DRD 0x3
+#define AMD_ERRCODE_R4_DWR 0x4
+#define AMD_ERRCODE_R4_IRD 0x5
+#define AMD_ERRCODE_R4_PREFETCH 0x6
+#define AMD_ERRCODE_R4_EVICT 0x7
+#define AMD_ERRCODE_R4_SNOOP 0x8
+
+#define AMD_ERRCODE_PP_MASK 0x0600
+#define AMD_ERRCODE_PP_SHIFT 9
+#define AMD_ERRCODE_PP_SRC 0x0
+#define AMD_ERRCODE_PP_RSP 0x1
+#define AMD_ERRCODE_PP_OBS 0x2
+#define AMD_ERRCODE_PP_GEN 0x3
+
+#define AMD_ERRCODE_T_MASK 0x0100
+#define AMD_ERRCODE_T_SHIFT 8
+#define AMD_ERRCODE_T_NONE 0x0
+#define AMD_ERRCODE_T_TIMEOUT 0x1
+
+#define AMD_ERRCODE_II_MASK 0x000c
+#define AMD_ERRCODE_II_SHIFT 2
+#define AMD_ERRCODE_II_MEM 0x0
+#define AMD_ERRCODE_II_IO 0x2
+#define AMD_ERRCODE_II_GEN 0x3
+
+#define AMD_ERRCODE_TLB_BIT 4
+#define AMD_ERRCODE_MEM_BIT 8
+#define AMD_ERRCODE_BUS_BIT 11
+
+#define AMD_ERRCODE_TLB_MASK 0xfff0
+#define AMD_ERRCODE_TLB_VAL 0x0010
+#define AMD_ERRCODE_MEM_MASK 0xff00
+#define AMD_ERRCODE_MEM_VAL 0x0100
+#define AMD_ERRCODE_BUS_MASK 0xf800
+#define AMD_ERRCODE_BUS_VAL 0x0800
+
+#define AMD_ERRCODE_MKTLB(tt, ll) \
+ (AMD_ERRCODE_TLB_VAL | \
+ (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \
+ ((ll) & AMD_ERRCODE_LL_MASK))
+#define AMD_ERRCODE_ISTLB(code) \
+ (((code) & AMD_ERRCODE_TLB_MASK) == AMD_ERRCODE_TLB_VAL)
+
+#define AMD_ERRCODE_MKMEM(r4, tt, ll) \
+ (AMD_ERRCODE_MEM_VAL | \
+ (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \
+ (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \
+ ((ll) & AMD_ERRCODE_LL_MASK))
+#define AMD_ERRCODE_ISMEM(code) \
+ (((code) & AMD_ERRCODE_MEM_MASK) == AMD_ERRCODE_MEM_VAL)
+
+#define AMD_ERRCODE_MKBUS(pp, t, r4, ii, ll) \
+ (AMD_ERRCODE_BUS_VAL | \
+ (((pp) << AMD_ERRCODE_PP_SHIFT) & AMD_ERRCODE_PP_MASK) | \
+ (((t) << AMD_ERRCODE_T_SHIFT) & AMD_ERRCODE_T_MASK) | \
+ (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \
+ (((ii) << AMD_ERRCODE_II_SHIFT) & AMD_ERRCODE_II_MASK) | \
+ ((ll) & AMD_ERRCODE_LL_MASK))
+#define AMD_ERRCODE_ISBUS(code) \
+ (((code) & AMD_ERRCODE_BUS_MASK) == AMD_ERRCODE_BUS_VAL)
+
+#define AMD_NB_ADDRLO_MASK 0xfffffff8
+#define AMD_NB_ADDRHI_MASK 0x000000ff
+
+#define AMD_SYNDTYPE_ECC 0
+#define AMD_SYNDTYPE_CHIPKILL 1
+
+#define AMD_NB_SCRUBCTL_DRAM_MASK 0x0000001f
+#define AMD_NB_SCRUBCTL_DRAM_SHIFT 0
+#define AMD_NB_SCRUBCTL_L2_MASK 0x00001f00
+#define AMD_NB_SCRUBCTL_L2_SHIFT 8
+#define AMD_NB_SCRUBCTL_DC_MASK 0x001f0000
+#define AMD_NB_SCRUBCTL_DC_SHIFT 16
+
+#define AMD_NB_SCRUBCTL_RATE_NONE 0
+#define AMD_NB_SCRUBCTL_RATE_MAX 0x16
+
+#define AMD_NB_SCRUBADDR_LO_MASK 0xffffffc0
+#define AMD_NB_SCRUBADDR_LO_SCRUBREDIREN 0x1
+#define AMD_NB_SCRUBADDR_HI_MASK 0x000000ff
+
+#define AMD_NB_SCRUBADDR_MKLO(addr) \
+ ((addr) & AMD_NB_SCRUBADDR_LO_MASK)
+
+#define AMD_NB_SCRUBADDR_MKHI(addr) \
+ (((addr) >> 32) & AMD_NB_SCRUBADDR_HI_MASK)
+
+#define AMD_NB_MKSCRUBCTL(dc, l2, dr) ( \
+ (((dc) << AMD_NB_SCRUBCTL_DC_SHIFT) & AMD_NB_SCRUBCTL_DC_MASK) | \
+ (((l2) << AMD_NB_SCRUBCTL_L2_SHIFT) & AMD_NB_SCRUBCTL_L2_MASK) | \
+ (((dr) << AMD_NB_SCRUBCTL_DRAM_SHIFT) & AMD_NB_SCRUBCTL_DRAM_MASK))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MCA_AMD_H */
diff --git a/usr/src/uts/intel/sys/mca_x86.h b/usr/src/uts/intel/sys/mca_x86.h
new file mode 100644
index 0000000000..78066bdc63
--- /dev/null
+++ b/usr/src/uts/intel/sys/mca_x86.h
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_MCA_X86_H
+#define _SYS_MCA_X86_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Constants for the Memory Check Architecture as implemented on generic x86
+ * CPUs.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Intel has defined a number of MSRs as part of the IA32 architecture. The
+ * MCG registers are part of that set, as are the first four banks (0-3) as
+ * implemented by the P4 processor. Bank MSRs were laid out slightly
+ * differently on the P6 family of processors, and thus have their own #defines
+ * following the architecture-generic ones.
+ */
+#define IA32_MSR_MCG_CAP 0x179
+#define IA32_MSR_MCG_STATUS 0x17a
+#define IA32_MSR_MCG_CTL 0x17b
+
+#define MCG_CAP_COUNT_MASK 0x000000ffULL
+#define MCG_CAP_CTL_P 0x00000100ULL
+#define MCG_CAP_EXT_P 0x00000200ULL
+#define MCG_CAP_EXT_CNT_MASK 0x00ff0000ULL
+#define MCG_CAP_EXT_CNT_SHIFT 16
+
+#define MCG_STATUS_RIPV 0x01
+#define MCG_STATUS_EIPV 0x02
+#define MCG_STATUS_MCIP 0x04
+
+#define IA32_MSR_MC0_CTL 0x400
+#define IA32_MSR_MC0_STATUS 0x401
+#define IA32_MSR_MC0_ADDR 0x402
+#define IA32_MSR_MC0_MISC 0x403
+
+#define IA32_MSR_MC1_CTL 0x404
+#define IA32_MSR_MC1_STATUS 0x405
+#define IA32_MSR_MC1_ADDR 0x406
+#define IA32_MSR_MC1_MISC 0x407
+
+#define IA32_MSR_MC2_CTL 0x408
+#define IA32_MSR_MC2_STATUS 0x409
+#define IA32_MSR_MC2_ADDR 0x40a
+#define IA32_MSR_MC2_MISC 0x40b
+
+#define IA32_MSR_MC3_CTL 0x40c
+#define IA32_MSR_MC3_STATUS 0x40d
+#define IA32_MSR_MC3_ADDR 0x40e
+#define IA32_MSR_MC3_MISC 0x40f
+
+#define MSR_MC_STATUS_VAL 0x8000000000000000ULL
+#define MSR_MC_STATUS_O 0x4000000000000000ULL
+#define MSR_MC_STATUS_UC 0x2000000000000000ULL
+#define MSR_MC_STATUS_EN 0x1000000000000000ULL
+#define MSR_MC_STATUS_MISCV 0x0800000000000000ULL
+#define MSR_MC_STATUS_ADDRV 0x0400000000000000ULL
+#define MSR_MC_STATUS_PCC 0x0200000000000000ULL
+#define MSR_MC_STATUS_OTHER_MASK 0x01ffffff00000000ULL
+#define MSR_MC_STATUS_OTHER_SHIFT 32
+#define MSR_MC_STATUS_MSERR_MASK 0x00000000ffff0000ULL
+#define MSR_MC_STATUS_MSERR_SHIFT 16
+#define MSR_MC_STATUS_MCAERR_MASK 0x000000000000ffffULL
+
+/*
+ * P6 MCA bank MSRs. Note that the ordering is 0, 1, 2, *4*, 3. Yes, really.
+ */
+#define P6_MSR_MC0_CTL 0x400
+#define P6_MSR_MC0_STATUS 0x401
+#define P6_MSR_MC0_ADDR 0x402
+#define P6_MSR_MC0_MISC 0x403
+
+#define P6_MSR_MC1_CTL 0x404
+#define P6_MSR_MC1_STATUS 0x405
+#define P6_MSR_MC1_ADDR 0x406
+#define P6_MSR_MC1_MISC 0x407
+
+#define P6_MSR_MC2_CTL 0x408
+#define P6_MSR_MC2_STATUS 0x409
+#define P6_MSR_MC2_ADDR 0x40a
+#define P6_MSR_MC2_MISC 0x40b
+
+#define P6_MSR_MC4_CTL 0x40c
+#define P6_MSR_MC4_STATUS 0x40d
+#define P6_MSR_MC4_ADDR 0x40e
+#define P6_MSR_MC4_MISC 0x40f
+
+#define P6_MSR_MC3_CTL 0x410
+#define P6_MSR_MC3_STATUS 0x411
+#define P6_MSR_MC3_ADDR 0x412
+#define P6_MSR_MC3_MISC 0x413
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MCA_X86_H */
diff --git a/usr/src/uts/intel/sys/memtest.h b/usr/src/uts/intel/sys/memtest.h
new file mode 100644
index 0000000000..8e9d4fc8ef
--- /dev/null
+++ b/usr/src/uts/intel/sys/memtest.h
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MEMTEST_H
+#define _MEMTEST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Interfaces for the memory error injection driver (memtest). This driver is
+ * intended for use only by mtst.
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MEMTEST_DEVICE "/devices/pseudo/memtest@0:memtest"
+
+#define MEMTEST_VERSION 1
+
+#define MEMTESTIOC ('M' << 8)
+#define MEMTESTIOC_INQUIRE (MEMTESTIOC | 0)
+#define MEMTESTIOC_CONFIG (MEMTESTIOC | 1)
+#define MEMTESTIOC_INJECT (MEMTESTIOC | 2)
+#define MEMTESTIOC_MEMREQ (MEMTESTIOC | 3)
+#define MEMTESTIOC_MEMREL (MEMTESTIOC | 4)
+
+#define MEMTEST_F_DEBUG 0x1
+
+typedef struct memtest_inq {
+ uint_t minq_version; /* [out] driver version */
+} memtest_inq_t;
+
+/*
+ * Used by the userland injector to request a memory region from the driver.
+ * This region (or a portion thereof) will be used for the error. The caller
+ * is expected to fill in the restrictions, if any, that are to be applied to
+ * the region. If the driver cannot allocate a region that meets the supplied
+ * restrictions, the ioctl will fail. Upon success, all members will be filled
+ * in with values that reflect the allocated area.
+ */
+
+#define MEMTEST_MEMREQ_MAXNUM 5 /* maximum number of open allocations */
+#define MEMTEST_MEMREQ_MAXSIZE 8192 /* maximum size of each allocation */
+
+#define MEMTEST_MEMREQ_UNSPEC ((uint64_t)-1)
+
+typedef struct memtest_memreq {
+ int mreq_cpuid; /* cpu restriction (opt, -1 if unset) */
+ uint32_t mreq_size; /* size of allocation */
+ uint64_t mreq_vaddr; /* [out] VA of allocation */
+ uint64_t mreq_paddr; /* [out] PA of allocation */
+} memtest_memreq_t;
+
+/*
+ * Arrays of statements are passed to the memtest driver for error injection.
+ */
+#define MEMTEST_INJECT_MAXNUM 20 /* Max # of stmts per INJECT ioctl */
+
+#define MEMTEST_INJ_STMT_MSR 0x1 /* an MSR to be written */
+#define MEMTEST_INJ_STMT_PCICFG 0x2 /* address in PCI config space */
+#define MEMTEST_INJ_STMT_INT 0x3 /* a specific interrupt to be raised */
+#define MEMTEST_INJ_STMT_POLL 0x4 /* tell CPU module to poll for CEs */
+
+/* Must be kept in sync with mtst_inj_statement in mtst_cpumod_api.h */
+typedef struct memtest_inj_stmt {
+ int mis_cpuid; /* target CPU for statement */
+ uint_t mis_type; /* MEMTEST_INJ_STMT_* */
+ union {
+ struct { /* MEMTEST_INJ_STMT_MSR */
+ uint32_t _mis_msrnum; /* MSR number */
+ uint32_t _mis_pad; /* reserved */
+ uint64_t _mis_msrval; /* value for MSR */
+ } _mis_msr;
+ struct { /* MEMTEST_INJ_STMT_PCICFG */
+ uint32_t _mis_pciaddr; /* address in config space */
+ uint32_t _mis_pcival; /* value for PCI config reg */
+ } _mis_pci;
+ uint8_t _mis_int; /* MEMTEST_INJ_STMT_INT; int num */
+ } _mis_data;
+} memtest_inj_stmt_t;
+
+#define mis_msrnum _mis_data._mis_msr._mis_msrnum
+#define mis_msrval _mis_data._mis_msr._mis_msrval
+#define mis_pciaddr _mis_data._mis_pci._mis_pciaddr
+#define mis_pcival _mis_data._mis_pci._mis_pcival
+#define mis_int _mis_data._mis_int
+
+typedef struct memtest_inject {
+ int mi_nstmts;
+ uint32_t mi_pad;
+ memtest_inj_stmt_t mi_stmts[1];
+} memtest_inject_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMTEST_H */
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 4b93663dbd..2f52d6ee4b 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -262,54 +262,7 @@ extern "C" {
#define MSR_PRP4_LBSTK_TO_14 0x6ce
#define MSR_PRP4_LBSTK_TO_15 0x6cf
-#define REG_MCG_CAP 0x179
-#define REG_MCG_STATUS 0x17a
-#define REG_MCG_CTL 0x17b
-
-#define REG_MC0_CTL 0x400
-#define REG_MC0_STATUS 0x401
-#define REG_MC0_ADDR 0x402
-#define REG_MC0_MISC 0x403
-#define REG_MC1_CTL 0x404
-#define REG_MC1_STATUS 0x405
-#define REG_MC1_ADDR 0x406
-#define REG_MC1_MISC 0x407
-#define REG_MC2_CTL 0x408
-#define REG_MC2_STATUS 0x409
-#define REG_MC2_ADDR 0x40a
-#define REG_MC2_MISC 0x40b
-#define REG_MC4_CTL 0x40c
-#define REG_MC4_STATUS 0x40d
-#define REG_MC4_ADDR 0x40e
-#define REG_MC4_MISC 0x40f
-#define REG_MC3_CTL 0x410
-#define REG_MC3_STATUS 0x411
-#define REG_MC3_ADDR 0x412
-#define REG_MC3_MISC 0x413
-
-#define P6_MCG_CAP_COUNT 5
-#define MCG_CAP_COUNT_MASK 0xff
-#define MCG_CAP_CTL_P 0x100
-
-#define MCG_STATUS_RIPV 0x01
-#define MCG_STATUS_EIPV 0x02
-#define MCG_STATUS_MCIP 0x04
-
-#define MCG_CTL_VALUE 0xffffffff
-
#define MCI_CTL_VALUE 0xffffffff
-#define MCI_STATUS_ERRCODE 0xffff
-#define MCI_STATUS_MSERRCODE 0xffff0000
-#define MCI_STATUS_PCC ((long long)0x200000000000000)
-#define MCI_STATUS_ADDRV ((long long)0x400000000000000)
-#define MCI_STATUS_MISCV ((long long)0x800000000000000)
-#define MCI_STATUS_EN ((long long)0x1000000000000000)
-#define MCI_STATUS_UC ((long long)0x2000000000000000)
-#define MCI_STATUS_O ((long long)0x4000000000000000)
-#define MCI_STATUS_VAL ((long long)0x8000000000000000)
-
-#define MSERRCODE_SHFT 16
-
#define MTRRTYPE_MASK 0xff
@@ -437,6 +390,8 @@ typedef struct mtrrvar {
#define X86_VENDOR_TM 9 /* GenuineTMx86 */
#define X86_VENDOR_NSC 10 /* Geode by NSC */
+#define X86_VENDOR_STRLEN 13 /* vendor string max len + \0 */
+
#if !defined(_ASM)
#if defined(_KERNEL) || defined(_KMEMUSER)
@@ -471,8 +426,6 @@ struct cpuid_regs {
extern uint64_t rdmsr(uint_t);
extern void wrmsr(uint_t, const uint64_t);
extern void invalidate_cache(void);
-struct regs;
-extern int mca_exception(struct regs *);
extern ulong_t getcr4(void);
extern void setcr4(ulong_t);
extern void mtrr_sync(void);
diff --git a/usr/src/uts/sparc/sys/Makefile b/usr/src/uts/sparc/sys/Makefile
index 88221c9101..72c122f969 100644
--- a/usr/src/uts/sparc/sys/Makefile
+++ b/usr/src/uts/sparc/sys/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -59,19 +59,37 @@ HDRS= \
vmparam.h \
sysconfig_impl.h
-FPUHDRS= fpu_simulator.h fpusystm.h globals.h ieee.h
+FPUHDRS= \
+ fpu_simulator.h \
+ fpusystm.h \
+ globals.h \
+ ieee.h
+
+FMCPUHDRS= \
+ UltraSPARC-II.h \
+ UltraSPARC-III.h \
+ UltraSPARC-T1.h
ROOTDIR= $(ROOT)/usr/include/sys
-ROOTDIRS= $(ROOTDIR) $(ROOTDIR)/fpu
+ROOTDIRS= \
+ $(ROOTDIR) \
+ $(ROOTDIR)/fm/cpu \
+ $(ROOTDIR)/fpu
ROOTHDRS= $(HDRS:%=$(ROOTDIR)/%)
ROOTFPUHDRS= $(FPUHDRS:%=$(ROOTDIR)/fpu/%)
+ROOTFMCPUHDRS= $(FMCPUHDRS:%=$(ROOTDIR)/fm/cpu/%)
fpu/%.check: fpu/%.h
$(DOT_H_CHECK)
-CHECKHDRS= $(HDRS:%.h=%.check) \
- $(FPUHDRS:%.h=fpu/%.check)
+fm/cpu/%.check: fm/cpu/%.h
+ $(DOT_H_CHECK)
+
+CHECKHDRS= \
+ $(HDRS:%.h=%.check) \
+ $(FPUHDRS:%.h=fpu/%.check) \
+ $(FMCPUHDRS:%.h=fm/cpu/%.check)
# install rules
$(ROOTDIR)/%: %
@@ -80,11 +98,14 @@ $(ROOTDIR)/%: %
$(ROOTDIR)/fpu/%: fpu/%
$(INS.file)
+$(ROOTDIR)/fm/cpu/%: fm/cpu/%
+ $(INS.file)
+
.KEEP_STATE:
-.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS)
+.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS)
-install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS)
+install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS)
$(ROOTDIRS):
$(INS.dir)
diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h
index c6013c9515..c6013c9515 100644
--- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h
+++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h
diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h
index 6422868396..6422868396 100644
--- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h
+++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h
diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h
index e6ffdfe922..e6ffdfe922 100644
--- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h
+++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h
diff --git a/usr/src/uts/sun4u/cpu/us3_common.c b/usr/src/uts/sun4u/cpu/us3_common.c
index f503c84984..6d1a99fa7b 100644
--- a/usr/src/uts/sun4u/cpu/us3_common.c
+++ b/usr/src/uts/sun4u/cpu/us3_common.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -6400,13 +6400,14 @@ void
cpu_ereport_post(struct async_flt *aflt)
{
char *cpu_type, buf[FM_MAX_CLASS];
+ char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
nv_alloc_t *nva = NULL;
nvlist_t *ereport, *detector, *resource;
errorq_elem_t *eqep;
ch_async_flt_t *ch_flt = (ch_async_flt_t *)aflt;
char unum[UNUM_NAMLEN];
int len = 0;
- uint8_t msg_type;
+ uint8_t msg_type, mask;
plat_ecc_ch_async_flt_t plat_ecc_ch_flt;
if (aflt->flt_panic || panicstr) {
@@ -6447,9 +6448,11 @@ cpu_ereport_post(struct async_flt *aflt)
cpu_type = FM_EREPORT_CPU_UNSUPPORTED;
break;
}
+ mask = cpunodes[aflt->flt_inst].version;
+ (void) snprintf(sbuf, sizeof (sbuf), "%llX",
+ (u_longlong_t)cpunodes[aflt->flt_inst].device_id);
(void) fm_fmri_cpu_set(detector, FM_CPU_SCHEME_VERSION, NULL,
- aflt->flt_inst, (uint8_t)cpunodes[aflt->flt_inst].version,
- cpunodes[aflt->flt_inst].device_id);
+ aflt->flt_inst, &mask, (const char *)sbuf);
/*
* Encode all the common data into the ereport.