Merge tag 'v3.6-rc6' into x86/mce
Merge Linux v3.6-rc6, to refresh this tree. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -25,10 +25,6 @@ unsigned long acpi_realmode_flags;
|
||||
static char temp_stack[4096];
|
||||
#endif
|
||||
|
||||
asmlinkage void acpi_enter_s3(void)
|
||||
{
|
||||
acpi_enter_sleep_state(3, wake_sleep_flags);
|
||||
}
|
||||
/**
|
||||
* acpi_suspend_lowlevel - save kernel state
|
||||
*
|
||||
|
@@ -2,7 +2,6 @@
|
||||
* Variables and functions used by the code in sleep.c
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/realmode.h>
|
||||
|
||||
extern unsigned long saved_video_mode;
|
||||
@@ -11,7 +10,6 @@ extern long saved_magic;
|
||||
extern int wakeup_pmode_return;
|
||||
|
||||
extern u8 wake_sleep_flags;
|
||||
extern asmlinkage void acpi_enter_s3(void);
|
||||
|
||||
extern unsigned long acpi_copy_wakeup_routine(unsigned long);
|
||||
extern void wakeup_long64(void);
|
||||
|
@@ -74,7 +74,9 @@ restore_registers:
|
||||
ENTRY(do_suspend_lowlevel)
|
||||
call save_processor_state
|
||||
call save_registers
|
||||
call acpi_enter_s3
|
||||
pushl $3
|
||||
call acpi_enter_sleep_state
|
||||
addl $4, %esp
|
||||
|
||||
# In case of S3 failure, we'll emerge here. Jump
|
||||
# to ret_point to recover
|
||||
|
@@ -71,7 +71,9 @@ ENTRY(do_suspend_lowlevel)
|
||||
movq %rsi, saved_rsi
|
||||
|
||||
addq $8, %rsp
|
||||
call acpi_enter_s3
|
||||
movl $3, %edi
|
||||
xorl %eax, %eax
|
||||
call acpi_enter_sleep_state
|
||||
/* in case something went wrong, restore the machine status and go on */
|
||||
jmp resume_point
|
||||
|
||||
|
@@ -165,7 +165,7 @@ static const unsigned char * const k7_nops[ASM_NOP_MAX+2] =
|
||||
#endif
|
||||
|
||||
#ifdef P6_NOP1
|
||||
static const unsigned char __initconst_or_module p6nops[] =
|
||||
static const unsigned char p6nops[] =
|
||||
{
|
||||
P6_NOP1,
|
||||
P6_NOP2,
|
||||
@@ -224,7 +224,7 @@ void __init arch_init_ideal_nops(void)
|
||||
ideal_nops = intel_nops;
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
#ifdef CONFIG_X86_64
|
||||
ideal_nops = k8_nops;
|
||||
|
@@ -1204,7 +1204,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
|
||||
BUG_ON(!cfg->vector);
|
||||
|
||||
vector = cfg->vector;
|
||||
for_each_cpu(cpu, cfg->domain)
|
||||
for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
|
||||
per_cpu(vector_irq, cpu)[vector] = -1;
|
||||
|
||||
cfg->vector = 0;
|
||||
@@ -1212,7 +1212,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
|
||||
|
||||
if (likely(!cfg->move_in_progress))
|
||||
return;
|
||||
for_each_cpu(cpu, cfg->old_domain) {
|
||||
for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
|
||||
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
|
||||
vector++) {
|
||||
if (per_cpu(vector_irq, cpu)[vector] != irq)
|
||||
@@ -1356,6 +1356,16 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
|
||||
if (!IO_APIC_IRQ(irq))
|
||||
return;
|
||||
|
||||
/*
|
||||
* For legacy irqs, cfg->domain starts with cpu 0. Now that IO-APIC
|
||||
* can handle this irq and the apic driver is finialized at this point,
|
||||
* update the cfg->domain.
|
||||
*/
|
||||
if (irq < legacy_pic->nr_legacy_irqs &&
|
||||
cpumask_equal(cfg->domain, cpumask_of(0)))
|
||||
apic->vector_allocation_domain(0, cfg->domain,
|
||||
apic->target_cpus());
|
||||
|
||||
if (assign_irq_vector(irq, cfg, apic->target_cpus()))
|
||||
return;
|
||||
|
||||
|
@@ -144,6 +144,8 @@ static int __init x86_xsave_setup(char *s)
|
||||
{
|
||||
setup_clear_cpu_cap(X86_FEATURE_XSAVE);
|
||||
setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
|
||||
setup_clear_cpu_cap(X86_FEATURE_AVX);
|
||||
setup_clear_cpu_cap(X86_FEATURE_AVX2);
|
||||
return 1;
|
||||
}
|
||||
__setup("noxsave", x86_xsave_setup);
|
||||
|
@@ -55,13 +55,6 @@ static struct severity {
|
||||
#define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
|
||||
#define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
|
||||
#define MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV)
|
||||
#define MCACOD 0xffff
|
||||
/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
|
||||
#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */
|
||||
#define MCACOD_SCRUBMSK 0xfff0
|
||||
#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */
|
||||
#define MCACOD_DATA 0x0134 /* Data Load */
|
||||
#define MCACOD_INSTR 0x0150 /* Instruction Fetch */
|
||||
|
||||
MCESEV(
|
||||
NO, "Invalid",
|
||||
|
@@ -103,6 +103,8 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
|
||||
|
||||
static DEFINE_PER_CPU(struct work_struct, mce_work);
|
||||
|
||||
static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
|
||||
|
||||
/*
|
||||
* CPU/chipset specific EDAC code can register a notifier call here to print
|
||||
* MCE errors in a human-readable form.
|
||||
@@ -650,14 +652,18 @@ EXPORT_SYMBOL_GPL(machine_check_poll);
|
||||
* Do a quick check if any of the events requires a panic.
|
||||
* This decides if we keep the events around or clear them.
|
||||
*/
|
||||
static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp)
|
||||
static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < banks; i++) {
|
||||
m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i));
|
||||
if (m->status & MCI_STATUS_VAL)
|
||||
if (m->status & MCI_STATUS_VAL) {
|
||||
__set_bit(i, validp);
|
||||
if (quirk_no_way_out)
|
||||
quirk_no_way_out(i, m, regs);
|
||||
}
|
||||
if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY)
|
||||
ret = 1;
|
||||
}
|
||||
@@ -1040,7 +1046,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
|
||||
*final = m;
|
||||
|
||||
memset(valid_banks, 0, sizeof(valid_banks));
|
||||
no_way_out = mce_no_way_out(&m, &msg, valid_banks);
|
||||
no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs);
|
||||
|
||||
barrier();
|
||||
|
||||
@@ -1451,6 +1457,34 @@ static void __mcheck_cpu_init_generic(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* During IFU recovery Sandy Bridge -EP4S processors set the RIPV and
|
||||
* EIPV bits in MCG_STATUS to zero on the affected logical processor (SDM
|
||||
* Vol 3B Table 15-20). But this confuses both the code that determines
|
||||
* whether the machine check occurred in kernel or user mode, and also
|
||||
* the severity assessment code. Pretend that EIPV was set, and take the
|
||||
* ip/cs values from the pt_regs that mce_gather_info() ignored earlier.
|
||||
*/
|
||||
static void quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs)
|
||||
{
|
||||
if (bank != 0)
|
||||
return;
|
||||
if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0)
|
||||
return;
|
||||
if ((m->status & (MCI_STATUS_OVER|MCI_STATUS_UC|
|
||||
MCI_STATUS_EN|MCI_STATUS_MISCV|MCI_STATUS_ADDRV|
|
||||
MCI_STATUS_PCC|MCI_STATUS_S|MCI_STATUS_AR|
|
||||
MCACOD)) !=
|
||||
(MCI_STATUS_UC|MCI_STATUS_EN|
|
||||
MCI_STATUS_MISCV|MCI_STATUS_ADDRV|MCI_STATUS_S|
|
||||
MCI_STATUS_AR|MCACOD_INSTR))
|
||||
return;
|
||||
|
||||
m->mcgstatus |= MCG_STATUS_EIPV;
|
||||
m->ip = regs->ip;
|
||||
m->cs = regs->cs;
|
||||
}
|
||||
|
||||
/* Add per CPU specific workarounds here */
|
||||
static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
|
||||
{
|
||||
@@ -1548,6 +1582,9 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
|
||||
*/
|
||||
if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0)
|
||||
mce_bootlog = 0;
|
||||
|
||||
if (c->x86 == 6 && c->x86_model == 45)
|
||||
quirk_no_way_out = quirk_sandybridge_ifu;
|
||||
}
|
||||
if (monarch_timeout < 0)
|
||||
monarch_timeout = 0;
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include <asm/smp.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/ldt.h>
|
||||
|
||||
#include "perf_event.h"
|
||||
|
||||
@@ -1738,6 +1740,29 @@ valid_user_frame(const void __user *fp, unsigned long size)
|
||||
return (__range_not_ok(fp, size, TASK_SIZE) == 0);
|
||||
}
|
||||
|
||||
static unsigned long get_segment_base(unsigned int segment)
|
||||
{
|
||||
struct desc_struct *desc;
|
||||
int idx = segment >> 3;
|
||||
|
||||
if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
|
||||
if (idx > LDT_ENTRIES)
|
||||
return 0;
|
||||
|
||||
if (idx > current->active_mm->context.size)
|
||||
return 0;
|
||||
|
||||
desc = current->active_mm->context.ldt;
|
||||
} else {
|
||||
if (idx > GDT_ENTRIES)
|
||||
return 0;
|
||||
|
||||
desc = __this_cpu_ptr(&gdt_page.gdt[0]);
|
||||
}
|
||||
|
||||
return get_desc_base(desc + idx);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#include <asm/compat.h>
|
||||
@@ -1746,13 +1771,17 @@ static inline int
|
||||
perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||
{
|
||||
/* 32-bit process in 64-bit kernel. */
|
||||
unsigned long ss_base, cs_base;
|
||||
struct stack_frame_ia32 frame;
|
||||
const void __user *fp;
|
||||
|
||||
if (!test_thread_flag(TIF_IA32))
|
||||
return 0;
|
||||
|
||||
fp = compat_ptr(regs->bp);
|
||||
cs_base = get_segment_base(regs->cs);
|
||||
ss_base = get_segment_base(regs->ss);
|
||||
|
||||
fp = compat_ptr(ss_base + regs->bp);
|
||||
while (entry->nr < PERF_MAX_STACK_DEPTH) {
|
||||
unsigned long bytes;
|
||||
frame.next_frame = 0;
|
||||
@@ -1765,8 +1794,8 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||
if (!valid_user_frame(fp, sizeof(frame)))
|
||||
break;
|
||||
|
||||
perf_callchain_store(entry, frame.return_address);
|
||||
fp = compat_ptr(frame.next_frame);
|
||||
perf_callchain_store(entry, cs_base + frame.return_address);
|
||||
fp = compat_ptr(ss_base + frame.next_frame);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -1789,6 +1818,12 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't know what to do with VM86 stacks.. ignore them for now.
|
||||
*/
|
||||
if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
|
||||
return;
|
||||
|
||||
fp = (void __user *)regs->bp;
|
||||
|
||||
perf_callchain_store(entry, regs->ip);
|
||||
@@ -1816,16 +1851,50 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with code segment offsets for the various execution modes:
|
||||
*
|
||||
* VM86 - the good olde 16 bit days, where the linear address is
|
||||
* 20 bits and we use regs->ip + 0x10 * regs->cs.
|
||||
*
|
||||
* IA32 - Where we need to look at GDT/LDT segment descriptor tables
|
||||
* to figure out what the 32bit base address is.
|
||||
*
|
||||
* X32 - has TIF_X32 set, but is running in x86_64
|
||||
*
|
||||
* X86_64 - CS,DS,SS,ES are all zero based.
|
||||
*/
|
||||
static unsigned long code_segment_base(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* If we are in VM86 mode, add the segment offset to convert to a
|
||||
* linear address.
|
||||
*/
|
||||
if (regs->flags & X86_VM_MASK)
|
||||
return 0x10 * regs->cs;
|
||||
|
||||
/*
|
||||
* For IA32 we look at the GDT/LDT segment base to convert the
|
||||
* effective IP to a linear address.
|
||||
*/
|
||||
#ifdef CONFIG_X86_32
|
||||
if (user_mode(regs) && regs->cs != __USER_CS)
|
||||
return get_segment_base(regs->cs);
|
||||
#else
|
||||
if (test_thread_flag(TIF_IA32)) {
|
||||
if (user_mode(regs) && regs->cs != __USER32_CS)
|
||||
return get_segment_base(regs->cs);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long perf_instruction_pointer(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long ip;
|
||||
|
||||
if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
|
||||
ip = perf_guest_cbs->get_guest_ip();
|
||||
else
|
||||
ip = instruction_pointer(regs);
|
||||
return perf_guest_cbs->get_guest_ip();
|
||||
|
||||
return ip;
|
||||
return regs->ip + code_segment_base(regs);
|
||||
}
|
||||
|
||||
unsigned long perf_misc_flags(struct pt_regs *regs)
|
||||
@@ -1838,7 +1907,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
|
||||
else
|
||||
misc |= PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
} else {
|
||||
if (!kernel_ip(regs->ip))
|
||||
if (user_mode(regs))
|
||||
misc |= PERF_RECORD_MISC_USER;
|
||||
else
|
||||
misc |= PERF_RECORD_MISC_KERNEL;
|
||||
|
@@ -516,6 +516,26 @@ static inline bool kernel_ip(unsigned long ip)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all PMUs provide the right context information to place the reported IP
|
||||
* into full context. Specifically segment registers are typically not
|
||||
* supplied.
|
||||
*
|
||||
* Assuming the address is a linear address (it is for IBS), we fake the CS and
|
||||
* vm86 mode using the known zero-based code segment and 'fix up' the registers
|
||||
* to reflect this.
|
||||
*
|
||||
* Intel PEBS/LBR appear to typically provide the effective address, nothing
|
||||
* much we can do about that but pray and treat it like a linear address.
|
||||
*/
|
||||
static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip)
|
||||
{
|
||||
regs->cs = kernel_ip(ip) ? __KERNEL_CS : __USER_CS;
|
||||
if (regs->flags & X86_VM_MASK)
|
||||
regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK);
|
||||
regs->ip = ip;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
|
||||
int amd_pmu_init(void);
|
||||
|
@@ -13,6 +13,8 @@
|
||||
|
||||
#include <asm/apic.h>
|
||||
|
||||
#include "perf_event.h"
|
||||
|
||||
static u32 ibs_caps;
|
||||
|
||||
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
|
||||
@@ -536,7 +538,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
|
||||
if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
|
||||
regs.flags &= ~PERF_EFLAGS_EXACT;
|
||||
} else {
|
||||
instruction_pointer_set(®s, ibs_data.regs[1]);
|
||||
set_linear_ip(®s, ibs_data.regs[1]);
|
||||
regs.flags |= PERF_EFLAGS_EXACT;
|
||||
}
|
||||
|
||||
|
@@ -1522,8 +1522,16 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr)
|
||||
arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL;
|
||||
arr[0].host = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask;
|
||||
arr[0].guest = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_host_mask;
|
||||
/*
|
||||
* If PMU counter has PEBS enabled it is not enough to disable counter
|
||||
* on a guest entry since PEBS memory write can overshoot guest entry
|
||||
* and corrupt guest memory. Disabling PEBS solves the problem.
|
||||
*/
|
||||
arr[1].msr = MSR_IA32_PEBS_ENABLE;
|
||||
arr[1].host = cpuc->pebs_enabled;
|
||||
arr[1].guest = 0;
|
||||
|
||||
*nr = 1;
|
||||
*nr = 2;
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -2000,6 +2008,7 @@ __init int intel_pmu_init(void)
|
||||
break;
|
||||
|
||||
case 28: /* Atom */
|
||||
case 54: /* Cedariew */
|
||||
memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
|
||||
|
@@ -499,7 +499,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
* We sampled a branch insn, rewind using the LBR stack
|
||||
*/
|
||||
if (ip == to) {
|
||||
regs->ip = from;
|
||||
set_linear_ip(regs, from);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
} while (to < ip);
|
||||
|
||||
if (to == ip) {
|
||||
regs->ip = old_to;
|
||||
set_linear_ip(regs, old_to);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -569,7 +569,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
|
||||
* A possible PERF_SAMPLE_REGS will have to transfer all regs.
|
||||
*/
|
||||
regs = *iregs;
|
||||
regs.ip = pebs->ip;
|
||||
regs.flags = pebs->flags;
|
||||
set_linear_ip(®s, pebs->ip);
|
||||
regs.bp = pebs->bp;
|
||||
regs.sp = pebs->sp;
|
||||
|
||||
|
@@ -686,7 +686,8 @@ void intel_pmu_lbr_init_atom(void)
|
||||
* to have an operational LBR which can freeze
|
||||
* on PMU interrupt
|
||||
*/
|
||||
if (boot_cpu_data.x86_mask < 10) {
|
||||
if (boot_cpu_data.x86_model == 28
|
||||
&& boot_cpu_data.x86_mask < 10) {
|
||||
pr_cont("LBR disabled due to erratum");
|
||||
return;
|
||||
}
|
||||
|
@@ -796,7 +796,6 @@ static struct intel_uncore_type *nhm_msr_uncores[] = {
|
||||
|
||||
DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(mm_cfg, mm_cfg, "config:63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
|
||||
|
||||
@@ -902,16 +901,21 @@ static struct attribute_group nhmex_uncore_cbox_format_group = {
|
||||
.attrs = nhmex_uncore_cbox_formats_attr,
|
||||
};
|
||||
|
||||
/* msr offset for each instance of cbox */
|
||||
static unsigned nhmex_cbox_msr_offsets[] = {
|
||||
0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type nhmex_uncore_cbox = {
|
||||
.name = "cbox",
|
||||
.num_counters = 6,
|
||||
.num_boxes = 8,
|
||||
.num_boxes = 10,
|
||||
.perf_ctr_bits = 48,
|
||||
.event_ctl = NHMEX_C0_MSR_PMON_EV_SEL0,
|
||||
.perf_ctr = NHMEX_C0_MSR_PMON_CTR0,
|
||||
.event_mask = NHMEX_PMON_RAW_EVENT_MASK,
|
||||
.box_ctl = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
|
||||
.msr_offset = NHMEX_C_MSR_OFFSET,
|
||||
.msr_offsets = nhmex_cbox_msr_offsets,
|
||||
.pair_ctr_ctl = 1,
|
||||
.ops = &nhmex_uncore_ops,
|
||||
.format_group = &nhmex_uncore_cbox_format_group
|
||||
@@ -1032,24 +1036,22 @@ static struct intel_uncore_type nhmex_uncore_bbox = {
|
||||
|
||||
static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
|
||||
struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||
struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
|
||||
|
||||
if (event->attr.config & NHMEX_S_PMON_MM_CFG_EN) {
|
||||
reg1->config = event->attr.config1;
|
||||
reg2->config = event->attr.config2;
|
||||
} else {
|
||||
reg1->config = ~0ULL;
|
||||
reg2->config = ~0ULL;
|
||||
}
|
||||
/* only TO_R_PROG_EV event uses the match/mask register */
|
||||
if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
|
||||
NHMEX_S_EVENT_TO_R_PROG_EV)
|
||||
return 0;
|
||||
|
||||
if (box->pmu->pmu_idx == 0)
|
||||
reg1->reg = NHMEX_S0_MSR_MM_CFG;
|
||||
else
|
||||
reg1->reg = NHMEX_S1_MSR_MM_CFG;
|
||||
|
||||
reg1->idx = 0;
|
||||
|
||||
reg1->config = event->attr.config1;
|
||||
reg2->config = event->attr.config2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1059,8 +1061,8 @@ static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct per
|
||||
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||
struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
|
||||
|
||||
wrmsrl(reg1->reg, 0);
|
||||
if (reg1->config != ~0ULL || reg2->config != ~0ULL) {
|
||||
if (reg1->idx != EXTRA_REG_NONE) {
|
||||
wrmsrl(reg1->reg, 0);
|
||||
wrmsrl(reg1->reg + 1, reg1->config);
|
||||
wrmsrl(reg1->reg + 2, reg2->config);
|
||||
wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
|
||||
@@ -1074,7 +1076,6 @@ static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
|
||||
&format_attr_edge.attr,
|
||||
&format_attr_inv.attr,
|
||||
&format_attr_thresh8.attr,
|
||||
&format_attr_mm_cfg.attr,
|
||||
&format_attr_match.attr,
|
||||
&format_attr_mask.attr,
|
||||
NULL,
|
||||
@@ -1142,6 +1143,9 @@ static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
|
||||
EVENT_EXTRA_END
|
||||
};
|
||||
|
||||
/* Nehalem-EX or Westmere-EX ? */
|
||||
bool uncore_nhmex;
|
||||
|
||||
static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
|
||||
{
|
||||
struct intel_uncore_extra_reg *er;
|
||||
@@ -1171,18 +1175,29 @@ static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64
|
||||
return false;
|
||||
|
||||
/* mask of the shared fields */
|
||||
mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
|
||||
if (uncore_nhmex)
|
||||
mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
|
||||
else
|
||||
mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
|
||||
er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
|
||||
|
||||
raw_spin_lock_irqsave(&er->lock, flags);
|
||||
/* add mask of the non-shared field if it's in use */
|
||||
if (__BITS_VALUE(atomic_read(&er->ref), idx, 8))
|
||||
mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
|
||||
if (uncore_nhmex)
|
||||
mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
else
|
||||
mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
}
|
||||
|
||||
if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
|
||||
atomic_add(1 << (idx * 8), &er->ref);
|
||||
mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
if (uncore_nhmex)
|
||||
mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
else
|
||||
mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
|
||||
WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
er->config &= ~mask;
|
||||
er->config |= (config & mask);
|
||||
ret = true;
|
||||
@@ -1216,7 +1231,10 @@ u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
|
||||
|
||||
/* get the non-shared control bits and shift them */
|
||||
idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
|
||||
config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
if (uncore_nhmex)
|
||||
config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
else
|
||||
config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
|
||||
if (new_idx > orig_idx) {
|
||||
idx = new_idx - orig_idx;
|
||||
config <<= 3 * idx;
|
||||
@@ -1226,6 +1244,10 @@ u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
|
||||
}
|
||||
|
||||
/* add the shared control bits back */
|
||||
if (uncore_nhmex)
|
||||
config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
|
||||
else
|
||||
config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
|
||||
config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
|
||||
if (modify) {
|
||||
/* adjust the main event selector */
|
||||
@@ -1264,7 +1286,8 @@ again:
|
||||
}
|
||||
|
||||
/* for the match/mask registers */
|
||||
if ((uncore_box_is_fake(box) || !reg2->alloc) &&
|
||||
if (reg2->idx != EXTRA_REG_NONE &&
|
||||
(uncore_box_is_fake(box) || !reg2->alloc) &&
|
||||
!nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
|
||||
goto fail;
|
||||
|
||||
@@ -1278,7 +1301,8 @@ again:
|
||||
if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
|
||||
nhmex_mbox_alter_er(event, idx[0], true);
|
||||
reg1->alloc |= alloc;
|
||||
reg2->alloc = 1;
|
||||
if (reg2->idx != EXTRA_REG_NONE)
|
||||
reg2->alloc = 1;
|
||||
}
|
||||
return NULL;
|
||||
fail:
|
||||
@@ -1342,9 +1366,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
struct extra_reg *er;
|
||||
unsigned msr;
|
||||
int reg_idx = 0;
|
||||
|
||||
if (WARN_ON_ONCE(reg1->idx != -1))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* The mbox events may require 2 extra MSRs at the most. But only
|
||||
* the lower 32 bits in these MSRs are significant, so we can use
|
||||
@@ -1355,11 +1376,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
continue;
|
||||
if (event->attr.config1 & ~er->valid_mask)
|
||||
return -EINVAL;
|
||||
if (er->idx == __BITS_VALUE(reg1->idx, 0, 8) ||
|
||||
er->idx == __BITS_VALUE(reg1->idx, 1, 8))
|
||||
continue;
|
||||
if (WARN_ON_ONCE(reg_idx >= 2))
|
||||
return -EINVAL;
|
||||
|
||||
msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
|
||||
if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
|
||||
@@ -1368,6 +1384,8 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
/* always use the 32~63 bits to pass the PLD config */
|
||||
if (er->idx == EXTRA_REG_NHMEX_M_PLD)
|
||||
reg_idx = 1;
|
||||
else if (WARN_ON_ONCE(reg_idx > 0))
|
||||
return -EINVAL;
|
||||
|
||||
reg1->idx &= ~(0xff << (reg_idx * 8));
|
||||
reg1->reg &= ~(0xffff << (reg_idx * 16));
|
||||
@@ -1376,17 +1394,21 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
reg1->config = event->attr.config1;
|
||||
reg_idx++;
|
||||
}
|
||||
/* use config2 to pass the filter config */
|
||||
reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
|
||||
if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
|
||||
reg2->config = event->attr.config2;
|
||||
else
|
||||
reg2->config = ~0ULL;
|
||||
if (box->pmu->pmu_idx == 0)
|
||||
reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
|
||||
else
|
||||
reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
|
||||
|
||||
/*
|
||||
* The mbox only provides ability to perform address matching
|
||||
* for the PLD events.
|
||||
*/
|
||||
if (reg_idx == 2) {
|
||||
reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
|
||||
if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
|
||||
reg2->config = event->attr.config2;
|
||||
else
|
||||
reg2->config = ~0ULL;
|
||||
if (box->pmu->pmu_idx == 0)
|
||||
reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
|
||||
else
|
||||
reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1422,34 +1444,36 @@ static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct per
|
||||
wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
|
||||
nhmex_mbox_shared_reg_config(box, idx));
|
||||
|
||||
wrmsrl(reg2->reg, 0);
|
||||
if (reg2->config != ~0ULL) {
|
||||
wrmsrl(reg2->reg + 1,
|
||||
reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
|
||||
wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
|
||||
(reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
|
||||
wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
|
||||
if (reg2->idx != EXTRA_REG_NONE) {
|
||||
wrmsrl(reg2->reg, 0);
|
||||
if (reg2->config != ~0ULL) {
|
||||
wrmsrl(reg2->reg + 1,
|
||||
reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
|
||||
wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
|
||||
(reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
|
||||
wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
|
||||
}
|
||||
}
|
||||
|
||||
wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
|
||||
}
|
||||
|
||||
DEFINE_UNCORE_FORMAT_ATTR(count_mode, count_mode, "config:2-3");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode, "config:4-5");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(wrap_mode, wrap_mode, "config:6");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(flag_mode, flag_mode, "config:7");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(inc_sel, inc_sel, "config:9-13");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel, set_flag_sel, "config:19-21");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_cfg, filter_cfg, "config2:63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_match, filter_match, "config2:0-33");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask, "config2:34-61");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(dsp, dsp, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(thr, thr, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(fvc, fvc, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(pgt, pgt, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(map, map, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(iss, iss, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(pld, pld, "config1:32-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(count_mode, count_mode, "config:2-3");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode, "config:4-5");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(wrap_mode, wrap_mode, "config:6");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(flag_mode, flag_mode, "config:7");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(inc_sel, inc_sel, "config:9-13");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel, set_flag_sel, "config:19-21");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en, filter_cfg_en, "config2:63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_match, filter_match, "config2:0-33");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask, "config2:34-61");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(dsp, dsp, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(thr, thr, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(fvc, fvc, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(pgt, pgt, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(map, map, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(iss, iss, "config1:0-31");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(pld, pld, "config1:32-63");
|
||||
|
||||
static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
|
||||
&format_attr_count_mode.attr,
|
||||
@@ -1458,7 +1482,7 @@ static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
|
||||
&format_attr_flag_mode.attr,
|
||||
&format_attr_inc_sel.attr,
|
||||
&format_attr_set_flag_sel.attr,
|
||||
&format_attr_filter_cfg.attr,
|
||||
&format_attr_filter_cfg_en.attr,
|
||||
&format_attr_filter_match.attr,
|
||||
&format_attr_filter_mask.attr,
|
||||
&format_attr_dsp.attr,
|
||||
@@ -1482,6 +1506,12 @@ static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
|
||||
static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
|
||||
INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
|
||||
INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
|
||||
static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
|
||||
NHMEX_UNCORE_OPS_COMMON_INIT(),
|
||||
.enable_event = nhmex_mbox_msr_enable_event,
|
||||
@@ -1513,7 +1543,7 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
|
||||
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||
int port;
|
||||
|
||||
/* adjust the main event selector */
|
||||
/* adjust the main event selector and extra register index */
|
||||
if (reg1->idx % 2) {
|
||||
reg1->idx--;
|
||||
hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
|
||||
@@ -1522,29 +1552,17 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
|
||||
hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
|
||||
}
|
||||
|
||||
/* adjust address or config of extra register */
|
||||
/* adjust extra register config */
|
||||
port = reg1->idx / 6 + box->pmu->pmu_idx * 4;
|
||||
switch (reg1->idx % 6) {
|
||||
case 0:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
|
||||
break;
|
||||
case 1:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
|
||||
break;
|
||||
case 2:
|
||||
/* the 8~15 bits to the 0~7 bits */
|
||||
/* shift the 8~15 bits to the 0~7 bits */
|
||||
reg1->config >>= 8;
|
||||
break;
|
||||
case 3:
|
||||
/* the 0~7 bits to the 8~15 bits */
|
||||
/* shift the 0~7 bits to the 8~15 bits */
|
||||
reg1->config <<= 8;
|
||||
break;
|
||||
case 4:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
|
||||
break;
|
||||
case 5:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1671,7 +1689,7 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
|
||||
struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
|
||||
int port, idx;
|
||||
int idx;
|
||||
|
||||
idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
|
||||
NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
|
||||
@@ -1681,27 +1699,11 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event
|
||||
reg1->idx = idx;
|
||||
reg1->config = event->attr.config1;
|
||||
|
||||
port = idx / 6 + box->pmu->pmu_idx * 4;
|
||||
idx %= 6;
|
||||
switch (idx) {
|
||||
case 0:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
|
||||
break;
|
||||
case 1:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_QLX_CFG(port);
|
||||
break;
|
||||
switch (idx % 6) {
|
||||
case 4:
|
||||
case 5:
|
||||
if (idx == 4)
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
|
||||
else
|
||||
reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
|
||||
reg2->config = event->attr.config2;
|
||||
hwc->config |= event->attr.config & (~0ULL << 32);
|
||||
reg2->config = event->attr.config2;
|
||||
break;
|
||||
};
|
||||
return 0;
|
||||
@@ -1727,28 +1729,34 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||
struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
|
||||
int idx, er_idx;
|
||||
int idx, port;
|
||||
|
||||
idx = reg1->idx % 6;
|
||||
er_idx = idx;
|
||||
if (er_idx > 2)
|
||||
er_idx--;
|
||||
er_idx += (reg1->idx / 6) * 5;
|
||||
idx = reg1->idx;
|
||||
port = idx / 6 + box->pmu->pmu_idx * 4;
|
||||
|
||||
switch (idx) {
|
||||
switch (idx % 6) {
|
||||
case 0:
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
|
||||
break;
|
||||
case 1:
|
||||
wrmsrl(reg1->reg, reg1->config);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
wrmsrl(reg1->reg, nhmex_rbox_shared_reg_config(box, er_idx));
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
|
||||
nhmex_rbox_shared_reg_config(box, 2 + (idx / 6) * 5));
|
||||
break;
|
||||
case 4:
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
|
||||
hwc->config >> 32);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
|
||||
break;
|
||||
case 5:
|
||||
wrmsrl(reg1->reg, reg1->config);
|
||||
wrmsrl(reg1->reg + 1, hwc->config >> 32);
|
||||
wrmsrl(reg1->reg + 2, reg2->config);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
|
||||
hwc->config >> 32);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
|
||||
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -1756,8 +1764,8 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per
|
||||
(hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
|
||||
}
|
||||
|
||||
DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config:32-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config1:0-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
|
||||
@@ -2303,6 +2311,7 @@ int uncore_pmu_event_init(struct perf_event *event)
|
||||
event->hw.idx = -1;
|
||||
event->hw.last_tag = ~0ULL;
|
||||
event->hw.extra_reg.idx = EXTRA_REG_NONE;
|
||||
event->hw.branch_reg.idx = EXTRA_REG_NONE;
|
||||
|
||||
if (event->attr.config == UNCORE_FIXED_EVENT) {
|
||||
/* no fixed counter */
|
||||
@@ -2373,7 +2382,7 @@ static void __init uncore_type_exit(struct intel_uncore_type *type)
|
||||
type->attr_groups[1] = NULL;
|
||||
}
|
||||
|
||||
static void uncore_types_exit(struct intel_uncore_type **types)
|
||||
static void __init uncore_types_exit(struct intel_uncore_type **types)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; types[i]; i++)
|
||||
@@ -2814,7 +2823,13 @@ static int __init uncore_cpu_init(void)
|
||||
snbep_uncore_cbox.num_boxes = max_cores;
|
||||
msr_uncores = snbep_msr_uncores;
|
||||
break;
|
||||
case 46:
|
||||
case 46: /* Nehalem-EX */
|
||||
uncore_nhmex = true;
|
||||
case 47: /* Westmere-EX aka. Xeon E7 */
|
||||
if (!uncore_nhmex)
|
||||
nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
|
||||
if (nhmex_uncore_cbox.num_boxes > max_cores)
|
||||
nhmex_uncore_cbox.num_boxes = max_cores;
|
||||
msr_uncores = nhmex_msr_uncores;
|
||||
break;
|
||||
default:
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include "perf_event.h"
|
||||
|
||||
#define UNCORE_PMU_NAME_LEN 32
|
||||
#define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC)
|
||||
#define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC)
|
||||
|
||||
#define UNCORE_FIXED_EVENT 0xff
|
||||
#define UNCORE_PMC_IDX_MAX_GENERIC 8
|
||||
@@ -230,6 +230,7 @@
|
||||
#define NHMEX_S1_MSR_MASK 0xe5a
|
||||
|
||||
#define NHMEX_S_PMON_MM_CFG_EN (0x1ULL << 63)
|
||||
#define NHMEX_S_EVENT_TO_R_PROG_EV 0
|
||||
|
||||
/* NHM-EX Mbox */
|
||||
#define NHMEX_M0_MSR_GLOBAL_CTL 0xca0
|
||||
@@ -275,18 +276,12 @@
|
||||
NHMEX_M_PMON_CTL_INC_SEL_MASK | \
|
||||
NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
|
||||
|
||||
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK 0x1f
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK (0x7 << 5)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK (0x7 << 8)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR (1 << 23)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK \
|
||||
(NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 11) - 1) | (1 << 23))
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n)))
|
||||
|
||||
#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 12) - 1) | (1 << 24))
|
||||
#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (12 + 3 * (n)))
|
||||
|
||||
/*
|
||||
* use the 9~13 bits to select event If the 7th bit is not set,
|
||||
* otherwise use the 19~21 bits to select event.
|
||||
@@ -368,6 +363,7 @@ struct intel_uncore_type {
|
||||
unsigned num_shared_regs:8;
|
||||
unsigned single_fixed:1;
|
||||
unsigned pair_ctr_ctl:1;
|
||||
unsigned *msr_offsets;
|
||||
struct event_constraint unconstrainted;
|
||||
struct event_constraint *constraints;
|
||||
struct intel_uncore_pmu *pmus;
|
||||
@@ -485,29 +481,31 @@ unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx)
|
||||
return idx * 8 + box->pmu->type->perf_ctr;
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
|
||||
static inline unsigned uncore_msr_box_offset(struct intel_uncore_box *box)
|
||||
{
|
||||
struct intel_uncore_pmu *pmu = box->pmu;
|
||||
return pmu->type->msr_offsets ?
|
||||
pmu->type->msr_offsets[pmu->pmu_idx] :
|
||||
pmu->type->msr_offset * pmu->pmu_idx;
|
||||
}
|
||||
|
||||
static inline unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
|
||||
{
|
||||
if (!box->pmu->type->box_ctl)
|
||||
return 0;
|
||||
return box->pmu->type->box_ctl +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
return box->pmu->type->box_ctl + uncore_msr_box_offset(box);
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
|
||||
static inline unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
|
||||
{
|
||||
if (!box->pmu->type->fixed_ctl)
|
||||
return 0;
|
||||
return box->pmu->type->fixed_ctl +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
return box->pmu->type->fixed_ctl + uncore_msr_box_offset(box);
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
|
||||
static inline unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
|
||||
{
|
||||
return box->pmu->type->fixed_ctr +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
return box->pmu->type->fixed_ctr + uncore_msr_box_offset(box);
|
||||
}
|
||||
|
||||
static inline
|
||||
@@ -515,7 +513,7 @@ unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
|
||||
{
|
||||
return box->pmu->type->event_ctl +
|
||||
(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
uncore_msr_box_offset(box);
|
||||
}
|
||||
|
||||
static inline
|
||||
@@ -523,7 +521,7 @@ unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
|
||||
{
|
||||
return box->pmu->type->perf_ctr +
|
||||
(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
uncore_msr_box_offset(box);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@@ -270,7 +270,7 @@ void fixup_irqs(void)
|
||||
|
||||
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
|
||||
break_affinity = 1;
|
||||
affinity = cpu_all_mask;
|
||||
affinity = cpu_online_mask;
|
||||
}
|
||||
|
||||
chip = irq_data_get_irq_chip(data);
|
||||
@@ -328,6 +328,7 @@ void fixup_irqs(void)
|
||||
chip->irq_retrigger(data);
|
||||
raw_spin_unlock(&desc->lock);
|
||||
}
|
||||
__this_cpu_write(vector_irq[vector], -1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -107,7 +107,7 @@ static int __init create_setup_data_nodes(struct dentry *parent)
|
||||
{
|
||||
struct setup_data_node *node;
|
||||
struct setup_data *data;
|
||||
int error = -ENOMEM;
|
||||
int error;
|
||||
struct dentry *d;
|
||||
struct page *pg;
|
||||
u64 pa_data;
|
||||
@@ -121,8 +121,10 @@ static int __init create_setup_data_nodes(struct dentry *parent)
|
||||
|
||||
while (pa_data) {
|
||||
node = kmalloc(sizeof(*node), GFP_KERNEL);
|
||||
if (!node)
|
||||
if (!node) {
|
||||
error = -ENOMEM;
|
||||
goto err_dir;
|
||||
}
|
||||
|
||||
pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
|
||||
if (PageHighMem(pg)) {
|
||||
|
@@ -143,11 +143,12 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr,
|
||||
unsigned int *current_size)
|
||||
{
|
||||
struct microcode_header_amd *mc_hdr;
|
||||
unsigned int actual_size;
|
||||
unsigned int actual_size, patch_size;
|
||||
u16 equiv_cpu_id;
|
||||
|
||||
/* size of the current patch we're staring at */
|
||||
*current_size = *(u32 *)(ucode_ptr + 4) + SECTION_HDR_SIZE;
|
||||
patch_size = *(u32 *)(ucode_ptr + 4);
|
||||
*current_size = patch_size + SECTION_HDR_SIZE;
|
||||
|
||||
equiv_cpu_id = find_equiv_id();
|
||||
if (!equiv_cpu_id)
|
||||
@@ -174,7 +175,7 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr,
|
||||
/*
|
||||
* now that the header looks sane, verify its size
|
||||
*/
|
||||
actual_size = verify_ucode_size(cpu, *current_size, leftover_size);
|
||||
actual_size = verify_ucode_size(cpu, patch_size, leftover_size);
|
||||
if (!actual_size)
|
||||
return 0;
|
||||
|
||||
|
@@ -225,6 +225,9 @@ static ssize_t microcode_write(struct file *file, const char __user *buf,
|
||||
if (do_microcode_update(buf, len) == 0)
|
||||
ret = (ssize_t)len;
|
||||
|
||||
if (ret > 0)
|
||||
perf_check_microcode();
|
||||
|
||||
mutex_unlock(µcode_mutex);
|
||||
put_online_cpus();
|
||||
|
||||
|
Reference in New Issue
Block a user