Merge branch 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
apic, amd: Make firmware bug messages more meaningful
mce, amd: Remove goto in threshold_create_device()
mce, amd: Add helper functions to setup APIC
mce, amd: Shorten local variables mci_misc_{hi,lo}
mce, amd: Implement mce_threshold_block_init() helper function

+87 -66
+8 -7
arch/x86/kernel/apic/apic.c
··· 431 431 reserved = reserve_eilvt_offset(offset, new); 432 432 433 433 if (reserved != new) { 434 - pr_err(FW_BUG "cpu %d, try to setup vector 0x%x, but " 435 - "vector 0x%x was already reserved by another core, " 436 - "APIC%lX=0x%x\n", 437 - smp_processor_id(), new, reserved, reg, old); 434 + pr_err(FW_BUG "cpu %d, try to use APIC%lX (LVT offset %d) for " 435 + "vector 0x%x, but the register is already in use for " 436 + "vector 0x%x on another cpu\n", 437 + smp_processor_id(), reg, offset, new, reserved); 438 438 return -EINVAL; 439 439 } 440 440 441 441 if (!eilvt_entry_is_changeable(old, new)) { 442 - pr_err(FW_BUG "cpu %d, try to setup vector 0x%x but " 443 - "register already in use, APIC%lX=0x%x\n", 444 - smp_processor_id(), new, reg, old); 442 + pr_err(FW_BUG "cpu %d, try to use APIC%lX (LVT offset %d) for " 443 + "vector 0x%x, but the register is already in use for " 444 + "vector 0x%x on this cpu\n", 445 + smp_processor_id(), reg, offset, new, old); 445 446 return -EBUSY; 446 447 } 447 448
+78 -59
arch/x86/kernel/cpu/mcheck/mce_amd.c
··· 31 31 #include <asm/mce.h> 32 32 #include <asm/msr.h> 33 33 34 - #define PFX "mce_threshold: " 35 - #define VERSION "version 1.1.1" 36 34 #define NR_BANKS 6 37 35 #define NR_BLOCKS 9 38 36 #define THRESHOLD_MAX 0xFFF ··· 57 59 struct list_head miscj; 58 60 }; 59 61 60 - /* defaults used early on boot */ 61 - static struct threshold_block threshold_defaults = { 62 - .interrupt_enable = 0, 63 - .threshold_limit = THRESHOLD_MAX, 64 - }; 65 - 66 62 struct threshold_bank { 67 63 struct kobject *kobj; 68 64 struct threshold_block *blocks; ··· 81 89 struct thresh_restart { 82 90 struct threshold_block *b; 83 91 int reset; 92 + int set_lvt_off; 93 + int lvt_off; 84 94 u16 old_limit; 95 + }; 96 + 97 + static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) 98 + { 99 + int msr = (hi & MASK_LVTOFF_HI) >> 20; 100 + 101 + if (apic < 0) { 102 + pr_err(FW_BUG "cpu %d, failed to setup threshold interrupt " 103 + "for bank %d, block %d (MSR%08X=0x%x%08x)\n", b->cpu, 104 + b->bank, b->block, b->address, hi, lo); 105 + return 0; 106 + } 107 + 108 + if (apic != msr) { 109 + pr_err(FW_BUG "cpu %d, invalid threshold interrupt offset %d " 110 + "for bank %d, block %d (MSR%08X=0x%x%08x)\n", 111 + b->cpu, apic, b->bank, b->block, b->address, hi, lo); 112 + return 0; 113 + } 114 + 115 + return 1; 85 116 }; 86 117 87 118 /* must be called with correct cpu affinity */ ··· 112 97 static void threshold_restart_bank(void *_tr) 113 98 { 114 99 struct thresh_restart *tr = _tr; 115 - u32 mci_misc_hi, mci_misc_lo; 100 + u32 hi, lo; 116 101 117 - rdmsr(tr->b->address, mci_misc_lo, mci_misc_hi); 102 + rdmsr(tr->b->address, lo, hi); 118 103 119 - if (tr->b->threshold_limit < (mci_misc_hi & THRESHOLD_MAX)) 104 + if (tr->b->threshold_limit < (hi & THRESHOLD_MAX)) 120 105 tr->reset = 1; /* limit cannot be lower than err count */ 121 106 122 107 if (tr->reset) { /* reset err count and overflow bit */ 123 - mci_misc_hi = 124 - (mci_misc_hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) | 108 + hi = 109 + (hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) | 125 110 (THRESHOLD_MAX - tr->b->threshold_limit); 126 111 } else if (tr->old_limit) { /* change limit w/o reset */ 127 - int new_count = (mci_misc_hi & THRESHOLD_MAX) + 112 + int new_count = (hi & THRESHOLD_MAX) + 128 113 (tr->old_limit - tr->b->threshold_limit); 129 114 130 - mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) | 115 + hi = (hi & ~MASK_ERR_COUNT_HI) | 131 116 (new_count & THRESHOLD_MAX); 132 117 } 133 118 134 - tr->b->interrupt_enable ? 135 - (mci_misc_hi = (mci_misc_hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : 136 - (mci_misc_hi &= ~MASK_INT_TYPE_HI); 119 + if (tr->set_lvt_off) { 120 + if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) { 121 + /* set new lvt offset */ 122 + hi &= ~MASK_LVTOFF_HI; 123 + hi |= tr->lvt_off << 20; 124 + } 125 + } 137 126 138 - mci_misc_hi |= MASK_COUNT_EN_HI; 139 - wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi); 127 + tr->b->interrupt_enable ? 128 + (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : 129 + (hi &= ~MASK_INT_TYPE_HI); 130 + 131 + hi |= MASK_COUNT_EN_HI; 132 + wrmsr(tr->b->address, lo, hi); 133 + } 134 + 135 + static void mce_threshold_block_init(struct threshold_block *b, int offset) 136 + { 137 + struct thresh_restart tr = { 138 + .b = b, 139 + .set_lvt_off = 1, 140 + .lvt_off = offset, 141 + }; 142 + 143 + b->threshold_limit = THRESHOLD_MAX; 144 + threshold_restart_bank(&tr); 145 + }; 146 + 147 + static int setup_APIC_mce(int reserved, int new) 148 + { 149 + if (reserved < 0 && !setup_APIC_eilvt(new, THRESHOLD_APIC_VECTOR, 150 + APIC_EILVT_MSG_FIX, 0)) 151 + return new; 152 + 153 + return reserved; 140 154 } 141 155 142 156 /* cpu init entry point, called from mce.c with preempt off */ 143 157 void mce_amd_feature_init(struct cpuinfo_x86 *c) 144 158 { 159 + struct threshold_block b; 145 160 unsigned int cpu = smp_processor_id(); 146 161 u32 low = 0, high = 0, address = 0; 147 162 unsigned int bank, block; 148 - struct thresh_restart tr; 149 - int lvt_off = -1; 150 - u8 offset; 163 + int offset = -1; 151 164 152 165 for (bank = 0; bank < NR_BANKS; ++bank) { 153 166 for (block = 0; block < NR_BLOCKS; ++block) { ··· 206 163 if (shared_bank[bank] && c->cpu_core_id) 207 164 break; 208 165 #endif 209 - offset = (high & MASK_LVTOFF_HI) >> 20; 210 - if (lvt_off < 0) { 211 - if (setup_APIC_eilvt(offset, 212 - THRESHOLD_APIC_VECTOR, 213 - APIC_EILVT_MSG_FIX, 0)) { 214 - pr_err(FW_BUG "cpu %d, failed to " 215 - "setup threshold interrupt " 216 - "for bank %d, block %d " 217 - "(MSR%08X=0x%x%08x)", 218 - smp_processor_id(), bank, block, 219 - address, high, low); 220 - continue; 221 - } 222 - lvt_off = offset; 223 - } else if (lvt_off != offset) { 224 - pr_err(FW_BUG "cpu %d, invalid threshold " 225 - "interrupt offset %d for bank %d," 226 - "block %d (MSR%08X=0x%x%08x)", 227 - smp_processor_id(), lvt_off, bank, 228 - block, address, high, low); 229 - continue; 230 - } 166 + offset = setup_APIC_mce(offset, 167 + (high & MASK_LVTOFF_HI) >> 20); 231 168 232 - high &= ~MASK_LVTOFF_HI; 233 - high |= lvt_off << 20; 234 - wrmsr(address, low, high); 169 + memset(&b, 0, sizeof(b)); 170 + b.cpu = cpu; 171 + b.bank = bank; 172 + b.block = block; 173 + b.address = address; 235 174 236 - threshold_defaults.address = address; 237 - tr.b = &threshold_defaults; 238 - tr.reset = 0; 239 - tr.old_limit = 0; 240 - threshold_restart_bank(&tr); 241 - 175 + mce_threshold_block_init(&b, offset); 242 176 mce_threshold_vector = amd_threshold_interrupt; 243 177 } 244 178 } ··· 318 298 319 299 b->interrupt_enable = !!new; 320 300 301 + memset(&tr, 0, sizeof(tr)); 321 302 tr.b = b; 322 - tr.reset = 0; 323 - tr.old_limit = 0; 324 303 325 304 smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); 326 305 ··· 340 321 if (new < 1) 341 322 new = 1; 342 323 324 + memset(&tr, 0, sizeof(tr)); 343 325 tr.old_limit = b->threshold_limit; 344 326 b->threshold_limit = new; 345 327 tr.b = b; 346 - tr.reset = 0; 347 328 348 329 smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); 349 330 ··· 622 603 continue; 623 604 err = threshold_create_bank(cpu, bank); 624 605 if (err) 625 - goto out; 606 + return err; 626 607 } 627 - out: 608 + 628 609 return err; 629 610 } 630 611
+1
arch/x86/oprofile/op_model_amd.c
··· 610 610 ret = setup_ibs_ctl(i); 611 611 if (ret) 612 612 return ret; 613 + pr_err(FW_BUG "using offset %d for IBS interrupts\n", i); 613 614 return 0; 614 615 } 615 616