aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-msm/pmu.c
blob: 2b2de6b38eceb60be019d04c0edd802f89f40e14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/pmu.h>
#include <mach/irqs.h>
#include <mach/socinfo.h>

#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP)
static DEFINE_PER_CPU(u32, pmu_irq_cookie);

static int
multicore_request_irq(int irq, irq_handler_t *handle_irq)
{
	int err = 0;
	int cpu;

	err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
			&pmu_irq_cookie);

	if (!err) {
		for_each_cpu(cpu, cpu_online_mask) {
			smp_call_function_single(cpu,
					enable_irq_callback, &irq, 1);
		}
	}

	return err;
}

static void
multicore_free_irq(int irq)
{
	int cpu;
	struct irq_desc *desc = irq_to_desc(irq);

	if ((irq >= 0) && desc) {
		for_each_cpu(cpu, desc->percpu_enabled)
			smp_call_function_single(cpu,
					disable_irq_callback, &irq, 1);
		free_percpu_irq(irq, &pmu_irq_cookie);
	}
}

static struct arm_pmu_platdata multicore_data = {
	.request_pmu_irq = multicore_request_irq,
	.free_pmu_irq = multicore_free_irq,
};
#endif

static struct resource cpu_pmu_resource[] = {
	{
		.start = INT_ARMQC_PERFMON,
		.end = INT_ARMQC_PERFMON,
		.flags	= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_CPU_HAS_L2_PMU
static struct resource l2_pmu_resource[] = {
	{
		.start = SC_SICL2PERFMONIRPTREQ,
		.end = SC_SICL2PERFMONIRPTREQ,
		.flags = IORESOURCE_IRQ,
	},
};

static struct platform_device l2_pmu_device = {
	.name		= "l2-arm-pmu",
	.id		= ARM_PMU_DEVICE_L2CC,
	.resource	= l2_pmu_resource,
	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
};

#endif

static struct platform_device cpu_pmu_device = {
	.name		= "cpu-arm-pmu",
	.id		= ARM_PMU_DEVICE_CPU,
	.resource	= cpu_pmu_resource,
	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
};


static struct platform_device *pmu_devices[] = {
	&cpu_pmu_device,
#ifdef CONFIG_CPU_HAS_L2_PMU
	&l2_pmu_device,
#endif
};

static int __init msm_pmu_init(void)
{
	/*
	 * For the targets we know are multicore's set the request/free IRQ
	 * handlers to call the percpu API.
	 * Defaults to unicore API {request,free}_irq().
	 * See arch/arm/kernel/perf_event.c
	 */
#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP)
	cpu_pmu_device.dev.platform_data = &multicore_data;
#endif

	return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices));
}

arch_initcall(msm_pmu_init);