#include <sys/param.h>
#include <sys/systm.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
typedef struct errata {
u_short e_num;
u_short e_reported;
u_int e_data1;
const uint8_t *e_set;
int (*e_act)(struct cpu_info *, struct errata *);
uint64_t e_data2;
} errata_t;
typedef enum cpurev {
BH_E4, CH_CG, CH_D0, DH_CG, DH_D0, DH_E3, DH_E6, JH_E1,
JH_E6, SH_B0, SH_B3, SH_C0, SH_CG, SH_D0, SH_E4, SH_E5,
DR_BA, DR_B2, DR_B3, RB_C2, RB_C3, BL_C2, BL_C3, DA_C2,
DA_C3, HY_D0, HY_D1, PH_E0, LN_B0,
OINK
} cpurev_t;
static const u_int cpurevs[] = {
BH_E4, 0x0020fb1, CH_CG, 0x0000f82, CH_CG, 0x0000fb2,
CH_D0, 0x0010f80, CH_D0, 0x0010fb0, DH_CG, 0x0000fc0,
DH_CG, 0x0000fe0, DH_CG, 0x0000ff0, DH_D0, 0x0010fc0,
DH_D0, 0x0010ff0, DH_E3, 0x0020fc0, DH_E3, 0x0020ff0,
DH_E6, 0x0020fc2, DH_E6, 0x0020ff2, JH_E1, 0x0020f10,
JH_E6, 0x0020f12, JH_E6, 0x0020f32, SH_B0, 0x0000f40,
SH_B3, 0x0000f51, SH_C0, 0x0000f48, SH_C0, 0x0000f58,
SH_CG, 0x0000f4a, SH_CG, 0x0000f5a, SH_CG, 0x0000f7a,
SH_D0, 0x0010f40, SH_D0, 0x0010f50, SH_D0, 0x0010f70,
SH_E4, 0x0020f51, SH_E4, 0x0020f71, SH_E5, 0x0020f42,
DR_BA, 0x0100f2a, DR_B2, 0x0100f22, DR_B3, 0x0100f23,
RB_C2, 0x0100f42, RB_C3, 0x0100f43, BL_C2, 0x0100f52,
BL_C3, 0x0100f53, DA_C2, 0x0100f62, DA_C3, 0x0100f63,
HY_D0, 0x0100f80, HY_D1, 0x0100f81, HY_D1, 0x0100f91,
PH_E0, 0x0100fa0, LN_B0, 0x0300f10, SH_B0, 0x0000f50,
OINK
};
static const uint8_t amd64_errata_set1[] = {
SH_B3, SH_C0, SH_CG, DH_CG, CH_CG, OINK
};
#ifdef MULTIPROCESSOR
static const uint8_t amd64_errata_set2[] = {
SH_B3, SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, OINK
};
#endif
static const uint8_t amd64_errata_set3[] = {
JH_E1, DH_E3, OINK
};
#if 0
static const uint8_t amd64_errata_set4[] = {
SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, JH_E1,
DH_E3, SH_E4, BH_E4, SH_E5, DH_E6, JH_E6, OINK
};
#endif
static const uint8_t amd64_errata_set5[] = {
SH_B3, OINK
};
static const uint8_t amd64_errata_set6[] = {
SH_C0, SH_CG, DH_CG, CH_CG, OINK
};
static const uint8_t amd64_errata_set7[] = {
SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, OINK
};
static const uint8_t amd64_errata_set8[] = {
BH_E4, CH_CG, CH_CG, CH_D0, CH_D0, DH_CG, DH_CG, DH_CG,
DH_D0, DH_D0, DH_E3, DH_E3, DH_E6, DH_E6, JH_E1, JH_E6,
JH_E6, SH_B0, SH_B3, SH_C0, SH_C0, SH_CG, SH_CG, SH_CG,
SH_D0, SH_D0, SH_D0, SH_E4, SH_E4, SH_E5, OINK
};
static const uint8_t amd64_errata_set9[] = {
DR_BA, DR_B2, DR_B3, RB_C2, RB_C3, BL_C2, BL_C3, DA_C2,
DA_C3, HY_D0, HY_D1, PH_E0, LN_B0, OINK
};
int amd64_errata_setmsr(struct cpu_info *, errata_t *);
int amd64_errata_testmsr(struct cpu_info *, errata_t *);
static errata_t errata[] = {
{
81, 0, MSR_DC_CFG, amd64_errata_set5,
amd64_errata_testmsr, DC_CFG_DIS_SMC_CHK_BUF
},
{
86, 0, MSR_NB_CFG, amd64_errata_set1,
amd64_errata_testmsr, NB_CFG_DISDATMSK
},
{
89, 0, MSR_NB_CFG, amd64_errata_set8,
amd64_errata_testmsr, NB_CFG_DISIOREQLOCK
},
{
94, 0, MSR_IC_CFG, amd64_errata_set1,
amd64_errata_testmsr, IC_CFG_DIS_SEQ_PREFETCH
},
{
97, 0, MSR_DC_CFG, amd64_errata_set6,
amd64_errata_testmsr, DC_CFG_DIS_CNV_WC_SSO
},
{
104, 0, MSR_NB_CFG, amd64_errata_set7,
amd64_errata_testmsr, NB_CFG_DISDATMSK
},
{
113, 0, MSR_BU_CFG, amd64_errata_set3,
amd64_errata_setmsr, BU_CFG_WBENHWSBDIS
},
#ifdef MULTIPROCESSOR
{
69, 0, MSR_BU_CFG, amd64_errata_set5,
amd64_errata_setmsr, BU_CFG_WBPFSMCCHKDIS
},
{
101, 0, 0, amd64_errata_set2,
NULL, 0
},
{
106, 0, MSR_LS_CFG, amd64_errata_set2,
amd64_errata_testmsr, LS_CFG_DIS_LS2_SQUISH
},
{
107, 0, MSR_BU_CFG, amd64_errata_set2,
amd64_errata_testmsr, BU_CFG_THRL2IDXCMPDIS
},
#if 0
{
122, 0, MSR_HWCR, amd64_errata_set4,
amd64_errata_setmsr, HWCR_FFDIS
},
#endif
#endif
{
721, 0, MSR_DE_CFG, amd64_errata_set9,
amd64_errata_setmsr, DE_CFG_721
},
};
int
amd64_errata_testmsr(struct cpu_info *ci, errata_t *e)
{
uint64_t val;
(void)ci;
val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE);
if ((val & e->e_data2) != 0)
return 0;
e->e_reported = 1;
return 1;
}
int
amd64_errata_setmsr(struct cpu_info *ci, errata_t *e)
{
uint64_t val;
(void)ci;
val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE);
if ((val & e->e_data2) != 0)
return 0;
wrmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE, val | e->e_data2);
#ifdef ERRATA_DEBUG
printf("ERRATA: writing a fix\n");
val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE);
if ((val & e->e_data2) != 0)
printf("ERRATA: fix seems to have worked!\n");
#endif
e->e_reported = 1;
return 2;
}
void
amd64_errata(struct cpu_info *ci)
{
errata_t *e, *ex;
cpurev_t rev;
int i, j;
int rc;
int found = 0;
int corrected = 0;
u_int32_t regs[4];
static int printed = 0;
cpuid(0x80000001, regs);
for (i = 0; ; i += 2) {
if ((rev = cpurevs[i]) == OINK) {
#ifdef ERRATA_DEBUG
printf("ERRATA: this CPU ok\n");
#endif
return;
}
if (cpurevs[i + 1] == regs[0]) {
#ifdef ERRATA_DEBUG
printf("ERRATA: this CPU has errata\n");
#endif
break;
}
}
ex = errata + sizeof(errata) / sizeof(errata[0]);
for (e = errata; e < ex; e++)
e->e_reported = 0;
for (e = errata; e < ex; e++) {
if (e->e_reported)
continue;
if (e->e_set != NULL) {
for (j = 0; e->e_set[j] != OINK; j++)
if (e->e_set[j] == rev)
break;
if (e->e_set[j] == OINK)
continue;
}
#ifdef ERRATA_DEBUG
printf("%s: testing for erratum %d\n",
ci->ci_dev->dv_xname, e->e_num);
#endif
rc = (e->e_act == NULL) ? 1 : (*e->e_act)(ci, e);
if (rc == 0)
continue;
if (rc == 1)
found++;
if (rc == 2)
corrected++;
e->e_reported = rc;
#ifdef ERRATA_DEBUG
printf("%s: erratum %d present%s\n",
ci->ci_dev->dv_xname, e->e_num,
(rc == 2) ? " and patched" : "");
#endif
}
#define ERRATA_VERBOSE
#ifdef ERRATA_VERBOSE
if (corrected) {
int first = 1;
if (!printed) {
printf("%s: AMD %s", ci->ci_dev->dv_xname,
(corrected == 1) ? "erratum" : "errata");
}
for (e = errata; e < ex; e++) {
if (e->e_reported == 2) {
if (!printed) {
if (! first)
printf(",");
printf(" %d", e->e_num);
}
first = 0;
}
}
if (!printed)
printf(" detected and fixed\n");
}
#endif
if (found) {
int first = 1;
if (!printed) {
printf("%s: AMD %s", ci->ci_dev->dv_xname,
(found == 1) ? "erratum" : "errata");
}
for (e = errata; e < ex; e++) {
if (e->e_reported == 1) {
if (!printed) {
if (! first)
printf(",");
printf(" %d", e->e_num);
}
first = 0;
}
}
if (!printed)
printf(" present, BIOS upgrade may be required\n");
}
printed = 1;
}