···261261 return is_kernel;262262}263263264264+static bool pmc_overflow(unsigned long val)265265+{266266+ if ((int)val < 0)267267+ return true;268268+269269+ /*270270+ * Events on POWER7 can roll back if a speculative event doesn't271271+ * eventually complete. Unfortunately in some rare cases they will272272+ * raise a performance monitor exception. We need to catch this to273273+ * ensure we reset the PMC. In all cases the PMC will be 256 or less274274+ * cycles from overflow.275275+ *276276+ * We only do this if the first pass fails to find any overflowing277277+ * PMCs because a user might set a period of less than 256 and we278278+ * don't want to mistakenly reset them.279279+ */280280+ if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))281281+ return true;282282+283283+ return false;284284+}285285+264286static void power4_handle_interrupt(struct pt_regs *regs,265287 struct op_counter_config *ctr)266288{···303281304282 for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {305283 val = classic_ctr_read(i);306306- if (val < 0) {284284+ if (pmc_overflow(val)) {307285 if (oprofile_running && ctr[i].enabled) {308286 oprofile_add_ext_sample(pc, regs, i, is_kernel);309287 classic_ctr_write(i, reset_value[i]);
+55-42
arch/x86/oprofile/op_model_amd.c
···316316 wrmsrl(MSR_AMD64_IBSOPCTL, 0);317317}318318319319-static inline int eilvt_is_available(int offset)319319+static inline int get_eilvt(int offset)320320{321321- /* check if we may assign a vector */322321 return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);322322+}323323+324324+static inline int put_eilvt(int offset)325325+{326326+ return !setup_APIC_eilvt(offset, 0, 0, 1);323327}324328325329static inline int ibs_eilvt_valid(void)326330{327331 int offset;328332 u64 val;333333+ int valid = 0;334334+335335+ preempt_disable();329336330337 rdmsrl(MSR_AMD64_IBSCTL, val);331338 offset = val & IBSCTL_LVT_OFFSET_MASK;···340333 if (!(val & IBSCTL_LVT_OFFSET_VALID)) {341334 pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",342335 smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);343343- return 0;336336+ goto out;344337 }345338346346- if (!eilvt_is_available(offset)) {339339+ if (!get_eilvt(offset)) {347340 pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",348341 smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);349349- return 0;342342+ goto out;350343 }351344352352- return 1;345345+ valid = 1;346346+out:347347+ preempt_enable();348348+349349+ return valid;353350}354351355352static inline int get_ibs_offset(void)···611600612601static int force_ibs_eilvt_setup(void)613602{614614- int i;603603+ int offset;615604 int ret;616605617617- /* find the next free available EILVT entry */618618- for (i = 1; i < 4; i++) {619619- if (!eilvt_is_available(i))620620- continue;621621- ret = setup_ibs_ctl(i);622622- if (ret)623623- return ret;624624- pr_err(FW_BUG "using offset %d for IBS interrupts\n", i);625625- return 0;606606+ /*607607+ * find the next free available EILVT entry, skip offset 0,608608+ * pin search to this cpu609609+ */610610+ preempt_disable();611611+ for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) {612612+ if (get_eilvt(offset))613613+ break;614614+ }615615+ preempt_enable();616616+617617+ if (offset == APIC_EILVT_NR_MAX) {618618+ printk(KERN_DEBUG "No EILVT entry available\n");619619+ return -EBUSY;626620 }627621628628- printk(KERN_DEBUG "No EILVT entry available\n");629629-630630- return -EBUSY;631631-}632632-633633-static int __init_ibs_nmi(void)634634-{635635- int ret;636636-637637- if (ibs_eilvt_valid())638638- return 0;639639-640640- ret = force_ibs_eilvt_setup();622622+ ret = setup_ibs_ctl(offset);641623 if (ret)642642- return ret;624624+ goto out;643625644644- if (!ibs_eilvt_valid())645645- return -EFAULT;626626+ if (!ibs_eilvt_valid()) {627627+ ret = -EFAULT;628628+ goto out;629629+ }646630631631+ pr_err(FW_BUG "using offset %d for IBS interrupts\n", offset);647632 pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");648633649634 return 0;635635+out:636636+ preempt_disable();637637+ put_eilvt(offset);638638+ preempt_enable();639639+ return ret;650640}651641652642/*653643 * check and reserve APIC extended interrupt LVT offset for IBS if654644 * available655655- *656656- * init_ibs() preforms implicitly cpu-local operations, so pin this657657- * thread to its current CPU658645 */659646660647static void init_ibs(void)661648{662662- preempt_disable();663663-664649 ibs_caps = get_ibs_caps();650650+665651 if (!ibs_caps)652652+ return;653653+654654+ if (ibs_eilvt_valid())666655 goto out;667656668668- if (__init_ibs_nmi() < 0)669669- ibs_caps = 0;670670- else671671- printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);657657+ if (!force_ibs_eilvt_setup())658658+ goto out;659659+660660+ /* Failed to setup ibs */661661+ ibs_caps = 0;662662+ return;672663673664out:674674- preempt_enable();665665+ printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);675666}676667677668static int (*create_arch_files)(struct super_block *sb, struct dentry *root);