Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
fda0e18c
Commit
fda0e18c
authored
14 years ago
by
Russell King
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'devel-pmu' into devel
parents
98830bc9
d1e86d64
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1316 additions
and
1950 deletions
+1316
-1950
arch/arm/Kconfig
arch/arm/Kconfig
+2
-24
arch/arm/include/asm/perf_event.h
arch/arm/include/asm/perf_event.h
+17
-0
arch/arm/include/asm/pmu.h
arch/arm/include/asm/pmu.h
+12
-15
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_event.c
+892
-36
arch/arm/kernel/pmu.c
arch/arm/kernel/pmu.c
+83
-44
arch/arm/oprofile/Makefile
arch/arm/oprofile/Makefile
+1
-6
arch/arm/oprofile/backtrace.c
arch/arm/oprofile/backtrace.c
+0
-83
arch/arm/oprofile/common.c
arch/arm/oprofile/common.c
+309
-66
arch/arm/oprofile/op_arm_model.h
arch/arm/oprofile/op_arm_model.h
+0
-35
arch/arm/oprofile/op_counter.h
arch/arm/oprofile/op_counter.h
+0
-27
arch/arm/oprofile/op_model_arm11_core.c
arch/arm/oprofile/op_model_arm11_core.c
+0
-162
arch/arm/oprofile/op_model_arm11_core.h
arch/arm/oprofile/op_model_arm11_core.h
+0
-45
arch/arm/oprofile/op_model_mpcore.c
arch/arm/oprofile/op_model_mpcore.c
+0
-306
arch/arm/oprofile/op_model_mpcore.h
arch/arm/oprofile/op_model_mpcore.h
+0
-61
arch/arm/oprofile/op_model_v6.c
arch/arm/oprofile/op_model_v6.c
+0
-78
arch/arm/oprofile/op_model_v7.c
arch/arm/oprofile/op_model_v7.c
+0
-415
arch/arm/oprofile/op_model_v7.h
arch/arm/oprofile/op_model_v7.h
+0
-103
arch/arm/oprofile/op_model_xscale.c
arch/arm/oprofile/op_model_xscale.c
+0
-444
No files found.
arch/arm/Kconfig
View file @
fda0e18c
...
...
@@ -13,7 +13,7 @@ config ARM
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
select GENERIC_ATOMIC64 if (!CPU_32v6K)
select HAVE_OPROFILE
select HAVE_OPROFILE
if (HAVE_PERF_EVENTS)
select HAVE_ARCH_KGDB
select HAVE_KPROBES if (!XIP_KERNEL)
select HAVE_KRETPROBES if (HAVE_KPROBES)
...
...
@@ -181,28 +181,6 @@ config ARM_L1_CACHE_SHIFT_6
help
Setting ARM L1 cache line size to 64 Bytes.
if OPROFILE
config OPROFILE_ARMV6
def_bool y
depends on CPU_V6 && !SMP
select OPROFILE_ARM11_CORE
config OPROFILE_MPCORE
def_bool y
depends on CPU_V6 && SMP
select OPROFILE_ARM11_CORE
config OPROFILE_ARM11_CORE
bool
config OPROFILE_ARMV7
def_bool y
depends on CPU_V7 && !SMP
bool
endif
config VECTORS_BASE
hex
default 0xffff0000 if MMU || CPU_HIGH_VECTOR
...
...
@@ -1314,7 +1292,7 @@ config HIGHPTE
config HW_PERF_EVENTS
bool "Enable hardware performance counter support for perf events"
depends on PERF_EVENTS && CPU_HAS_PMU
&& (CPU_V6 || CPU_V7)
depends on PERF_EVENTS && CPU_HAS_PMU
default y
help
Enable hardware performance counter support for perf events. If
...
...
This diff is collapsed.
Click to expand it.
arch/arm/include/asm/perf_event.h
View file @
fda0e18c
...
...
@@ -28,4 +28,21 @@ set_perf_event_pending(void)
* same indexes here for consistency. */
#define PERF_EVENT_INDEX_OFFSET 1
/* ARM perf PMU IDs for use by internal perf clients. */
enum
arm_perf_pmu_ids
{
ARM_PERF_PMU_ID_XSCALE1
=
0
,
ARM_PERF_PMU_ID_XSCALE2
,
ARM_PERF_PMU_ID_V6
,
ARM_PERF_PMU_ID_V6MP
,
ARM_PERF_PMU_ID_CA8
,
ARM_PERF_PMU_ID_CA9
,
ARM_NUM_PMU_IDS
,
};
extern
enum
arm_perf_pmu_ids
armpmu_get_pmu_id
(
void
);
extern
int
armpmu_get_max_events
(
void
);
#endif
/* __ARM_PERF_EVENT_H__ */
This diff is collapsed.
Click to expand it.
arch/arm/include/asm/pmu.h
View file @
fda0e18c
...
...
@@ -19,31 +19,26 @@ enum arm_pmu_type {
#ifdef CONFIG_CPU_HAS_PMU
struct
pmu_irqs
{
const
int
*
irqs
;
int
num_irqs
;
};
/**
* reserve_pmu() - reserve the hardware performance counters
*
* Reserve the hardware performance counters in the system for exclusive use.
* The
'struct pmu_irqs'
for the system is returned on success, ERR_PTR()
* The
platform_device
for the system is returned on success, ERR_PTR()
* encoded error on failure.
*/
extern
const
struct
pmu_irqs
*
reserve_pmu
(
void
);
extern
struct
platform_device
*
reserve_pmu
(
enum
arm_pmu_type
device
);
/**
* release_pmu() - Relinquish control of the performance counters
*
* Release the performance counters and allow someone else to use them.
* Callers must have disabled the counters and released IRQs before calling
* this. The
'struct pmu_irqs'
returned from reserve_pmu() must be passed as
* this. The
platform_device
returned from reserve_pmu() must be passed as
* a cookie.
*/
extern
int
release_pmu
(
const
struct
pmu_irqs
*
irqs
);
release_pmu
(
struct
platform_device
*
pdev
);
/**
* init_pmu() - Initialise the PMU.
...
...
@@ -53,24 +48,26 @@ release_pmu(const struct pmu_irqs *irqs);
* the actual hardware initialisation.
*/
extern
int
init_pmu
(
void
);
init_pmu
(
enum
arm_pmu_type
device
);
#else
/* CONFIG_CPU_HAS_PMU */
static
inline
const
struct
pmu_irqs
*
reserve_pmu
(
void
)
#include <linux/err.h>
static
inline
struct
platform_device
*
reserve_pmu
(
enum
arm_pmu_type
device
)
{
return
ERR_PTR
(
-
ENODEV
);
}
static
inline
int
release_pmu
(
const
struct
pmu_irqs
*
irqs
)
release_pmu
(
struct
platform_device
*
pdev
)
{
return
-
ENODEV
;
}
static
inline
int
init_pmu
(
void
)
init_pmu
(
enum
arm_pmu_type
device
)
{
return
-
ENODEV
;
}
...
...
This diff is collapsed.
Click to expand it.
arch/arm/kernel/perf_event.c
View file @
fda0e18c
This diff is collapsed.
Click to expand it.
arch/arm/kernel/pmu.c
View file @
fda0e18c
...
...
@@ -2,6 +2,7 @@
* linux/arch/arm/kernel/pmu.c
*
* Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
* Copyright (C) 2010 ARM Ltd, Will Deacon
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
...
...
@@ -9,65 +10,78 @@
*
*/
#define pr_fmt(fmt) "PMU: " fmt
#include <linux/cpumask.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/pmu.h>
/*
* Define the IRQs for the system. We could use something like a platform
* device but that seems fairly heavyweight for this. Also, the performance
* counters can't be removed or hotplugged.
*
* Ordering is important: init_pmu() will use the ordering to set the affinity
* to the corresponding core. e.g. the first interrupt will go to cpu 0, the
* second goes to cpu 1 etc.
*/
static
const
int
irqs
[]
=
{
#if defined(CONFIG_ARCH_OMAP2)
3
,
#elif defined(CONFIG_ARCH_BCMRING)
IRQ_PMUIRQ
,
#elif defined(CONFIG_MACH_REALVIEW_EB)
IRQ_EB11MP_PMU_CPU0
,
IRQ_EB11MP_PMU_CPU1
,
IRQ_EB11MP_PMU_CPU2
,
IRQ_EB11MP_PMU_CPU3
,
#elif defined(CONFIG_ARCH_OMAP3)
INT_34XX_BENCH_MPU_EMUL
,
#elif defined(CONFIG_ARCH_IOP32X)
IRQ_IOP32X_CORE_PMU
,
#elif defined(CONFIG_ARCH_IOP33X)
IRQ_IOP33X_CORE_PMU
,
#elif defined(CONFIG_ARCH_PXA)
IRQ_PMU
,
#endif
};
static
volatile
long
pmu_lock
;
static
struct
platform_device
*
pmu_devices
[
ARM_NUM_PMU_DEVICES
];
static
int
__devinit
pmu_device_probe
(
struct
platform_device
*
pdev
)
{
if
(
pdev
->
id
<
0
||
pdev
->
id
>=
ARM_NUM_PMU_DEVICES
)
{
pr_warning
(
"received registration request for unknown "
"device %d
\n
"
,
pdev
->
id
);
return
-
EINVAL
;
}
if
(
pmu_devices
[
pdev
->
id
])
pr_warning
(
"registering new PMU device type %d overwrites "
"previous registration!
\n
"
,
pdev
->
id
);
else
pr_info
(
"registered new PMU device of type %d
\n
"
,
pdev
->
id
);
static
const
struct
pmu_irqs
pmu_irqs
=
{
.
irqs
=
irqs
,
.
num_irqs
=
ARRAY_SIZE
(
irqs
),
pmu_devices
[
pdev
->
id
]
=
pdev
;
return
0
;
}
static
struct
platform_driver
pmu_driver
=
{
.
driver
=
{
.
name
=
"arm-pmu"
,
},
.
probe
=
pmu_device_probe
,
};
static
volatile
long
pmu_lock
;
static
int
__init
register_pmu_driver
(
void
)
{
return
platform_driver_register
(
&
pmu_driver
);
}
device_initcall
(
register_pmu_driver
);
const
struct
pmu_irqs
*
reserve_pmu
(
void
)
struct
platform_device
*
reserve_pmu
(
enum
arm_pmu_type
device
)
{
return
test_and_set_bit_lock
(
0
,
&
pmu_lock
)
?
ERR_PTR
(
-
EBUSY
)
:
&
pmu_irqs
;
struct
platform_device
*
pdev
;
if
(
test_and_set_bit_lock
(
device
,
&
pmu_lock
))
{
pdev
=
ERR_PTR
(
-
EBUSY
);
}
else
if
(
pmu_devices
[
device
]
==
NULL
)
{
clear_bit_unlock
(
device
,
&
pmu_lock
);
pdev
=
ERR_PTR
(
-
ENODEV
);
}
else
{
pdev
=
pmu_devices
[
device
];
}
return
pdev
;
}
EXPORT_SYMBOL_GPL
(
reserve_pmu
);
int
release_pmu
(
const
struct
pmu_irqs
*
irqs
)
release_pmu
(
struct
platform_device
*
pdev
)
{
if
(
WARN_ON
(
irqs
!=
&
pmu_irqs
))
if
(
WARN_ON
(
pdev
!=
pmu_devices
[
pdev
->
id
]
))
return
-
EINVAL
;
clear_bit_unlock
(
0
,
&
pmu_lock
);
clear_bit_unlock
(
pdev
->
id
,
&
pmu_lock
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
release_pmu
);
...
...
@@ -87,17 +101,42 @@ set_irq_affinity(int irq,
#endif
}
int
init_pmu
(
void
)
static
int
init_
cpu_
pmu
(
void
)
{
int
i
,
err
=
0
;
struct
platform_device
*
pdev
=
pmu_devices
[
ARM_PMU_DEVICE_CPU
];
if
(
!
pdev
)
{
err
=
-
ENODEV
;
goto
out
;
}
for
(
i
=
0
;
i
<
p
mu_irqs
.
num_irq
s
;
++
i
)
{
err
=
set_irq_affinity
(
p
mu_irqs
.
irqs
[
i
]
,
i
);
for
(
i
=
0
;
i
<
p
dev
->
num_resource
s
;
++
i
)
{
err
=
set_irq_affinity
(
p
latform_get_irq
(
pdev
,
i
)
,
i
);
if
(
err
)
break
;
}
out:
return
err
;
}
int
init_pmu
(
enum
arm_pmu_type
device
)
{
int
err
=
0
;
switch
(
device
)
{
case
ARM_PMU_DEVICE_CPU
:
err
=
init_cpu_pmu
();
break
;
default:
pr_warning
(
"attempt to initialise unknown device %d
\n
"
,
device
);
err
=
-
EINVAL
;
}
return
err
;
}
EXPORT_SYMBOL_GPL
(
init_pmu
);
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/Makefile
View file @
fda0e18c
...
...
@@ -6,9 +6,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o
\
timer_int.o
)
oprofile-y
:=
$(DRIVER_OBJS)
common.o backtrace.o
oprofile-$(CONFIG_CPU_XSCALE)
+=
op_model_xscale.o
oprofile-$(CONFIG_OPROFILE_ARM11_CORE)
+=
op_model_arm11_core.o
oprofile-$(CONFIG_OPROFILE_ARMV6)
+=
op_model_v6.o
oprofile-$(CONFIG_OPROFILE_MPCORE)
+=
op_model_mpcore.o
oprofile-$(CONFIG_OPROFILE_ARMV7)
+=
op_model_v7.o
oprofile-y
:=
$(DRIVER_OBJS)
common.o
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/backtrace.c
deleted
100644 → 0
View file @
98830bc9
/*
* Arm specific backtracing code for oprofile
*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* Based on i386 oprofile backtrace code by John Levon, David Smith
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
#include <asm/stacktrace.h>
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
(
VERIFY_READ
,
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
>=
buftail
[
0
].
fp
)
return
NULL
;
return
buftail
[
0
].
fp
-
1
;
}
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
;
frame
.
fp
=
regs
->
ARM_fp
;
frame
.
sp
=
regs
->
ARM_sp
;
frame
.
lr
=
regs
->
ARM_lr
;
frame
.
pc
=
regs
->
ARM_pc
;
walk_stackframe
(
&
frame
,
report_trace
,
&
depth
);
return
;
}
while
(
depth
--
&&
tail
&&
!
((
unsigned
long
)
tail
&
3
))
tail
=
user_backtrace
(
tail
);
}
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/common.c
View file @
fda0e18c
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_arm_model.h
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_arm_model.h
* interface to ARM machine specific operations
*
* @remark Copyright 2004 Oprofile Authors
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
*/
#ifndef OP_ARM_MODEL_H
#define OP_ARM_MODEL_H
struct
op_arm_model_spec
{
int
(
*
init
)(
void
);
unsigned
int
num_counters
;
int
(
*
setup_ctrs
)(
void
);
int
(
*
start
)(
void
);
void
(
*
stop
)(
void
);
char
*
name
;
};
#ifdef CONFIG_CPU_XSCALE
extern
struct
op_arm_model_spec
op_xscale_spec
;
#endif
extern
struct
op_arm_model_spec
op_armv6_spec
;
extern
struct
op_arm_model_spec
op_mpcore_spec
;
extern
struct
op_arm_model_spec
op_armv7_spec
;
extern
void
arm_backtrace
(
struct
pt_regs
*
const
regs
,
unsigned
int
depth
);
extern
int
__init
op_arm_init
(
struct
oprofile_operations
*
ops
,
struct
op_arm_model_spec
*
spec
);
extern
void
op_arm_exit
(
void
);
#endif
/* OP_ARM_MODEL_H */
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_counter.h
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_counter.h
*
* @remark Copyright 2004 Oprofile Authors
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
*/
#ifndef OP_COUNTER_H
#define OP_COUNTER_H
/* Per performance monitor configuration as set via
* oprofilefs.
*/
struct
op_counter_config
{
unsigned
long
count
;
unsigned
long
enabled
;
unsigned
long
event
;
unsigned
long
unit_mask
;
unsigned
long
kernel
;
unsigned
long
user
;
};
extern
struct
op_counter_config
*
counter_config
;
#endif
/* OP_COUNTER_H */
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_arm11_core.c
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_model_arm11_core.c
* ARM11 Event Monitor Driver
* @remark Copyright 2004 ARM SMP Development Team
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_arm11_core.h"
/*
* ARM11 PMU support
*/
static
inline
void
arm11_write_pmnc
(
u32
val
)
{
/* upper 4bits and 7, 11 are write-as-0 */
val
&=
0x0ffff77f
;
asm
volatile
(
"mcr p15, 0, %0, c15, c12, 0"
:
:
"r"
(
val
));
}
static
inline
u32
arm11_read_pmnc
(
void
)
{
u32
val
;
asm
volatile
(
"mrc p15, 0, %0, c15, c12, 0"
:
"=r"
(
val
));
return
val
;
}
static
void
arm11_reset_counter
(
unsigned
int
cnt
)
{
u32
val
=
-
(
u32
)
counter_config
[
CPU_COUNTER
(
smp_processor_id
(),
cnt
)].
count
;
switch
(
cnt
)
{
case
CCNT
:
asm
volatile
(
"mcr p15, 0, %0, c15, c12, 1"
:
:
"r"
(
val
));
break
;
case
PMN0
:
asm
volatile
(
"mcr p15, 0, %0, c15, c12, 2"
:
:
"r"
(
val
));
break
;
case
PMN1
:
asm
volatile
(
"mcr p15, 0, %0, c15, c12, 3"
:
:
"r"
(
val
));
break
;
}
}
int
arm11_setup_pmu
(
void
)
{
unsigned
int
cnt
;
u32
pmnc
;
if
(
arm11_read_pmnc
()
&
PMCR_E
)
{
printk
(
KERN_ERR
"oprofile: CPU%u PMU still enabled when setup new event counter.
\n
"
,
smp_processor_id
());
return
-
EBUSY
;
}
/* initialize PMNC, reset overflow, D bit, C bit and P bit. */
arm11_write_pmnc
(
PMCR_OFL_PMN0
|
PMCR_OFL_PMN1
|
PMCR_OFL_CCNT
|
PMCR_C
|
PMCR_P
);
for
(
pmnc
=
0
,
cnt
=
PMN0
;
cnt
<=
CCNT
;
cnt
++
)
{
unsigned
long
event
;
if
(
!
counter_config
[
CPU_COUNTER
(
smp_processor_id
(),
cnt
)].
enabled
)
continue
;
event
=
counter_config
[
CPU_COUNTER
(
smp_processor_id
(),
cnt
)].
event
&
255
;
/*
* Set event (if destined for PMNx counters)
*/
if
(
cnt
==
PMN0
)
{
pmnc
|=
event
<<
20
;
}
else
if
(
cnt
==
PMN1
)
{
pmnc
|=
event
<<
12
;
}
/*
* We don't need to set the event if it's a cycle count
* Enable interrupt for this counter
*/
pmnc
|=
PMCR_IEN_PMN0
<<
cnt
;
arm11_reset_counter
(
cnt
);
}
arm11_write_pmnc
(
pmnc
);
return
0
;
}
int
arm11_start_pmu
(
void
)
{
arm11_write_pmnc
(
arm11_read_pmnc
()
|
PMCR_E
);
return
0
;
}
int
arm11_stop_pmu
(
void
)
{
unsigned
int
cnt
;
arm11_write_pmnc
(
arm11_read_pmnc
()
&
~
PMCR_E
);
for
(
cnt
=
PMN0
;
cnt
<=
CCNT
;
cnt
++
)
arm11_reset_counter
(
cnt
);
return
0
;
}
/*
* CPU counters' IRQ handler (one IRQ per CPU)
*/
static
irqreturn_t
arm11_pmu_interrupt
(
int
irq
,
void
*
arg
)
{
struct
pt_regs
*
regs
=
get_irq_regs
();
unsigned
int
cnt
;
u32
pmnc
;
pmnc
=
arm11_read_pmnc
();
for
(
cnt
=
PMN0
;
cnt
<=
CCNT
;
cnt
++
)
{
if
((
pmnc
&
(
PMCR_OFL_PMN0
<<
cnt
))
&&
(
pmnc
&
(
PMCR_IEN_PMN0
<<
cnt
)))
{
arm11_reset_counter
(
cnt
);
oprofile_add_sample
(
regs
,
CPU_COUNTER
(
smp_processor_id
(),
cnt
));
}
}
/* Clear counter flag(s) */
arm11_write_pmnc
(
pmnc
);
return
IRQ_HANDLED
;
}
int
arm11_request_interrupts
(
const
int
*
irqs
,
int
nr
)
{
unsigned
int
i
;
int
ret
=
0
;
for
(
i
=
0
;
i
<
nr
;
i
++
)
{
ret
=
request_irq
(
irqs
[
i
],
arm11_pmu_interrupt
,
IRQF_DISABLED
,
"CP15 PMU"
,
NULL
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
"oprofile: unable to request IRQ%u for MPCORE-EM
\n
"
,
irqs
[
i
]);
break
;
}
}
if
(
i
!=
nr
)
while
(
i
--
!=
0
)
free_irq
(
irqs
[
i
],
NULL
);
return
ret
;
}
void
arm11_release_interrupts
(
const
int
*
irqs
,
int
nr
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
nr
;
i
++
)
free_irq
(
irqs
[
i
],
NULL
);
}
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_arm11_core.h
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_model_arm11_core.h
* ARM11 Event Monitor Driver
* @remark Copyright 2004 ARM SMP Development Team
* @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
* @remark Copyright 2000-2004 MontaVista Software Inc
* @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
* @remark Copyright 2004 Intel Corporation
* @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
* @remark Copyright 2004 Oprofile Authors
*
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
*/
#ifndef OP_MODEL_ARM11_CORE_H
#define OP_MODEL_ARM11_CORE_H
/*
* Per-CPU PMCR
*/
#define PMCR_E (1 << 0)
/* Enable */
#define PMCR_P (1 << 1)
/* Count reset */
#define PMCR_C (1 << 2)
/* Cycle counter reset */
#define PMCR_D (1 << 3)
/* Cycle counter counts every 64th cpu cycle */
#define PMCR_IEN_PMN0 (1 << 4)
/* Interrupt enable count reg 0 */
#define PMCR_IEN_PMN1 (1 << 5)
/* Interrupt enable count reg 1 */
#define PMCR_IEN_CCNT (1 << 6)
/* Interrupt enable cycle counter */
#define PMCR_OFL_PMN0 (1 << 8)
/* Count reg 0 overflow */
#define PMCR_OFL_PMN1 (1 << 9)
/* Count reg 1 overflow */
#define PMCR_OFL_CCNT (1 << 10)
/* Cycle counter overflow */
#define PMN0 0
#define PMN1 1
#define CCNT 2
#define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter))
int
arm11_setup_pmu
(
void
);
int
arm11_start_pmu
(
void
);
int
arm11_stop_pmu
(
void
);
int
arm11_request_interrupts
(
const
int
*
,
int
);
void
arm11_release_interrupts
(
const
int
*
,
int
);
#endif
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_mpcore.c
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_model_mpcore.c
* MPCORE Event Monitor Driver
* @remark Copyright 2004 ARM SMP Development Team
* @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
* @remark Copyright 2000-2004 MontaVista Software Inc
* @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
* @remark Copyright 2004 Intel Corporation
* @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
* @remark Copyright 2004 Oprofile Authors
*
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
*
* Counters:
* 0: PMN0 on CPU0, per-cpu configurable event counter
* 1: PMN1 on CPU0, per-cpu configurable event counter
* 2: CCNT on CPU0
* 3: PMN0 on CPU1
* 4: PMN1 on CPU1
* 5: CCNT on CPU1
* 6: PMN0 on CPU1
* 7: PMN1 on CPU1
* 8: CCNT on CPU1
* 9: PMN0 on CPU1
* 10: PMN1 on CPU1
* 11: CCNT on CPU1
* 12-19: configurable SCU event counters
*/
/* #define DEBUG */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <mach/hardware.h>
#include <mach/board-eb.h>
#include <asm/system.h>
#include <asm/pmu.h>
#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_arm11_core.h"
#include "op_model_mpcore.h"
/*
* MPCore SCU event monitor support
*/
#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10)
/*
* Bitmask of used SCU counters
*/
static
unsigned
int
scu_em_used
;
static
const
struct
pmu_irqs
*
pmu_irqs
;
/*
* 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
*/
static
inline
void
scu_reset_counter
(
struct
eventmonitor
__iomem
*
emc
,
unsigned
int
n
)
{
writel
(
-
(
u32
)
counter_config
[
SCU_COUNTER
(
n
)].
count
,
&
emc
->
MC
[
n
]);
}
static
inline
void
scu_set_event
(
struct
eventmonitor
__iomem
*
emc
,
unsigned
int
n
,
u32
event
)
{
event
&=
0xff
;
writeb
(
event
,
&
emc
->
MCEB
[
n
]);
}
/*
* SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU)
*/
static
irqreturn_t
scu_em_interrupt
(
int
irq
,
void
*
arg
)
{
struct
eventmonitor
__iomem
*
emc
=
SCU_EVENTMONITORS_VA_BASE
;
unsigned
int
cnt
;
cnt
=
irq
-
IRQ_EB11MP_PMU_SCU0
;
oprofile_add_sample
(
get_irq_regs
(),
SCU_COUNTER
(
cnt
));
scu_reset_counter
(
emc
,
cnt
);
/* Clear overflow flag for this counter */
writel
(
1
<<
(
cnt
+
16
),
&
emc
->
PMCR
);
return
IRQ_HANDLED
;
}
/* Configure just the SCU counters that the user has requested */
static
void
scu_setup
(
void
)
{
struct
eventmonitor
__iomem
*
emc
=
SCU_EVENTMONITORS_VA_BASE
;
unsigned
int
i
;
scu_em_used
=
0
;
for
(
i
=
0
;
i
<
NUM_SCU_COUNTERS
;
i
++
)
{
if
(
counter_config
[
SCU_COUNTER
(
i
)].
enabled
&&
counter_config
[
SCU_COUNTER
(
i
)].
event
)
{
scu_set_event
(
emc
,
i
,
0
);
/* disable counter for now */
scu_em_used
|=
1
<<
i
;
}
}
}
static
int
scu_start
(
void
)
{
struct
eventmonitor
__iomem
*
emc
=
SCU_EVENTMONITORS_VA_BASE
;
unsigned
int
temp
,
i
;
unsigned
long
event
;
int
ret
=
0
;
/*
* request the SCU counter interrupts that we need
*/
for
(
i
=
0
;
i
<
NUM_SCU_COUNTERS
;
i
++
)
{
if
(
scu_em_used
&
(
1
<<
i
))
{
ret
=
request_irq
(
IRQ_EB11MP_PMU_SCU0
+
i
,
scu_em_interrupt
,
IRQF_DISABLED
,
"SCU PMU"
,
NULL
);
if
(
ret
)
{
printk
(
KERN_ERR
"oprofile: unable to request IRQ%u for SCU Event Monitor
\n
"
,
IRQ_EB11MP_PMU_SCU0
+
i
);
goto
err_free_scu
;
}
}
}
/*
* clear overflow and enable interrupt for all used counters
*/
temp
=
readl
(
&
emc
->
PMCR
);
for
(
i
=
0
;
i
<
NUM_SCU_COUNTERS
;
i
++
)
{
if
(
scu_em_used
&
(
1
<<
i
))
{
scu_reset_counter
(
emc
,
i
);
event
=
counter_config
[
SCU_COUNTER
(
i
)].
event
;
scu_set_event
(
emc
,
i
,
event
);
/* clear overflow/interrupt */
temp
|=
1
<<
(
i
+
16
);
/* enable interrupt*/
temp
|=
1
<<
(
i
+
8
);
}
}
/* Enable all 8 counters */
temp
|=
PMCR_E
;
writel
(
temp
,
&
emc
->
PMCR
);
return
0
;
err_free_scu:
while
(
i
--
)
free_irq
(
IRQ_EB11MP_PMU_SCU0
+
i
,
NULL
);
return
ret
;
}
static
void
scu_stop
(
void
)
{
struct
eventmonitor
__iomem
*
emc
=
SCU_EVENTMONITORS_VA_BASE
;
unsigned
int
temp
,
i
;
/* Disable counter interrupts */
/* Don't disable all 8 counters (with the E bit) as they may be in use */
temp
=
readl
(
&
emc
->
PMCR
);
for
(
i
=
0
;
i
<
NUM_SCU_COUNTERS
;
i
++
)
{
if
(
scu_em_used
&
(
1
<<
i
))
temp
&=
~
(
1
<<
(
i
+
8
));
}
writel
(
temp
,
&
emc
->
PMCR
);
/* Free counter interrupts and reset counters */
for
(
i
=
0
;
i
<
NUM_SCU_COUNTERS
;
i
++
)
{
if
(
scu_em_used
&
(
1
<<
i
))
{
scu_reset_counter
(
emc
,
i
);
free_irq
(
IRQ_EB11MP_PMU_SCU0
+
i
,
NULL
);
}
}
}
struct
em_function_data
{
int
(
*
fn
)(
void
);
int
ret
;
};
static
void
em_func
(
void
*
data
)
{
struct
em_function_data
*
d
=
data
;
int
ret
=
d
->
fn
();
if
(
ret
)
d
->
ret
=
ret
;
}
static
int
em_call_function
(
int
(
*
fn
)(
void
))
{
struct
em_function_data
data
;
data
.
fn
=
fn
;
data
.
ret
=
0
;
preempt_disable
();
smp_call_function
(
em_func
,
&
data
,
1
);
em_func
(
&
data
);
preempt_enable
();
return
data
.
ret
;
}
/*
* Glue to stick the individual ARM11 PMUs and the SCU
* into the oprofile framework.
*/
static
int
em_setup_ctrs
(
void
)
{
int
ret
;
/* Configure CPU counters by cross-calling to the other CPUs */
ret
=
em_call_function
(
arm11_setup_pmu
);
if
(
ret
==
0
)
scu_setup
();
return
0
;
}
static
int
em_start
(
void
)
{
int
ret
;
pmu_irqs
=
reserve_pmu
();
if
(
IS_ERR
(
pmu_irqs
))
{
ret
=
PTR_ERR
(
pmu_irqs
);
goto
out
;
}
ret
=
arm11_request_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
if
(
ret
==
0
)
{
em_call_function
(
arm11_start_pmu
);
ret
=
scu_start
();
if
(
ret
)
{
arm11_release_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
}
else
{
release_pmu
(
pmu_irqs
);
pmu_irqs
=
NULL
;
}
}
out:
return
ret
;
}
static
void
em_stop
(
void
)
{
em_call_function
(
arm11_stop_pmu
);
arm11_release_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
scu_stop
();
release_pmu
(
pmu_irqs
);
}
/*
* Why isn't there a function to route an IRQ to a specific CPU in
* genirq?
*/
static
void
em_route_irq
(
int
irq
,
unsigned
int
cpu
)
{
struct
irq_desc
*
desc
=
irq_desc
+
irq
;
const
struct
cpumask
*
mask
=
cpumask_of
(
cpu
);
spin_lock_irq
(
&
desc
->
lock
);
cpumask_copy
(
desc
->
affinity
,
mask
);
desc
->
chip
->
set_affinity
(
irq
,
mask
);
spin_unlock_irq
(
&
desc
->
lock
);
}
static
int
em_setup
(
void
)
{
/*
* Send SCU PMU interrupts to the "owner" CPU.
*/
em_route_irq
(
IRQ_EB11MP_PMU_SCU0
,
0
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU1
,
0
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU2
,
1
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU3
,
1
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU4
,
2
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU5
,
2
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU6
,
3
);
em_route_irq
(
IRQ_EB11MP_PMU_SCU7
,
3
);
return
init_pmu
();
}
struct
op_arm_model_spec
op_mpcore_spec
=
{
.
init
=
em_setup
,
.
num_counters
=
MPCORE_NUM_COUNTERS
,
.
setup_ctrs
=
em_setup_ctrs
,
.
start
=
em_start
,
.
stop
=
em_stop
,
.
name
=
"arm/mpcore"
,
};
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_mpcore.h
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_model_mpcore.c
* MPCORE Event Monitor Driver
* @remark Copyright 2004 ARM SMP Development Team
* @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
* @remark Copyright 2000-2004 MontaVista Software Inc
* @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
* @remark Copyright 2004 Intel Corporation
* @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
* @remark Copyright 2004 Oprofile Authors
*
* @remark Read the file COPYING
*
* @author Zwane Mwaikambo
*/
#ifndef OP_MODEL_MPCORE_H
#define OP_MODEL_MPCORE_H
struct
eventmonitor
{
unsigned
long
PMCR
;
unsigned
char
MCEB
[
8
];
unsigned
long
MC
[
8
];
};
/*
* List of userspace counter numbers: note that the structure is important.
* The code relies on CPUn's counters being CPU0's counters + 3n
* and on CPU0's counters starting at 0
*/
#define COUNTER_CPU0_PMN0 0
#define COUNTER_CPU0_PMN1 1
#define COUNTER_CPU0_CCNT 2
#define COUNTER_CPU1_PMN0 3
#define COUNTER_CPU1_PMN1 4
#define COUNTER_CPU1_CCNT 5
#define COUNTER_CPU2_PMN0 6
#define COUNTER_CPU2_PMN1 7
#define COUNTER_CPU2_CCNT 8
#define COUNTER_CPU3_PMN0 9
#define COUNTER_CPU3_PMN1 10
#define COUNTER_CPU3_CCNT 11
#define COUNTER_SCU_MN0 12
#define COUNTER_SCU_MN1 13
#define COUNTER_SCU_MN2 14
#define COUNTER_SCU_MN3 15
#define COUNTER_SCU_MN4 16
#define COUNTER_SCU_MN5 17
#define COUNTER_SCU_MN6 18
#define COUNTER_SCU_MN7 19
#define NUM_SCU_COUNTERS 8
#define SCU_COUNTER(number) ((number) + COUNTER_SCU_MN0)
#define MPCORE_NUM_COUNTERS SCU_COUNTER(NUM_SCU_COUNTERS)
#endif
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_v6.c
deleted
100644 → 0
View file @
98830bc9
/**
* @file op_model_v6.c
* ARM11 Performance Monitor Driver
*
* Based on op_model_xscale.c
*
* @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
* @remark Copyright 2000-2004 MontaVista Software Inc
* @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
* @remark Copyright 2004 Intel Corporation
* @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
* @remark Copyright 2004 OProfile Authors
*
* @remark Read the file COPYING
*
* @author Tony Lindgren <tony@atomide.com>
*/
/* #define DEBUG */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/pmu.h>
#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_arm11_core.h"
static
const
struct
pmu_irqs
*
pmu_irqs
;
static
void
armv6_pmu_stop
(
void
)
{
arm11_stop_pmu
();
arm11_release_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
release_pmu
(
pmu_irqs
);
pmu_irqs
=
NULL
;
}
static
int
armv6_pmu_start
(
void
)
{
int
ret
;
pmu_irqs
=
reserve_pmu
();
if
(
IS_ERR
(
pmu_irqs
))
{
ret
=
PTR_ERR
(
pmu_irqs
);
goto
out
;
}
ret
=
arm11_request_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
if
(
ret
>=
0
)
{
ret
=
arm11_start_pmu
();
}
else
{
release_pmu
(
pmu_irqs
);
pmu_irqs
=
NULL
;
}
out:
return
ret
;
}
static
int
armv6_detect_pmu
(
void
)
{
return
0
;
}
struct
op_arm_model_spec
op_armv6_spec
=
{
.
init
=
armv6_detect_pmu
,
.
num_counters
=
3
,
.
setup_ctrs
=
arm11_setup_pmu
,
.
start
=
armv6_pmu_start
,
.
stop
=
armv6_pmu_stop
,
.
name
=
"arm/armv6"
,
};
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_v7.c
deleted
100644 → 0
View file @
98830bc9
/**
* op_model_v7.c
* ARM V7 (Cortex A8) Event Monitor Driver
*
* Copyright 2008 Jean Pihet <jpihet@mvista.com>
* Copyright 2004 ARM SMP Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <asm/pmu.h>
#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_v7.h"
/* #define DEBUG */
/*
* ARM V7 PMNC support
*/
static
u32
cnt_en
[
CNTMAX
];
static
inline
void
armv7_pmnc_write
(
u32
val
)
{
val
&=
PMNC_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c12, 0"
:
:
"r"
(
val
));
}
static
inline
u32
armv7_pmnc_read
(
void
)
{
u32
val
;
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 0"
:
"=r"
(
val
));
return
val
;
}
static
inline
u32
armv7_pmnc_enable_counter
(
unsigned
int
cnt
)
{
u32
val
;
if
(
cnt
>=
CNTMAX
)
{
printk
(
KERN_ERR
"oprofile: CPU%u enabling wrong PMNC counter"
" %d
\n
"
,
smp_processor_id
(),
cnt
);
return
-
1
;
}
if
(
cnt
==
CCNT
)
val
=
CNTENS_C
;
else
val
=
(
1
<<
(
cnt
-
CNT0
));
val
&=
CNTENS_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c12, 1"
:
:
"r"
(
val
));
return
cnt
;
}
static
inline
u32
armv7_pmnc_disable_counter
(
unsigned
int
cnt
)
{
u32
val
;
if
(
cnt
>=
CNTMAX
)
{
printk
(
KERN_ERR
"oprofile: CPU%u disabling wrong PMNC counter"
" %d
\n
"
,
smp_processor_id
(),
cnt
);
return
-
1
;
}
if
(
cnt
==
CCNT
)
val
=
CNTENC_C
;
else
val
=
(
1
<<
(
cnt
-
CNT0
));
val
&=
CNTENC_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c12, 2"
:
:
"r"
(
val
));
return
cnt
;
}
static
inline
u32
armv7_pmnc_enable_intens
(
unsigned
int
cnt
)
{
u32
val
;
if
(
cnt
>=
CNTMAX
)
{
printk
(
KERN_ERR
"oprofile: CPU%u enabling wrong PMNC counter"
" interrupt enable %d
\n
"
,
smp_processor_id
(),
cnt
);
return
-
1
;
}
if
(
cnt
==
CCNT
)
val
=
INTENS_C
;
else
val
=
(
1
<<
(
cnt
-
CNT0
));
val
&=
INTENS_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c14, 1"
:
:
"r"
(
val
));
return
cnt
;
}
static
inline
u32
armv7_pmnc_getreset_flags
(
void
)
{
u32
val
;
/* Read */
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 3"
:
"=r"
(
val
));
/* Write to clear flags */
val
&=
FLAG_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c12, 3"
:
:
"r"
(
val
));
return
val
;
}
static
inline
int
armv7_pmnc_select_counter
(
unsigned
int
cnt
)
{
u32
val
;
if
((
cnt
==
CCNT
)
||
(
cnt
>=
CNTMAX
))
{
printk
(
KERN_ERR
"oprofile: CPU%u selecting wrong PMNC counteri"
" %d
\n
"
,
smp_processor_id
(),
cnt
);
return
-
1
;
}
val
=
(
cnt
-
CNT0
)
&
SELECT_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c12, 5"
:
:
"r"
(
val
));
return
cnt
;
}
static
inline
void
armv7_pmnc_write_evtsel
(
unsigned
int
cnt
,
u32
val
)
{
if
(
armv7_pmnc_select_counter
(
cnt
)
==
cnt
)
{
val
&=
EVTSEL_MASK
;
asm
volatile
(
"mcr p15, 0, %0, c9, c13, 1"
:
:
"r"
(
val
));
}
}
static
void
armv7_pmnc_reset_counter
(
unsigned
int
cnt
)
{
u32
cpu_cnt
=
CPU_COUNTER
(
smp_processor_id
(),
cnt
);
u32
val
=
-
(
u32
)
counter_config
[
cpu_cnt
].
count
;
switch
(
cnt
)
{
case
CCNT
:
armv7_pmnc_disable_counter
(
cnt
);
asm
volatile
(
"mcr p15, 0, %0, c9, c13, 0"
:
:
"r"
(
val
));
if
(
cnt_en
[
cnt
]
!=
0
)
armv7_pmnc_enable_counter
(
cnt
);
break
;
case
CNT0
:
case
CNT1
:
case
CNT2
:
case
CNT3
:
armv7_pmnc_disable_counter
(
cnt
);
if
(
armv7_pmnc_select_counter
(
cnt
)
==
cnt
)
asm
volatile
(
"mcr p15, 0, %0, c9, c13, 2"
:
:
"r"
(
val
));
if
(
cnt_en
[
cnt
]
!=
0
)
armv7_pmnc_enable_counter
(
cnt
);
break
;
default:
printk
(
KERN_ERR
"oprofile: CPU%u resetting wrong PMNC counter"
" %d
\n
"
,
smp_processor_id
(),
cnt
);
break
;
}
}
int
armv7_setup_pmnc
(
void
)
{
unsigned
int
cnt
;
if
(
armv7_pmnc_read
()
&
PMNC_E
)
{
printk
(
KERN_ERR
"oprofile: CPU%u PMNC still enabled when setup"
" new event counter.
\n
"
,
smp_processor_id
());
return
-
EBUSY
;
}
/* Initialize & Reset PMNC: C bit and P bit */
armv7_pmnc_write
(
PMNC_P
|
PMNC_C
);
for
(
cnt
=
CCNT
;
cnt
<
CNTMAX
;
cnt
++
)
{
unsigned
long
event
;
u32
cpu_cnt
=
CPU_COUNTER
(
smp_processor_id
(),
cnt
);
/*
* Disable counter
*/
armv7_pmnc_disable_counter
(
cnt
);
cnt_en
[
cnt
]
=
0
;
if
(
!
counter_config
[
cpu_cnt
].
enabled
)
continue
;
event
=
counter_config
[
cpu_cnt
].
event
&
255
;
/*
* Set event (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
*/
if
(
cnt
!=
CCNT
)
armv7_pmnc_write_evtsel
(
cnt
,
event
);
/*
* Enable interrupt for this counter
*/
armv7_pmnc_enable_intens
(
cnt
);
/*
* Reset counter
*/
armv7_pmnc_reset_counter
(
cnt
);
/*
* Enable counter
*/
armv7_pmnc_enable_counter
(
cnt
);
cnt_en
[
cnt
]
=
1
;
}
return
0
;
}
static
inline
void
armv7_start_pmnc
(
void
)
{
armv7_pmnc_write
(
armv7_pmnc_read
()
|
PMNC_E
);
}
static
inline
void
armv7_stop_pmnc
(
void
)
{
armv7_pmnc_write
(
armv7_pmnc_read
()
&
~
PMNC_E
);
}
/*
* CPU counters' IRQ handler (one IRQ per CPU)
*/
static
irqreturn_t
armv7_pmnc_interrupt
(
int
irq
,
void
*
arg
)
{
struct
pt_regs
*
regs
=
get_irq_regs
();
unsigned
int
cnt
;
u32
flags
;
/*
* Stop IRQ generation
*/
armv7_stop_pmnc
();
/*
* Get and reset overflow status flags
*/
flags
=
armv7_pmnc_getreset_flags
();
/*
* Cycle counter
*/
if
(
flags
&
FLAG_C
)
{
u32
cpu_cnt
=
CPU_COUNTER
(
smp_processor_id
(),
CCNT
);
armv7_pmnc_reset_counter
(
CCNT
);
oprofile_add_sample
(
regs
,
cpu_cnt
);
}
/*
* PMNC counters 0:3
*/
for
(
cnt
=
CNT0
;
cnt
<
CNTMAX
;
cnt
++
)
{
if
(
flags
&
(
1
<<
(
cnt
-
CNT0
)))
{
u32
cpu_cnt
=
CPU_COUNTER
(
smp_processor_id
(),
cnt
);
armv7_pmnc_reset_counter
(
cnt
);
oprofile_add_sample
(
regs
,
cpu_cnt
);
}
}
/*
* Allow IRQ generation
*/
armv7_start_pmnc
();
return
IRQ_HANDLED
;
}
int
armv7_request_interrupts
(
const
int
*
irqs
,
int
nr
)
{
unsigned
int
i
;
int
ret
=
0
;
for
(
i
=
0
;
i
<
nr
;
i
++
)
{
ret
=
request_irq
(
irqs
[
i
],
armv7_pmnc_interrupt
,
IRQF_DISABLED
,
"CP15 PMNC"
,
NULL
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
"oprofile: unable to request IRQ%u"
" for ARMv7
\n
"
,
irqs
[
i
]);
break
;
}
}
if
(
i
!=
nr
)
while
(
i
--
!=
0
)
free_irq
(
irqs
[
i
],
NULL
);
return
ret
;
}
void
armv7_release_interrupts
(
const
int
*
irqs
,
int
nr
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
nr
;
i
++
)
free_irq
(
irqs
[
i
],
NULL
);
}
#ifdef DEBUG
static
void
armv7_pmnc_dump_regs
(
void
)
{
u32
val
;
unsigned
int
cnt
;
printk
(
KERN_INFO
"PMNC registers dump:
\n
"
);
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 0"
:
"=r"
(
val
));
printk
(
KERN_INFO
"PMNC =0x%08x
\n
"
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 1"
:
"=r"
(
val
));
printk
(
KERN_INFO
"CNTENS=0x%08x
\n
"
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c14, 1"
:
"=r"
(
val
));
printk
(
KERN_INFO
"INTENS=0x%08x
\n
"
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 3"
:
"=r"
(
val
));
printk
(
KERN_INFO
"FLAGS =0x%08x
\n
"
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c12, 5"
:
"=r"
(
val
));
printk
(
KERN_INFO
"SELECT=0x%08x
\n
"
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c13, 0"
:
"=r"
(
val
));
printk
(
KERN_INFO
"CCNT =0x%08x
\n
"
,
val
);
for
(
cnt
=
CNT0
;
cnt
<
CNTMAX
;
cnt
++
)
{
armv7_pmnc_select_counter
(
cnt
);
asm
volatile
(
"mrc p15, 0, %0, c9, c13, 2"
:
"=r"
(
val
));
printk
(
KERN_INFO
"CNT[%d] count =0x%08x
\n
"
,
cnt
-
CNT0
,
val
);
asm
volatile
(
"mrc p15, 0, %0, c9, c13, 1"
:
"=r"
(
val
));
printk
(
KERN_INFO
"CNT[%d] evtsel=0x%08x
\n
"
,
cnt
-
CNT0
,
val
);
}
}
#endif
static
const
struct
pmu_irqs
*
pmu_irqs
;
static
void
armv7_pmnc_stop
(
void
)
{
#ifdef DEBUG
armv7_pmnc_dump_regs
();
#endif
armv7_stop_pmnc
();
armv7_release_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
release_pmu
(
pmu_irqs
);
pmu_irqs
=
NULL
;
}
static
int
armv7_pmnc_start
(
void
)
{
int
ret
;
pmu_irqs
=
reserve_pmu
();
if
(
IS_ERR
(
pmu_irqs
))
return
PTR_ERR
(
pmu_irqs
);
#ifdef DEBUG
armv7_pmnc_dump_regs
();
#endif
ret
=
armv7_request_interrupts
(
pmu_irqs
->
irqs
,
pmu_irqs
->
num_irqs
);
if
(
ret
>=
0
)
{
armv7_start_pmnc
();
}
else
{
release_pmu
(
pmu_irqs
);
pmu_irqs
=
NULL
;
}
return
ret
;
}
static
int
armv7_detect_pmnc
(
void
)
{
return
0
;
}
struct
op_arm_model_spec
op_armv7_spec
=
{
.
init
=
armv7_detect_pmnc
,
.
num_counters
=
5
,
.
setup_ctrs
=
armv7_setup_pmnc
,
.
start
=
armv7_pmnc_start
,
.
stop
=
armv7_pmnc_stop
,
.
name
=
"arm/armv7"
,
};
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_v7.h
deleted
100644 → 0
View file @
98830bc9
/**
* op_model_v7.h
* ARM v7 (Cortex A8) Event Monitor Driver
*
* Copyright 2008 Jean Pihet <jpihet@mvista.com>
* Copyright 2004 ARM SMP Development Team
* Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
* Copyright 2000-2004 MontaVista Software Inc
* Copyright 2004 Dave Jiang <dave.jiang@intel.com>
* Copyright 2004 Intel Corporation
* Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
* Copyright 2004 Oprofile Authors
*
* Read the file COPYING
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef OP_MODEL_V7_H
#define OP_MODEL_V7_H
/*
* Per-CPU PMNC: config reg
*/
#define PMNC_E (1 << 0)
/* Enable all counters */
#define PMNC_P (1 << 1)
/* Reset all counters */
#define PMNC_C (1 << 2)
/* Cycle counter reset */
#define PMNC_D (1 << 3)
/* CCNT counts every 64th cpu cycle */
#define PMNC_X (1 << 4)
/* Export to ETM */
#define PMNC_DP (1 << 5)
/* Disable CCNT if non-invasive debug*/
#define PMNC_MASK 0x3f
/* Mask for writable bits */
/*
* Available counters
*/
#define CCNT 0
#define CNT0 1
#define CNT1 2
#define CNT2 3
#define CNT3 4
#define CNTMAX 5
#define CPU_COUNTER(cpu, counter) ((cpu) * CNTMAX + (counter))
/*
* CNTENS: counters enable reg
*/
#define CNTENS_P0 (1 << 0)
#define CNTENS_P1 (1 << 1)
#define CNTENS_P2 (1 << 2)
#define CNTENS_P3 (1 << 3)
#define CNTENS_C (1 << 31)
#define CNTENS_MASK 0x8000000f
/* Mask for writable bits */
/*
* CNTENC: counters disable reg
*/
#define CNTENC_P0 (1 << 0)
#define CNTENC_P1 (1 << 1)
#define CNTENC_P2 (1 << 2)
#define CNTENC_P3 (1 << 3)
#define CNTENC_C (1 << 31)
#define CNTENC_MASK 0x8000000f
/* Mask for writable bits */
/*
* INTENS: counters overflow interrupt enable reg
*/
#define INTENS_P0 (1 << 0)
#define INTENS_P1 (1 << 1)
#define INTENS_P2 (1 << 2)
#define INTENS_P3 (1 << 3)
#define INTENS_C (1 << 31)
#define INTENS_MASK 0x8000000f
/* Mask for writable bits */
/*
* EVTSEL: Event selection reg
*/
#define EVTSEL_MASK 0x7f
/* Mask for writable bits */
/*
* SELECT: Counter selection reg
*/
#define SELECT_MASK 0x1f
/* Mask for writable bits */
/*
* FLAG: counters overflow flag status reg
*/
#define FLAG_P0 (1 << 0)
#define FLAG_P1 (1 << 1)
#define FLAG_P2 (1 << 2)
#define FLAG_P3 (1 << 3)
#define FLAG_C (1 << 31)
#define FLAG_MASK 0x8000000f
/* Mask for writable bits */
int
armv7_setup_pmu
(
void
);
int
armv7_start_pmu
(
void
);
int
armv7_stop_pmu
(
void
);
int
armv7_request_interrupts
(
const
int
*
,
int
);
void
armv7_release_interrupts
(
const
int
*
,
int
);
#endif
This diff is collapsed.
Click to expand it.
arch/arm/oprofile/op_model_xscale.c
deleted
100644 → 0
View file @
98830bc9
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment