diff --git a/drivers/edac/intel-bff.c b/drivers/edac/intel-bff.c index c46d5255f34b..06a79745c2fb 100644 --- a/drivers/edac/intel-bff.c +++ b/drivers/edac/intel-bff.c @@ -19,13 +19,18 @@ #include #include +#include +#include #include +#include #include #include #include +#include #include #include #include +#include #include #include @@ -72,12 +77,87 @@ MODULE_DEVICE_TABLE(x86cpu, bff_cpu_ids); static const enum bff_bank_type *bff_bank_types; +/* Diamond Rapids maps APICID[2] to the IMH instance within a socket. */ +#define APICID_IMH_NUM GENMASK(2, 2) +#define IMH_NUM(apicid) FIELD_GET(APICID_IMH_NUM, apicid) +#define NUM_IMH_PER_SOCKET 2 + +static void bff_set_imh_id(struct mce *mce, unsigned long *id) +{ + int imh_num; + + imh_num = NUM_IMH_PER_SOCKET * topology_physical_package_id(mce->extcpu) + + IMH_NUM(mce->apicid); + + *id |= imh_num; +} + +static bool bff_set_cache_id(int cpu, int level, unsigned long *id) +{ + int cacheid; + + guard(cpus_read_lock)(); + + cacheid = get_cpu_cacheinfo_id(cpu, level); + if (cacheid == -1) { + pr_warn("Could not get L%d cache id for CPU %d\n", level, cpu); + return false; + } + + *id |= cacheid; + + return true; +} + +/* + * Cache IDs are only unique within a cache level. + * Include the MCA bank number so each BFF-capable hardware + * resource has a unique tracking ID. + */ +#define BFF_ID_BANK_FIELD GENMASK(63, 32) + +static unsigned long bff_get_id(struct mce *mce) +{ + unsigned long id = FIELD_PREP(BFF_ID_BANK_FIELD, mce->bank); + + switch (bff_bank_types[mce->bank]) { + case BFF_BANK_DCU: + case BFF_BANK_DTLB: + if (!bff_set_cache_id(mce->extcpu, 1, &id)) + return ULONG_MAX; + break; + + case BFF_BANK_MLC: + if (!bff_set_cache_id(mce->extcpu, 2, &id)) + return ULONG_MAX; + break; + + case BFF_BANK_CCF: + if (!bff_set_cache_id(mce->extcpu, 3, &id)) + return ULONG_MAX; + break; + + case BFF_BANK_HSF: + case BFF_BANK_IOCACHE: + bff_set_imh_id(mce, &id); + break; + + default: + return ULONG_MAX; + } + + return id; +} + static void bff_reset_and_report(struct mce *mce) { /* Reset bitfix filter using the CPU that logged the yellow status */ if (wrmsrq_on_cpu(mce->extcpu, MSR_MCx_BFF_CTL(mce->bank), MCI_BFF_RESET)) pr_warn("Failed to reset bitfix filter for CPU %d Bank %d\n", mce->extcpu, mce->bank); + + /* Placeholder use of bff_get_id() */ + pr_debug("unique_id = 0x%lx\n", bff_get_id(mce)); } static int bff_mce_notify(struct notifier_block *nb, unsigned long val, void *data)