pmu.h 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 *  linux/arch/arm/include/asm/pmu.h
 *
 *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
 *
 * 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 __ARM_PMU_H__
#define __ARM_PMU_H__

15
#include <linux/interrupt.h>
16
#include <linux/perf_event.h>
17

18 19 20 21
/*
 * Types of PMUs that can be accessed directly and require mutual
 * exclusion between profiling tools.
 */
22 23 24 25 26
enum arm_pmu_type {
	ARM_PMU_DEVICE_CPU	= 0,
	ARM_NUM_PMU_DEVICES,
};

27 28 29
/*
 * struct arm_pmu_platdata - ARM PMU platform data
 *
30 31 32 33 34 35 36 37 38 39
 * @handle_irq: an optional handler which will be called from the
 *	interrupt and passed the address of the low level handler,
 *	and can be used to implement any platform specific handling
 *	before or after calling it.
 * @enable_irq: an optional handler which will be called after
 *	request_irq and be used to handle some platform specific
 *	irq enablement
 * @disable_irq: an optional handler which will be called before
 *	free_irq and be used to handle some platform specific
 *	irq disablement
40 41 42 43
 */
struct arm_pmu_platdata {
	irqreturn_t (*handle_irq)(int irq, void *dev,
				  irq_handler_t pmu_handler);
44 45
	void (*enable_irq)(int irq);
	void (*disable_irq)(int irq);
46 47
};

48 49 50 51 52 53
#ifdef CONFIG_CPU_HAS_PMU

/**
 * reserve_pmu() - reserve the hardware performance counters
 *
 * Reserve the hardware performance counters in the system for exclusive use.
54
 * Returns 0 on success or -EBUSY if the lock is already held.
55
 */
56
extern int
57
reserve_pmu(enum arm_pmu_type type);
58 59 60 61 62 63

/**
 * release_pmu() - Relinquish control of the performance counters
 *
 * Release the performance counters and allow someone else to use them.
 */
64
extern void
65
release_pmu(enum arm_pmu_type type);
66 67 68

#else /* CONFIG_CPU_HAS_PMU */

69 70
#include <linux/err.h>

71
static inline int
72
reserve_pmu(enum arm_pmu_type type)
73 74 75 76
{
	return -ENODEV;
}

77 78
static inline void
release_pmu(enum arm_pmu_type type)	{ }
79 80 81

#endif /* CONFIG_CPU_HAS_PMU */

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
#ifdef CONFIG_HW_PERF_EVENTS

/* The events for a given PMU register set. */
struct pmu_hw_events {
	/*
	 * The events that are active on the PMU for the given index.
	 */
	struct perf_event	**events;

	/*
	 * A 1 bit for an index indicates that the counter is being used for
	 * an event. A 0 means that the counter can be used.
	 */
	unsigned long           *used_mask;

	/*
	 * Hardware lock to serialize accesses to PMU registers. Needed for the
	 * read/modify/write sequences.
	 */
	raw_spinlock_t		pmu_lock;
};

struct arm_pmu {
	struct pmu	pmu;
	enum arm_pmu_type type;
	cpumask_t	active_irqs;
108
	char		*name;
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
	void		(*enable)(struct hw_perf_event *evt, int idx);
	void		(*disable)(struct hw_perf_event *evt, int idx);
	int		(*get_event_idx)(struct pmu_hw_events *hw_events,
					 struct hw_perf_event *hwc);
	int		(*set_event_filter)(struct hw_perf_event *evt,
					    struct perf_event_attr *attr);
	u32		(*read_counter)(int idx);
	void		(*write_counter)(int idx, u32 val);
	void		(*start)(void);
	void		(*stop)(void);
	void		(*reset)(void *);
	int		(*map_event)(struct perf_event *event);
	int		num_events;
	atomic_t	active_events;
	struct mutex	reserve_mutex;
	u64		max_period;
	struct platform_device	*plat_device;
	struct pmu_hw_events	*(*get_hw_events)(void);
};

#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))

int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);

u64 armpmu_event_update(struct perf_event *event,
			struct hw_perf_event *hwc,
136
			int idx);
137 138 139 140 141 142 143

int armpmu_event_set_period(struct perf_event *event,
			    struct hw_perf_event *hwc,
			    int idx);

#endif /* CONFIG_HW_PERF_EVENTS */

144
#endif /* __ARM_PMU_H__ */