mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (50 commits) perf python scripting: Add futex-contention script perf python scripting: Fixup cut'n'paste error in sctop script perf scripting: Shut up 'perf record' final status perf record: Remove newline character from perror() argument perf python scripting: Support fedora 11 (audit 1.7.17) perf python scripting: Improve the syscalls-by-pid script perf python scripting: print the syscall name on sctop perf python scripting: Improve the syscalls-counts script perf python scripting: Improve the failed-syscalls-by-pid script kprobes: Remove redundant text_mutex lock in optimize x86/oprofile: Fix uninitialized variable use in debug printk tracing: Fix 'faild' -> 'failed' typo perf probe: Fix format specified for Dwarf_Off parameter perf trace: Fix detection of script extension perf trace: Use $PERF_EXEC_PATH in canned report scripts perf tools: Document event modifiers perf tools: Remove direct slang.h include perf_events: Fix for transaction recovery in group_sched_in() perf_events: Revert: Fix transaction recovery in group_sched_in() perf, x86: Use NUMA aware allocations for PEBS/BTS/DS allocations ...
This commit is contained in:
commit
a042e26137
48 changed files with 1501 additions and 670 deletions
|
|
@ -121,6 +121,7 @@
|
|||
#define MSR_AMD64_IBSDCLINAD 0xc0011038
|
||||
#define MSR_AMD64_IBSDCPHYSAD 0xc0011039
|
||||
#define MSR_AMD64_IBSCTL 0xc001103a
|
||||
#define MSR_AMD64_IBSBRTARGET 0xc001103b
|
||||
|
||||
/* Fam 10h MSRs */
|
||||
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
|
||||
|
|
|
|||
|
|
@ -111,17 +111,18 @@ union cpuid10_edx {
|
|||
#define X86_PMC_IDX_FIXED_BTS (X86_PMC_IDX_FIXED + 16)
|
||||
|
||||
/* IbsFetchCtl bits/masks */
|
||||
#define IBS_FETCH_RAND_EN (1ULL<<57)
|
||||
#define IBS_FETCH_VAL (1ULL<<49)
|
||||
#define IBS_FETCH_ENABLE (1ULL<<48)
|
||||
#define IBS_FETCH_CNT 0xFFFF0000ULL
|
||||
#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
|
||||
#define IBS_FETCH_RAND_EN (1ULL<<57)
|
||||
#define IBS_FETCH_VAL (1ULL<<49)
|
||||
#define IBS_FETCH_ENABLE (1ULL<<48)
|
||||
#define IBS_FETCH_CNT 0xFFFF0000ULL
|
||||
#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
|
||||
|
||||
/* IbsOpCtl bits */
|
||||
#define IBS_OP_CNT_CTL (1ULL<<19)
|
||||
#define IBS_OP_VAL (1ULL<<18)
|
||||
#define IBS_OP_ENABLE (1ULL<<17)
|
||||
#define IBS_OP_MAX_CNT 0x0000FFFFULL
|
||||
#define IBS_OP_CNT_CTL (1ULL<<19)
|
||||
#define IBS_OP_VAL (1ULL<<18)
|
||||
#define IBS_OP_ENABLE (1ULL<<17)
|
||||
#define IBS_OP_MAX_CNT 0x0000FFFFULL
|
||||
#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
extern void init_hw_perf_events(void);
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ struct x86_pmu {
|
|||
* Intel DebugStore bits
|
||||
*/
|
||||
int bts, pebs;
|
||||
int bts_active, pebs_active;
|
||||
int pebs_record_size;
|
||||
void (*drain_pebs)(struct pt_regs *regs);
|
||||
struct event_constraint *pebs_constraints;
|
||||
|
|
@ -380,7 +381,7 @@ static void release_pmc_hardware(void) {}
|
|||
|
||||
#endif
|
||||
|
||||
static int reserve_ds_buffers(void);
|
||||
static void reserve_ds_buffers(void);
|
||||
static void release_ds_buffers(void);
|
||||
|
||||
static void hw_perf_event_destroy(struct perf_event *event)
|
||||
|
|
@ -477,7 +478,7 @@ static int x86_setup_perfctr(struct perf_event *event)
|
|||
if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
|
||||
(hwc->sample_period == 1)) {
|
||||
/* BTS is not supported by this architecture. */
|
||||
if (!x86_pmu.bts)
|
||||
if (!x86_pmu.bts_active)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* BTS is currently only allowed for user-mode. */
|
||||
|
|
@ -496,12 +497,13 @@ static int x86_pmu_hw_config(struct perf_event *event)
|
|||
int precise = 0;
|
||||
|
||||
/* Support for constant skid */
|
||||
if (x86_pmu.pebs)
|
||||
if (x86_pmu.pebs_active) {
|
||||
precise++;
|
||||
|
||||
/* Support for IP fixup */
|
||||
if (x86_pmu.lbr_nr)
|
||||
precise++;
|
||||
/* Support for IP fixup */
|
||||
if (x86_pmu.lbr_nr)
|
||||
precise++;
|
||||
}
|
||||
|
||||
if (event->attr.precise_ip > precise)
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -543,11 +545,8 @@ static int __x86_pmu_event_init(struct perf_event *event)
|
|||
if (atomic_read(&active_events) == 0) {
|
||||
if (!reserve_pmc_hardware())
|
||||
err = -EBUSY;
|
||||
else {
|
||||
err = reserve_ds_buffers();
|
||||
if (err)
|
||||
release_pmc_hardware();
|
||||
}
|
||||
else
|
||||
reserve_ds_buffers();
|
||||
}
|
||||
if (!err)
|
||||
atomic_inc(&active_events);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,107 @@ static void fini_debug_store_on_cpu(int cpu)
|
|||
wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
|
||||
}
|
||||
|
||||
static int alloc_pebs_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
int node = cpu_to_node(cpu);
|
||||
int max, thresh = 1; /* always use a single PEBS record */
|
||||
void *buffer;
|
||||
|
||||
if (!x86_pmu.pebs)
|
||||
return 0;
|
||||
|
||||
buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
|
||||
if (unlikely(!buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
|
||||
|
||||
ds->pebs_buffer_base = (u64)(unsigned long)buffer;
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
ds->pebs_absolute_maximum = ds->pebs_buffer_base +
|
||||
max * x86_pmu.pebs_record_size;
|
||||
|
||||
ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
|
||||
thresh * x86_pmu.pebs_record_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_pebs_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
|
||||
if (!ds || !x86_pmu.pebs)
|
||||
return;
|
||||
|
||||
kfree((void *)(unsigned long)ds->pebs_buffer_base);
|
||||
ds->pebs_buffer_base = 0;
|
||||
}
|
||||
|
||||
static int alloc_bts_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
int node = cpu_to_node(cpu);
|
||||
int max, thresh;
|
||||
void *buffer;
|
||||
|
||||
if (!x86_pmu.bts)
|
||||
return 0;
|
||||
|
||||
buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
|
||||
if (unlikely(!buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
|
||||
thresh = max / 16;
|
||||
|
||||
ds->bts_buffer_base = (u64)(unsigned long)buffer;
|
||||
ds->bts_index = ds->bts_buffer_base;
|
||||
ds->bts_absolute_maximum = ds->bts_buffer_base +
|
||||
max * BTS_RECORD_SIZE;
|
||||
ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
|
||||
thresh * BTS_RECORD_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_bts_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
|
||||
if (!ds || !x86_pmu.bts)
|
||||
return;
|
||||
|
||||
kfree((void *)(unsigned long)ds->bts_buffer_base);
|
||||
ds->bts_buffer_base = 0;
|
||||
}
|
||||
|
||||
static int alloc_ds_buffer(int cpu)
|
||||
{
|
||||
int node = cpu_to_node(cpu);
|
||||
struct debug_store *ds;
|
||||
|
||||
ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
|
||||
if (unlikely(!ds))
|
||||
return -ENOMEM;
|
||||
|
||||
per_cpu(cpu_hw_events, cpu).ds = ds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_ds_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
|
||||
if (!ds)
|
||||
return;
|
||||
|
||||
per_cpu(cpu_hw_events, cpu).ds = NULL;
|
||||
kfree(ds);
|
||||
}
|
||||
|
||||
static void release_ds_buffers(void)
|
||||
{
|
||||
int cpu;
|
||||
|
|
@ -82,93 +183,77 @@ static void release_ds_buffers(void)
|
|||
return;
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
fini_debug_store_on_cpu(cpu);
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
|
||||
if (!ds)
|
||||
continue;
|
||||
|
||||
per_cpu(cpu_hw_events, cpu).ds = NULL;
|
||||
|
||||
kfree((void *)(unsigned long)ds->pebs_buffer_base);
|
||||
kfree((void *)(unsigned long)ds->bts_buffer_base);
|
||||
kfree(ds);
|
||||
release_pebs_buffer(cpu);
|
||||
release_bts_buffer(cpu);
|
||||
release_ds_buffer(cpu);
|
||||
}
|
||||
|
||||
put_online_cpus();
|
||||
}
|
||||
|
||||
static int reserve_ds_buffers(void)
|
||||
static void reserve_ds_buffers(void)
|
||||
{
|
||||
int cpu, err = 0;
|
||||
int bts_err = 0, pebs_err = 0;
|
||||
int cpu;
|
||||
|
||||
x86_pmu.bts_active = 0;
|
||||
x86_pmu.pebs_active = 0;
|
||||
|
||||
if (!x86_pmu.bts && !x86_pmu.pebs)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (!x86_pmu.bts)
|
||||
bts_err = 1;
|
||||
|
||||
if (!x86_pmu.pebs)
|
||||
pebs_err = 1;
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct debug_store *ds;
|
||||
void *buffer;
|
||||
int max, thresh;
|
||||
if (alloc_ds_buffer(cpu)) {
|
||||
bts_err = 1;
|
||||
pebs_err = 1;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
ds = kzalloc(sizeof(*ds), GFP_KERNEL);
|
||||
if (unlikely(!ds))
|
||||
if (!bts_err && alloc_bts_buffer(cpu))
|
||||
bts_err = 1;
|
||||
|
||||
if (!pebs_err && alloc_pebs_buffer(cpu))
|
||||
pebs_err = 1;
|
||||
|
||||
if (bts_err && pebs_err)
|
||||
break;
|
||||
per_cpu(cpu_hw_events, cpu).ds = ds;
|
||||
|
||||
if (x86_pmu.bts) {
|
||||
buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (unlikely(!buffer))
|
||||
break;
|
||||
|
||||
max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
|
||||
thresh = max / 16;
|
||||
|
||||
ds->bts_buffer_base = (u64)(unsigned long)buffer;
|
||||
ds->bts_index = ds->bts_buffer_base;
|
||||
ds->bts_absolute_maximum = ds->bts_buffer_base +
|
||||
max * BTS_RECORD_SIZE;
|
||||
ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
|
||||
thresh * BTS_RECORD_SIZE;
|
||||
}
|
||||
|
||||
if (x86_pmu.pebs) {
|
||||
buffer = kzalloc(PEBS_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (unlikely(!buffer))
|
||||
break;
|
||||
|
||||
max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
|
||||
|
||||
ds->pebs_buffer_base = (u64)(unsigned long)buffer;
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
ds->pebs_absolute_maximum = ds->pebs_buffer_base +
|
||||
max * x86_pmu.pebs_record_size;
|
||||
/*
|
||||
* Always use single record PEBS
|
||||
*/
|
||||
ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
|
||||
x86_pmu.pebs_record_size;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (err)
|
||||
release_ds_buffers();
|
||||
else {
|
||||
if (bts_err) {
|
||||
for_each_possible_cpu(cpu)
|
||||
release_bts_buffer(cpu);
|
||||
}
|
||||
|
||||
if (pebs_err) {
|
||||
for_each_possible_cpu(cpu)
|
||||
release_pebs_buffer(cpu);
|
||||
}
|
||||
|
||||
if (bts_err && pebs_err) {
|
||||
for_each_possible_cpu(cpu)
|
||||
release_ds_buffer(cpu);
|
||||
} else {
|
||||
if (x86_pmu.bts && !bts_err)
|
||||
x86_pmu.bts_active = 1;
|
||||
|
||||
if (x86_pmu.pebs && !pebs_err)
|
||||
x86_pmu.pebs_active = 1;
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
init_debug_store_on_cpu(cpu);
|
||||
}
|
||||
|
||||
put_online_cpus();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -233,7 +318,7 @@ static int intel_pmu_drain_bts_buffer(void)
|
|||
if (!event)
|
||||
return 0;
|
||||
|
||||
if (!ds)
|
||||
if (!x86_pmu.bts_active)
|
||||
return 0;
|
||||
|
||||
at = (struct bts_record *)(unsigned long)ds->bts_buffer_base;
|
||||
|
|
@ -503,7 +588,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
|
|||
struct pebs_record_core *at, *top;
|
||||
int n;
|
||||
|
||||
if (!ds || !x86_pmu.pebs)
|
||||
if (!x86_pmu.pebs_active)
|
||||
return;
|
||||
|
||||
at = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base;
|
||||
|
|
@ -545,7 +630,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
|
|||
u64 status = 0;
|
||||
int bit, n;
|
||||
|
||||
if (!ds || !x86_pmu.pebs)
|
||||
if (!x86_pmu.pebs_active)
|
||||
return;
|
||||
|
||||
at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
|
||||
|
|
@ -630,9 +715,8 @@ static void intel_ds_init(void)
|
|||
|
||||
#else /* CONFIG_CPU_SUP_INTEL */
|
||||
|
||||
static int reserve_ds_buffers(void)
|
||||
static void reserve_ds_buffers(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_ds_buffers(void)
|
||||
|
|
|
|||
|
|
@ -726,6 +726,12 @@ int __init op_nmi_init(struct oprofile_operations *ops)
|
|||
case 0x11:
|
||||
cpu_type = "x86-64/family11h";
|
||||
break;
|
||||
case 0x12:
|
||||
cpu_type = "x86-64/family12h";
|
||||
break;
|
||||
case 0x14:
|
||||
cpu_type = "x86-64/family14h";
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,17 +48,24 @@ static unsigned long reset_value[NUM_VIRT_COUNTERS];
|
|||
|
||||
static u32 ibs_caps;
|
||||
|
||||
struct op_ibs_config {
|
||||
struct ibs_config {
|
||||
unsigned long op_enabled;
|
||||
unsigned long fetch_enabled;
|
||||
unsigned long max_cnt_fetch;
|
||||
unsigned long max_cnt_op;
|
||||
unsigned long rand_en;
|
||||
unsigned long dispatched_ops;
|
||||
unsigned long branch_target;
|
||||
};
|
||||
|
||||
static struct op_ibs_config ibs_config;
|
||||
static u64 ibs_op_ctl;
|
||||
struct ibs_state {
|
||||
u64 ibs_op_ctl;
|
||||
int branch_target;
|
||||
unsigned long sample_size;
|
||||
};
|
||||
|
||||
static struct ibs_config ibs_config;
|
||||
static struct ibs_state ibs_state;
|
||||
|
||||
/*
|
||||
* IBS cpuid feature detection
|
||||
|
|
@ -71,8 +78,16 @@ static u64 ibs_op_ctl;
|
|||
* bit 0 is used to indicate the existence of IBS.
|
||||
*/
|
||||
#define IBS_CAPS_AVAIL (1U<<0)
|
||||
#define IBS_CAPS_FETCHSAM (1U<<1)
|
||||
#define IBS_CAPS_OPSAM (1U<<2)
|
||||
#define IBS_CAPS_RDWROPCNT (1U<<3)
|
||||
#define IBS_CAPS_OPCNT (1U<<4)
|
||||
#define IBS_CAPS_BRNTRGT (1U<<5)
|
||||
#define IBS_CAPS_OPCNTEXT (1U<<6)
|
||||
|
||||
#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
|
||||
| IBS_CAPS_FETCHSAM \
|
||||
| IBS_CAPS_OPSAM)
|
||||
|
||||
/*
|
||||
* IBS APIC setup
|
||||
|
|
@ -99,12 +114,12 @@ static u32 get_ibs_caps(void)
|
|||
/* check IBS cpuid feature flags */
|
||||
max_level = cpuid_eax(0x80000000);
|
||||
if (max_level < IBS_CPUID_FEATURES)
|
||||
return IBS_CAPS_AVAIL;
|
||||
return IBS_CAPS_DEFAULT;
|
||||
|
||||
ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
|
||||
if (!(ibs_caps & IBS_CAPS_AVAIL))
|
||||
/* cpuid flags not valid */
|
||||
return IBS_CAPS_AVAIL;
|
||||
return IBS_CAPS_DEFAULT;
|
||||
|
||||
return ibs_caps;
|
||||
}
|
||||
|
|
@ -197,8 +212,8 @@ op_amd_handle_ibs(struct pt_regs * const regs,
|
|||
rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
|
||||
if (ctl & IBS_OP_VAL) {
|
||||
rdmsrl(MSR_AMD64_IBSOPRIP, val);
|
||||
oprofile_write_reserve(&entry, regs, val,
|
||||
IBS_OP_CODE, IBS_OP_SIZE);
|
||||
oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
|
||||
ibs_state.sample_size);
|
||||
oprofile_add_data64(&entry, val);
|
||||
rdmsrl(MSR_AMD64_IBSOPDATA, val);
|
||||
oprofile_add_data64(&entry, val);
|
||||
|
|
@ -210,10 +225,14 @@ op_amd_handle_ibs(struct pt_regs * const regs,
|
|||
oprofile_add_data64(&entry, val);
|
||||
rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
|
||||
oprofile_add_data64(&entry, val);
|
||||
if (ibs_state.branch_target) {
|
||||
rdmsrl(MSR_AMD64_IBSBRTARGET, val);
|
||||
oprofile_add_data(&entry, (unsigned long)val);
|
||||
}
|
||||
oprofile_write_commit(&entry);
|
||||
|
||||
/* reenable the IRQ */
|
||||
ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
|
||||
ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
|
||||
wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
|
||||
}
|
||||
}
|
||||
|
|
@ -226,21 +245,32 @@ static inline void op_amd_start_ibs(void)
|
|||
if (!ibs_caps)
|
||||
return;
|
||||
|
||||
memset(&ibs_state, 0, sizeof(ibs_state));
|
||||
|
||||
/*
|
||||
* Note: Since the max count settings may out of range we
|
||||
* write back the actual used values so that userland can read
|
||||
* it.
|
||||
*/
|
||||
|
||||
if (ibs_config.fetch_enabled) {
|
||||
val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
|
||||
val = ibs_config.max_cnt_fetch >> 4;
|
||||
val = min(val, IBS_FETCH_MAX_CNT);
|
||||
ibs_config.max_cnt_fetch = val << 4;
|
||||
val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
|
||||
val |= IBS_FETCH_ENABLE;
|
||||
wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
|
||||
}
|
||||
|
||||
if (ibs_config.op_enabled) {
|
||||
ibs_op_ctl = ibs_config.max_cnt_op >> 4;
|
||||
val = ibs_config.max_cnt_op >> 4;
|
||||
if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
|
||||
/*
|
||||
* IbsOpCurCnt not supported. See
|
||||
* op_amd_randomize_ibs_op() for details.
|
||||
*/
|
||||
ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL);
|
||||
val = clamp(val, 0x0081ULL, 0xFF80ULL);
|
||||
ibs_config.max_cnt_op = val << 4;
|
||||
} else {
|
||||
/*
|
||||
* The start value is randomized with a
|
||||
|
|
@ -248,13 +278,24 @@ static inline void op_amd_start_ibs(void)
|
|||
* with the half of the randomized range. Also
|
||||
* avoid underflows.
|
||||
*/
|
||||
ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
|
||||
IBS_OP_MAX_CNT);
|
||||
val += IBS_RANDOM_MAXCNT_OFFSET;
|
||||
if (ibs_caps & IBS_CAPS_OPCNTEXT)
|
||||
val = min(val, IBS_OP_MAX_CNT_EXT);
|
||||
else
|
||||
val = min(val, IBS_OP_MAX_CNT);
|
||||
ibs_config.max_cnt_op =
|
||||
(val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
|
||||
}
|
||||
if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
|
||||
ibs_op_ctl |= IBS_OP_CNT_CTL;
|
||||
ibs_op_ctl |= IBS_OP_ENABLE;
|
||||
val = op_amd_randomize_ibs_op(ibs_op_ctl);
|
||||
val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
|
||||
val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
|
||||
val |= IBS_OP_ENABLE;
|
||||
ibs_state.ibs_op_ctl = val;
|
||||
ibs_state.sample_size = IBS_OP_SIZE;
|
||||
if (ibs_config.branch_target) {
|
||||
ibs_state.branch_target = 1;
|
||||
ibs_state.sample_size++;
|
||||
}
|
||||
val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
|
||||
wrmsrl(MSR_AMD64_IBSOPCTL, val);
|
||||
}
|
||||
}
|
||||
|
|
@ -281,29 +322,25 @@ static inline int eilvt_is_available(int offset)
|
|||
|
||||
static inline int ibs_eilvt_valid(void)
|
||||
{
|
||||
u64 val;
|
||||
int offset;
|
||||
u64 val;
|
||||
|
||||
rdmsrl(MSR_AMD64_IBSCTL, val);
|
||||
offset = val & IBSCTL_LVT_OFFSET_MASK;
|
||||
|
||||
if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
|
||||
pr_err(FW_BUG "cpu %d, invalid IBS "
|
||||
"interrupt offset %d (MSR%08X=0x%016llx)",
|
||||
smp_processor_id(), offset,
|
||||
MSR_AMD64_IBSCTL, val);
|
||||
pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
|
||||
smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = val & IBSCTL_LVT_OFFSET_MASK;
|
||||
if (!eilvt_is_available(offset)) {
|
||||
pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
|
||||
smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eilvt_is_available(offset))
|
||||
return !0;
|
||||
|
||||
pr_err(FW_BUG "cpu %d, IBS interrupt offset %d "
|
||||
"not available (MSR%08X=0x%016llx)",
|
||||
smp_processor_id(), offset,
|
||||
MSR_AMD64_IBSCTL, val);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int get_ibs_offset(void)
|
||||
|
|
@ -630,28 +667,33 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root)
|
|||
/* model specific files */
|
||||
|
||||
/* setup some reasonable defaults */
|
||||
memset(&ibs_config, 0, sizeof(ibs_config));
|
||||
ibs_config.max_cnt_fetch = 250000;
|
||||
ibs_config.fetch_enabled = 0;
|
||||
ibs_config.max_cnt_op = 250000;
|
||||
ibs_config.op_enabled = 0;
|
||||
ibs_config.dispatched_ops = 0;
|
||||
|
||||
dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
|
||||
oprofilefs_create_ulong(sb, dir, "enable",
|
||||
&ibs_config.fetch_enabled);
|
||||
oprofilefs_create_ulong(sb, dir, "max_count",
|
||||
&ibs_config.max_cnt_fetch);
|
||||
oprofilefs_create_ulong(sb, dir, "rand_enable",
|
||||
&ibs_config.rand_en);
|
||||
if (ibs_caps & IBS_CAPS_FETCHSAM) {
|
||||
dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
|
||||
oprofilefs_create_ulong(sb, dir, "enable",
|
||||
&ibs_config.fetch_enabled);
|
||||
oprofilefs_create_ulong(sb, dir, "max_count",
|
||||
&ibs_config.max_cnt_fetch);
|
||||
oprofilefs_create_ulong(sb, dir, "rand_enable",
|
||||
&ibs_config.rand_en);
|
||||
}
|
||||
|
||||
dir = oprofilefs_mkdir(sb, root, "ibs_op");
|
||||
oprofilefs_create_ulong(sb, dir, "enable",
|
||||
&ibs_config.op_enabled);
|
||||
oprofilefs_create_ulong(sb, dir, "max_count",
|
||||
&ibs_config.max_cnt_op);
|
||||
if (ibs_caps & IBS_CAPS_OPCNT)
|
||||
oprofilefs_create_ulong(sb, dir, "dispatched_ops",
|
||||
&ibs_config.dispatched_ops);
|
||||
if (ibs_caps & IBS_CAPS_OPSAM) {
|
||||
dir = oprofilefs_mkdir(sb, root, "ibs_op");
|
||||
oprofilefs_create_ulong(sb, dir, "enable",
|
||||
&ibs_config.op_enabled);
|
||||
oprofilefs_create_ulong(sb, dir, "max_count",
|
||||
&ibs_config.max_cnt_op);
|
||||
if (ibs_caps & IBS_CAPS_OPCNT)
|
||||
oprofilefs_create_ulong(sb, dir, "dispatched_ops",
|
||||
&ibs_config.dispatched_ops);
|
||||
if (ibs_caps & IBS_CAPS_BRNTRGT)
|
||||
oprofilefs_create_ulong(sb, dir, "branch_target",
|
||||
&ibs_config.branch_target);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue