]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - arch/x86/kernel/cpu/mcheck/mce_amd.c
x86, MCE, AMD: Hide interrupt_enable sysfs node
[mirror_ubuntu-jammy-kernel.git] / arch / x86 / kernel / cpu / mcheck / mce_amd.c
index 99b57179f9129b770d0e3f069f09ab06f4f686ec..f4873a64f46dcb2dac8db0c3585afecc642e70ee 100644 (file)
@@ -51,6 +51,7 @@ struct threshold_block {
        unsigned int            cpu;
        u32                     address;
        u16                     interrupt_enable;
+       bool                    interrupt_capable;
        u16                     threshold_limit;
        struct kobject          kobj;
        struct list_head        miscj;
@@ -83,6 +84,21 @@ struct thresh_restart {
        u16                     old_limit;
 };
 
+static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
+{
+       /*
+        * bank 4 supports APIC LVT interrupts implicitly since forever.
+        */
+       if (bank == 4)
+               return true;
+
+       /*
+        * IntP: interrupt present; if this bit is set, the thresholding
+        * bank can generate APIC LVT interrupts
+        */
+       return msr_high_bits & BIT(28);
+}
+
 static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
 {
        int msr = (hi & MASK_LVTOFF_HI) >> 20;
@@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
        return 1;
 };
 
-/* must be called with correct cpu affinity */
-/* Called via smp_call_function_single() */
+/*
+ * Called via smp_call_function_single(), must be called with correct
+ * cpu affinity.
+ */
 static void threshold_restart_bank(void *_tr)
 {
        struct thresh_restart *tr = _tr;
@@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr)
                    (new_count & THRESHOLD_MAX);
        }
 
+       /* clear IntType */
+       hi &= ~MASK_INT_TYPE_HI;
+
+       if (!tr->b->interrupt_capable)
+               goto done;
+
        if (tr->set_lvt_off) {
                if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
                        /* set new lvt offset */
@@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr)
                }
        }
 
-       tr->b->interrupt_enable ?
-           (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
-           (hi &= ~MASK_INT_TYPE_HI);
+       if (tr->b->interrupt_enable)
+               hi |= INT_TYPE_APIC;
+
+ done:
 
        hi |= MASK_COUNT_EN_HI;
        wrmsr(tr->b->address, lo, hi);
@@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                        if (shared_bank[bank] && c->cpu_core_id)
                                break;
 
-                       offset = setup_APIC_mce(offset,
-                                               (high & MASK_LVTOFF_HI) >> 20);
-
                        memset(&b, 0, sizeof(b));
-                       b.cpu           = cpu;
-                       b.bank          = bank;
-                       b.block         = block;
-                       b.address       = address;
+                       b.cpu                   = cpu;
+                       b.bank                  = bank;
+                       b.block                 = block;
+                       b.address               = address;
+                       b.interrupt_capable     = lvt_interrupt_supported(bank, high);
+
+                       if (b.interrupt_capable) {
+                               int new = (high & MASK_LVTOFF_HI) >> 20;
+                               offset  = setup_APIC_mce(offset, new);
+                       }
 
                        mce_threshold_block_init(&b, offset);
                        mce_threshold_vector = amd_threshold_interrupt;
@@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
        struct thresh_restart tr;
        unsigned long new;
 
+       if (!b->interrupt_capable)
+               return -EINVAL;
+
        if (strict_strtoul(buf, 0, &new) < 0)
                return -EINVAL;
 
@@ -390,10 +421,10 @@ RW_ATTR(threshold_limit);
 RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
-       &interrupt_enable.attr,
        &threshold_limit.attr,
        &error_count.attr,
-       NULL
+       NULL,   /* possibly interrupt_enable if supported, see below */
+       NULL,
 };
 
 #define to_block(k)    container_of(k, struct threshold_block, kobj)
@@ -467,8 +498,14 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
        b->cpu                  = cpu;
        b->address              = address;
        b->interrupt_enable     = 0;
+       b->interrupt_capable    = lvt_interrupt_supported(bank, high);
        b->threshold_limit      = THRESHOLD_MAX;
 
+       if (b->interrupt_capable)
+               threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
+       else
+               threshold_ktype.default_attrs[2] = NULL;
+
        INIT_LIST_HEAD(&b->miscj);
 
        if (per_cpu(threshold_banks, cpu)[bank]->blocks) {