perf_event_cpu.c 7.9 KB
Newer Older
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
/*
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Copyright (C) 2012 ARM Limited
 *
 * Author: Will Deacon <will.deacon@arm.com>
 */
#define pr_fmt(fmt) "CPU PMU: " fmt

#include <linux/bitmap.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
26
#include <linux/slab.h>
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#include <linux/spinlock.h>

#include <asm/cputype.h>
#include <asm/irq_regs.h>
#include <asm/pmu.h>

/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *cpu_pmu;

static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);

/*
 * Despite the names, these two functions are CPU-specific and are used
 * by the OProfile/perf code.
 */
const char *perf_pmu_name(void)
{
	if (!cpu_pmu)
		return NULL;

49
	return cpu_pmu->name;
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
}
EXPORT_SYMBOL_GPL(perf_pmu_name);

int perf_num_counters(void)
{
	int max_events = 0;

	if (cpu_pmu != NULL)
		max_events = cpu_pmu->num_events;

	return max_events;
}
EXPORT_SYMBOL_GPL(perf_num_counters);

/* Include the PMU-specific implementations. */
#include "perf_event_xscale.c"
#include "perf_event_v6.c"
#include "perf_event_v7.c"

static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
{
71
	return this_cpu_ptr(&cpu_hw_events);
72 73
}

74
static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
{
	int i, irq, irqs;
	struct platform_device *pmu_device = cpu_pmu->plat_device;

	irqs = min(pmu_device->num_resources, num_possible_cpus());

	for (i = 0; i < irqs; ++i) {
		if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
			continue;
		irq = platform_get_irq(pmu_device, i);
		if (irq >= 0)
			free_irq(irq, cpu_pmu);
	}
}

90
static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
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 118 119 120
{
	int i, err, irq, irqs;
	struct platform_device *pmu_device = cpu_pmu->plat_device;

	if (!pmu_device)
		return -ENODEV;

	irqs = min(pmu_device->num_resources, num_possible_cpus());
	if (irqs < 1) {
		pr_err("no irqs for PMUs defined\n");
		return -ENODEV;
	}

	for (i = 0; i < irqs; ++i) {
		err = 0;
		irq = platform_get_irq(pmu_device, i);
		if (irq < 0)
			continue;

		/*
		 * If we have a single PMU interrupt that we can't shift,
		 * assume that we're running on a uniprocessor machine and
		 * continue. Otherwise, continue without this interrupt.
		 */
		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
				    irq, i);
			continue;
		}

121 122
		err = request_irq(irq, handler,
				  IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
123 124 125 126 127 128 129 130 131 132 133 134 135
				  cpu_pmu);
		if (err) {
			pr_err("unable to request IRQ%d for ARM PMU counters\n",
				irq);
			return err;
		}

		cpumask_set_cpu(i, &cpu_pmu->active_irqs);
	}

	return 0;
}

136
static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
137 138 139 140 141 142 143 144
{
	int cpu;
	for_each_possible_cpu(cpu) {
		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
		events->events = per_cpu(hw_events, cpu);
		events->used_mask = per_cpu(used_mask, cpu);
		raw_spin_lock_init(&events->pmu_lock);
	}
145 146 147 148

	cpu_pmu->get_hw_events	= cpu_pmu_get_cpu_events;
	cpu_pmu->request_irq	= cpu_pmu_request_irq;
	cpu_pmu->free_irq	= cpu_pmu_free_irq;
149 150

	/* Ensure the PMU has sane values out of reset. */
151
	if (cpu_pmu->reset)
152
		on_each_cpu(cpu_pmu->reset, cpu_pmu, 1);
153 154 155 156 157 158 159 160
}

/*
 * PMU hardware loses all context when a CPU goes offline.
 * When a CPU is hotplugged back in, since some hardware registers are
 * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
 * junk values out of them.
 */
161 162
static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
			  void *hcpu)
163 164 165 166 167
{
	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
		return NOTIFY_DONE;

	if (cpu_pmu && cpu_pmu->reset)
168
		cpu_pmu->reset(cpu_pmu);
169 170
	else
		return NOTIFY_DONE;
171 172 173 174

	return NOTIFY_OK;
}

175
static struct notifier_block cpu_pmu_hotplug_notifier = {
176 177 178 179 180 181
	.notifier_call = cpu_pmu_notify,
};

/*
 * PMU platform driver and devicetree bindings.
 */
182
static struct of_device_id cpu_pmu_of_device_ids[] = {
183 184 185 186 187 188 189 190 191 192 193
	{.compatible = "arm,cortex-a15-pmu",	.data = armv7_a15_pmu_init},
	{.compatible = "arm,cortex-a9-pmu",	.data = armv7_a9_pmu_init},
	{.compatible = "arm,cortex-a8-pmu",	.data = armv7_a8_pmu_init},
	{.compatible = "arm,cortex-a7-pmu",	.data = armv7_a7_pmu_init},
	{.compatible = "arm,cortex-a5-pmu",	.data = armv7_a5_pmu_init},
	{.compatible = "arm,arm11mpcore-pmu",	.data = armv6mpcore_pmu_init},
	{.compatible = "arm,arm1176-pmu",	.data = armv6pmu_init},
	{.compatible = "arm,arm1136-pmu",	.data = armv6pmu_init},
	{},
};

194
static struct platform_device_id cpu_pmu_plat_device_ids[] = {
195 196 197 198 199 200 201
	{.name = "arm-pmu"},
	{},
};

/*
 * CPU PMU identification and probing.
 */
202
static int probe_current_pmu(struct arm_pmu *pmu)
203 204
{
	int cpu = get_cpu();
205 206
	unsigned long implementor = read_cpuid_implementor();
	unsigned long part_number = read_cpuid_part_number();
207
	int ret = -ENODEV;
208 209 210 211

	pr_info("probing PMU on CPU %d\n", cpu);

	/* ARM Ltd CPUs. */
212
	if (implementor == ARM_CPU_IMP_ARM) {
213
		switch (part_number) {
214 215 216
		case ARM_CPU_PART_ARM1136:
		case ARM_CPU_PART_ARM1156:
		case ARM_CPU_PART_ARM1176:
217
			ret = armv6pmu_init(pmu);
218
			break;
219
		case ARM_CPU_PART_ARM11MPCORE:
220
			ret = armv6mpcore_pmu_init(pmu);
221
			break;
222
		case ARM_CPU_PART_CORTEX_A8:
223
			ret = armv7_a8_pmu_init(pmu);
224
			break;
225
		case ARM_CPU_PART_CORTEX_A9:
226
			ret = armv7_a9_pmu_init(pmu);
227
			break;
228
		case ARM_CPU_PART_CORTEX_A5:
229
			ret = armv7_a5_pmu_init(pmu);
230
			break;
231
		case ARM_CPU_PART_CORTEX_A15:
232
			ret = armv7_a15_pmu_init(pmu);
233
			break;
234
		case ARM_CPU_PART_CORTEX_A7:
235
			ret = armv7_a7_pmu_init(pmu);
236 237 238
			break;
		}
	/* Intel CPUs [xscale]. */
239 240 241
	} else if (implementor == ARM_CPU_IMP_INTEL) {
		switch (xscale_cpu_arch_version()) {
		case ARM_CPU_XSCALE_ARCH_V1:
242
			ret = xscale1pmu_init(pmu);
243
			break;
244
		case ARM_CPU_XSCALE_ARCH_V2:
245
			ret = xscale2pmu_init(pmu);
246 247 248 249 250
			break;
		}
	}

	put_cpu();
251
	return ret;
252 253
}

254
static int cpu_pmu_device_probe(struct platform_device *pdev)
255 256
{
	const struct of_device_id *of_id;
257
	const int (*init_fn)(struct arm_pmu *);
258
	struct device_node *node = pdev->dev.of_node;
259 260
	struct arm_pmu *pmu;
	int ret = -ENODEV;
261 262 263 264 265 266

	if (cpu_pmu) {
		pr_info("attempt to register multiple PMU devices!");
		return -ENOSPC;
	}

267 268 269 270 271 272
	pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL);
	if (!pmu) {
		pr_info("failed to allocate PMU device!");
		return -ENOMEM;
	}

273 274
	if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
		init_fn = of_id->data;
275
		ret = init_fn(pmu);
276
	} else {
277
		ret = probe_current_pmu(pmu);
278 279
	}

280
	if (ret) {
281 282
		pr_info("failed to probe PMU!");
		goto out_free;
283
	}
284

285
	cpu_pmu = pmu;
286 287
	cpu_pmu->plat_device = pdev;
	cpu_pmu_init(cpu_pmu);
288
	ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW);
289

290 291 292 293 294 295 296
	if (!ret)
		return 0;

out_free:
	pr_info("failed to register PMU devices!");
	kfree(pmu);
	return ret;
297 298 299 300 301 302 303 304 305 306 307 308 309 310
}

static struct platform_driver cpu_pmu_driver = {
	.driver		= {
		.name	= "arm-pmu",
		.pm	= &armpmu_dev_pm_ops,
		.of_match_table = cpu_pmu_of_device_ids,
	},
	.probe		= cpu_pmu_device_probe,
	.id_table	= cpu_pmu_plat_device_ids,
};

static int __init register_pmu_driver(void)
{
311 312 313 314 315 316 317 318 319 320 321
	int err;

	err = register_cpu_notifier(&cpu_pmu_hotplug_notifier);
	if (err)
		return err;

	err = platform_driver_register(&cpu_pmu_driver);
	if (err)
		unregister_cpu_notifier(&cpu_pmu_hotplug_notifier);

	return err;
322 323
}
device_initcall(register_pmu_driver);