Skip to content

Commit a669efc

Browse files
abresticralfbaechle
authored andcommitted
MIPS: Add hook to get C0 performance counter interrupt
The hardware perf event driver and oprofile interpret the global cp0_perfcount_irq differently: in the hardware perf event driver it is an offset from MIPS_CPU_IRQ_BASE and in oprofile it is the actual IRQ number. This still works most of the time since MIPS_CPU_IRQ_BASE is usually 0, but is clearly wrong. Since the performance counter interrupt may vary from platform to platform like the C0 timer interrupt, add the optional get_c0_perfcount_int hook which returns the IRQ number of the performance counter. The hook should return < 0 if the performance counter interrupt is shared with the timer. If the hook is not present, the CPU vector reported in C0_IntCtl (cp0_perfcount_irq) is used. Signed-off-by: Andrew Bresticker <abrestic@chromium.org> Reviewed-by: Qais Yousef <qais.yousef@imgtec.com> Tested-by: Qais Yousef <qais.yousef@imgtec.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Andrew Bresticker <abrestic@chromium.org> Cc: Jeffrey Deans <jeffrey.deans@imgtec.com> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Qais Yousef <qais.yousef@imgtec.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: John Crispin <blogic@openwrt.org> Cc: David Daney <ddaney.cavm@gmail.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7805/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
1 parent 079a460 commit a669efc

File tree

9 files changed

+51
-36
lines changed

9 files changed

+51
-36
lines changed

arch/mips/ath79/irq.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ void __init arch_init_irq(void)
359359
BUG();
360360
}
361361

362-
cp0_perfcount_irq = ATH79_MISC_IRQ(5);
363362
mips_cpu_irq_init();
364363
ath79_misc_irq_init();
365364

arch/mips/ath79/setup.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ const char *get_system_type(void)
182182
return ath79_sys_type;
183183
}
184184

185+
int get_c0_perfcount_int(void)
186+
{
187+
return ATH79_MISC_IRQ(5);
188+
}
189+
185190
unsigned int get_c0_compare_int(void)
186191
{
187192
return CP0_LEGACY_COMPARE_IRQ;

arch/mips/include/asm/time.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extern unsigned int mips_hpt_frequency;
4646
* so it lives here.
4747
*/
4848
extern int (*perf_irq)(void);
49+
extern int __weak get_c0_perfcount_int(void);
4950

5051
/*
5152
* Initialize the calling CPU's compare interrupt as clockevent device

arch/mips/kernel/perf_event_mipsxx.c

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,22 +1613,13 @@ init_hw_perf_events(void)
16131613
counters = counters_total_to_per_cpu(counters);
16141614
#endif
16151615

1616-
#ifdef MSC01E_INT_BASE
1617-
if (cpu_has_veic) {
1618-
/*
1619-
* Using platform specific interrupt controller defines.
1620-
*/
1621-
irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
1622-
} else {
1623-
#endif
1624-
if ((cp0_perfcount_irq >= 0) &&
1625-
(cp0_compare_irq != cp0_perfcount_irq))
1626-
irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
1627-
else
1628-
irq = -1;
1629-
#ifdef MSC01E_INT_BASE
1630-
}
1631-
#endif
1616+
if (get_c0_perfcount_int)
1617+
irq = get_c0_perfcount_int();
1618+
else if ((cp0_perfcount_irq >= 0) &&
1619+
(cp0_compare_irq != cp0_perfcount_irq))
1620+
irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
1621+
else
1622+
irq = -1;
16321623

16331624
mipspmu.map_raw_event = mipsxx_pmu_map_raw_event;
16341625

arch/mips/lantiq/irq.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static struct resource ltq_eiu_irq[MAX_EIU];
7070
static void __iomem *ltq_icu_membase[MAX_IM];
7171
static void __iomem *ltq_eiu_membase;
7272
static struct irq_domain *ltq_domain;
73+
static int ltq_perfcount_irq;
7374

7475
int ltq_eiu_get_irq(int exin)
7576
{
@@ -449,7 +450,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
449450
#endif
450451

451452
/* tell oprofile which irq to use */
452-
cp0_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
453+
ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
453454

454455
/*
455456
* if the timer irq is not one of the mips irqs we need to
@@ -461,6 +462,11 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
461462
return 0;
462463
}
463464

465+
int get_c0_perfcount_int(void)
466+
{
467+
return ltq_perfcount_irq;
468+
}
469+
464470
unsigned int get_c0_compare_int(void)
465471
{
466472
return MIPS_CPU_TIMER_IRQ;

arch/mips/mti-malta/malta-time.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,20 @@ void read_persistent_clock(struct timespec *ts)
121121
ts->tv_nsec = 0;
122122
}
123123

124-
static void __init plat_perf_setup(void)
124+
int get_c0_perfcount_int(void)
125125
{
126-
#ifdef MSC01E_INT_BASE
127126
if (cpu_has_veic) {
128127
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
129128
mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
130-
} else
131-
#endif
132-
if (cp0_perfcount_irq >= 0) {
129+
} else if (cp0_perfcount_irq >= 0) {
133130
if (cpu_has_vint)
134131
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
135132
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
136-
#ifdef CONFIG_SMP
137-
irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq);
138-
#endif
133+
} else {
134+
mips_cpu_perf_irq = -1;
139135
}
136+
137+
return mips_cpu_perf_irq;
140138
}
141139

142140
unsigned int get_c0_compare_int(void)
@@ -201,6 +199,4 @@ void __init plat_time_init(void)
201199
#endif
202200
}
203201
#endif
204-
205-
plat_perf_setup();
206202
}

arch/mips/mti-sead3/sead3-time.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,16 @@ void read_persistent_clock(struct timespec *ts)
8181
ts->tv_nsec = 0;
8282
}
8383

84-
static void __init plat_perf_setup(void)
84+
int get_c0_perfcount_int(void)
8585
{
8686
if (cp0_perfcount_irq >= 0) {
8787
if (cpu_has_vint)
8888
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
8989
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
90+
} else {
91+
mips_cpu_perf_irq = -1;
9092
}
93+
return mips_cpu_perf_irq;
9194
}
9295

9396
unsigned int get_c0_compare_int(void)
@@ -108,6 +111,4 @@ void __init plat_time_init(void)
108111
(est_freq % 1000000) * 100 / 1000000);
109112

110113
mips_scroll_message();
111-
112-
plat_perf_setup();
113114
}

arch/mips/oprofile/op_model_mipsxx.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/interrupt.h>
1212
#include <linux/smp.h>
1313
#include <asm/irq_regs.h>
14+
#include <asm/time.h>
1415

1516
#include "op_impl.h"
1617

@@ -35,6 +36,7 @@
3536
#define M_PERFCTL_COUNT_ALL_THREADS (1UL << 13)
3637

3738
static int (*save_perf_irq)(void);
39+
static int perfcount_irq;
3840

3941
/*
4042
* XLR has only one set of counters per core. Designate the
@@ -431,8 +433,16 @@ static int __init mipsxx_init(void)
431433
save_perf_irq = perf_irq;
432434
perf_irq = mipsxx_perfcount_handler;
433435

434-
if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
435-
return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int,
436+
if (get_c0_perfcount_int)
437+
perfcount_irq = get_c0_perfcount_int();
438+
else if ((cp0_perfcount_irq >= 0) &&
439+
(cp0_compare_irq != cp0_perfcount_irq))
440+
perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
441+
else
442+
perfcount_irq = -1;
443+
444+
if (perfcount_irq >= 0)
445+
return request_irq(perfcount_irq, mipsxx_perfcount_int,
436446
0, "Perfcounter", save_perf_irq);
437447

438448
return 0;
@@ -442,8 +452,8 @@ static void mipsxx_exit(void)
442452
{
443453
int counters = op_model_mipsxx_ops.num_counters;
444454

445-
if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
446-
free_irq(cp0_perfcount_irq, save_perf_irq);
455+
if (perfcount_irq >= 0)
456+
free_irq(perfcount_irq, save_perf_irq);
447457

448458
counters = counters_per_cpu_to_total(counters);
449459
on_each_cpu(reset_counters, (void *)(long)counters, 1);

arch/mips/ralink/irq.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#define RALINK_INTC_IRQ_PERFC (RALINK_INTC_IRQ_BASE + 9)
4646

4747
static void __iomem *rt_intc_membase;
48+
static int rt_perfcount_irq;
4849

4950
static inline void rt_intc_w32(u32 val, unsigned reg)
5051
{
@@ -73,6 +74,11 @@ static struct irq_chip ralink_intc_irq_chip = {
7374
.irq_mask_ack = ralink_intc_irq_mask,
7475
};
7576

77+
int get_c0_perfcount_int(void)
78+
{
79+
return rt_perfcount_irq;
80+
}
81+
7682
unsigned int get_c0_compare_int(void)
7783
{
7884
return CP0_LEGACY_COMPARE_IRQ;
@@ -167,7 +173,7 @@ static int __init intc_of_init(struct device_node *node,
167173
irq_set_handler_data(irq, domain);
168174

169175
/* tell the kernel which irq is used for performance monitoring */
170-
cp0_perfcount_irq = irq_create_mapping(domain, 9);
176+
rt_perfcount_irq = irq_create_mapping(domain, 9);
171177

172178
return 0;
173179
}

0 commit comments

Comments
 (0)