Index: sys/x86/include/apicreg.h =================================================================== --- sys/x86/include/apicreg.h +++ sys/x86/include/apicreg.h @@ -241,6 +241,18 @@ LAPIC_CCR_TIMER = 0x39, LAPIC_DCR_TIMER = 0x3e, LAPIC_SELF_IPI = 0x3f, /* Only in x2APIC */ + LAPIC_EXT_FEATURES = 0x40, /* AMD */ + LAPIC_EXT_CTRL = 0x41, /* AMD */ + LAPIC_EXT_SEOI = 0x42, /* AMD */ + LAPIC_EXT_IER0 = 0x48, /* AMD */ + LAPIC_EXT_IER1 = 0x49, /* AMD */ + LAPIC_EXT_IER2 = 0x4a, /* AMD */ + LAPIC_EXT_IER3 = 0x4b, /* AMD */ + LAPIC_EXT_IER4 = 0x4c, /* AMD */ + LAPIC_EXT_IER5 = 0x4d, /* AMD */ + LAPIC_EXT_IER6 = 0x4e, /* AMD */ + LAPIC_EXT_IER7 = 0x4f, /* AMD */ + LAPIC_EXT_LVT = 0x50, /* AMD */ }; /* @@ -295,6 +307,7 @@ #define APIC_VER_MAXLVT 0x00ff0000 #define MAXLVTSHIFT 16 #define APIC_VER_EOI_SUPPRESSION 0x01000000 +#define APIC_VER_AMD_EXT_SPACE 0x80000000 /* fields in LDR */ #define APIC_LDR_RESERVED 0x00ffffff @@ -418,6 +431,13 @@ #define APIC_TDCR_128 0x0a #define APIC_TDCR_1 0x0b +/* Constants related to AMD Extended APIC Features Register */ +#define APIC_EXTF_ELVT_MASK 0x00ff0000 +#define APIC_EXTF_ELVT_SHIFT 16 +#define APIC_EXTF_EXTID_CAP 0x00000004 +#define APIC_EXTF_SEIO_CAP 0x00000002 +#define APIC_EXTF_IER_CAP 0x00000001 + /* LVT table indices */ #define APIC_LVT_LINT0 0 #define APIC_LVT_LINT1 1 @@ -428,6 +448,13 @@ #define APIC_LVT_CMCI 6 #define APIC_LVT_MAX APIC_LVT_CMCI +/* Extended LVT constants, seem to be assigned by fiat */ +#define APIC_ELVT_IBS 0 /* Instruction based sampling */ +#define APIC_ELVT_MCA 1 /* MCE thresholding */ +#define APIC_ELVT_DEI 2 /* Deferred error interrupt */ +#define APIC_ELVT_3 3 /* Free */ +#define APIC_ELVT_MAX APIC_ELVT_3 + /****************************************************************************** * I/O APIC defines */ Index: sys/x86/include/apicvar.h =================================================================== --- sys/x86/include/apicvar.h +++ sys/x86/include/apicvar.h @@ -232,6 +232,9 @@ /* CMC */ void (*enable_cmc)(void); + /* AMD ELVT */ + int (*enable_mca_elvt)(void); + /* IPI */ void (*ipi_raw)(register_t, u_int); void (*ipi_vectored)(u_int, int); @@ -396,6 +399,13 @@ apic_ops.enable_cmc(); } +static inline int +lapic_enable_mca_elvt(void) +{ + + return (apic_ops.enable_mca_elvt()); +} + static inline void lapic_ipi_raw(register_t icrlo, u_int dest) { Index: sys/x86/x86/local_apic.c =================================================================== --- sys/x86/x86/local_apic.c +++ sys/x86/x86/local_apic.c @@ -319,6 +319,7 @@ static void native_lapic_disable_pmc(void); static void native_lapic_reenable_pmc(void); static void native_lapic_enable_cmc(void); +static int native_lapic_enable_mca_elvt(void); static int native_lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked); static int native_lapic_set_lvt_mode(u_int apic_id, u_int lvt, @@ -357,6 +358,7 @@ .disable_pmc = native_lapic_disable_pmc, .reenable_pmc = native_lapic_reenable_pmc, .enable_cmc = native_lapic_enable_cmc, + .enable_mca_elvt = native_lapic_enable_mca_elvt, #ifdef SMP .ipi_raw = native_lapic_ipi_raw, .ipi_vectored = native_lapic_ipi_vectored, @@ -608,12 +610,14 @@ static void native_lapic_dump(const char* str) { + uint32_t version; uint32_t maxlvt; - maxlvt = (lapic_read32(LAPIC_VERSION) & APIC_VER_MAXLVT) >> MAXLVTSHIFT; + version = lapic_read32(LAPIC_VERSION); + maxlvt = (version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; printf("cpu%d %s:\n", PCPU_GET(cpuid), str); printf(" ID: 0x%08x VER: 0x%08x LDR: 0x%08x DFR: 0x%08x", - lapic_read32(LAPIC_ID), lapic_read32(LAPIC_VERSION), + lapic_read32(LAPIC_ID), version, lapic_read32(LAPIC_LDR), x2apic_mode ? 0 : lapic_read32(LAPIC_DFR)); if ((cpu_feature2 & CPUID2_X2APIC) != 0) printf(" x2APIC: %d", x2apic_mode); @@ -628,6 +632,20 @@ printf("\n"); if (maxlvt >= APIC_LVT_CMCI) printf(" cmci: 0x%08x\n", lapic_read32(LAPIC_LVT_CMCI)); + if (cpu_vendor_id == CPU_VENDOR_AMD && + (version & APIC_VER_AMD_EXT_SPACE) != 0) { + uint32_t extf; + int elvt; + int i; + + extf = lapic_read32(LAPIC_EXT_FEATURES); + printf(" AMD ext features: 0x%08x\n", extf); + elvt = (extf & APIC_EXTF_ELVT_MASK) >> APIC_EXTF_ELVT_SHIFT; + for (i = 0; i < elvt; i++) { + printf(" AMD elvt%d: 0x%08x\n", i, + lapic_read32(LAPIC_EXT_LVT + i)); + } + } } static void @@ -1311,6 +1329,38 @@ printf("lapic%u: CMCI unmasked\n", apic_id); } +static int +native_lapic_enable_mca_elvt(void) +{ + uint32_t elvt; + uint32_t value; + +#ifdef DEV_ATPIC + if (!x2apic_mode && lapic_map == NULL) + return (-1); +#endif + + if (cpu_vendor_id != CPU_VENDOR_AMD || + (lapic_read32(LAPIC_VERSION) & APIC_VER_AMD_EXT_SPACE) == 0) { + return (-1); + } + elvt = (lapic_read32(LAPIC_EXT_FEATURES) & APIC_EXTF_ELVT_MASK) >> + APIC_EXTF_ELVT_SHIFT; + if (elvt <= APIC_ELVT_MCA) + return (-1); + + value = lapic_read32(LAPIC_EXT_LVT + APIC_ELVT_MCA); + if ((value & APIC_LVT_M) == 0) { + printf("AMD Extended LVT0 is already active\n"); + return (-1); + } + value &= ~(APIC_LVT_M | APIC_LVT_DM | APIC_LVT_VECTOR); + value |= APIC_LVT_DM_FIXED; + value |= APIC_CMC_INT; + lapic_write32(LAPIC_EXT_LVT + APIC_ELVT_MCA, value); + return (APIC_ELVT_MCA); +} + void lapic_handle_error(void) {