On Tue, May 28, 2013 at 05:45:12PM -0500, suravee.suthikulpa...@amd.com wrote: > +static void perf_iommu_start(struct perf_event *event, int flags) > +{ > + struct hw_perf_event *hwc = &event->hw; > + > + pr_debug("perf: amd_iommu:perf_iommu_start\n"); > + if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) > + return; > + > + WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); > + hwc->state = 0; > + > + if (flags & PERF_EF_RELOAD) { > + u64 prev_raw_count = local64_read(&hwc->prev_count); > + amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), > + _GET_BANK(event), _GET_CNTR(event), > + IOMMU_PC_COUNTER_REG, &prev_raw_count, true); > + } > + > + perf_iommu_enable_event(event); > + perf_event_update_userpage(event); > + > +} > + > +static void perf_iommu_read(struct perf_event *event) > +{ > + u64 count = 0ULL; > + u64 prev_raw_count = 0ULL; > + u64 delta = 0ULL; > + struct hw_perf_event *hwc = &event->hw; > + pr_debug("perf: amd_iommu:perf_iommu_read\n"); > + > + amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), > + _GET_BANK(event), _GET_CNTR(event), > + IOMMU_PC_COUNTER_REG, &count, false); > + > + /* IOMMU pc counter register is only 48 bits */ > + count &= 0xFFFFFFFFFFFFULL; > + > + prev_raw_count = local64_read(&hwc->prev_count); > + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, > + count) != prev_raw_count) > + return; > + > + delta = count - prev_raw_count; > + local64_add(delta, &event->count); > + > +}
OK, so it looks like you have the event as a free-running counter; that is, I don't see it being reset anywhere. Combined with the fact that you're only 48bit wide, it looks like you have a problem. perf_iommu_read()'s delta is wrong. Imagine we've just wrapped and prev_raw_count = 0xFFFFFFFFFFFFUL and count = 0x1. Then we do a 64bit subtraction and end up with delta = 0xffff000000000002 or 18446462598732840962 instead of 2. (also there's trailing whitespace in that function) > + > +static void perf_iommu_stop(struct perf_event *event, int flags) > +{ > + struct hw_perf_event *hwc = &event->hw; > + u64 config; > + > + pr_debug("perf: amd_iommu:perf_iommu_stop\n"); > + > + if (hwc->state & PERF_HES_UPTODATE) > + return; > + > + perf_iommu_disable_event(event); > + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); > + hwc->state |= PERF_HES_STOPPED; > + > + if (hwc->state & PERF_HES_UPTODATE) > + return; > + > + config = hwc->config; > + perf_iommu_read(event); > + hwc->state |= PERF_HES_UPTODATE; > +} _______________________________________________ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu