From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753163Ab1IGQkb (ORCPT ); Wed, 7 Sep 2011 12:40:31 -0400 Received: from am1ehsobe004.messaging.microsoft.com ([213.199.154.207]:8060 "EHLO AM1EHSOBE004.bigfish.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751198Ab1IGQkY (ORCPT ); Wed, 7 Sep 2011 12:40:24 -0400 X-SpamScore: 4 X-BigFish: VPS4(zz853kzz1202hzz8275bhz32i668h839h62h) X-Spam-TCS-SCL: 1:0 X-Forefront-Antispam-Report: CIP:163.181.249.108;KIP:(null);UIP:(null);IPVD:NLI;H:ausb3twp01.amd.com;RD:none;EFVD:NLI X-WSS-ID: 0LR5VN5-01-AZ9-02 X-M-MSG: From: Robert Richter To: Peter Zijlstra CC: Ingo Molnar , Stephane Eranian , LKML , Robert Richter Subject: [PATCH 4/7] perf, x86: Implement IBS interrupt handler Date: Wed, 7 Sep 2011 18:36:13 +0200 Message-ID: <1315413376-769-5-git-send-email-robert.richter@amd.com> X-Mailer: git-send-email 1.7.6.1 In-Reply-To: <1315413376-769-1-git-send-email-robert.richter@amd.com> References: <1315413376-769-1-git-send-email-robert.richter@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-OriginatorOrg: amd.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch implements code to handle ibs interrupts. If ibs data is available a raw perf_event data sample is created and sent back to the userland. This patch only implements the storage of ibs data in the raw sample, but this could be extended in a later patch by generating generic event data such as the rip from the ibs sampling data. V2: * Added bit mask for msr offsets. * Added caps field to raw sample format. * Rebase on Don's NMI patches that introduce register_nmi_handler(). Signed-off-by: Robert Richter --- arch/x86/include/asm/msr-index.h | 5 ++ arch/x86/kernel/cpu/perf_event_amd_ibs.c | 84 ++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index d52609a..eca3363 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -127,6 +127,8 @@ #define MSR_AMD64_IBSFETCHCTL 0xc0011030 #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 +#define MSR_AMD64_IBSFETCH_REG_COUNT 3 +#define MSR_AMD64_IBSFETCH_REG_MASK ((1UL< +#include + +#include + #define IBS_FETCH_CONFIG_MASK (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT) #define IBS_OP_CONFIG_MASK IBS_OP_MAX_CNT @@ -23,6 +28,18 @@ struct perf_ibs { u64 config_mask; u64 cnt_mask; u64 enable_mask; + u64 valid_mask; + unsigned long offset_mask[1]; + int offset_max; +}; + +struct perf_ibs_data { + u32 size; + union { + u32 data[0]; /* data buffer starts here */ + u32 caps; + }; + u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX]; }; static struct perf_ibs perf_ibs_fetch; @@ -97,6 +114,9 @@ static struct perf_ibs perf_ibs_fetch = { .config_mask = IBS_FETCH_CONFIG_MASK, .cnt_mask = IBS_FETCH_MAX_CNT, .enable_mask = IBS_FETCH_ENABLE, + .valid_mask = IBS_FETCH_VAL, + .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, + .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, }; static struct perf_ibs perf_ibs_op = { @@ -109,8 +129,71 @@ static struct perf_ibs perf_ibs_op = { .config_mask = IBS_OP_CONFIG_MASK, .cnt_mask = IBS_OP_MAX_CNT, .enable_mask = IBS_OP_ENABLE, + .valid_mask = IBS_OP_VAL, + .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, + .offset_max = MSR_AMD64_IBSOP_REG_COUNT, }; +static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) +{ + struct perf_event *event = NULL; + struct hw_perf_event *hwc = &event->hw; + struct perf_sample_data data; + struct perf_raw_record raw; + struct pt_regs regs; + struct perf_ibs_data ibs_data; + int offset, size; + unsigned int msr; + u64 *buf; + + msr = hwc->config_base; + buf = ibs_data.regs; + rdmsrl(msr, *buf); + if (!(*buf++ & perf_ibs->valid_mask)) + return 0; + + perf_sample_data_init(&data, 0); + if (event->attr.sample_type & PERF_SAMPLE_RAW) { + ibs_data.caps = ibs_caps; + size = 1; + offset = 1; + do { + rdmsrl(msr + offset, *buf++); + size++; + offset = find_next_bit(perf_ibs->offset_mask, + perf_ibs->offset_max, + offset + 1); + } while (offset < perf_ibs->offset_max); + raw.size = sizeof(u32) + sizeof(u64) * size; + raw.data = ibs_data.data; + data.raw = &raw; + } + + regs = *iregs; /* XXX: update ip from ibs sample */ + + if (perf_event_overflow(event, &data, ®s)) + ; /* stop */ + else + /* reenable */ + wrmsrl(hwc->config_base, hwc->config | perf_ibs->enable_mask); + + return 1; +} + +static int __kprobes +perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs) +{ + int handled = 0; + + handled += perf_ibs_handle_irq(&perf_ibs_fetch, regs); + handled += perf_ibs_handle_irq(&perf_ibs_op, regs); + + if (handled) + inc_irq_stat(apic_perf_irqs); + + return handled; +} + static __init int perf_event_ibs_init(void) { if (!ibs_caps) @@ -118,6 +201,7 @@ static __init int perf_event_ibs_init(void) perf_pmu_register(&perf_ibs_fetch.pmu, "ibs_fetch", -1); perf_pmu_register(&perf_ibs_op.pmu, "ibs_op", -1); + register_nmi_handler(NMI_LOCAL, &perf_ibs_nmi_handler, 0, "perf_ibs"); printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); return 0; -- 1.7.6.1