Commit 24880bef authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'oprofile-removal-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/linux

Pull oprofile and dcookies removal from Viresh Kumar:
 "Remove oprofile and dcookies support

  The 'oprofile' user-space tools don't use the kernel OPROFILE support
  any more, and haven't in a long time. User-space has been converted to
  the perf interfaces.

  The dcookies stuff is only used by the oprofile code. Now that
  oprofile's support is getting removed from the kernel, there is no
  need for dcookies as well.

  Remove kernel's old oprofile and dcookies support"

* tag 'oprofile-removal-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/linux:
  fs: Remove dcookies support
  drivers: Remove CONFIG_OPROFILE support
  arch: xtensa: Remove CONFIG_OPROFILE support
  arch: x86: Remove CONFIG_OPROFILE support
  arch: sparc: Remove CONFIG_OPROFILE support
  arch: sh: Remove CONFIG_OPROFILE support
  arch: s390: Remove CONFIG_OPROFILE support
  arch: powerpc: Remove oprofile
  arch: powerpc: Stop building and using oprofile
  arch: parisc: Remove CONFIG_OPROFILE support
  arch: mips: Remove CONFIG_OPROFILE support
  arch: microblaze: Remove CONFIG_OPROFILE support
  arch: ia64: Remove rest of perfmon support
  arch: ia64: Remove CONFIG_OPROFILE support
  arch: hexagon: Don't select HAVE_OPROFILE
  arch: arc: Remove CONFIG_OPROFILE support
  arch: arm: Remove CONFIG_OPROFILE support
  arch: alpha: Remove CONFIG_OPROFILE support
parents b52bb135 be65de6b
......@@ -8,8 +8,7 @@ Although RCU is usually used to protect read-mostly data structures,
it is possible to use RCU to provide dynamic non-maskable interrupt
handlers, as well as dynamic irq handlers. This document describes
how to do this, drawing loosely from Zwane Mwaikambo's NMI-timer
work in "arch/x86/oprofile/nmi_timer_int.c" and in
"arch/x86/kernel/traps.c".
work in "arch/x86/kernel/traps.c".
The relevant pieces of code are listed below, each followed by a
brief explanation::
......
......@@ -3458,20 +3458,6 @@
For example, to override I2C bus2:
omap_mux=i2c2_scl.i2c2_scl=0x100,i2c2_sda.i2c2_sda=0x100
oprofile.timer= [HW]
Use timer interrupt instead of performance counters
oprofile.cpu_type= Force an oprofile cpu type
This might be useful if you have an older oprofile
userland or if you want common events.
Format: { arch_perfmon }
arch_perfmon: [X86] Force use of architectural
perfmon on Intel CPUs instead of the
CPU specific event set.
timer: [X86] Force use of architectural NMI
timer mode (see also oprofile.timer
for generic hr timer mode)
oops=panic Always panic on oopses. Default is to just kill the
process, but there is a small probability of
deadlocking the machine.
......
......@@ -1317,7 +1317,6 @@ When kbuild executes, the following steps are followed (roughly):
libs-y += arch/sparc/lib/
drivers-$(CONFIG_PM) += arch/sparc/power/
drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/
7.5 Architecture-specific boot images
-------------------------------------
......
......@@ -135,7 +135,6 @@ FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fo
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
OPROFILE_MAGIC 0x6f70726f super_block ``drivers/oprofile/oprofilefs.h``
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
......
......@@ -141,7 +141,6 @@ FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fo
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
OPROFILE_MAGIC 0x6f70726f super_block ``drivers/oprofile/oprofilefs.h``
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
......
......@@ -124,7 +124,6 @@ FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fo
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
OPROFILE_MAGIC 0x6f70726f super_block ``drivers/oprofile/oprofilefs.h``
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
......
......@@ -1413,7 +1413,6 @@ F: arch/arm*/include/asm/hw_breakpoint.h
F: arch/arm*/include/asm/perf_event.h
F: arch/arm*/kernel/hw_breakpoint.c
F: arch/arm*/kernel/perf_*
F: arch/arm/oprofile/common.c
F: drivers/perf/
F: include/linux/perf/arm_pmu.h
......@@ -4060,7 +4059,6 @@ W: http://www.ibm.com/developerworks/power/cell/
F: arch/powerpc/include/asm/cell*.h
F: arch/powerpc/include/asm/spu*.h
F: arch/powerpc/include/uapi/asm/spu*.h
F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/
CELLWISE CW2015 BATTERY DRIVER
......@@ -13291,15 +13289,6 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/drivers/opl4/
OPROFILE
M: Robert Richter <rric@kernel.org>
L: oprofile-list@lists.sf.net
S: Maintained
F: arch/*/include/asm/oprofile*.h
F: arch/*/oprofile/
F: drivers/oprofile/
F: include/linux/oprofile.h
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
M: Mark Fasheh <mark@fasheh.com>
M: Joel Becker <jlbec@evilplan.org>
......
......@@ -33,38 +33,6 @@ config HOTPLUG_SMT
config GENERIC_ENTRY
bool
config OPROFILE
tristate "OProfile system profiling"
depends on PROFILING
depends on HAVE_OPROFILE
select RING_BUFFER
select RING_BUFFER_ALLOW_SWAP
help
OProfile is a profiling system capable of profiling the
whole system, include the kernel, kernel modules, libraries,
and applications.
If unsure, say N.
config OPROFILE_EVENT_MULTIPLEX
bool "OProfile multiplexing support (EXPERIMENTAL)"
default n
depends on OPROFILE && X86
help
The number of hardware counters is limited. The multiplexing
feature enables OProfile to gather more events than counters
are provided by the hardware. This is realized by switching
between events at a user specified time interval.
If unsure, say N.
config HAVE_OPROFILE
bool
config OPROFILE_NMI_TIMER
def_bool y
depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI && !PPC64
config KPROBES
bool "Kprobes"
depends on MODULES
......
......@@ -14,7 +14,6 @@ config ALPHA
select HAVE_AOUT
select HAVE_ASM_MODVERSIONS
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
select NEED_DMA_MAP_STATE
......
......@@ -40,7 +40,6 @@ head-y := arch/alpha/kernel/head.o
core-y += arch/alpha/kernel/ arch/alpha/mm/
core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/
drivers-$(CONFIG_OPROFILE) += arch/alpha/oprofile/
libs-y += arch/alpha/lib/
# export what is needed by arch/alpha/boot/Makefile
......
# SPDX-License-Identifier: GPL-2.0
ccflags-y := -Werror -Wno-sign-compare
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o
oprofile-$(CONFIG_ALPHA_GENERIC) += op_model_ev4.o \
op_model_ev5.o \
op_model_ev6.o \
op_model_ev67.o
oprofile-$(CONFIG_ALPHA_EV4) += op_model_ev4.o
oprofile-$(CONFIG_ALPHA_EV5) += op_model_ev5.o
oprofile-$(CONFIG_ALPHA_EV6) += op_model_ev6.o \
op_model_ev67.o
/**
* @file arch/alpha/oprofile/common.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/errno.h>
#include <asm/ptrace.h>
#include <asm/special_insns.h>
#include "op_impl.h"
extern struct op_axp_model op_model_ev4 __attribute__((weak));
extern struct op_axp_model op_model_ev5 __attribute__((weak));
extern struct op_axp_model op_model_pca56 __attribute__((weak));
extern struct op_axp_model op_model_ev6 __attribute__((weak));
extern struct op_axp_model op_model_ev67 __attribute__((weak));
static struct op_axp_model *model;
extern void (*perf_irq)(unsigned long, struct pt_regs *);
static void (*save_perf_irq)(unsigned long, struct pt_regs *);
static struct op_counter_config ctr[20];
static struct op_system_config sys;
static struct op_register_config reg;
/* Called from do_entInt to handle the performance monitor interrupt. */
static void
op_handle_interrupt(unsigned long which, struct pt_regs *regs)
{
model->handle_interrupt(which, regs, ctr);
/* If the user has selected an interrupt frequency that is
not exactly the width of the counter, write a new value
into the counter such that it'll overflow after N more
events. */
if ((reg.need_reset >> which) & 1)
model->reset_ctr(&reg, which);
}
static int
op_axp_setup(void)
{
unsigned long i, e;
/* Install our interrupt handler into the existing hook. */
save_perf_irq = perf_irq;
perf_irq = op_handle_interrupt;
/* Compute the mask of enabled counters. */
for (i = e = 0; i < model->num_counters; ++i)
if (ctr[i].enabled)
e |= 1 << i;
reg.enable = e;
/* Pre-compute the values to stuff in the hardware registers. */
model->reg_setup(&reg, ctr, &sys);
/* Configure the registers on all cpus. */
smp_call_function(model->cpu_setup, &reg, 1);
model->cpu_setup(&reg);
return 0;
}
static void
op_axp_shutdown(void)
{
/* Remove our interrupt handler. We may be removing this module. */
perf_irq = save_perf_irq;
}
static void
op_axp_cpu_start(void *dummy)
{
wrperfmon(1, reg.enable);
}
static int
op_axp_start(void)
{
smp_call_function(op_axp_cpu_start, NULL, 1);
op_axp_cpu_start(NULL);
return 0;
}
static inline void
op_axp_cpu_stop(void *dummy)
{
/* Disable performance monitoring for all counters. */
wrperfmon(0, -1);
}
static void
op_axp_stop(void)
{
smp_call_function(op_axp_cpu_stop, NULL, 1);
op_axp_cpu_stop(NULL);
}
static int
op_axp_create_files(struct dentry *root)
{
int i;
for (i = 0; i < model->num_counters; ++i) {
struct dentry *dir;
char buf[4];
snprintf(buf, sizeof buf, "%d", i);
dir = oprofilefs_mkdir(root, buf);
oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
oprofilefs_create_ulong(dir, "event", &ctr[i].event);
oprofilefs_create_ulong(dir, "count", &ctr[i].count);
/* Dummies. */
oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
oprofilefs_create_ulong(dir, "user", &ctr[i].user);
oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
}
if (model->can_set_proc_mode) {
oprofilefs_create_ulong(root, "enable_pal",
&sys.enable_pal);
oprofilefs_create_ulong(root, "enable_kernel",
&sys.enable_kernel);
oprofilefs_create_ulong(root, "enable_user",
&sys.enable_user);
}
return 0;
}
int __init
oprofile_arch_init(struct oprofile_operations *ops)
{
struct op_axp_model *lmodel = NULL;
switch (implver()) {
case IMPLVER_EV4:
lmodel = &op_model_ev4;
break;
case IMPLVER_EV5:
/* 21164PC has a slightly different set of events.
Recognize the chip by the presence of the MAX insns. */
if (!amask(AMASK_MAX))
lmodel = &op_model_pca56;
else
lmodel = &op_model_ev5;
break;
case IMPLVER_EV6:
/* 21264A supports ProfileMe.
Recognize the chip by the presence of the CIX insns. */
if (!amask(AMASK_CIX))
lmodel = &op_model_ev67;
else
lmodel = &op_model_ev6;
break;
}
if (!lmodel)
return -ENODEV;
model = lmodel;
ops->create_files = op_axp_create_files;
ops->setup = op_axp_setup;
ops->shutdown = op_axp_shutdown;
ops->start = op_axp_start;
ops->stop = op_axp_stop;
ops->cpu_type = lmodel->cpu_type;
printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
lmodel->cpu_type);
return 0;
}
void
oprofile_arch_exit(void)
{
}
/**
* @file arch/alpha/oprofile/op_impl.h
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
/* Per-counter configuration as set via oprofilefs. */
struct op_counter_config {
unsigned long enabled;
unsigned long event;
unsigned long count;
/* Dummies because I am too lazy to hack the userspace tools. */
unsigned long kernel;
unsigned long user;
unsigned long unit_mask;
};
/* System-wide configuration as set via oprofilefs. */
struct op_system_config {
unsigned long enable_pal;
unsigned long enable_kernel;
unsigned long enable_user;
};
/* Cached values for the various performance monitoring registers. */
struct op_register_config {
unsigned long enable;
unsigned long mux_select;
unsigned long proc_mode;
unsigned long freq;
unsigned long reset_values;
unsigned long need_reset;
};
/* Per-architecture configuration and hooks. */
struct op_axp_model {
void (*reg_setup) (struct op_register_config *,
struct op_counter_config *,
struct op_system_config *);
void (*cpu_setup) (void *);
void (*reset_ctr) (struct op_register_config *, unsigned long);
void (*handle_interrupt) (unsigned long, struct pt_regs *,
struct op_counter_config *);
char *cpu_type;
unsigned char num_counters;
unsigned char can_set_proc_mode;
};
#endif
/**
* @file arch/alpha/oprofile/op_model_ev4.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include "op_impl.h"
/* Compute all of the registers in preparation for enabling profiling. */
static void
ev4_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys)
{
unsigned long ctl = 0, count, hilo;
/* Select desired events. We've mapped the event numbers
such that they fit directly into the event selection fields.
Note that there is no "off" setting. In both cases we select
the EXTERNAL event source, hoping that it'll be the lowest
frequency, and set the frequency counter to LOW. The interrupts
for these "disabled" counter overflows are ignored by the
interrupt handler.
This is most irritating, because the hardware *can* enable and
disable the interrupts for these counters independently, but the
wrperfmon interface doesn't allow it. */
ctl |= (ctr[0].enabled ? ctr[0].event << 8 : 14 << 8);
ctl |= (ctr[1].enabled ? (ctr[1].event - 16) << 32 : 7ul << 32);
/* EV4 can not read or write its counter registers. The only
thing one can do at all is see if you overflow and get an
interrupt. We can set the width of the counters, to some
extent. Take the interrupt count selected by the user,
map it onto one of the possible values, and write it back. */
count = ctr[0].count;
if (count <= 4096)
count = 4096, hilo = 1;
else
count = 65536, hilo = 0;
ctr[0].count = count;
ctl |= (ctr[0].enabled && hilo) << 3;
count = ctr[1].count;
if (count <= 256)
count = 256, hilo = 1;
else
count = 4096, hilo = 0;
ctr[1].count = count;
ctl |= (ctr[1].enabled && hilo);
reg->mux_select = ctl;
/* Select performance monitoring options. */
/* ??? Need to come up with some mechanism to trace only
selected processes. EV4 does not have a mechanism to
select kernel or user mode only. For now, enable always. */
reg->proc_mode = 0;
/* Frequency is folded into mux_select for EV4. */
reg->freq = 0;
/* See above regarding no writes. */
reg->reset_values = 0;
reg->need_reset = 0;
}
/* Program all of the registers in preparation for enabling profiling. */
static void
ev4_cpu_setup(void *x)
{
struct op_register_config *reg = x;
wrperfmon(2, reg->mux_select);
wrperfmon(3, reg->proc_mode);
}
static void
ev4_handle_interrupt(unsigned long which, struct pt_regs *regs,
struct op_counter_config *ctr)
{
/* EV4 can't properly disable counters individually.
Discard "disabled" events now. */
if (!ctr[which].enabled)
return;
/* Record the sample. */
oprofile_add_sample(regs, which);
}
struct op_axp_model op_model_ev4 = {
.reg_setup = ev4_reg_setup,
.cpu_setup = ev4_cpu_setup,
.reset_ctr = NULL,
.handle_interrupt = ev4_handle_interrupt,
.cpu_type = "alpha/ev4",
.num_counters = 2,
.can_set_proc_mode = 0,
};
/**
* @file arch/alpha/oprofile/op_model_ev5.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include "op_impl.h"
/* Compute all of the registers in preparation for enabling profiling.
The 21164 (EV5) and 21164PC (PCA65) vary in the bit placement and
meaning of the "CBOX" events. Given that we don't care about meaning
at this point, arrange for the difference in bit placement to be
handled by common code. */
static void
common_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys,
int cbox1_ofs, int cbox2_ofs)
{
int i, ctl, reset, need_reset;
/* Select desired events. The event numbers are selected such
that they map directly into the event selection fields:
PCSEL0: 0, 1
PCSEL1: 24-39
CBOX1: 40-47
PCSEL2: 48-63
CBOX2: 64-71
There are two special cases, in that CYCLES can be measured
on PCSEL[02], and SCACHE_WRITE can be measured on CBOX[12].
These event numbers are canonicalizes to their first appearance. */
ctl = 0;
for (i = 0; i < 3; ++i) {
unsigned long event = ctr[i].event;
if (!ctr[i].enabled)
continue;
/* Remap the duplicate events, as described above. */
if (i == 2) {
if (event == 0)
event = 12+48;
else if (event == 2+41)
event = 4+65;
}
/* Convert the event numbers onto mux_select bit mask. */
if (event < 2)
ctl |= event << 31;
else if (event < 24)
/* error */;
else if (event < 40)
ctl |= (event - 24) << 4;
else if (event < 48)
ctl |= (event - 40) << cbox1_ofs | 15 << 4;
else if (event < 64)
ctl |= event - 48;
else if (event < 72)
ctl |= (event - 64) << cbox2_ofs | 15;
}
reg->mux_select = ctl;
/* Select processor mode. */
/* ??? Need to come up with some mechanism to trace only selected
processes. For now select from pal, kernel and user mode. */
ctl = 0;
ctl |= !sys->enable_pal << 9;
ctl |= !sys->enable_kernel << 8;
ctl |= !sys->enable_user << 30;
reg->proc_mode = ctl;
/* Select interrupt frequencies. Take the interrupt count selected
by the user, and map it onto one of the possible counter widths.
If the user value is in between, compute a value to which the
counter is reset at each interrupt. */
ctl = reset = need_reset = 0;
for (i = 0; i < 3; ++i) {
unsigned long max, hilo, count = ctr[i].count;
if (!ctr[i].enabled)
continue;
if (count <= 256)
count = 256, hilo = 3, max = 256;
else {
max = (i == 2 ? 16384 : 65536);
hilo = 2;
if (count > max)
count = max;
}
ctr[i].count = count;
ctl |= hilo << (8 - i*2);
reset |= (max - count) << (48 - 16*i);
if (count != max)
need_reset |= 1 << i;
}
reg->freq = ctl;
reg->reset_values = reset;
reg->need_reset = need_reset;
}
static void
ev5_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys)
{
common_reg_setup(reg, ctr, sys, 19, 22);
}
static void
pca56_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys)
{
common_reg_setup(reg, ctr, sys, 8, 11);
}
/* Program all of the registers in preparation for enabling profiling. */
static void
ev5_cpu_setup (void *x)
{
struct op_register_config *reg = x;
wrperfmon(2, reg->mux_select);
wrperfmon(3, reg->proc_mode);
wrperfmon(4, reg->freq);
wrperfmon(6, reg->reset_values);
}
/* CTR is a counter for which the user has requested an interrupt count
in between one of the widths selectable in hardware. Reset the count
for CTR to the value stored in REG->RESET_VALUES.
For EV5, this means disabling profiling, reading the current values,
masking in the value for the desired register, writing, then turning
profiling back on.
This can be streamlined if profiling is only enabled for user mode.
In that case we know that the counters are not currently incrementing
(due to being in kernel mode). */
static void
ev5_reset_ctr(struct op_register_config *reg, unsigned long ctr)
{
unsigned long values, mask, not_pk, reset_values;
mask = (ctr == 0 ? 0xfffful << 48
: ctr == 1 ? 0xfffful << 32
: 0x3fff << 16);
not_pk = 1 << 9 | 1 << 8;
reset_values = reg->reset_values;
if ((reg->proc_mode & not_pk) == not_pk) {
values = wrperfmon(5, 0);
values = (reset_values & mask) | (values & ~mask & -2);
wrperfmon(6, values);
} else {
wrperfmon(0, -1);
values = wrperfmon(5, 0);
values = (reset_values & mask) | (values & ~mask & -2);
wrperfmon(6, values);
wrperfmon(1, reg->enable);
}
}
static void
ev5_handle_interrupt(unsigned long which, struct pt_regs *regs,
struct op_counter_config *ctr)
{
/* Record the sample. */
oprofile_add_sample(regs, which);
}
struct op_axp_model op_model_ev5 = {
.reg_setup = ev5_reg_setup,
.cpu_setup = ev5_cpu_setup,
.reset_ctr = ev5_reset_ctr,
.handle_interrupt = ev5_handle_interrupt,
.cpu_type = "alpha/ev5",
.num_counters = 3,
.can_set_proc_mode = 1,
};
struct op_axp_model op_model_pca56 = {
.reg_setup = pca56_reg_setup,
.cpu_setup = ev5_cpu_setup,
.reset_ctr = ev5_reset_ctr,
.handle_interrupt = ev5_handle_interrupt,
.cpu_type = "alpha/pca56",
.num_counters = 3,
.can_set_proc_mode = 1,
};
/**
* @file arch/alpha/oprofile/op_model_ev6.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include "op_impl.h"
/* Compute all of the registers in preparation for enabling profiling. */
static void
ev6_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys)
{
unsigned long ctl, reset, need_reset, i;
/* Select desired events. We've mapped the event numbers
such that they fit directly into the event selection fields. */
ctl = 0;
if (ctr[0].enabled && ctr[0].event)
ctl |= (ctr[0].event & 1) << 4;
if (ctr[1].enabled)
ctl |= (ctr[1].event - 2) & 15;
reg->mux_select = ctl;
/* Select logging options. */
/* ??? Need to come up with some mechanism to trace only
selected processes. EV6 does not have a mechanism to
select kernel or user mode only. For now, enable always. */
reg->proc_mode = 0;
/* EV6 cannot change the width of the counters as with the
other implementations. But fortunately, we can write to
the counters and set the value such that it will overflow
at the right time. */
reset = need_reset = 0;
for (i = 0; i < 2; ++i) {
unsigned long count = ctr[i].count;
if (!ctr[i].enabled)
continue;
if (count > 0x100000)
count = 0x100000;
ctr[i].count = count;
reset |= (0x100000 - count) << (i ? 6 : 28);
if (count != 0x100000)
need_reset |= 1 << i;
}
reg->reset_values = reset;
reg->need_reset = need_reset;
}
/* Program all of the registers in preparation for enabling profiling. */
static void
ev6_cpu_setup (void *x)
{
struct op_register_config *reg = x;
wrperfmon(2, reg->mux_select);
wrperfmon(3, reg->proc_mode);
wrperfmon(6, reg->reset_values | 3);
}
/* CTR is a counter for which the user has requested an interrupt count
in between one of the widths selectable in hardware. Reset the count
for CTR to the value stored in REG->RESET_VALUES. */
static void
ev6_reset_ctr(struct op_register_config *reg, unsigned long ctr)
{
wrperfmon(6, reg->reset_values | (1 << ctr));
}
static void
ev6_handle_interrupt(unsigned long which, struct pt_regs *regs,
struct op_counter_config *ctr)
{
/* Record the sample. */
oprofile_add_sample(regs, which);
}
struct op_axp_model op_model_ev6 = {
.reg_setup = ev6_reg_setup,
.cpu_setup = ev6_cpu_setup,
.reset_ctr = ev6_reset_ctr,
.handle_interrupt = ev6_handle_interrupt,
.cpu_type = "alpha/ev6",
.num_counters = 2,
.can_set_proc_mode = 0,
};
/**
* @file arch/alpha/oprofile/op_model_ev67.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
* @author Falk Hueffner <falk@debian.org>
*/
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include "op_impl.h"
/* Compute all of the registers in preparation for enabling profiling. */
static void
ev67_reg_setup(struct op_register_config *reg,
struct op_counter_config *ctr,
struct op_system_config *sys)
{
unsigned long ctl, reset, need_reset, i;
/* Select desired events. */
ctl = 1UL << 4; /* Enable ProfileMe mode. */
/* The event numbers are chosen so we can use them directly if
PCTR1 is enabled. */
if (ctr[1].enabled) {
ctl |= (ctr[1].event & 3) << 2;
} else {
if (ctr[0].event == 0) /* cycles */
ctl |= 1UL << 2;
}
reg->mux_select = ctl;
/* Select logging options. */
/* ??? Need to come up with some mechanism to trace only
selected processes. EV67 does not have a mechanism to
select kernel or user mode only. For now, enable always. */
reg->proc_mode = 0;
/* EV67 cannot change the width of the counters as with the
other implementations. But fortunately, we can write to
the counters and set the value such that it will overflow
at the right time. */
reset = need_reset = 0;
for (i = 0; i < 2; ++i) {
unsigned long count = ctr[i].count;
if (!ctr[i].enabled)
continue;
if (count > 0x100000)
count = 0x100000;
ctr[i].count = count;
reset |= (0x100000 - count) << (i ? 6 : 28);
if (count != 0x100000)
need_reset |= 1 << i;
}
reg->reset_values = reset;
reg->need_reset = need_reset;
}
/* Program all of the registers in preparation for enabling profiling. */
static void
ev67_cpu_setup (void *x)
{
struct op_register_config *reg = x;
wrperfmon(2, reg->mux_select);
wrperfmon(3, reg->proc_mode);
wrperfmon(6, reg->reset_values | 3);
}
/* CTR is a counter for which the user has requested an interrupt count
in between one of the widths selectable in hardware. Reset the count
for CTR to the value stored in REG->RESET_VALUES. */
static void
ev67_reset_ctr(struct op_register_config *reg, unsigned long ctr)
{
wrperfmon(6, reg->reset_values | (1 << ctr));
}
/* ProfileMe conditions which will show up as counters. We can also
detect the following, but it seems unlikely that anybody is
interested in counting them:
* Reset
* MT_FPCR (write to floating point control register)
* Arithmetic trap
* Dstream Fault
* Machine Check (ECC fault, etc.)
* OPCDEC (illegal opcode)
* Floating point disabled
* Differentiate between DTB single/double misses and 3 or 4 level
page tables
* Istream access violation
* Interrupt
* Icache Parity Error.
* Instruction killed (nop, trapb)
Unfortunately, there seems to be no way to detect Dcache and Bcache
misses; the latter could be approximated by making the counter
count Bcache misses, but that is not precise.
We model this as 20 counters:
* PCTR0
* PCTR1
* 9 ProfileMe events, induced by PCTR0
* 9 ProfileMe events, induced by PCTR1
*/
enum profileme_counters {
PM_STALLED, /* Stalled for at least one cycle
between the fetch and map stages */
PM_TAKEN, /* Conditional branch taken */
PM_MISPREDICT, /* Branch caused mispredict trap */
PM_ITB_MISS, /* ITB miss */
PM_DTB_MISS, /* DTB miss */
PM_REPLAY, /* Replay trap */
PM_LOAD_STORE, /* Load-store order trap */
PM_ICACHE_MISS, /* Icache miss */
PM_UNALIGNED, /* Unaligned Load/Store */
PM_NUM_COUNTERS
};
static inline void
op_add_pm(unsigned long pc, int kern, unsigned long counter,
struct op_counter_config *ctr, unsigned long event)
{
unsigned long fake_counter = 2 + event;
if (counter == 1)
fake_counter += PM_NUM_COUNTERS;
if (ctr[fake_counter].enabled)
oprofile_add_pc(pc, kern, fake_counter);
}
static void
ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
struct op_counter_config *ctr)
{
unsigned long pmpc, pctr_ctl;
int kern = !user_mode(regs);
int mispredict = 0;
union {
unsigned long v;
struct {
unsigned reserved: 30; /* 0-29 */
unsigned overcount: 3; /* 30-32 */
unsigned icache_miss: 1; /* 33 */
unsigned trap_type: 4; /* 34-37 */
unsigned load_store: 1; /* 38 */
unsigned trap: 1; /* 39 */
unsigned mispredict: 1; /* 40 */
} fields;
} i_stat;
enum trap_types {
TRAP_REPLAY,
TRAP_INVALID0,
TRAP_DTB_DOUBLE_MISS_3,
TRAP_DTB_DOUBLE_MISS_4,
TRAP_FP_DISABLED,
TRAP_UNALIGNED,
TRAP_DTB_SINGLE_MISS,
TRAP_DSTREAM_FAULT,
TRAP_OPCDEC,
TRAP_INVALID1,
TRAP_MACHINE_CHECK,
TRAP_INVALID2,
TRAP_ARITHMETIC,
TRAP_INVALID3,
TRAP_MT_FPCR,
TRAP_RESET
};
pmpc = wrperfmon(9, 0);
/* ??? Don't know how to handle physical-mode PALcode address. */
if (pmpc & 1)
return;
pmpc &= ~2; /* clear reserved bit */
i_stat.v = wrperfmon(8, 0);
if (i_stat.fields.trap) {
switch (i_stat.fields.trap_type) {
case TRAP_INVALID1:
case TRAP_INVALID2:
case TRAP_INVALID3:
/* Pipeline redirection occurred. PMPC points
to PALcode. Recognize ITB miss by PALcode
offset address, and get actual PC from
EXC_ADDR. */
oprofile_add_pc(regs->pc, kern, which);
if ((pmpc & ((1 << 15) - 1)) == 581)
op_add_pm(regs->pc, kern, which,
ctr, PM_ITB_MISS);
/* Most other bit and counter values will be
those for the first instruction in the
fault handler, so we're done. */
return;
case TRAP_REPLAY:
op_add_pm(pmpc, kern, which, ctr,
(i_stat.fields.load_store
? PM_LOAD_STORE : PM_REPLAY));
break;
case TRAP_DTB_DOUBLE_MISS_3:
case TRAP_DTB_DOUBLE_MISS_4:
case TRAP_DTB_SINGLE_MISS:
op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
break;
case TRAP_UNALIGNED:
op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
break;
case TRAP_INVALID0:
case TRAP_FP_DISABLED:
case TRAP_DSTREAM_FAULT:
case TRAP_OPCDEC:
case TRAP_MACHINE_CHECK:
case TRAP_ARITHMETIC:
case TRAP_MT_FPCR:
case TRAP_RESET:
break;
}
/* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR
mispredicts do not set this bit but can be
recognized by the presence of one of these
instructions at the PMPC location with bit 39
set. */
if (i_stat.fields.mispredict) {
mispredict = 1;
op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
}
}
oprofile_add_pc(pmpc, kern, which);
pctr_ctl = wrperfmon(5, 0);
if (pctr_ctl & (1UL << 27))
op_add_pm(pmpc, kern, which, ctr, PM_STALLED);
/* Unfortunately, TAK is undefined on mispredicted branches.
??? It is also undefined for non-cbranch insns, should
check that. */
if (!mispredict && pctr_ctl & (1UL << 0))
op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
}
struct op_axp_model op_model_ev67 = {
.reg_setup = ev67_reg_setup,
.cpu_setup = ev67_cpu_setup,
.reset_ctr = ev67_reset_ctr,
.handle_interrupt = ev67_handle_interrupt,
.cpu_type = "alpha/ev67",
.num_counters = 20,
.can_set_proc_mode = 0,
};
......@@ -37,7 +37,6 @@ config ARC
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HANDLE_DOMAIN_IRQ
select IRQ_DOMAIN
......
......@@ -96,8 +96,6 @@ core-$(CONFIG_ARC_PLAT_TB10X) += arch/arc/plat-tb10x/
core-$(CONFIG_ARC_PLAT_AXS10X) += arch/arc/plat-axs10x/
core-$(CONFIG_ARC_SOC_HSDK) += arch/arc/plat-hsdk/
drivers-$(CONFIG_OPROFILE) += arch/arc/oprofile/
libs-y += arch/arc/lib/ $(LIBGCC)
boot := arch/arc/boot
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* Based on orig code from @author John Levon <levon@movementarian.org>
*/
#include <linux/oprofile.h>
#include <linux/perf_event.h>
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
/*
* A failure here, forces oprofile core to switch to Timer based PC
* sampling, which will happen if say perf is not enabled/available
*/
return oprofile_perf_init(ops);
}
void oprofile_arch_exit(void)
{
oprofile_perf_exit();
}
......@@ -102,7 +102,6 @@ config ARM
select HAVE_KRETPROBES if HAVE_KPROBES
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI
select HAVE_OPROFILE if HAVE_PERF_EVENTS
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
......
......@@ -260,8 +260,6 @@ core-y += $(machdirs) $(platdirs)
core- += $(patsubst %,arch/arm/mach-%/, $(machine-))
core- += $(patsubst %,arch/arm/plat-%/, $(plat-))
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
libs-y := arch/arm/lib/ $(libs-y)
# Default target when executing plain make
......
......@@ -21,7 +21,6 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_JUMP_LABEL=y
CONFIG_CC_STACKPROTECTOR_REGULAR=y
CONFIG_MODULES=y
......
......@@ -11,7 +11,6 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_PERF_EVENTS is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -5,7 +5,6 @@ CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -27,7 +27,6 @@ CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_PM_DEBUG=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -16,7 +16,6 @@ CONFIG_KALLSYMS_ALL=y
# CONFIG_BASE_FULL is not set
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
......
......@@ -67,7 +67,6 @@ CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_KIRKWOOD_CPUIDLE=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -5,7 +5,6 @@ CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -4,7 +4,6 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=19
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -13,7 +13,6 @@ CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLOB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -62,7 +62,6 @@ CONFIG_CRYPTO_AES_ARM=m
CONFIG_CRYPTO_AES_ARM_BS=m
CONFIG_CRYPTO_GHASH_ARM_CE=m
CONFIG_CRYPTO_CHACHA20_NEON=m
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
......
......@@ -5,7 +5,6 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_EXPERT=y
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -13,7 +13,6 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
CONFIG_SLOB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
......
......@@ -10,7 +10,6 @@ CONFIG_EMBEDDED=y
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -18,7 +18,6 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -5,7 +5,6 @@ CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -11,7 +11,6 @@ CONFIG_CPUSETS=y
# CONFIG_NET_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
ifeq ($(CONFIG_HW_PERF_EVENTS),y)
DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
endif
oprofile-y := $(DRIVER_OBJS) common.o
/**
* @file common.c
*
* @remark Copyright 2004 Oprofile Authors
* @remark Copyright 2010 ARM Ltd.
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
* @author Will Deacon [move to perf]
*/
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/oprofile.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/stacktrace.h>
#include <linux/uaccess.h>
#include <asm/perf_event.h>
#include <asm/ptrace.h>
#ifdef CONFIG_HW_PERF_EVENTS
/*
* OProfile has a curious naming scheme for the ARM PMUs, but they are
* part of the user ABI so we need to map from the perf PMU name for
* supported PMUs.
*/
static struct op_perf_name {
char *perf_name;
char *op_name;
} op_perf_name_map[] = {
{ "armv5_xscale1", "arm/xscale1" },
{ "armv5_xscale2", "arm/xscale2" },
{ "armv6_1136", "arm/armv6" },
{ "armv6_1156", "arm/armv6" },
{ "armv6_1176", "arm/armv6" },
{ "armv6_11mpcore", "arm/mpcore" },
{ "armv7_cortex_a8", "arm/armv7" },
{ "armv7_cortex_a9", "arm/armv7-ca9" },
};
char *op_name_from_perf_id(void)
{
int i;
struct op_perf_name names;
const char *perf_name = perf_pmu_name();
for (i = 0; i < ARRAY_SIZE(op_perf_name_map); ++i) {
names = op_perf_name_map[i];
if (!strcmp(names.perf_name, perf_name))
return names.op_name;
}
return NULL;
}
#endif
static int report_trace(struct stackframe *frame, void *d)
{
unsigned int *depth = d;
if (*depth) {
oprofile_add_trace(frame->pc);
(*depth)--;
}
return *depth == 0;
}
/*
* The registers we're interested in are at the end of the variable
* length saved register structure. The fp points at the end of this
* structure so the address of this struct is:
* (struct frame_tail *)(xxx->fp)-1
*/
struct frame_tail {
struct frame_tail *fp;
unsigned long sp;
unsigned long lr;
} __attribute__((packed));
static struct frame_tail* user_backtrace(struct frame_tail *tail)
{
struct frame_tail buftail[2];
/* Also check accessibility of one struct frame_tail beyond */
if (!access_ok(tail, sizeof(buftail)))
return NULL;
if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail)))
return NULL;
oprofile_add_trace(buftail[0].lr);
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
if (tail + 1 >= buftail[0].fp)
return NULL;
return buftail[0].fp-1;
}
static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
{
struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
if (!user_mode(regs)) {
struct stackframe frame;
arm_get_current_stackframe(regs, &frame);
walk_stackframe(&frame, report_trace, &depth);
return;
}
while (depth-- && tail && !((unsigned long) tail & 3))
tail = user_backtrace(tail);
}
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
/* provide backtrace support also in timer mode: */
ops->backtrace = arm_backtrace;
return oprofile_perf_init(ops);
}
void oprofile_arch_exit(void)
{
oprofile_perf_exit();
}
......@@ -7,7 +7,6 @@ config HEXAGON
select ARCH_32BIT_OFF_T
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_NO_PREEMPT
select HAVE_OPROFILE
# Other pending projects/to-do items.
# select HAVE_REGS_AND_STACK_ACCESS_API
# select HAVE_HW_BREAKPOINT if PERF_EVENTS
......
......@@ -24,7 +24,6 @@ config IA64
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_EXIT_THREAD
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_FTRACE_MCOUNT_RECORD
......
......@@ -52,7 +52,6 @@ core-y += arch/ia64/kernel/ arch/ia64/mm/
core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/
drivers-y += arch/ia64/pci/ arch/ia64/hp/common/
drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/
PHONY += compressed check
......
......@@ -2,7 +2,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
......
......@@ -69,7 +69,6 @@ extern int ia64_last_device_vector;
#define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
#define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */
#define IA64_PERFMON_VECTOR 0xee /* performance monitor interrupt vector */
#define IA64_TIMER_VECTOR 0xef /* use highest-prio group 15 interrupt for timer */
#define IA64_MCA_WAKEUP_VECTOR 0xf0 /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
#define IA64_IPI_LOCAL_TLB_FLUSH 0xfc /* SMP flush local TLB */
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*/
#ifndef _ASM_IA64_PERFMON_H
#define _ASM_IA64_PERFMON_H
#include <uapi/asm/perfmon.h>
extern long perfmonctl(int fd, int cmd, void *arg, int narg);
typedef struct {
void (*handler)(int irq, void *arg, struct pt_regs *regs);
} pfm_intr_handler_desc_t;
extern void pfm_save_regs (struct task_struct *);
extern void pfm_load_regs (struct task_struct *);
extern void pfm_exit_thread(struct task_struct *);
extern int pfm_use_debug_registers(struct task_struct *);
extern int pfm_release_debug_registers(struct task_struct *);
extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin);
extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs);
extern void pfm_init_percpu(void);
extern void pfm_handle_work(void);
extern int pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
extern int pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
/*
* Reset PMD register flags
*/
#define PFM_PMD_SHORT_RESET 0
#define PFM_PMD_LONG_RESET 1
typedef union {
unsigned int val;
struct {
unsigned int notify_user:1; /* notify user program of overflow */
unsigned int reset_ovfl_pmds:1; /* reset overflowed PMDs */
unsigned int block_task:1; /* block monitored task on kernel exit */
unsigned int mask_monitoring:1; /* mask monitors via PMCx.plm */
unsigned int reserved:28; /* for future use */
} bits;
} pfm_ovfl_ctrl_t;
typedef struct {
unsigned char ovfl_pmd; /* index of overflowed PMD */
unsigned char ovfl_notify; /* =1 if monitor requested overflow notification */
unsigned short active_set; /* event set active at the time of the overflow */
pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */
unsigned long pmd_last_reset; /* last reset value of of the PMD */
unsigned long smpl_pmds[4]; /* bitmask of other PMD of interest on overflow */
unsigned long smpl_pmds_values[PMU_MAX_PMDS]; /* values for the other PMDs of interest */
unsigned long pmd_value; /* current 64-bit value of the PMD */
unsigned long pmd_eventid; /* eventid associated with PMD */
} pfm_ovfl_arg_t;
typedef struct {
char *fmt_name;
pfm_uuid_t fmt_uuid;
size_t fmt_arg_size;
unsigned long fmt_flags;
int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg);
int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size);
int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg);
int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp);
int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs);
struct list_head fmt_list;
} pfm_buffer_fmt_t;
extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt);
extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid);
/*
* perfmon interface exported to modules
*/
extern int pfm_mod_read_pmds(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs);
extern int pfm_mod_write_pmcs(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs);
extern int pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs);
extern int pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs);
/*
* describe the content of the local_cpu_date->pfm_syst_info field
*/
#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */
#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */
#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */
/*
* sysctl control structure. visible to sampling formats
*/
typedef struct {
int debug; /* turn on/off debugging via syslog */
int debug_ovfl; /* turn on/off debug printk in overflow handler */
int fastctxsw; /* turn on/off fast (unsecure) ctxsw */
int expert_mode; /* turn on/off value checking */
} pfm_sysctl_t;
extern pfm_sysctl_t pfm_sysctl;
#endif /* _ASM_IA64_PERFMON_H */
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*/
#ifndef _UAPI_ASM_IA64_PERFMON_H
#define _UAPI_ASM_IA64_PERFMON_H
/*
* perfmon commands supported on all CPU models
*/
#define PFM_WRITE_PMCS 0x01
#define PFM_WRITE_PMDS 0x02
#define PFM_READ_PMDS 0x03
#define PFM_STOP 0x04
#define PFM_START 0x05
#define PFM_ENABLE 0x06 /* obsolete */
#define PFM_DISABLE 0x07 /* obsolete */
#define PFM_CREATE_CONTEXT 0x08
#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */
#define PFM_RESTART 0x0a
#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */
#define PFM_GET_FEATURES 0x0c
#define PFM_DEBUG 0x0d
#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */
#define PFM_GET_PMC_RESET_VAL 0x0f
#define PFM_LOAD_CONTEXT 0x10
#define PFM_UNLOAD_CONTEXT 0x11
/*
* PMU model specific commands (may not be supported on all PMU models)
*/
#define PFM_WRITE_IBRS 0x20
#define PFM_WRITE_DBRS 0x21
/*
* context flags
*/
#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */
#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */
#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */
/*
* event set flags
*/
#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */
/*
* PMC flags
*/
#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */
#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */
/*
* PMD/PMC/IBR/DBR return flags (ignored on input)
*
* Those flags are used on output and must be checked in case EAGAIN is returned
* by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure.
*/
#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */
#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */
#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL)
#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0)
typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */
/*
* Request structure used to define a context
*/
typedef struct {
pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */
unsigned long ctx_flags; /* noblock/block */
unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */
unsigned short ctx_reserved1; /* for future use */
int ctx_fd; /* return arg: unique identification for context */
void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */
unsigned long ctx_reserved2[11];/* for future use */
} pfarg_context_t;
/*
* Request structure used to write/read a PMC or PMD
*/
typedef struct {
unsigned int reg_num; /* which register */
unsigned short reg_set; /* event set for this register */
unsigned short reg_reserved1; /* for future use */
unsigned long reg_value; /* initial pmc/pmd value */
unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */
unsigned long reg_long_reset; /* reset after buffer overflow notification */
unsigned long reg_short_reset; /* reset after counter overflow */
unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */
unsigned long reg_random_seed; /* seed value when randomization is used */
unsigned long reg_random_mask; /* bitmask used to limit random value */
unsigned long reg_last_reset_val;/* return: PMD last reset value */
unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */
unsigned long reg_smpl_eventid; /* opaque sampling event identifier */
unsigned long reg_reserved2[3]; /* for future use */
} pfarg_reg_t;
typedef struct {
unsigned int dbreg_num; /* which debug register */
unsigned short dbreg_set; /* event set for this register */
unsigned short dbreg_reserved1; /* for future use */
unsigned long dbreg_value; /* value for debug register */
unsigned long dbreg_flags; /* return: dbreg error */
unsigned long dbreg_reserved2[1]; /* for future use */
} pfarg_dbreg_t;
typedef struct {
unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */
unsigned int ft_reserved; /* reserved for future use */
unsigned long reserved[4]; /* for future use */
} pfarg_features_t;
typedef struct {
pid_t load_pid; /* process to load the context into */
unsigned short load_set; /* first event set to load */
unsigned short load_reserved1; /* for future use */
unsigned long load_reserved2[3]; /* for future use */
} pfarg_load_t;
typedef struct {
int msg_type; /* generic message header */
int msg_ctx_fd; /* generic message header */
unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */
unsigned short msg_active_set; /* active set at the time of overflow */
unsigned short msg_reserved1; /* for future use */
unsigned int msg_reserved2; /* for future use */
unsigned long msg_tstamp; /* for perf tuning/debug */
} pfm_ovfl_msg_t;
typedef struct {
int msg_type; /* generic message header */
int msg_ctx_fd; /* generic message header */
unsigned long msg_tstamp; /* for perf tuning */
} pfm_end_msg_t;
typedef struct {
int msg_type; /* type of the message */
int msg_ctx_fd; /* unique identifier for the context */
unsigned long msg_tstamp; /* for perf tuning */
} pfm_gen_msg_t;
#define PFM_MSG_OVFL 1 /* an overflow happened */
#define PFM_MSG_END 2 /* task to which context was attached ended */
typedef union {
pfm_ovfl_msg_t pfm_ovfl_msg;
pfm_end_msg_t pfm_end_msg;
pfm_gen_msg_t pfm_gen_msg;
} pfm_msg_t;
/*
* Define the version numbers for both perfmon as a whole and the sampling buffer format.
*/
#define PFM_VERSION_MAJ 2U
#define PFM_VERSION_MIN 0U
#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff)
#define PFM_VERSION_MINOR(x) ((x) & 0xffff)
/*
* miscellaneous architected definitions
*/
#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */
#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */
#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */
#endif /* _UAPI_ASM_IA64_PERFMON_H */
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2002-2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*
* This file implements the default sampling buffer format
* for Linux/ia64 perfmon subsystem.
*/
#ifndef __PERFMON_DEFAULT_SMPL_H__
#define __PERFMON_DEFAULT_SMPL_H__ 1
#define PFM_DEFAULT_SMPL_UUID { \
0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97}
/*
* format specific parameters (passed at context creation)
*/
typedef struct {
unsigned long buf_size; /* size of the buffer in bytes */
unsigned int flags; /* buffer specific flags */
unsigned int res1; /* for future use */
unsigned long reserved[2]; /* for future use */
} pfm_default_smpl_arg_t;
/*
* combined context+format specific structure. Can be passed
* to PFM_CONTEXT_CREATE
*/
typedef struct {
pfarg_context_t ctx_arg;
pfm_default_smpl_arg_t buf_arg;
} pfm_default_smpl_ctx_arg_t;
/*
* This header is at the beginning of the sampling buffer returned to the user.
* It is directly followed by the first record.
*/
typedef struct {
unsigned long hdr_count; /* how many valid entries */
unsigned long hdr_cur_offs; /* current offset from top of buffer */
unsigned long hdr_reserved2; /* reserved for future use */
unsigned long hdr_overflows; /* how many times the buffer overflowed */
unsigned long hdr_buf_size; /* how many bytes in the buffer */
unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */
unsigned int hdr_reserved1; /* for future use */
unsigned long hdr_reserved[10]; /* for future use */
} pfm_default_smpl_hdr_t;
/*
* Entry header in the sampling buffer. The header is directly followed
* with the values of the PMD registers of interest saved in increasing
* index order: PMD4, PMD5, and so on. How many PMDs are present depends
* on how the session was programmed.
*
* In the case where multiple counters overflow at the same time, multiple
* entries are written consecutively.
*
* last_reset_value member indicates the initial value of the overflowed PMD.
*/
typedef struct {
int pid; /* thread id (for NPTL, this is gettid()) */
unsigned char reserved1[3]; /* reserved for future use */
unsigned char ovfl_pmd; /* index of overflowed PMD */
unsigned long last_reset_val; /* initial value of overflowed PMD */
unsigned long ip; /* where did the overflow interrupt happened */
unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */
unsigned short cpu; /* cpu on which the overflow occurred */
unsigned short set; /* event set active when overflow occurred */
int tgid; /* thread group id (for NPTL, this is getpid()) */
} pfm_default_smpl_entry_t;
#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */
#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS))
#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE)
#define PFM_DEFAULT_SMPL_VERSION_MAJ 2U
#define PFM_DEFAULT_SMPL_VERSION_MIN 0U
#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff))
#endif /* __PERFMON_DEFAULT_SMPL_H__ */
......@@ -648,46 +648,6 @@ static int version_info(struct seq_file *m)
return 0;
}
static int perfmon_info(struct seq_file *m)
{
u64 pm_buffer[16];
pal_perf_mon_info_u_t pm_info;
if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0)
return 0;
seq_printf(m,
"PMC/PMD pairs : %d\n"
"Counter width : %d bits\n"
"Cycle event number : %d\n"
"Retired event number : %d\n"
"Implemented PMC : ",
pm_info.pal_perf_mon_info_s.generic,
pm_info.pal_perf_mon_info_s.width,
pm_info.pal_perf_mon_info_s.cycles,
pm_info.pal_perf_mon_info_s.retired);
bitregister_process(m, pm_buffer, 256);
seq_puts(m, "\nImplemented PMD : ");
bitregister_process(m, pm_buffer+4, 256);
seq_puts(m, "\nCycles count capable : ");
bitregister_process(m, pm_buffer+8, 256);
seq_puts(m, "\nRetired bundles count capable : ");
#ifdef CONFIG_ITANIUM
/*
* PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES
* which is wrong, both PMC4 and PMD5 support it.
*/
if (pm_buffer[12] == 0x10)
pm_buffer[12]=0x30;
#endif
bitregister_process(m, pm_buffer+12, 256);
seq_putc(m, '\n');
return 0;
}
static int frequency_info(struct seq_file *m)
{
struct pal_freq_ratio proc, itc, bus;
......@@ -816,7 +776,6 @@ static const palinfo_entry_t palinfo_entries[]={
{ "power_info", power_info, },
{ "register_info", register_info, },
{ "processor_info", processor_info, },
{ "perfmon_info", perfmon_info, },
{ "frequency_info", frequency_info, },
{ "bus_info", bus_info },
{ "tr_info", tr_info, }
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002-2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*
* This file implements the default sampling buffer format
* for the Linux/ia64 perfmon-2 subsystem.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <linux/smp.h>
#include <asm/perfmon.h>
#include <asm/perfmon_default_smpl.h>
MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
MODULE_DESCRIPTION("perfmon default sampling format");
MODULE_LICENSE("GPL");
#define DEFAULT_DEBUG 1
#ifdef DEFAULT_DEBUG
#define DPRINT(a) \
do { \
if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
} while (0)
#define DPRINT_ovfl(a) \
do { \
if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
} while (0)
#else
#define DPRINT(a)
#define DPRINT_ovfl(a)
#endif
static int
default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
{
pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data;
int ret = 0;
if (data == NULL) {
DPRINT(("[%d] no argument passed\n", task_pid_nr(task)));
return -EINVAL;
}
DPRINT(("[%d] validate flags=0x%x CPU%d\n", task_pid_nr(task), flags, cpu));
/*
* must hold at least the buffer header + one minimally sized entry
*/
if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL;
DPRINT(("buf_size=%lu\n", arg->buf_size));
return ret;
}
static int
default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size)
{
pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
/*
* size has been validated in default_validate
*/
*size = arg->buf_size;
return 0;
}
static int
default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data)
{
pfm_default_smpl_hdr_t *hdr;
pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
hdr = (pfm_default_smpl_hdr_t *)buf;
hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION;
hdr->hdr_buf_size = arg->buf_size;
hdr->hdr_cur_offs = sizeof(*hdr);
hdr->hdr_overflows = 0UL;
hdr->hdr_count = 0UL;
DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n",
task_pid_nr(task),
buf,
hdr->hdr_buf_size,
sizeof(*hdr),
hdr->hdr_version,
hdr->hdr_cur_offs));
return 0;
}
static int
default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp)
{
pfm_default_smpl_hdr_t *hdr;
pfm_default_smpl_entry_t *ent;
void *cur, *last;
unsigned long *e, entry_size;
unsigned int npmds, i;
unsigned char ovfl_pmd;
unsigned char ovfl_notify;
if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) {
DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg));
return -EINVAL;
}
hdr = (pfm_default_smpl_hdr_t *)buf;
cur = buf+hdr->hdr_cur_offs;
last = buf+hdr->hdr_buf_size;
ovfl_pmd = arg->ovfl_pmd;
ovfl_notify = arg->ovfl_notify;
/*
* precheck for sanity
*/
if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
npmds = hweight64(arg->smpl_pmds[0]);
ent = (pfm_default_smpl_entry_t *)cur;
prefetch(arg->smpl_pmds_values);
entry_size = sizeof(*ent) + (npmds << 3);
/* position for first pmd */
e = (unsigned long *)(ent+1);
hdr->hdr_count++;
DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n",
task->pid,
hdr->hdr_count,
cur, last,
last-cur,
ovfl_pmd,
ovfl_notify, npmds));
/*
* current = task running at the time of the overflow.
*
* per-task mode:
* - this is usually the task being monitored.
* Under certain conditions, it might be a different task
*
* system-wide:
* - this is not necessarily the task controlling the session
*/
ent->pid = current->pid;
ent->ovfl_pmd = ovfl_pmd;
ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val;
/*
* where did the fault happen (includes slot number)
*/
ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3);
ent->tstamp = stamp;
ent->cpu = smp_processor_id();
ent->set = arg->active_set;
ent->tgid = current->tgid;
/*
* selectively store PMDs in increasing index number
*/
if (npmds) {
unsigned long *val = arg->smpl_pmds_values;
for(i=0; i < npmds; i++) {
*e++ = *val++;
}
}
/*
* update position for next entry
*/
hdr->hdr_cur_offs += entry_size;
cur += entry_size;
/*
* post check to avoid losing the last sample
*/
if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
/*
* keep same ovfl_pmds, ovfl_notify
*/
arg->ovfl_ctrl.bits.notify_user = 0;
arg->ovfl_ctrl.bits.block_task = 0;
arg->ovfl_ctrl.bits.mask_monitoring = 0;
arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */
return 0;
full:
DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify));
/*
* increment number of buffer overflow.
* important to detect duplicate set of samples.
*/
hdr->hdr_overflows++;
/*
* if no notification requested, then we saturate the buffer
*/
if (ovfl_notify == 0) {
arg->ovfl_ctrl.bits.notify_user = 0;
arg->ovfl_ctrl.bits.block_task = 0;
arg->ovfl_ctrl.bits.mask_monitoring = 1;
arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0;
} else {
arg->ovfl_ctrl.bits.notify_user = 1;
arg->ovfl_ctrl.bits.block_task = 1; /* ignored for non-blocking context */
arg->ovfl_ctrl.bits.mask_monitoring = 1;
arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */
}
return -1; /* we are full, sorry */
}
static int
default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
{
pfm_default_smpl_hdr_t *hdr;
hdr = (pfm_default_smpl_hdr_t *)buf;
hdr->hdr_count = 0UL;
hdr->hdr_cur_offs = sizeof(*hdr);
ctrl->bits.mask_monitoring = 0;
ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */
return 0;
}
static int
default_exit(struct task_struct *task, void *buf, struct pt_regs *regs)
{
DPRINT(("[%d] exit(%p)\n", task_pid_nr(task), buf));
return 0;
}
static pfm_buffer_fmt_t default_fmt={
.fmt_name = "default_format",
.fmt_uuid = PFM_DEFAULT_SMPL_UUID,
.fmt_arg_size = sizeof(pfm_default_smpl_arg_t),
.fmt_validate = default_validate,
.fmt_getsize = default_get_size,
.fmt_init = default_init,
.fmt_handler = default_handler,
.fmt_restart = default_restart,
.fmt_restart_active = default_restart,
.fmt_exit = default_exit,
};
static int __init
pfm_default_smpl_init_module(void)
{
int ret;
ret = pfm_register_buffer_fmt(&default_fmt);
if (ret == 0) {
printk("perfmon_default_smpl: %s v%u.%u registered\n",
default_fmt.fmt_name,
PFM_DEFAULT_SMPL_VERSION_MAJ,
PFM_DEFAULT_SMPL_VERSION_MIN);
} else {
printk("perfmon_default_smpl: %s cannot register ret=%d\n",
default_fmt.fmt_name,
ret);
}
return ret;
}
static void __exit
pfm_default_smpl_cleanup_module(void)
{
int ret;
ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid);
printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret);
}
module_init(pfm_default_smpl_init_module);
module_exit(pfm_default_smpl_cleanup_module);
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file contains the generic PMU register description tables
* and pmc checker used by perfmon.c.
*
* Copyright (C) 2002-2003 Hewlett Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*/
static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={
/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
{ PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
};
static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={
/* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
/* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
/* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
/* pmd3 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
{ PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
};
/*
* impl_pmcs, impl_pmds are computed at runtime to minimize errors!
*/
static pmu_config_t pmu_conf_gen={
.pmu_name = "Generic",
.pmu_family = 0xff, /* any */
.ovfl_val = (1UL << 32) - 1,
.num_ibrs = 0, /* does not use */
.num_dbrs = 0, /* does not use */
.pmd_desc = pfm_gen_pmd_desc,
.pmc_desc = pfm_gen_pmc_desc
};
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file contains the Itanium PMU register description tables
* and pmc checker used by perfmon.c.
* and pmc checker.
*
* Copyright (C) 2002-2003 Hewlett Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file contains the McKinley PMU register description tables
* and pmc checker used by perfmon.c.
*
* Copyright (C) 2002-2003 Hewlett Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
*/
static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
{ PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
};
static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
/* pmd0 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
/* pmd1 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
/* pmd2 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
/* pmd3 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
/* pmd8 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd9 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd10 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd11 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd12 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd13 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd14 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd15 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd16 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
/* pmd17 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
{ PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
};
/*
* PMC reserved fields must have their power-up values preserved
*/
static int
pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs)
{
unsigned long tmp1, tmp2, ival = *val;
/* remove reserved areas from user value */
tmp1 = ival & PMC_RSVD_MASK(cnum);
/* get reserved fields values */
tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
*val = tmp1 | tmp2;
DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n",
cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val));
return 0;
}
/*
* task can be NULL if the context is unloaded
*/
static int
pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
{
int ret = 0, check_case1 = 0;
unsigned long val8 = 0, val14 = 0, val13 = 0;
int is_loaded;
/* first preserve the reserved fields */
pfm_mck_reserved(cnum, val, regs);
/* sanitfy check */
if (ctx == NULL) return -EINVAL;
is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED;
/*
* we must clear the debug registers if pmc13 has a value which enable
* memory pipeline event constraints. In this case we need to clear the
* the debug registers if they have not yet been accessed. This is required
* to avoid picking stale state.
* PMC13 is "active" if:
* one of the pmc13.cfg_dbrpXX field is different from 0x3
* AND
* at the corresponding pmc13.ena_dbrpXX is set.
*/
DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, *val, ctx->ctx_fl_using_dbreg, is_loaded));
if (cnum == 13 && is_loaded
&& (*val & 0x1e00000000000UL) && (*val & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) {
DPRINT(("pmc[%d]=0x%lx has active pmc13 settings, clearing dbr\n", cnum, *val));
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
/*
* a count of 0 will mark the debug registers as in use and also
* ensure that they are properly cleared.
*/
ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs);
if (ret) return ret;
}
/*
* we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled
* before they are (fl_using_dbreg==0) to avoid picking up stale information.
*/
if (cnum == 14 && is_loaded && ((*val & 0x2222UL) != 0x2222UL) && ctx->ctx_fl_using_dbreg == 0) {
DPRINT(("pmc[%d]=0x%lx has active pmc14 settings, clearing ibr\n", cnum, *val));
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
/*
* a count of 0 will mark the debug registers as in use and also
* ensure that they are properly cleared.
*/
ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs);
if (ret) return ret;
}
switch(cnum) {
case 4: *val |= 1UL << 23; /* force power enable bit */
break;
case 8: val8 = *val;
val13 = ctx->ctx_pmcs[13];
val14 = ctx->ctx_pmcs[14];
check_case1 = 1;
break;
case 13: val8 = ctx->ctx_pmcs[8];
val13 = *val;
val14 = ctx->ctx_pmcs[14];
check_case1 = 1;
break;
case 14: val8 = ctx->ctx_pmcs[8];
val13 = ctx->ctx_pmcs[13];
val14 = *val;
check_case1 = 1;
break;
}
/* check illegal configuration which can produce inconsistencies in tagging
* i-side events in L1D and L2 caches
*/
if (check_case1) {
ret = ((val13 >> 45) & 0xf) == 0
&& ((val8 & 0x1) == 0)
&& ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
if (ret) DPRINT((KERN_DEBUG "perfmon: failure check_case1\n"));
}
return ret ? -EINVAL : 0;
}
/*
* impl_pmcs, impl_pmds are computed at runtime to minimize errors!
*/
static pmu_config_t pmu_conf_mck={
.pmu_name = "Itanium 2",
.pmu_family = 0x1f,
.flags = PFM_PMU_IRQ_RESEND,
.ovfl_val = (1UL << 47) - 1,
.pmd_desc = pfm_mck_pmd_desc,
.pmc_desc = pfm_mck_pmc_desc,
.num_ibrs = 8,
.num_dbrs = 8,
.use_rr_dbregs = 1 /* debug register are use for range restrictions */
};
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
/**
* @file backtrace.c
*
* @remark Copyright 2004 Silicon Graphics Inc. All Rights Reserved.
* @remark Read the file COPYING
*
* @author Greg Banks <gnb@melbourne.sgi.com>
* @author Keith Owens <kaos@melbourne.sgi.com>
* Based on work done for the ia64 port of the SGI kernprof patch, which is
* Copyright (c) 2003-2004 Silicon Graphics Inc. All Rights Reserved.
*/
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/ptrace.h>
/*
* For IA64 we need to perform a complex little dance to get both
* the struct pt_regs and a synthetic struct switch_stack in place
* to allow the unwind code to work. This dance requires our unwind
* using code to be called from a function called from unw_init_running().
* There we only get a single void* data pointer, so use this struct
* to hold all the data we need during the unwind.
*/
typedef struct
{
unsigned int depth;
struct pt_regs *regs;
struct unw_frame_info frame;
unsigned long *prev_pfs_loc; /* state for WAR for old spinlock ool code */
} ia64_backtrace_t;
/* Returns non-zero if the PC is in the Interrupt Vector Table */
static __inline__ int in_ivt_code(unsigned long pc)
{
extern char ia64_ivt[];
return (pc >= (u_long)ia64_ivt && pc < (u_long)ia64_ivt+32768);
}
/*
* Unwind to next stack frame.
*/
static __inline__ int next_frame(ia64_backtrace_t *bt)
{
/*
* Avoid unsightly console message from unw_unwind() when attempting
* to unwind through the Interrupt Vector Table which has no unwind
* information.
*/
if (in_ivt_code(bt->frame.ip))
return 0;
/*
* WAR for spinlock contention from leaf functions. ia64_spinlock_contention_pre3_4
* has ar.pfs == r0. Leaf functions do not modify ar.pfs so ar.pfs remains
* as 0, stopping the backtrace. Record the previous ar.pfs when the current
* IP is in ia64_spinlock_contention_pre3_4 then unwind, if pfs_loc has not changed
* after unwind then use pt_regs.ar_pfs which is where the real ar.pfs is for
* leaf functions.
*/
if (bt->prev_pfs_loc && bt->regs && bt->frame.pfs_loc == bt->prev_pfs_loc)
bt->frame.pfs_loc = &bt->regs->ar_pfs;
bt->prev_pfs_loc = NULL;
return unw_unwind(&bt->frame) == 0;
}
static void do_ia64_backtrace(struct unw_frame_info *info, void *vdata)
{
ia64_backtrace_t *bt = vdata;
struct switch_stack *sw;
int count = 0;
u_long pc, sp;
sw = (struct switch_stack *)(info+1);
/* padding from unw_init_running */
sw = (struct switch_stack *)(((unsigned long)sw + 15) & ~15);
unw_init_frame_info(&bt->frame, current, sw);
/* skip over interrupt frame and oprofile calls */
do {
unw_get_sp(&bt->frame, &sp);
if (sp >= (u_long)bt->regs)
break;
if (!next_frame(bt))
return;
} while (count++ < 200);
/* finally, grab the actual sample */
while (bt->depth-- && next_frame(bt)) {
unw_get_ip(&bt->frame, &pc);
oprofile_add_trace(pc);
if (unw_is_intr_frame(&bt->frame)) {
/*
* Interrupt received on kernel stack; this can
* happen when timer interrupt fires while processing
* a softirq from the tail end of a hardware interrupt
* which interrupted a system call. Don't laugh, it
* happens! Splice the backtrace into two parts to
* avoid spurious cycles in the gprof output.
*/
/* TODO: split rather than drop the 2nd half */
break;
}
}
}
void
ia64_backtrace(struct pt_regs * const regs, unsigned int depth)
{
ia64_backtrace_t bt;
unsigned long flags;
/*
* On IA64 there is little hope of getting backtraces from
* user space programs -- the problems of getting the unwind
* information from arbitrary user programs are extreme.
*/
if (user_mode(regs))
return;
bt.depth = depth;
bt.regs = regs;
bt.prev_pfs_loc = NULL;
local_irq_save(flags);
unw_init_running(do_ia64_backtrace, &bt);
local_irq_restore(flags);
}
/**
* @file init.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/errno.h>
extern int perfmon_init(struct oprofile_operations *ops);
extern void perfmon_exit(void);
extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
ops->backtrace = ia64_backtrace;
return -ENODEV;
}
void oprofile_arch_exit(void)
{
}
......@@ -30,7 +30,6 @@ config MICROBLAZE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_OPROFILE
select HAVE_PCI
select IRQ_DOMAIN
select XILINX_INTC
......
......@@ -54,8 +54,6 @@ core-y += arch/microblaze/kernel/
core-y += arch/microblaze/mm/
core-$(CONFIG_PCI) += arch/microblaze/pci/
drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
boot := arch/microblaze/boot
# Are we making a simpleImage.<boardname> target? If so, crack out the boardname
......
# SPDX-License-Identifier: GPL-2.0
#
# arch/microblaze/oprofile/Makefile
#
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) microblaze_oprofile.o
/*
* Microblaze oprofile code
*
* Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2009 PetaLogix
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/oprofile.h>
#include <linux/init.h>
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
return -1;
}
void oprofile_arch_exit(void)
{
}
......@@ -74,7 +74,6 @@ config MIPS
select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RSEQ
......@@ -2845,7 +2844,7 @@ config NODES_SHIFT
config HW_PERF_EVENTS
bool "Enable hardware performance counter support for perf events"
depends on PERF_EVENTS && !OPROFILE && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON64)
depends on PERF_EVENTS && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON64)
default y
help
Enable hardware performance counter support for perf events. If
......
......@@ -316,7 +316,6 @@ libs-$(CONFIG_MIPS_FP_SUPPORT) += arch/mips/math-emu/
core-y += arch/mips/
drivers-y += arch/mips/crypto/
drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
# suspend and hibernation support
drivers-$(CONFIG_PM) += arch/mips/power/
......
......@@ -22,7 +22,6 @@ CONFIG_MIPS32_N32=y
# CONFIG_SUSPEND is not set
CONFIG_HIBERNATION=y
CONFIG_PM_STD_PARTITION="/dev/sda3"
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -14,7 +14,6 @@ CONFIG_SGI_IP32=y
CONFIG_PCI=y
CONFIG_MIPS32_O32=y
CONFIG_MIPS32_N32=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
......
......@@ -21,7 +21,6 @@ CONFIG_MIPS32_O32=y
CONFIG_MIPS32_N32=y
CONFIG_HIBERNATION=y
CONFIG_PM_STD_PARTITION="/dev/hda3"
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
......
......@@ -17,7 +17,6 @@ CONFIG_PCCARD=m
CONFIG_YENTA=m
CONFIG_PD6729=m
CONFIG_I82092=m
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
......
......@@ -30,7 +30,6 @@ CONFIG_PM=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
CONFIG_CPUFREQ_DT=y
CONFIG_OPROFILE=y
CONFIG_JUMP_LABEL=y
# CONFIG_STACKPROTECTOR is not set
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -56,15 +56,6 @@ extern int mach_i8259_irq(void);
(*(volatile u32 *)((char *)CKSEG1ADDR(LOONGSON_REG_BASE) + (x)))
#define LOONGSON_IRQ_BASE 32
#define LOONGSON2_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
#include <linux/interrupt.h>
static inline void do_perfcnt_IRQ(void)
{
#if IS_ENABLED(CONFIG_OPROFILE)
do_IRQ(LOONGSON2_PERFCNT_IRQ);
#endif
}
#define LOONGSON_FLASH_BASE 0x1c000000
#define LOONGSON_FLASH_SIZE 0x02000000 /* 32M */
......
......@@ -26,7 +26,7 @@ asmlinkage void mach_irq_dispatch(unsigned int pending)
if (pending & CAUSEF_IP7)
do_IRQ(MIPS_CPU_IRQ_BASE + 7);
else if (pending & CAUSEF_IP6) /* perf counter loverflow */
do_perfcnt_IRQ();
return;
else if (pending & CAUSEF_IP5)
i8259_irqdispatch();
else if (pending & CAUSEF_IP2)
......
......@@ -75,7 +75,6 @@ void mach_irq_dispatch(unsigned int pending)
if (pending & CAUSEF_IP7)
do_IRQ(LOONGSON_TIMER_IRQ);
else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
do_perfcnt_IRQ();
bonito_irqdispatch();
} else if (pending & CAUSEF_IP3) /* CPU UART */
do_IRQ(LOONGSON_UART_IRQ);
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
oprofile-$(CONFIG_CPU_MIPS32) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_R10000) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_SB1) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_XLR) += op_model_mipsxx.o
oprofile-$(CONFIG_CPU_LOONGSON2EF) += op_model_loongson2.o
oprofile-$(CONFIG_CPU_LOONGSON64) += op_model_loongson3.o
// SPDX-License-Identifier: GPL-2.0
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
#include <asm/stacktrace.h>
#include <linux/stacktrace.h>
#include <linux/kernel.h>
#include <asm/sections.h>
#include <asm/inst.h>
struct stackframe {
unsigned long sp;
unsigned long pc;
unsigned long ra;
};
static inline int get_mem(unsigned long addr, unsigned long *result)
{
unsigned long *address = (unsigned long *) addr;
if (!access_ok(address, sizeof(unsigned long)))
return -1;
if (__copy_from_user_inatomic(result, address, sizeof(unsigned long)))
return -3;
return 0;
}
/*
* These two instruction helpers were taken from process.c
*/
static inline int is_ra_save_ins(union mips_instruction *ip)
{
/* sw / sd $ra, offset($sp) */
return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op)
&& ip->i_format.rs == 29 && ip->i_format.rt == 31;
}
static inline int is_sp_move_ins(union mips_instruction *ip)
{
/* addiu/daddiu sp,sp,-imm */
if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
return 0;
if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
return 1;
return 0;
}
/*
* Looks for specific instructions that mark the end of a function.
* This usually means we ran into the code area of the previous function.
*/
static inline int is_end_of_function_marker(union mips_instruction *ip)
{
/* jr ra */
if (ip->r_format.func == jr_op && ip->r_format.rs == 31)
return 1;
/* lui gp */
if (ip->i_format.opcode == lui_op && ip->i_format.rt == 28)
return 1;
return 0;
}
/*
* TODO for userspace stack unwinding:
* - handle cases where the stack is adjusted inside a function
* (generally doesn't happen)
* - find optimal value for max_instr_check
* - try to find a better way to handle leaf functions
*/
static inline int unwind_user_frame(struct stackframe *old_frame,
const unsigned int max_instr_check)
{
struct stackframe new_frame = *old_frame;
off_t ra_offset = 0;
size_t stack_size = 0;
unsigned long addr;
if (old_frame->pc == 0 || old_frame->sp == 0 || old_frame->ra == 0)
return -9;
for (addr = new_frame.pc; (addr + max_instr_check > new_frame.pc)
&& (!ra_offset || !stack_size); --addr) {
union mips_instruction ip;
if (get_mem(addr, (unsigned long *) &ip))
return -11;
if (is_sp_move_ins(&ip)) {
int stack_adjustment = ip.i_format.simmediate;
if (stack_adjustment > 0)
/* This marks the end of the previous function,
which means we overran. */
break;
stack_size = (unsigned long) stack_adjustment;
} else if (is_ra_save_ins(&ip)) {
int ra_slot = ip.i_format.simmediate;
if (ra_slot < 0)
/* This shouldn't happen. */
break;
ra_offset = ra_slot;
} else if (is_end_of_function_marker(&ip))
break;
}
if (!ra_offset || !stack_size)
goto done;
if (ra_offset) {
new_frame.ra = old_frame->sp + ra_offset;
if (get_mem(new_frame.ra, &(new_frame.ra)))
return -13;
}
if (stack_size) {
new_frame.sp = old_frame->sp + stack_size;
if (get_mem(new_frame.sp, &(new_frame.sp)))
return -14;
}
if (new_frame.sp > old_frame->sp)
return -2;
done:
new_frame.pc = old_frame->ra;
*old_frame = new_frame;
return 0;
}
static inline void do_user_backtrace(unsigned long low_addr,
struct stackframe *frame,
unsigned int depth)
{
const unsigned int max_instr_check = 512;
const unsigned long high_addr = low_addr + THREAD_SIZE;
while (depth-- && !unwind_user_frame(frame, max_instr_check)) {
oprofile_add_trace(frame->ra);
if (frame->sp < low_addr || frame->sp > high_addr)
break;
}
}
#ifndef CONFIG_KALLSYMS
static inline void do_kernel_backtrace(unsigned long low_addr,
struct stackframe *frame,
unsigned int depth) { }
#else
static inline void do_kernel_backtrace(unsigned long low_addr,
struct stackframe *frame,
unsigned int depth)
{
while (depth-- && frame->pc) {
frame->pc = unwind_stack_by_address(low_addr,
&(frame->sp),
frame->pc,
&(frame->ra));
oprofile_add_trace(frame->ra);
}
}
#endif
void notrace op_mips_backtrace(struct pt_regs *const regs, unsigned int depth)
{
struct stackframe frame = { .sp = regs->regs[29],
.pc = regs->cp0_epc,
.ra = regs->regs[31] };
const int userspace = user_mode(regs);
const unsigned long low_addr = ALIGN(frame.sp, THREAD_SIZE);
if (userspace)
do_user_backtrace(low_addr, &frame, depth);
else
do_kernel_backtrace(low_addr, &frame, depth);
}
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2004, 2005 Ralf Baechle
* Copyright (C) 2005 MIPS Technologies, Inc.
*/
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/smp.h>
#include <asm/cpu-info.h>
#include <asm/cpu-type.h>
#include "op_impl.h"
extern struct op_mips_model op_model_mipsxx_ops __weak;
extern struct op_mips_model op_model_loongson2_ops __weak;
extern struct op_mips_model op_model_loongson3_ops __weak;
static struct op_mips_model *model;
static struct op_counter_config ctr[20];
static int op_mips_setup(void)
{
/* Pre-compute the values to stuff in the hardware registers. */
model->reg_setup(ctr);
/* Configure the registers on all cpus. */
on_each_cpu(model->cpu_setup, NULL, 1);
return 0;
}
static int op_mips_create_files(struct dentry *root)
{
int i;
for (i = 0; i < model->num_counters; ++i) {
struct dentry *dir;
char buf[4];
snprintf(buf, sizeof buf, "%d", i);
dir = oprofilefs_mkdir(root, buf);
oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
oprofilefs_create_ulong(dir, "event", &ctr[i].event);
oprofilefs_create_ulong(dir, "count", &ctr[i].count);
oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
oprofilefs_create_ulong(dir, "user", &ctr[i].user);
oprofilefs_create_ulong(dir, "exl", &ctr[i].exl);
/* Dummy. */
oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
}
return 0;
}
static int op_mips_start(void)
{
on_each_cpu(model->cpu_start, NULL, 1);
return 0;
}
static void op_mips_stop(void)
{
/* Disable performance monitoring for all counters. */
on_each_cpu(model->cpu_stop, NULL, 1);
}
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
struct op_mips_model *lmodel = NULL;
int res;
switch (boot_cpu_type()) {
case CPU_5KC:
case CPU_M14KC:
case CPU_M14KEC:
case CPU_20KC:
case CPU_24K:
case CPU_25KF:
case CPU_34K:
case CPU_1004K:
case CPU_74K:
case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_I6400:
case CPU_M5150:
case CPU_LOONGSON32:
case CPU_SB1:
case CPU_SB1A:
case CPU_R10000:
case CPU_R12000:
case CPU_R14000:
case CPU_R16000:
case CPU_XLR:
lmodel = &op_model_mipsxx_ops;
break;
case CPU_LOONGSON2EF:
lmodel = &op_model_loongson2_ops;
break;
case CPU_LOONGSON64:
lmodel = &op_model_loongson3_ops;
break;
}
/*
* Always set the backtrace. This allows unsupported CPU types to still
* use timer-based oprofile.
*/
ops->backtrace = op_mips_backtrace;
if (!lmodel)
return -ENODEV;
res = lmodel->init();
if (res)
return res;
model = lmodel;
ops->create_files = op_mips_create_files;
ops->setup = op_mips_setup;
//ops->shutdown = op_mips_shutdown;
ops->start = op_mips_start;
ops->stop = op_mips_stop;
ops->cpu_type = lmodel->cpu_type;
printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
lmodel->cpu_type);
return 0;
}
void oprofile_arch_exit(void)
{
if (model)
model->exit();
}
/**
* @file arch/alpha/oprofile/op_impl.h
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Richard Henderson <rth@twiddle.net>
*/
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
extern int (*perf_irq)(void);
/* Per-counter configuration as set via oprofilefs. */
struct op_counter_config {
unsigned long enabled;
unsigned long event;
unsigned long count;
/* Dummies because I am too lazy to hack the userspace tools. */
unsigned long kernel;
unsigned long user;
unsigned long exl;
unsigned long unit_mask;
};
/* Per-architecture configure and hooks. */
struct op_mips_model {
void (*reg_setup) (struct op_counter_config *);
void (*cpu_setup) (void *dummy);
int (*init)(void);
void (*exit)(void);
void (*cpu_start)(void *args);
void (*cpu_stop)(void *args);
char *cpu_type;
unsigned char num_counters;
};
void op_mips_backtrace(struct pt_regs * const regs, unsigned int depth);
#endif
/*
* Loongson2 performance counter driver for oprofile
*
* Copyright (C) 2009 Lemote Inc.
* Author: Yanhua <yanh@lemote.com>
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <loongson.h> /* LOONGSON2_PERFCNT_IRQ */
#include "op_impl.h"
#define LOONGSON2_CPU_TYPE "mips/loongson2"
#define LOONGSON2_PERFCNT_OVERFLOW (1ULL << 31)
#define LOONGSON2_PERFCTRL_EXL (1UL << 0)
#define LOONGSON2_PERFCTRL_KERNEL (1UL << 1)
#define LOONGSON2_PERFCTRL_SUPERVISOR (1UL << 2)
#define LOONGSON2_PERFCTRL_USER (1UL << 3)
#define LOONGSON2_PERFCTRL_ENABLE (1UL << 4)
#define LOONGSON2_PERFCTRL_EVENT(idx, event) \
(((event) & 0x0f) << ((idx) ? 9 : 5))
#define read_c0_perfctrl() __read_64bit_c0_register($24, 0)
#define write_c0_perfctrl(val) __write_64bit_c0_register($24, 0, val)
#define read_c0_perfcnt() __read_64bit_c0_register($25, 0)
#define write_c0_perfcnt(val) __write_64bit_c0_register($25, 0, val)
static struct loongson2_register_config {
unsigned int ctrl;
unsigned long long reset_counter1;
unsigned long long reset_counter2;
int cnt1_enabled, cnt2_enabled;
} reg;
static char *oprofid = "LoongsonPerf";
static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id);
static void reset_counters(void *arg)
{
write_c0_perfctrl(0);
write_c0_perfcnt(0);
}
static void loongson2_reg_setup(struct op_counter_config *cfg)
{
unsigned int ctrl = 0;
reg.reset_counter1 = 0;
reg.reset_counter2 = 0;
/*
* Compute the performance counter ctrl word.
* For now, count kernel and user mode.
*/
if (cfg[0].enabled) {
ctrl |= LOONGSON2_PERFCTRL_EVENT(0, cfg[0].event);
reg.reset_counter1 = 0x80000000ULL - cfg[0].count;
}
if (cfg[1].enabled) {
ctrl |= LOONGSON2_PERFCTRL_EVENT(1, cfg[1].event);
reg.reset_counter2 = 0x80000000ULL - cfg[1].count;
}
if (cfg[0].enabled || cfg[1].enabled) {
ctrl |= LOONGSON2_PERFCTRL_EXL | LOONGSON2_PERFCTRL_ENABLE;
if (cfg[0].kernel || cfg[1].kernel)
ctrl |= LOONGSON2_PERFCTRL_KERNEL;
if (cfg[0].user || cfg[1].user)
ctrl |= LOONGSON2_PERFCTRL_USER;
}
reg.ctrl = ctrl;
reg.cnt1_enabled = cfg[0].enabled;
reg.cnt2_enabled = cfg[1].enabled;
}
static void loongson2_cpu_setup(void *args)
{
write_c0_perfcnt((reg.reset_counter2 << 32) | reg.reset_counter1);
}
static void loongson2_cpu_start(void *args)
{
/* Start all counters on current CPU */
if (reg.cnt1_enabled || reg.cnt2_enabled)
write_c0_perfctrl(reg.ctrl);
}
static void loongson2_cpu_stop(void *args)
{
/* Stop all counters on current CPU */
write_c0_perfctrl(0);
memset(&reg, 0, sizeof(reg));
}
static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id)
{
uint64_t counter, counter1, counter2;
struct pt_regs *regs = get_irq_regs();
int enabled;
/* Check whether the irq belongs to me */
enabled = read_c0_perfctrl() & LOONGSON2_PERFCTRL_ENABLE;
if (!enabled)
return IRQ_NONE;
enabled = reg.cnt1_enabled | reg.cnt2_enabled;
if (!enabled)
return IRQ_NONE;
counter = read_c0_perfcnt();
counter1 = counter & 0xffffffff;
counter2 = counter >> 32;
if (counter1 & LOONGSON2_PERFCNT_OVERFLOW) {
if (reg.cnt1_enabled)
oprofile_add_sample(regs, 0);
counter1 = reg.reset_counter1;
}
if (counter2 & LOONGSON2_PERFCNT_OVERFLOW) {
if (reg.cnt2_enabled)
oprofile_add_sample(regs, 1);
counter2 = reg.reset_counter2;
}
write_c0_perfcnt((counter2 << 32) | counter1);
return IRQ_HANDLED;
}
static int __init loongson2_init(void)
{
return request_irq(LOONGSON2_PERFCNT_IRQ, loongson2_perfcount_handler,
IRQF_SHARED, "Perfcounter", oprofid);
}
static void loongson2_exit(void)
{
reset_counters(NULL);
free_irq(LOONGSON2_PERFCNT_IRQ, oprofid);
}
struct op_mips_model op_model_loongson2_ops = {
.reg_setup = loongson2_reg_setup,
.cpu_setup = loongson2_cpu_setup,
.init = loongson2_init,
.exit = loongson2_exit,
.cpu_start = loongson2_cpu_start,
.cpu_stop = loongson2_cpu_stop,
.cpu_type = LOONGSON2_CPU_TYPE,
.num_counters = 2
};
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/proc_fs.h>
#include <linux/oprofile.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <irq.h>
#include <loongson.h>
#include "op_impl.h"
#define LOONGSON3_PERFCNT_OVERFLOW (1ULL << 63)
#define LOONGSON3_PERFCTRL_EXL (1UL << 0)
#define LOONGSON3_PERFCTRL_KERNEL (1UL << 1)
#define LOONGSON3_PERFCTRL_SUPERVISOR (1UL << 2)
#define LOONGSON3_PERFCTRL_USER (1UL << 3)
#define LOONGSON3_PERFCTRL_ENABLE (1UL << 4)
#define LOONGSON3_PERFCTRL_W (1UL << 30)
#define LOONGSON3_PERFCTRL_M (1UL << 31)
#define LOONGSON3_PERFCTRL_EVENT(idx, event) \
(((event) & (idx ? 0x0f : 0x3f)) << 5)
/* Loongson-3 PerfCount performance counter1 register */
#define read_c0_perflo1() __read_64bit_c0_register($25, 0)
#define write_c0_perflo1(val) __write_64bit_c0_register($25, 0, val)
#define read_c0_perfhi1() __read_64bit_c0_register($25, 1)
#define write_c0_perfhi1(val) __write_64bit_c0_register($25, 1, val)
/* Loongson-3 PerfCount performance counter2 register */
#define read_c0_perflo2() __read_64bit_c0_register($25, 2)
#define write_c0_perflo2(val) __write_64bit_c0_register($25, 2, val)
#define read_c0_perfhi2() __read_64bit_c0_register($25, 3)
#define write_c0_perfhi2(val) __write_64bit_c0_register($25, 3, val)
static int (*save_perf_irq)(void);
static struct loongson3_register_config {
unsigned int control1;
unsigned int control2;
unsigned long long reset_counter1;
unsigned long long reset_counter2;
int ctr1_enable, ctr2_enable;
} reg;
static void reset_counters(void *arg)
{
write_c0_perfhi1(0);
write_c0_perfhi2(0);
write_c0_perflo1(0xc0000000);
write_c0_perflo2(0x40000000);
}
/* Compute all of the registers in preparation for enabling profiling. */
static void loongson3_reg_setup(struct op_counter_config *ctr)
{
unsigned int control1 = 0;
unsigned int control2 = 0;
reg.reset_counter1 = 0;
reg.reset_counter2 = 0;
/* Compute the performance counter control word. */
/* For now count kernel and user mode */
if (ctr[0].enabled) {
control1 |= LOONGSON3_PERFCTRL_EVENT(0, ctr[0].event) |
LOONGSON3_PERFCTRL_ENABLE;
if (ctr[0].kernel)
control1 |= LOONGSON3_PERFCTRL_KERNEL;
if (ctr[0].user)
control1 |= LOONGSON3_PERFCTRL_USER;
reg.reset_counter1 = 0x8000000000000000ULL - ctr[0].count;
}
if (ctr[1].enabled) {
control2 |= LOONGSON3_PERFCTRL_EVENT(1, ctr[1].event) |
LOONGSON3_PERFCTRL_ENABLE;
if (ctr[1].kernel)
control2 |= LOONGSON3_PERFCTRL_KERNEL;
if (ctr[1].user)
control2 |= LOONGSON3_PERFCTRL_USER;
reg.reset_counter2 = 0x8000000000000000ULL - ctr[1].count;
}
if (ctr[0].enabled)
control1 |= LOONGSON3_PERFCTRL_EXL;
if (ctr[1].enabled)
control2 |= LOONGSON3_PERFCTRL_EXL;
reg.control1 = control1;
reg.control2 = control2;
reg.ctr1_enable = ctr[0].enabled;
reg.ctr2_enable = ctr[1].enabled;
}
/* Program all of the registers in preparation for enabling profiling. */
static void loongson3_cpu_setup(void *args)
{
uint64_t perfcount1, perfcount2;
perfcount1 = reg.reset_counter1;
perfcount2 = reg.reset_counter2;
write_c0_perfhi1(perfcount1);
write_c0_perfhi2(perfcount2);
}
static void loongson3_cpu_start(void *args)
{
/* Start all counters on current CPU */
reg.control1 |= (LOONGSON3_PERFCTRL_W|LOONGSON3_PERFCTRL_M);
reg.control2 |= (LOONGSON3_PERFCTRL_W|LOONGSON3_PERFCTRL_M);
if (reg.ctr1_enable)
write_c0_perflo1(reg.control1);
if (reg.ctr2_enable)
write_c0_perflo2(reg.control2);
}
static void loongson3_cpu_stop(void *args)
{
/* Stop all counters on current CPU */
write_c0_perflo1(0xc0000000);
write_c0_perflo2(0x40000000);
memset(&reg, 0, sizeof(reg));
}
static int loongson3_perfcount_handler(void)
{
unsigned long flags;
uint64_t counter1, counter2;
uint32_t cause, handled = IRQ_NONE;
struct pt_regs *regs = get_irq_regs();
cause = read_c0_cause();
if (!(cause & CAUSEF_PCI))
return handled;
counter1 = read_c0_perfhi1();
counter2 = read_c0_perfhi2();
local_irq_save(flags);
if (counter1 & LOONGSON3_PERFCNT_OVERFLOW) {
if (reg.ctr1_enable)
oprofile_add_sample(regs, 0);
counter1 = reg.reset_counter1;
}
if (counter2 & LOONGSON3_PERFCNT_OVERFLOW) {
if (reg.ctr2_enable)
oprofile_add_sample(regs, 1);
counter2 = reg.reset_counter2;
}
local_irq_restore(flags);
write_c0_perfhi1(counter1);
write_c0_perfhi2(counter2);
if (!(cause & CAUSEF_TI))
handled = IRQ_HANDLED;
return handled;
}
static int loongson3_starting_cpu(unsigned int cpu)
{
write_c0_perflo1(reg.control1);
write_c0_perflo2(reg.control2);
return 0;
}
static int loongson3_dying_cpu(unsigned int cpu)
{
write_c0_perflo1(0xc0000000);
write_c0_perflo2(0x40000000);
return 0;
}
static int __init loongson3_init(void)
{
on_each_cpu(reset_counters, NULL, 1);
cpuhp_setup_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
"mips/oprofile/loongson3:starting",
loongson3_starting_cpu, loongson3_dying_cpu);
save_perf_irq = perf_irq;
perf_irq = loongson3_perfcount_handler;
return 0;
}
static void loongson3_exit(void)
{
on_each_cpu(reset_counters, NULL, 1);
cpuhp_remove_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING);
perf_irq = save_perf_irq;
}
struct op_mips_model op_model_loongson3_ops = {
.reg_setup = loongson3_reg_setup,
.cpu_setup = loongson3_cpu_setup,
.init = loongson3_init,
.exit = loongson3_exit,
.cpu_start = loongson3_cpu_start,
.cpu_stop = loongson3_cpu_stop,
.cpu_type = "mips/loongson3",
.num_counters = 2
};
This diff is collapsed.
......@@ -4,7 +4,6 @@ config PARISC
select ARCH_32BIT_OFF_T if !64BIT
select ARCH_MIGHT_HAVE_PC_PARPORT
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_SYSCALL_TRACEPOINTS
......
......@@ -116,8 +116,6 @@ kernel-y := mm/ kernel/ math-emu/
core-y += $(addprefix arch/parisc/, $(kernel-y))
libs-y += arch/parisc/lib/ $(LIBGCC)
drivers-$(CONFIG_OPROFILE) += arch/parisc/oprofile/
boot := arch/parisc/boot
PALO := $(shell if (which palo 2>&1); then : ; \
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.o
/**
* @file init.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/oprofile.h>
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
return -ENODEV;
}
void oprofile_arch_exit(void)
{
}
......@@ -226,7 +226,6 @@ config PPC
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
select HAVE_HARDLOCKUP_DETECTOR_ARCH if (PPC64 && PPC_BOOK3S)
select HAVE_OPROFILE
select HAVE_OPTPROBES if PPC64
select HAVE_PERF_EVENTS
select HAVE_PERF_EVENTS_NMI if PPC64
......
......@@ -276,8 +276,6 @@ head-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += arch/powerpc/kernel/prom_init.o
# See arch/powerpc/Kbuild for content of core part of the kernel
core-y += arch/powerpc/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
# Default to zImage, override when needed
all: zImage
......
......@@ -8,7 +8,6 @@ CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_SLUB_CPU_PARTIAL is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -6,7 +6,6 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -17,7 +17,6 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_BPF_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -7,7 +7,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -14,7 +14,6 @@ CONFIG_CPUSETS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
......
......@@ -12,7 +12,6 @@ CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
......
......@@ -9,7 +9,6 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -7,7 +7,6 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
......
......@@ -10,7 +10,6 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
......
......@@ -30,7 +30,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_BPF_SYSCALL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
......
......@@ -62,7 +62,6 @@ CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=m
CONFIG_VHOST_NET=m
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
......
......@@ -14,7 +14,6 @@ CONFIG_CPUSETS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
......
......@@ -19,7 +19,6 @@ CONFIG_USER_NS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
......
......@@ -13,7 +13,6 @@ CONFIG_EMBEDDED=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_PPC_POWERNV is not set
......
......@@ -29,7 +29,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_BPF_SYSCALL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment