Skip to content

Commit

Permalink
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull perf fixes from Ingo Molnar:
 "Most of the kernel diffstat relates to a group of Intel P6 and KNC
  (Xeon-Phi Knights Corner) PMU driver fixes, neither of which is in
  heavy use, so we took the fixes.

  The rest is diverse smallish fixes to the tooling and kernel side."

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86: Remove unused variable in nhmex_rbox_alter_er()
  perf/x86: Enable overflow on Intel KNC with a custom knc_pmu_handle_irq()
  perf/x86: Remove cpuc->enable check on Intl KNC event enable/disable
  perf/x86: Make Intel KNC use full 40-bit width of counters
  perf/x86/uncore: Handle pci_read_config_dword() errors
  perf/x86: Remove P6 cpuc->enabled check
  perf/x86: Update/fix generic events on P6 PMU
  perf/x86: Fix P6 FP_ASSIST event constraint
  perf, cpu hotplug: Use cached value of smp_processor_id()
  perf, cpu hotplug: Run CPU_STARTING notifiers with irqs disabled
  x86/perf: Fix virtualization sanity check
  perf test: Fix exclude_guest parse events tests
  perf tools: do not flush maps on COMM for perf report
  perf help: Fix --help for builtins
  perf trace: Check if sample raw_data field is set
  perf trace: Validate syscall id before growing syscall table
  • Loading branch information
torvalds committed Oct 26, 2012
2 parents f48d427 + 64dfab8 commit 6a2e52f
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 61 deletions.
10 changes: 6 additions & 4 deletions arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,14 @@ static bool check_hw_exists(void)
}

/*
* Now write a value and read it back to see if it matches,
* this is needed to detect certain hardware emulators (qemu/kvm)
* that don't trap on the MSR access and always return 0s.
* Read the current value, change it and read it back to see if it
* matches, this is needed to detect certain hardware emulators
* (qemu/kvm) that don't trap on the MSR access and always return 0s.
*/
val = 0xabcdUL;
reg = x86_pmu_event_addr(0);
if (rdmsrl_safe(reg, &val))
goto msr_fail;
val ^= 0xffffUL;
ret = wrmsrl_safe(reg, val);
ret |= rdmsrl_safe(reg, &val_new);
if (ret || val != val_new)
Expand Down
45 changes: 28 additions & 17 deletions arch/x86/kernel/cpu/perf_event_intel_uncore.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,24 @@ static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
{
struct pci_dev *pdev = box->pci_dev;
int box_ctl = uncore_pci_box_ctl(box);
u32 config;
u32 config = 0;

pci_read_config_dword(pdev, box_ctl, &config);
config |= SNBEP_PMON_BOX_CTL_FRZ;
pci_write_config_dword(pdev, box_ctl, config);
if (!pci_read_config_dword(pdev, box_ctl, &config)) {
config |= SNBEP_PMON_BOX_CTL_FRZ;
pci_write_config_dword(pdev, box_ctl, config);
}
}

static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
{
struct pci_dev *pdev = box->pci_dev;
int box_ctl = uncore_pci_box_ctl(box);
u32 config;
u32 config = 0;

pci_read_config_dword(pdev, box_ctl, &config);
config &= ~SNBEP_PMON_BOX_CTL_FRZ;
pci_write_config_dword(pdev, box_ctl, config);
if (!pci_read_config_dword(pdev, box_ctl, &config)) {
config &= ~SNBEP_PMON_BOX_CTL_FRZ;
pci_write_config_dword(pdev, box_ctl, config);
}
}

static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
Expand All @@ -156,7 +158,7 @@ static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct pe
{
struct pci_dev *pdev = box->pci_dev;
struct hw_perf_event *hwc = &event->hw;
u64 count;
u64 count = 0;

pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
Expand Down Expand Up @@ -603,11 +605,12 @@ static struct pci_driver snbep_uncore_pci_driver = {
/*
* build pci bus to socket mapping
*/
static void snbep_pci2phy_map_init(void)
static int snbep_pci2phy_map_init(void)
{
struct pci_dev *ubox_dev = NULL;
int i, bus, nodeid;
u32 config;
int err = 0;
u32 config = 0;

while (1) {
/* find the UBOX device */
Expand All @@ -618,10 +621,14 @@ static void snbep_pci2phy_map_init(void)
break;
bus = ubox_dev->bus->number;
/* get the Node ID of the local register */
pci_read_config_dword(ubox_dev, 0x40, &config);
err = pci_read_config_dword(ubox_dev, 0x40, &config);
if (err)
break;
nodeid = config;
/* get the Node ID mapping */
pci_read_config_dword(ubox_dev, 0x54, &config);
err = pci_read_config_dword(ubox_dev, 0x54, &config);
if (err)
break;
/*
* every three bits in the Node ID mapping register maps
* to a particular node.
Expand All @@ -633,7 +640,11 @@ static void snbep_pci2phy_map_init(void)
}
}
};
return;

if (ubox_dev)
pci_dev_put(ubox_dev);

return err ? pcibios_err_to_errno(err) : 0;
}
/* end of Sandy Bridge-EP uncore support */

Expand Down Expand Up @@ -1547,7 +1558,6 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
int port;

/* adjust the main event selector and extra register index */
if (reg1->idx % 2) {
Expand All @@ -1559,7 +1569,6 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
}

/* adjust extra register config */
port = reg1->idx / 6 + box->pmu->pmu_idx * 4;
switch (reg1->idx % 6) {
case 2:
/* shift the 8~15 bits to the 0~7 bits */
Expand Down Expand Up @@ -2578,9 +2587,11 @@ static int __init uncore_pci_init(void)

switch (boot_cpu_data.x86_model) {
case 45: /* Sandy Bridge-EP */
ret = snbep_pci2phy_map_init();
if (ret)
return ret;
pci_uncores = snbep_pci_uncores;
uncore_pci_driver = &snbep_uncore_pci_driver;
snbep_pci2phy_map_init();
break;
default:
return 0;
Expand Down
93 changes: 82 additions & 11 deletions arch/x86/kernel/cpu/perf_event_knc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <linux/perf_event.h>
#include <linux/types.h>

#include <asm/hardirq.h>

#include "perf_event.h"

static const u64 knc_perfmon_event_map[] =
Expand Down Expand Up @@ -173,30 +175,100 @@ static void knc_pmu_enable_all(int added)
static inline void
knc_pmu_disable_event(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
u64 val;

val = hwc->config;
if (cpuc->enabled)
val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;

(void)wrmsrl_safe(hwc->config_base + hwc->idx, val);
}

static void knc_pmu_enable_event(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
u64 val;

val = hwc->config;
if (cpuc->enabled)
val |= ARCH_PERFMON_EVENTSEL_ENABLE;
val |= ARCH_PERFMON_EVENTSEL_ENABLE;

(void)wrmsrl_safe(hwc->config_base + hwc->idx, val);
}

static inline u64 knc_pmu_get_status(void)
{
u64 status;

rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_STATUS, status);

return status;
}

static inline void knc_pmu_ack_status(u64 ack)
{
wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL, ack);
}

static int knc_pmu_handle_irq(struct pt_regs *regs)
{
struct perf_sample_data data;
struct cpu_hw_events *cpuc;
int handled = 0;
int bit, loops;
u64 status;

cpuc = &__get_cpu_var(cpu_hw_events);

knc_pmu_disable_all();

status = knc_pmu_get_status();
if (!status) {
knc_pmu_enable_all(0);
return handled;
}

loops = 0;
again:
knc_pmu_ack_status(status);
if (++loops > 100) {
WARN_ONCE(1, "perf: irq loop stuck!\n");
perf_event_print_debug();
goto done;
}

inc_irq_stat(apic_perf_irqs);

for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
struct perf_event *event = cpuc->events[bit];

handled++;

if (!test_bit(bit, cpuc->active_mask))
continue;

if (!intel_pmu_save_and_restart(event))
continue;

perf_sample_data_init(&data, 0, event->hw.last_period);

if (perf_event_overflow(event, &data, regs))
x86_pmu_stop(event, 0);
}

/*
* Repeat if there is more work to be done:
*/
status = knc_pmu_get_status();
if (status)
goto again;

done:
knc_pmu_enable_all(0);

return handled;
}


PMU_FORMAT_ATTR(event, "config:0-7" );
PMU_FORMAT_ATTR(umask, "config:8-15" );
PMU_FORMAT_ATTR(edge, "config:18" );
Expand All @@ -214,7 +286,7 @@ static struct attribute *intel_knc_formats_attr[] = {

static __initconst struct x86_pmu knc_pmu = {
.name = "knc",
.handle_irq = x86_pmu_handle_irq,
.handle_irq = knc_pmu_handle_irq,
.disable_all = knc_pmu_disable_all,
.enable_all = knc_pmu_enable_all,
.enable = knc_pmu_enable_event,
Expand All @@ -226,12 +298,11 @@ static __initconst struct x86_pmu knc_pmu = {
.event_map = knc_pmu_event_map,
.max_events = ARRAY_SIZE(knc_perfmon_event_map),
.apic = 1,
.max_period = (1ULL << 31) - 1,
.max_period = (1ULL << 39) - 1,
.version = 0,
.num_counters = 2,
/* in theory 40 bits, early silicon is buggy though */
.cntval_bits = 32,
.cntval_mask = (1ULL << 32) - 1,
.cntval_bits = 40,
.cntval_mask = (1ULL << 40) - 1,
.get_event_constraints = x86_get_event_constraints,
.event_constraints = knc_event_constraints,
.format_attrs = intel_knc_formats_attr,
Expand Down
Loading

0 comments on commit 6a2e52f

Please sign in to comment.