1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2026 Intel Corporation. */ 3 4 /* 5 * Intel driver to reset bitfix filters when they overflow. 6 * 7 * Each bitfix filter has limited slots to track corrected errors. 8 * These slots can be filled by transient corrected errors (e.g., 9 * bit flips from particle strikes) that don't represent permanent 10 * hardware defects. 11 * 12 * When the filter overflows (yellow status), reset it to reclaim 13 * slots occupied by transient corrected errors. If the overflow 14 * repeats frequently after reset, it indicates persistent hardware 15 * defects that need attention: the system should be scheduled for 16 * servicing. 17 */ 18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 20 #include <linux/bitfield.h> 21 #include <linux/bits.h> 22 #include <linux/cacheinfo.h> 23 #include <linux/cleanup.h> 24 #include <linux/cpufeature.h> 25 #include <linux/cpuhplock.h> 26 #include <linux/device-id/x86_cpu.h> 27 #include <linux/errno.h> 28 #include <linux/init.h> 29 #include <linux/limits.h> 30 #include <linux/module.h> 31 #include <linux/notifier.h> 32 #include <linux/printk.h> 33 #include <linux/topology.h> 34 #include <linux/types.h> 35 36 #include <asm/cpu_device_id.h> 37 #include <asm/cpufeatures.h> 38 #include <asm/intel-family.h> 39 #include <asm/mce.h> 40 #include <asm/msr.h> 41 #include <asm/msr-index.h> 42 43 /* Intel bitfix filter control register defines */ 44 #define MSR_MC0_BFF_CTL 0x000006c0 45 #define MSR_MCx_BFF_CTL(x) (MSR_MC0_BFF_CTL + (x)) 46 #define MCI_BFF_RESET BIT_ULL(0) 47 48 /* Machine check bank hardware unit types */ 49 enum bff_bank_type { 50 BFF_BANK_NONE = 0, 51 BFF_BANK_DCU, 52 BFF_BANK_DTLB, 53 BFF_BANK_MLC, 54 BFF_BANK_CCF, 55 BFF_BANK_HSF, 56 BFF_BANK_IOCACHE, 57 }; 58 59 /* 60 * Mapping from machine check bank numbers on Diamond Rapids CPU, that are 61 * supported by a bitfix filter, to hardware unit type. 62 */ 63 static const enum bff_bank_type dmr_mcbanks[MAX_NR_BANKS] = { 64 [1] = BFF_BANK_DCU, 65 [2] = BFF_BANK_DTLB, 66 [3] = BFF_BANK_MLC, 67 [6] = BFF_BANK_CCF, 68 [13] = BFF_BANK_HSF, 69 [17] = BFF_BANK_IOCACHE 70 }; 71 72 static const struct x86_cpu_id bff_cpu_ids[] __initconst = { 73 X86_MATCH_VFM(INTEL_DIAMONDRAPIDS_X, dmr_mcbanks), 74 {} 75 }; 76 MODULE_DEVICE_TABLE(x86cpu, bff_cpu_ids); 77 78 static const enum bff_bank_type *bff_bank_types; 79 80 /* Diamond Rapids maps APICID[2] to the IMH instance within a socket. */ 81 #define APICID_IMH_NUM GENMASK(2, 2) 82 #define IMH_NUM(apicid) FIELD_GET(APICID_IMH_NUM, apicid) 83 #define NUM_IMH_PER_SOCKET 2 84 85 static void bff_set_imh_id(struct mce *mce, unsigned long *id) 86 { 87 int imh_num; 88 89 imh_num = NUM_IMH_PER_SOCKET * topology_physical_package_id(mce->extcpu) + 90 IMH_NUM(mce->apicid); 91 92 *id |= imh_num; 93 } 94 95 static bool bff_set_cache_id(int cpu, int level, unsigned long *id) 96 { 97 int cacheid; 98 99 guard(cpus_read_lock)(); 100 101 cacheid = get_cpu_cacheinfo_id(cpu, level); 102 if (cacheid == -1) { 103 pr_warn("Could not get L%d cache id for CPU %d\n", level, cpu); 104 return false; 105 } 106 107 *id |= cacheid; 108 109 return true; 110 } 111 112 /* 113 * Cache IDs are only unique within a cache level. 114 * Include the MCA bank number so each BFF-capable hardware 115 * resource has a unique tracking ID. 116 */ 117 #define BFF_ID_BANK_FIELD GENMASK(63, 32) 118 119 static unsigned long bff_get_id(struct mce *mce) 120 { 121 unsigned long id = FIELD_PREP(BFF_ID_BANK_FIELD, mce->bank); 122 123 switch (bff_bank_types[mce->bank]) { 124 case BFF_BANK_DCU: 125 case BFF_BANK_DTLB: 126 if (!bff_set_cache_id(mce->extcpu, 1, &id)) 127 return ULONG_MAX; 128 break; 129 130 case BFF_BANK_MLC: 131 if (!bff_set_cache_id(mce->extcpu, 2, &id)) 132 return ULONG_MAX; 133 break; 134 135 case BFF_BANK_CCF: 136 if (!bff_set_cache_id(mce->extcpu, 3, &id)) 137 return ULONG_MAX; 138 break; 139 140 case BFF_BANK_HSF: 141 case BFF_BANK_IOCACHE: 142 bff_set_imh_id(mce, &id); 143 break; 144 145 default: 146 return ULONG_MAX; 147 } 148 149 return id; 150 } 151 152 static void bff_reset_and_report(struct mce *mce) 153 { 154 /* Reset bitfix filter using the CPU that logged the yellow status */ 155 if (wrmsrq_on_cpu(mce->extcpu, MSR_MCx_BFF_CTL(mce->bank), MCI_BFF_RESET)) 156 pr_warn("Failed to reset bitfix filter for CPU %d Bank %d\n", 157 mce->extcpu, mce->bank); 158 159 /* Placeholder use of bff_get_id() */ 160 pr_debug("unique_id = 0x%lx\n", bff_get_id(mce)); 161 } 162 163 static int bff_mce_notify(struct notifier_block *nb, unsigned long val, void *data) 164 { 165 struct mce *mce = data; 166 167 /* TES is undefined for uncorrected errors. */ 168 if (mce->status & MCI_STATUS_UC) 169 return NOTIFY_DONE; 170 171 if (MCI_STATUS_TES(mce->status) != MCI_STATUS_TES_YELLOW) 172 return NOTIFY_DONE; 173 174 if (mce->bank >= MAX_NR_BANKS || bff_bank_types[mce->bank] == BFF_BANK_NONE) 175 return NOTIFY_DONE; 176 177 bff_reset_and_report(mce); 178 179 return NOTIFY_DONE; 180 } 181 182 static struct notifier_block bff_notifier = { 183 .notifier_call = bff_mce_notify, 184 .priority = MCE_PRIO_EDAC, 185 }; 186 187 static int __init bff_init(void) 188 { 189 const struct x86_cpu_id *m; 190 u64 core_caps, mcg_cap; 191 192 if (!cpu_feature_enabled(X86_FEATURE_MCA)) 193 return -ENODEV; 194 rdmsrq(MSR_IA32_MCG_CAP, mcg_cap); 195 if (!(mcg_cap & MCG_TES_P)) 196 return -ENODEV; 197 198 if (!cpu_feature_enabled(X86_FEATURE_CORE_CAPABILITIES)) 199 return -ENODEV; 200 rdmsrq(MSR_IA32_CORE_CAPS, core_caps); 201 if (!(core_caps & MSR_IA32_CORE_CAPS_BFF_RESET)) 202 return -ENODEV; 203 204 m = x86_match_cpu(bff_cpu_ids); 205 if (!m) { 206 pr_info("CPU model not supported by the bitfix filter reset driver\n"); 207 return -ENODEV; 208 } 209 210 bff_bank_types = (const enum bff_bank_type *)m->driver_data; 211 212 mce_register_decode_chain(&bff_notifier); 213 214 return 0; 215 } 216 217 static void __exit bff_exit(void) 218 { 219 mce_unregister_decode_chain(&bff_notifier); 220 } 221 222 module_init(bff_init); 223 module_exit(bff_exit); 224 225 MODULE_LICENSE("GPL"); 226 MODULE_AUTHOR("Tony Luck"); 227 MODULE_DESCRIPTION("Intel bitfix filter reset driver"); 228