···1313#define __ARM_PMU_H__14141515#include <linux/interrupt.h>1616+#include <linux/perf_event.h>16171818+/*1919+ * Types of PMUs that can be accessed directly and require mutual2020+ * exclusion between profiling tools.2121+ */1722enum arm_pmu_type {1823 ARM_PMU_DEVICE_CPU = 0,1924 ARM_NUM_PMU_DEVICES,···4237 * reserve_pmu() - reserve the hardware performance counters4338 *4439 * Reserve the hardware performance counters in the system for exclusive use.4545- * The platform_device for the system is returned on success, ERR_PTR()4646- * encoded error on failure.4040+ * Returns 0 on success or -EBUSY if the lock is already held.4741 */4848-extern struct platform_device *4242+extern int4943reserve_pmu(enum arm_pmu_type type);50445145/**5246 * release_pmu() - Relinquish control of the performance counters5347 *5448 * Release the performance counters and allow someone else to use them.5555- * Callers must have disabled the counters and released IRQs before calling5656- * this. The platform_device returned from reserve_pmu() must be passed as5757- * a cookie.5849 */5959-extern int5050+extern void6051release_pmu(enum arm_pmu_type type);61526253/**···69687069#include <linux/err.h>71707272-static inline struct platform_device *7171+static inline int7372reserve_pmu(enum arm_pmu_type type)7473{7575- return ERR_PTR(-ENODEV);7676-}7777-7878-static inline int7979-release_pmu(enum arm_pmu_type type)8080-{8174 return -ENODEV;8275}83768484-static inline int8585-init_pmu(enum arm_pmu_type type)8686-{8787- return -ENODEV;8888-}7777+static inline void7878+release_pmu(enum arm_pmu_type type) { }89799080#endif /* CONFIG_CPU_HAS_PMU */8181+8282+#ifdef CONFIG_HW_PERF_EVENTS8383+8484+/* The events for a given PMU register set. */8585+struct pmu_hw_events {8686+ /*8787+ * The events that are active on the PMU for the given index.8888+ */8989+ struct perf_event **events;9090+9191+ /*9292+ * A 1 bit for an index indicates that the counter is being used for9393+ * an event. A 0 means that the counter can be used.9494+ */9595+ unsigned long *used_mask;9696+9797+ /*9898+ * Hardware lock to serialize accesses to PMU registers. Needed for the9999+ * read/modify/write sequences.100100+ */101101+ raw_spinlock_t pmu_lock;102102+};103103+104104+struct arm_pmu {105105+ struct pmu pmu;106106+ enum arm_perf_pmu_ids id;107107+ enum arm_pmu_type type;108108+ cpumask_t active_irqs;109109+ const char *name;110110+ irqreturn_t (*handle_irq)(int irq_num, void *dev);111111+ void (*enable)(struct hw_perf_event *evt, int idx);112112+ void (*disable)(struct hw_perf_event *evt, int idx);113113+ int (*get_event_idx)(struct pmu_hw_events *hw_events,114114+ struct hw_perf_event *hwc);115115+ int (*set_event_filter)(struct hw_perf_event *evt,116116+ struct perf_event_attr *attr);117117+ u32 (*read_counter)(int idx);118118+ void (*write_counter)(int idx, u32 val);119119+ void (*start)(void);120120+ void (*stop)(void);121121+ void (*reset)(void *);122122+ int (*map_event)(struct perf_event *event);123123+ int num_events;124124+ atomic_t active_events;125125+ struct mutex reserve_mutex;126126+ u64 max_period;127127+ struct platform_device *plat_device;128128+ struct pmu_hw_events *(*get_hw_events)(void);129129+};130130+131131+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))132132+133133+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);134134+135135+u64 armpmu_event_update(struct perf_event *event,136136+ struct hw_perf_event *hwc,137137+ int idx, int overflow);138138+139139+int armpmu_event_set_period(struct perf_event *event,140140+ struct hw_perf_event *hwc,141141+ int idx);142142+143143+#endif /* CONFIG_HW_PERF_EVENTS */9114492145#endif /* __ARM_PMU_H__ */
+259-226
arch/arm/kernel/perf_event.c
···1212 */1313#define pr_fmt(fmt) "hw perfevents: " fmt14141515+#include <linux/bitmap.h>1516#include <linux/interrupt.h>1617#include <linux/kernel.h>1718#include <linux/module.h>···2726#include <asm/pmu.h>2827#include <asm/stacktrace.h>29283030-static struct platform_device *pmu_device;3131-3229/*3333- * Hardware lock to serialize accesses to PMU registers. Needed for the3434- * read/modify/write sequences.3535- */3636-static DEFINE_RAW_SPINLOCK(pmu_lock);3737-3838-/*3939- * ARMv6 supports a maximum of 3 events, starting from index 1. If we add3030+ * ARMv6 supports a maximum of 3 events, starting from index 0. If we add4031 * another platform that supports more, we need to increase this to be the4132 * largest of all platforms.4233 *···3643 * cycle counter CCNT + 31 events counters CNT0..30.3744 * Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.3845 */3939-#define ARMPMU_MAX_HWEVENTS 334646+#define ARMPMU_MAX_HWEVENTS 3240474141-/* The events for a given CPU. */4242-struct cpu_hw_events {4343- /*4444- * The events that are active on the CPU for the given index. Index 04545- * is reserved.4646- */4747- struct perf_event *events[ARMPMU_MAX_HWEVENTS];4848+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);4949+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);5050+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);48514949- /*5050- * A 1 bit for an index indicates that the counter is being used for5151- * an event. A 0 means that the counter can be used.5252- */5353- unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];5454-5555- /*5656- * A 1 bit for an index indicates that the counter is actively being5757- * used.5858- */5959- unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];6060-};6161-static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);6262-6363-struct arm_pmu {6464- enum arm_perf_pmu_ids id;6565- const char *name;6666- irqreturn_t (*handle_irq)(int irq_num, void *dev);6767- void (*enable)(struct hw_perf_event *evt, int idx);6868- void (*disable)(struct hw_perf_event *evt, int idx);6969- int (*get_event_idx)(struct cpu_hw_events *cpuc,7070- struct hw_perf_event *hwc);7171- u32 (*read_counter)(int idx);7272- void (*write_counter)(int idx, u32 val);7373- void (*start)(void);7474- void (*stop)(void);7575- void (*reset)(void *);7676- const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]7777- [PERF_COUNT_HW_CACHE_OP_MAX]7878- [PERF_COUNT_HW_CACHE_RESULT_MAX];7979- const unsigned (*event_map)[PERF_COUNT_HW_MAX];8080- u32 raw_event_mask;8181- int num_events;8282- u64 max_period;8383-};5252+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))84538554/* Set at runtime when we know what CPU type we are. */8686-static const struct arm_pmu *armpmu;5555+static struct arm_pmu *cpu_pmu;87568857enum arm_perf_pmu_ids8958armpmu_get_pmu_id(void)9059{9160 int id = -ENODEV;92619393- if (armpmu != NULL)9494- id = armpmu->id;6262+ if (cpu_pmu != NULL)6363+ id = cpu_pmu->id;95649665 return id;9766}···64109{65110 int max_events = 0;661116767- if (armpmu != NULL)6868- max_events = armpmu->num_events;112112+ if (cpu_pmu != NULL)113113+ max_events = cpu_pmu->num_events;6911470115 return max_events;71116}···85130#define CACHE_OP_UNSUPPORTED 0xFFFF8613187132static int8888-armpmu_map_cache_event(u64 config)133133+armpmu_map_cache_event(const unsigned (*cache_map)134134+ [PERF_COUNT_HW_CACHE_MAX]135135+ [PERF_COUNT_HW_CACHE_OP_MAX]136136+ [PERF_COUNT_HW_CACHE_RESULT_MAX],137137+ u64 config)89138{90139 unsigned int cache_type, cache_op, cache_result, ret;91140···105146 if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)106147 return -EINVAL;107148108108- ret = (int)(*armpmu->cache_map)[cache_type][cache_op][cache_result];149149+ ret = (int)(*cache_map)[cache_type][cache_op][cache_result];109150110151 if (ret == CACHE_OP_UNSUPPORTED)111152 return -ENOENT;···114155}115156116157static int117117-armpmu_map_event(u64 config)158158+armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)118159{119119- int mapping = (*armpmu->event_map)[config];120120- return mapping == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : mapping;160160+ int mapping = (*event_map)[config];161161+ return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;121162}122163123164static int124124-armpmu_map_raw_event(u64 config)165165+armpmu_map_raw_event(u32 raw_event_mask, u64 config)125166{126126- return (int)(config & armpmu->raw_event_mask);167167+ return (int)(config & raw_event_mask);127168}128169129129-static int170170+static int map_cpu_event(struct perf_event *event,171171+ const unsigned (*event_map)[PERF_COUNT_HW_MAX],172172+ const unsigned (*cache_map)173173+ [PERF_COUNT_HW_CACHE_MAX]174174+ [PERF_COUNT_HW_CACHE_OP_MAX]175175+ [PERF_COUNT_HW_CACHE_RESULT_MAX],176176+ u32 raw_event_mask)177177+{178178+ u64 config = event->attr.config;179179+180180+ switch (event->attr.type) {181181+ case PERF_TYPE_HARDWARE:182182+ return armpmu_map_event(event_map, config);183183+ case PERF_TYPE_HW_CACHE:184184+ return armpmu_map_cache_event(cache_map, config);185185+ case PERF_TYPE_RAW:186186+ return armpmu_map_raw_event(raw_event_mask, config);187187+ }188188+189189+ return -ENOENT;190190+}191191+192192+int130193armpmu_event_set_period(struct perf_event *event,131194 struct hw_perf_event *hwc,132195 int idx)133196{197197+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);134198 s64 left = local64_read(&hwc->period_left);135199 s64 period = hwc->sample_period;136200 int ret = 0;···184202 return ret;185203}186204187187-static u64205205+u64188206armpmu_event_update(struct perf_event *event,189207 struct hw_perf_event *hwc,190208 int idx, int overflow)191209{210210+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);192211 u64 delta, prev_raw_count, new_raw_count;193212194213again:···229246static void230247armpmu_stop(struct perf_event *event, int flags)231248{249249+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);232250 struct hw_perf_event *hwc = &event->hw;233233-234234- if (!armpmu)235235- return;236251237252 /*238253 * ARM pmu always has to update the counter, so ignore···247266static void248267armpmu_start(struct perf_event *event, int flags)249268{269269+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);250270 struct hw_perf_event *hwc = &event->hw;251251-252252- if (!armpmu)253253- return;254271255272 /*256273 * ARM pmu always has to reprogram the period, so ignore···272293static void273294armpmu_del(struct perf_event *event, int flags)274295{275275- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);296296+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);297297+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();276298 struct hw_perf_event *hwc = &event->hw;277299 int idx = hwc->idx;278300279301 WARN_ON(idx < 0);280302281281- clear_bit(idx, cpuc->active_mask);282303 armpmu_stop(event, PERF_EF_UPDATE);283283- cpuc->events[idx] = NULL;284284- clear_bit(idx, cpuc->used_mask);304304+ hw_events->events[idx] = NULL;305305+ clear_bit(idx, hw_events->used_mask);285306286307 perf_event_update_userpage(event);287308}···289310static int290311armpmu_add(struct perf_event *event, int flags)291312{292292- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);313313+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);314314+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();293315 struct hw_perf_event *hwc = &event->hw;294316 int idx;295317 int err = 0;···298318 perf_pmu_disable(event->pmu);299319300320 /* If we don't have a space for the counter then finish early. */301301- idx = armpmu->get_event_idx(cpuc, hwc);321321+ idx = armpmu->get_event_idx(hw_events, hwc);302322 if (idx < 0) {303323 err = idx;304324 goto out;···310330 */311331 event->hw.idx = idx;312332 armpmu->disable(hwc, idx);313313- cpuc->events[idx] = event;314314- set_bit(idx, cpuc->active_mask);333333+ hw_events->events[idx] = event;315334316335 hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;317336 if (flags & PERF_EF_START)···324345 return err;325346}326347327327-static struct pmu pmu;328328-329348static int330330-validate_event(struct cpu_hw_events *cpuc,349349+validate_event(struct pmu_hw_events *hw_events,331350 struct perf_event *event)332351{352352+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);333353 struct hw_perf_event fake_event = event->hw;354354+ struct pmu *leader_pmu = event->group_leader->pmu;334355335335- if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF)356356+ if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)336357 return 1;337358338338- return armpmu->get_event_idx(cpuc, &fake_event) >= 0;359359+ return armpmu->get_event_idx(hw_events, &fake_event) >= 0;339360}340361341362static int342363validate_group(struct perf_event *event)343364{344365 struct perf_event *sibling, *leader = event->group_leader;345345- struct cpu_hw_events fake_pmu;366366+ struct pmu_hw_events fake_pmu;346367347368 memset(&fake_pmu, 0, sizeof(fake_pmu));348369···362383363384static irqreturn_t armpmu_platform_irq(int irq, void *dev)364385{365365- struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev);386386+ struct arm_pmu *armpmu = (struct arm_pmu *) dev;387387+ struct platform_device *plat_device = armpmu->plat_device;388388+ struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);366389367390 return plat->handle_irq(irq, dev, armpmu->handle_irq);368391}369392393393+static void394394+armpmu_release_hardware(struct arm_pmu *armpmu)395395+{396396+ int i, irq, irqs;397397+ struct platform_device *pmu_device = armpmu->plat_device;398398+399399+ irqs = min(pmu_device->num_resources, num_possible_cpus());400400+401401+ for (i = 0; i < irqs; ++i) {402402+ if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))403403+ continue;404404+ irq = platform_get_irq(pmu_device, i);405405+ if (irq >= 0)406406+ free_irq(irq, armpmu);407407+ }408408+409409+ release_pmu(armpmu->type);410410+}411411+370412static int371371-armpmu_reserve_hardware(void)413413+armpmu_reserve_hardware(struct arm_pmu *armpmu)372414{373415 struct arm_pmu_platdata *plat;374416 irq_handler_t handle_irq;375375- int i, err = -ENODEV, irq;417417+ int i, err, irq, irqs;418418+ struct platform_device *pmu_device = armpmu->plat_device;376419377377- pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);378378- if (IS_ERR(pmu_device)) {420420+ err = reserve_pmu(armpmu->type);421421+ if (err) {379422 pr_warning("unable to reserve pmu\n");380380- return PTR_ERR(pmu_device);423423+ return err;381424 }382382-383383- init_pmu(ARM_PMU_DEVICE_CPU);384425385426 plat = dev_get_platdata(&pmu_device->dev);386427 if (plat && plat->handle_irq)···408409 else409410 handle_irq = armpmu->handle_irq;410411411411- if (pmu_device->num_resources < 1) {412412+ irqs = min(pmu_device->num_resources, num_possible_cpus());413413+ if (irqs < 1) {412414 pr_err("no irqs for PMUs defined\n");413415 return -ENODEV;414416 }415417416416- for (i = 0; i < pmu_device->num_resources; ++i) {418418+ for (i = 0; i < irqs; ++i) {419419+ err = 0;417420 irq = platform_get_irq(pmu_device, i);418421 if (irq < 0)419422 continue;420423424424+ /*425425+ * If we have a single PMU interrupt that we can't shift,426426+ * assume that we're running on a uniprocessor machine and427427+ * continue. Otherwise, continue without this interrupt.428428+ */429429+ if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {430430+ pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",431431+ irq, i);432432+ continue;433433+ }434434+421435 err = request_irq(irq, handle_irq,422436 IRQF_DISABLED | IRQF_NOBALANCING,423423- "armpmu", NULL);437437+ "arm-pmu", armpmu);424438 if (err) {425425- pr_warning("unable to request IRQ%d for ARM perf "426426- "counters\n", irq);427427- break;439439+ pr_err("unable to request IRQ%d for ARM PMU counters\n",440440+ irq);441441+ armpmu_release_hardware(armpmu);442442+ return err;428443 }444444+445445+ cpumask_set_cpu(i, &armpmu->active_irqs);429446 }430447431431- if (err) {432432- for (i = i - 1; i >= 0; --i) {433433- irq = platform_get_irq(pmu_device, i);434434- if (irq >= 0)435435- free_irq(irq, NULL);436436- }437437- release_pmu(ARM_PMU_DEVICE_CPU);438438- pmu_device = NULL;439439- }440440-441441- return err;448448+ return 0;442449}443443-444444-static void445445-armpmu_release_hardware(void)446446-{447447- int i, irq;448448-449449- for (i = pmu_device->num_resources - 1; i >= 0; --i) {450450- irq = platform_get_irq(pmu_device, i);451451- if (irq >= 0)452452- free_irq(irq, NULL);453453- }454454- armpmu->stop();455455-456456- release_pmu(ARM_PMU_DEVICE_CPU);457457- pmu_device = NULL;458458-}459459-460460-static atomic_t active_events = ATOMIC_INIT(0);461461-static DEFINE_MUTEX(pmu_reserve_mutex);462450463451static void464452hw_perf_event_destroy(struct perf_event *event)465453{466466- if (atomic_dec_and_mutex_lock(&active_events, &pmu_reserve_mutex)) {467467- armpmu_release_hardware();468468- mutex_unlock(&pmu_reserve_mutex);454454+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);455455+ atomic_t *active_events = &armpmu->active_events;456456+ struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex;457457+458458+ if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) {459459+ armpmu_release_hardware(armpmu);460460+ mutex_unlock(pmu_reserve_mutex);469461 }462462+}463463+464464+static int465465+event_requires_mode_exclusion(struct perf_event_attr *attr)466466+{467467+ return attr->exclude_idle || attr->exclude_user ||468468+ attr->exclude_kernel || attr->exclude_hv;470469}471470472471static int473472__hw_perf_event_init(struct perf_event *event)474473{474474+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);475475 struct hw_perf_event *hwc = &event->hw;476476 int mapping, err;477477478478- /* Decode the generic type into an ARM event identifier. */479479- if (PERF_TYPE_HARDWARE == event->attr.type) {480480- mapping = armpmu_map_event(event->attr.config);481481- } else if (PERF_TYPE_HW_CACHE == event->attr.type) {482482- mapping = armpmu_map_cache_event(event->attr.config);483483- } else if (PERF_TYPE_RAW == event->attr.type) {484484- mapping = armpmu_map_raw_event(event->attr.config);485485- } else {486486- pr_debug("event type %x not supported\n", event->attr.type);487487- return -EOPNOTSUPP;488488- }478478+ mapping = armpmu->map_event(event);489479490480 if (mapping < 0) {491481 pr_debug("event %x:%llx not supported\n", event->attr.type,···483495 }484496485497 /*486486- * Check whether we need to exclude the counter from certain modes.487487- * The ARM performance counters are on all of the time so if someone488488- * has asked us for some excludes then we have to fail.498498+ * We don't assign an index until we actually place the event onto499499+ * hardware. Use -1 to signify that we haven't decided where to put it500500+ * yet. For SMP systems, each core has it's own PMU so we can't do any501501+ * clever allocation or constraints checking at this point.489502 */490490- if (event->attr.exclude_kernel || event->attr.exclude_user ||491491- event->attr.exclude_hv || event->attr.exclude_idle) {503503+ hwc->idx = -1;504504+ hwc->config_base = 0;505505+ hwc->config = 0;506506+ hwc->event_base = 0;507507+508508+ /*509509+ * Check whether we need to exclude the counter from certain modes.510510+ */511511+ if ((!armpmu->set_event_filter ||512512+ armpmu->set_event_filter(hwc, &event->attr)) &&513513+ event_requires_mode_exclusion(&event->attr)) {492514 pr_debug("ARM performance counters do not support "493515 "mode exclusion\n");494516 return -EPERM;495517 }496518497519 /*498498- * We don't assign an index until we actually place the event onto499499- * hardware. Use -1 to signify that we haven't decided where to put it500500- * yet. For SMP systems, each core has it's own PMU so we can't do any501501- * clever allocation or constraints checking at this point.520520+ * Store the event encoding into the config_base field.502521 */503503- hwc->idx = -1;504504-505505- /*506506- * Store the event encoding into the config_base field. config and507507- * event_base are unused as the only 2 things we need to know are508508- * the event mapping and the counter to use. The counter to use is509509- * also the indx and the config_base is the event type.510510- */511511- hwc->config_base = (unsigned long)mapping;512512- hwc->config = 0;513513- hwc->event_base = 0;522522+ hwc->config_base |= (unsigned long)mapping;514523515524 if (!hwc->sample_period) {516525 hwc->sample_period = armpmu->max_period;···527542528543static int armpmu_event_init(struct perf_event *event)529544{545545+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);530546 int err = 0;547547+ atomic_t *active_events = &armpmu->active_events;531548532532- switch (event->attr.type) {533533- case PERF_TYPE_RAW:534534- case PERF_TYPE_HARDWARE:535535- case PERF_TYPE_HW_CACHE:536536- break;537537-538538- default:549549+ if (armpmu->map_event(event) == -ENOENT)539550 return -ENOENT;540540- }541541-542542- if (!armpmu)543543- return -ENODEV;544551545552 event->destroy = hw_perf_event_destroy;546553547547- if (!atomic_inc_not_zero(&active_events)) {548548- mutex_lock(&pmu_reserve_mutex);549549- if (atomic_read(&active_events) == 0) {550550- err = armpmu_reserve_hardware();551551- }554554+ if (!atomic_inc_not_zero(active_events)) {555555+ mutex_lock(&armpmu->reserve_mutex);556556+ if (atomic_read(active_events) == 0)557557+ err = armpmu_reserve_hardware(armpmu);552558553559 if (!err)554554- atomic_inc(&active_events);555555- mutex_unlock(&pmu_reserve_mutex);560560+ atomic_inc(active_events);561561+ mutex_unlock(&armpmu->reserve_mutex);556562 }557563558564 if (err)···558582559583static void armpmu_enable(struct pmu *pmu)560584{561561- /* Enable all of the perf events on hardware. */562562- int idx, enabled = 0;563563- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);564564-565565- if (!armpmu)566566- return;567567-568568- for (idx = 0; idx <= armpmu->num_events; ++idx) {569569- struct perf_event *event = cpuc->events[idx];570570-571571- if (!event)572572- continue;573573-574574- armpmu->enable(&event->hw, idx);575575- enabled = 1;576576- }585585+ struct arm_pmu *armpmu = to_arm_pmu(pmu);586586+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();587587+ int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);577588578589 if (enabled)579590 armpmu->start();···568605569606static void armpmu_disable(struct pmu *pmu)570607{571571- if (armpmu)572572- armpmu->stop();608608+ struct arm_pmu *armpmu = to_arm_pmu(pmu);609609+ armpmu->stop();573610}574611575575-static struct pmu pmu = {576576- .pmu_enable = armpmu_enable,577577- .pmu_disable = armpmu_disable,578578- .event_init = armpmu_event_init,579579- .add = armpmu_add,580580- .del = armpmu_del,581581- .start = armpmu_start,582582- .stop = armpmu_stop,583583- .read = armpmu_read,584584-};612612+static void __init armpmu_init(struct arm_pmu *armpmu)613613+{614614+ atomic_set(&armpmu->active_events, 0);615615+ mutex_init(&armpmu->reserve_mutex);616616+617617+ armpmu->pmu = (struct pmu) {618618+ .pmu_enable = armpmu_enable,619619+ .pmu_disable = armpmu_disable,620620+ .event_init = armpmu_event_init,621621+ .add = armpmu_add,622622+ .del = armpmu_del,623623+ .start = armpmu_start,624624+ .stop = armpmu_stop,625625+ .read = armpmu_read,626626+ };627627+}628628+629629+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)630630+{631631+ armpmu_init(armpmu);632632+ return perf_pmu_register(&armpmu->pmu, name, type);633633+}585634586635/* Include the PMU-specific implementations. */587636#include "perf_event_xscale.c"···605630 * This requires SMP to be available, so exists as a separate initcall.606631 */607632static int __init608608-armpmu_reset(void)633633+cpu_pmu_reset(void)609634{610610- if (armpmu && armpmu->reset)611611- return on_each_cpu(armpmu->reset, NULL, 1);635635+ if (cpu_pmu && cpu_pmu->reset)636636+ return on_each_cpu(cpu_pmu->reset, NULL, 1);612637 return 0;613638}614614-arch_initcall(armpmu_reset);639639+arch_initcall(cpu_pmu_reset);615640641641+/*642642+ * PMU platform driver and devicetree bindings.643643+ */644644+static struct of_device_id armpmu_of_device_ids[] = {645645+ {.compatible = "arm,cortex-a9-pmu"},646646+ {.compatible = "arm,cortex-a8-pmu"},647647+ {.compatible = "arm,arm1136-pmu"},648648+ {.compatible = "arm,arm1176-pmu"},649649+ {},650650+};651651+652652+static struct platform_device_id armpmu_plat_device_ids[] = {653653+ {.name = "arm-pmu"},654654+ {},655655+};656656+657657+static int __devinit armpmu_device_probe(struct platform_device *pdev)658658+{659659+ cpu_pmu->plat_device = pdev;660660+ return 0;661661+}662662+663663+static struct platform_driver armpmu_driver = {664664+ .driver = {665665+ .name = "arm-pmu",666666+ .of_match_table = armpmu_of_device_ids,667667+ },668668+ .probe = armpmu_device_probe,669669+ .id_table = armpmu_plat_device_ids,670670+};671671+672672+static int __init register_pmu_driver(void)673673+{674674+ return platform_driver_register(&armpmu_driver);675675+}676676+device_initcall(register_pmu_driver);677677+678678+static struct pmu_hw_events *armpmu_get_cpu_events(void)679679+{680680+ return &__get_cpu_var(cpu_hw_events);681681+}682682+683683+static void __init cpu_pmu_init(struct arm_pmu *armpmu)684684+{685685+ int cpu;686686+ for_each_possible_cpu(cpu) {687687+ struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);688688+ events->events = per_cpu(hw_events, cpu);689689+ events->used_mask = per_cpu(used_mask, cpu);690690+ raw_spin_lock_init(&events->pmu_lock);691691+ }692692+ armpmu->get_hw_events = armpmu_get_cpu_events;693693+ armpmu->type = ARM_PMU_DEVICE_CPU;694694+}695695+696696+/*697697+ * CPU PMU identification and registration.698698+ */616699static int __init617700init_hw_perf_events(void)618701{···684651 case 0xB360: /* ARM1136 */685652 case 0xB560: /* ARM1156 */686653 case 0xB760: /* ARM1176 */687687- armpmu = armv6pmu_init();654654+ cpu_pmu = armv6pmu_init();688655 break;689656 case 0xB020: /* ARM11mpcore */690690- armpmu = armv6mpcore_pmu_init();657657+ cpu_pmu = armv6mpcore_pmu_init();691658 break;692659 case 0xC080: /* Cortex-A8 */693693- armpmu = armv7_a8_pmu_init();660660+ cpu_pmu = armv7_a8_pmu_init();694661 break;695662 case 0xC090: /* Cortex-A9 */696696- armpmu = armv7_a9_pmu_init();663663+ cpu_pmu = armv7_a9_pmu_init();697664 break;698665 case 0xC050: /* Cortex-A5 */699699- armpmu = armv7_a5_pmu_init();666666+ cpu_pmu = armv7_a5_pmu_init();700667 break;701668 case 0xC0F0: /* Cortex-A15 */702702- armpmu = armv7_a15_pmu_init();669669+ cpu_pmu = armv7_a15_pmu_init();703670 break;704671 }705672 /* Intel CPUs [xscale]. */···707674 part_number = (cpuid >> 13) & 0x7;708675 switch (part_number) {709676 case 1:710710- armpmu = xscale1pmu_init();677677+ cpu_pmu = xscale1pmu_init();711678 break;712679 case 2:713713- armpmu = xscale2pmu_init();680680+ cpu_pmu = xscale2pmu_init();714681 break;715682 }716683 }717684718718- if (armpmu) {685685+ if (cpu_pmu) {719686 pr_info("enabled with %s PMU driver, %d counters available\n",720720- armpmu->name, armpmu->num_events);687687+ cpu_pmu->name, cpu_pmu->num_events);688688+ cpu_pmu_init(cpu_pmu);689689+ armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);721690 } else {722691 pr_info("no hardware support available\n");723692 }724724-725725- perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);726693727694 return 0;728695}
+59-28
arch/arm/kernel/perf_event_v6.c
···5454};55555656enum armv6_counters {5757- ARMV6_CYCLE_COUNTER = 1,5757+ ARMV6_CYCLE_COUNTER = 0,5858 ARMV6_COUNTER0,5959 ARMV6_COUNTER1,6060};···433433 int idx)434434{435435 unsigned long val, mask, evt, flags;436436+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();436437437438 if (ARMV6_CYCLE_COUNTER == idx) {438439 mask = 0;···455454 * Mask out the current event and set the counter to count the event456455 * that we're interested in.457456 */458458- raw_spin_lock_irqsave(&pmu_lock, flags);457457+ raw_spin_lock_irqsave(&events->pmu_lock, flags);459458 val = armv6_pmcr_read();460459 val &= ~mask;461460 val |= evt;462461 armv6_pmcr_write(val);463463- raw_spin_unlock_irqrestore(&pmu_lock, flags);462462+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);463463+}464464+465465+static int counter_is_active(unsigned long pmcr, int idx)466466+{467467+ unsigned long mask = 0;468468+ if (idx == ARMV6_CYCLE_COUNTER)469469+ mask = ARMV6_PMCR_CCOUNT_IEN;470470+ else if (idx == ARMV6_COUNTER0)471471+ mask = ARMV6_PMCR_COUNT0_IEN;472472+ else if (idx == ARMV6_COUNTER1)473473+ mask = ARMV6_PMCR_COUNT1_IEN;474474+475475+ if (mask)476476+ return pmcr & mask;477477+478478+ WARN_ONCE(1, "invalid counter number (%d)\n", idx);479479+ return 0;464480}465481466482static irqreturn_t···486468{487469 unsigned long pmcr = armv6_pmcr_read();488470 struct perf_sample_data data;489489- struct cpu_hw_events *cpuc;471471+ struct pmu_hw_events *cpuc;490472 struct pt_regs *regs;491473 int idx;492474···505487 perf_sample_data_init(&data, 0);506488507489 cpuc = &__get_cpu_var(cpu_hw_events);508508- for (idx = 0; idx <= armpmu->num_events; ++idx) {490490+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {509491 struct perf_event *event = cpuc->events[idx];510492 struct hw_perf_event *hwc;511493512512- if (!test_bit(idx, cpuc->active_mask))494494+ if (!counter_is_active(pmcr, idx))513495 continue;514496515497 /*···526508 continue;527509528510 if (perf_event_overflow(event, &data, regs))529529- armpmu->disable(hwc, idx);511511+ cpu_pmu->disable(hwc, idx);530512 }531513532514 /*···545527armv6pmu_start(void)546528{547529 unsigned long flags, val;530530+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();548531549549- raw_spin_lock_irqsave(&pmu_lock, flags);532532+ raw_spin_lock_irqsave(&events->pmu_lock, flags);550533 val = armv6_pmcr_read();551534 val |= ARMV6_PMCR_ENABLE;552535 armv6_pmcr_write(val);553553- raw_spin_unlock_irqrestore(&pmu_lock, flags);536536+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);554537}555538556539static void557540armv6pmu_stop(void)558541{559542 unsigned long flags, val;543543+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();560544561561- raw_spin_lock_irqsave(&pmu_lock, flags);545545+ raw_spin_lock_irqsave(&events->pmu_lock, flags);562546 val = armv6_pmcr_read();563547 val &= ~ARMV6_PMCR_ENABLE;564548 armv6_pmcr_write(val);565565- raw_spin_unlock_irqrestore(&pmu_lock, flags);549549+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);566550}567551568552static int569569-armv6pmu_get_event_idx(struct cpu_hw_events *cpuc,553553+armv6pmu_get_event_idx(struct pmu_hw_events *cpuc,570554 struct hw_perf_event *event)571555{572556 /* Always place a cycle counter into the cycle counter. */···598578 int idx)599579{600580 unsigned long val, mask, evt, flags;581581+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();601582602583 if (ARMV6_CYCLE_COUNTER == idx) {603584 mask = ARMV6_PMCR_CCOUNT_IEN;···619598 * of ETM bus signal assertion cycles. The external reporting should620599 * be disabled and so this should never increment.621600 */622622- raw_spin_lock_irqsave(&pmu_lock, flags);601601+ raw_spin_lock_irqsave(&events->pmu_lock, flags);623602 val = armv6_pmcr_read();624603 val &= ~mask;625604 val |= evt;626605 armv6_pmcr_write(val);627627- raw_spin_unlock_irqrestore(&pmu_lock, flags);606606+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);628607}629608630609static void···632611 int idx)633612{634613 unsigned long val, mask, flags, evt = 0;614614+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();635615636616 if (ARMV6_CYCLE_COUNTER == idx) {637617 mask = ARMV6_PMCR_CCOUNT_IEN;···649627 * Unlike UP ARMv6, we don't have a way of stopping the counters. We650628 * simply disable the interrupt reporting.651629 */652652- raw_spin_lock_irqsave(&pmu_lock, flags);630630+ raw_spin_lock_irqsave(&events->pmu_lock, flags);653631 val = armv6_pmcr_read();654632 val &= ~mask;655633 val |= evt;656634 armv6_pmcr_write(val);657657- raw_spin_unlock_irqrestore(&pmu_lock, flags);635635+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);658636}659637660660-static const struct arm_pmu armv6pmu = {638638+static int armv6_map_event(struct perf_event *event)639639+{640640+ return map_cpu_event(event, &armv6_perf_map,641641+ &armv6_perf_cache_map, 0xFF);642642+}643643+644644+static struct arm_pmu armv6pmu = {661645 .id = ARM_PERF_PMU_ID_V6,662646 .name = "v6",663647 .handle_irq = armv6pmu_handle_irq,···674646 .get_event_idx = armv6pmu_get_event_idx,675647 .start = armv6pmu_start,676648 .stop = armv6pmu_stop,677677- .cache_map = &armv6_perf_cache_map,678678- .event_map = &armv6_perf_map,679679- .raw_event_mask = 0xFF,649649+ .map_event = armv6_map_event,680650 .num_events = 3,681651 .max_period = (1LLU << 32) - 1,682652};683653684684-static const struct arm_pmu *__init armv6pmu_init(void)654654+static struct arm_pmu *__init armv6pmu_init(void)685655{686656 return &armv6pmu;687657}···691665 * disable the interrupt reporting and update the event. When unthrottling we692666 * reset the period and enable the interrupt reporting.693667 */694694-static const struct arm_pmu armv6mpcore_pmu = {668668+669669+static int armv6mpcore_map_event(struct perf_event *event)670670+{671671+ return map_cpu_event(event, &armv6mpcore_perf_map,672672+ &armv6mpcore_perf_cache_map, 0xFF);673673+}674674+675675+static struct arm_pmu armv6mpcore_pmu = {695676 .id = ARM_PERF_PMU_ID_V6MP,696677 .name = "v6mpcore",697678 .handle_irq = armv6pmu_handle_irq,···709676 .get_event_idx = armv6pmu_get_event_idx,710677 .start = armv6pmu_start,711678 .stop = armv6pmu_stop,712712- .cache_map = &armv6mpcore_perf_cache_map,713713- .event_map = &armv6mpcore_perf_map,714714- .raw_event_mask = 0xFF,679679+ .map_event = armv6mpcore_map_event,715680 .num_events = 3,716681 .max_period = (1LLU << 32) - 1,717682};718683719719-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)684684+static struct arm_pmu *__init armv6mpcore_pmu_init(void)720685{721686 return &armv6mpcore_pmu;722687}723688#else724724-static const struct arm_pmu *__init armv6pmu_init(void)689689+static struct arm_pmu *__init armv6pmu_init(void)725690{726691 return NULL;727692}728693729729-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)694694+static struct arm_pmu *__init armv6mpcore_pmu_init(void)730695{731696 return NULL;732697}
+201-204
arch/arm/kernel/perf_event_v7.c
···1717 */18181919#ifdef CONFIG_CPU_V72020+2121+static struct arm_pmu armv7pmu;2222+2023/*2124 * Common ARMv7 event types2225 *···679676};680677681678/*682682- * Perf Events counters679679+ * Perf Events' indices683680 */684684-enum armv7_counters {685685- ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */686686- ARMV7_COUNTER0 = 2, /* First event counter */687687-};681681+#define ARMV7_IDX_CYCLE_COUNTER 0682682+#define ARMV7_IDX_COUNTER0 1683683+#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)688684689689-/*690690- * The cycle counter is ARMV7_CYCLE_COUNTER.691691- * The first event counter is ARMV7_COUNTER0.692692- * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1).693693- */694694-#define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1)685685+#define ARMV7_MAX_COUNTERS 32686686+#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)695687696688/*697689 * ARMv7 low level PMNC access698690 */691691+692692+/*693693+ * Perf Event to low level counters mapping694694+ */695695+#define ARMV7_IDX_TO_COUNTER(x) \696696+ (((x) - ARMV7_IDX_COUNTER0) & ARMV7_COUNTER_MASK)699697700698/*701699 * Per-CPU PMNC: config reg···712708#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */713709714710/*715715- * Available counters716716- */717717-#define ARMV7_CNT0 0 /* First event counter */718718-#define ARMV7_CCNT 31 /* Cycle counter */719719-720720-/* Perf Event to low level counters mapping */721721-#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0)722722-723723-/*724724- * CNTENS: counters enable reg725725- */726726-#define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))727727-#define ARMV7_CNTENS_C (1 << ARMV7_CCNT)728728-729729-/*730730- * CNTENC: counters disable reg731731- */732732-#define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))733733-#define ARMV7_CNTENC_C (1 << ARMV7_CCNT)734734-735735-/*736736- * INTENS: counters overflow interrupt enable reg737737- */738738-#define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))739739-#define ARMV7_INTENS_C (1 << ARMV7_CCNT)740740-741741-/*742742- * INTENC: counters overflow interrupt disable reg743743- */744744-#define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))745745-#define ARMV7_INTENC_C (1 << ARMV7_CCNT)746746-747747-/*748748- * EVTSEL: Event selection reg749749- */750750-#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */751751-752752-/*753753- * SELECT: Counter selection reg754754- */755755-#define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */756756-757757-/*758711 * FLAG: counters overflow flag status reg759712 */760760-#define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))761761-#define ARMV7_FLAG_C (1 << ARMV7_CCNT)762713#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */763714#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK764715765765-static inline unsigned long armv7_pmnc_read(void)716716+/*717717+ * PMXEVTYPER: Event selection reg718718+ */719719+#define ARMV7_EVTYPE_MASK 0xc00000ff /* Mask for writable bits */720720+#define ARMV7_EVTYPE_EVENT 0xff /* Mask for EVENT bits */721721+722722+/*723723+ * Event filters for PMUv2724724+ */725725+#define ARMV7_EXCLUDE_PL1 (1 << 31)726726+#define ARMV7_EXCLUDE_USER (1 << 30)727727+#define ARMV7_INCLUDE_HYP (1 << 27)728728+729729+static inline u32 armv7_pmnc_read(void)766730{767731 u32 val;768732 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val));769733 return val;770734}771735772772-static inline void armv7_pmnc_write(unsigned long val)736736+static inline void armv7_pmnc_write(u32 val)773737{774738 val &= ARMV7_PMNC_MASK;775739 isb();776740 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val));777741}778742779779-static inline int armv7_pmnc_has_overflowed(unsigned long pmnc)743743+static inline int armv7_pmnc_has_overflowed(u32 pmnc)780744{781745 return pmnc & ARMV7_OVERFLOWED_MASK;782746}783747784784-static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,785785- enum armv7_counters counter)748748+static inline int armv7_pmnc_counter_valid(int idx)749749+{750750+ return idx >= ARMV7_IDX_CYCLE_COUNTER && idx <= ARMV7_IDX_COUNTER_LAST;751751+}752752+753753+static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)786754{787755 int ret = 0;756756+ u32 counter;788757789789- if (counter == ARMV7_CYCLE_COUNTER)790790- ret = pmnc & ARMV7_FLAG_C;791791- else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST))792792- ret = pmnc & ARMV7_FLAG_P(counter);793793- else758758+ if (!armv7_pmnc_counter_valid(idx)) {794759 pr_err("CPU%u checking wrong counter %d overflow status\n",795795- smp_processor_id(), counter);760760+ smp_processor_id(), idx);761761+ } else {762762+ counter = ARMV7_IDX_TO_COUNTER(idx);763763+ ret = pmnc & BIT(counter);764764+ }796765797766 return ret;798767}799768800800-static inline int armv7_pmnc_select_counter(unsigned int idx)769769+static inline int armv7_pmnc_select_counter(int idx)801770{802802- u32 val;771771+ u32 counter;803772804804- if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) {805805- pr_err("CPU%u selecting wrong PMNC counter"806806- " %d\n", smp_processor_id(), idx);807807- return -1;773773+ if (!armv7_pmnc_counter_valid(idx)) {774774+ pr_err("CPU%u selecting wrong PMNC counter %d\n",775775+ smp_processor_id(), idx);776776+ return -EINVAL;808777 }809778810810- val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK;811811- asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));779779+ counter = ARMV7_IDX_TO_COUNTER(idx);780780+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));812781 isb();813782814783 return idx;···789812790813static inline u32 armv7pmu_read_counter(int idx)791814{792792- unsigned long value = 0;815815+ u32 value = 0;793816794794- if (idx == ARMV7_CYCLE_COUNTER)795795- asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));796796- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {797797- if (armv7_pmnc_select_counter(idx) == idx)798798- asm volatile("mrc p15, 0, %0, c9, c13, 2"799799- : "=r" (value));800800- } else817817+ if (!armv7_pmnc_counter_valid(idx))801818 pr_err("CPU%u reading wrong counter %d\n",802819 smp_processor_id(), idx);820820+ else if (idx == ARMV7_IDX_CYCLE_COUNTER)821821+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));822822+ else if (armv7_pmnc_select_counter(idx) == idx)823823+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value));803824804825 return value;805826}806827807828static inline void armv7pmu_write_counter(int idx, u32 value)808829{809809- if (idx == ARMV7_CYCLE_COUNTER)810810- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));811811- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {812812- if (armv7_pmnc_select_counter(idx) == idx)813813- asm volatile("mcr p15, 0, %0, c9, c13, 2"814814- : : "r" (value));815815- } else830830+ if (!armv7_pmnc_counter_valid(idx))816831 pr_err("CPU%u writing wrong counter %d\n",817832 smp_processor_id(), idx);833833+ else if (idx == ARMV7_IDX_CYCLE_COUNTER)834834+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));835835+ else if (armv7_pmnc_select_counter(idx) == idx)836836+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));818837}819838820820-static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)839839+static inline void armv7_pmnc_write_evtsel(int idx, u32 val)821840{822841 if (armv7_pmnc_select_counter(idx) == idx) {823823- val &= ARMV7_EVTSEL_MASK;842842+ val &= ARMV7_EVTYPE_MASK;824843 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));825844 }826845}827846828828-static inline u32 armv7_pmnc_enable_counter(unsigned int idx)847847+static inline int armv7_pmnc_enable_counter(int idx)829848{830830- u32 val;849849+ u32 counter;831850832832- if ((idx != ARMV7_CYCLE_COUNTER) &&833833- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {834834- pr_err("CPU%u enabling wrong PMNC counter"835835- " %d\n", smp_processor_id(), idx);836836- return -1;851851+ if (!armv7_pmnc_counter_valid(idx)) {852852+ pr_err("CPU%u enabling wrong PMNC counter %d\n",853853+ smp_processor_id(), idx);854854+ return -EINVAL;837855 }838856839839- if (idx == ARMV7_CYCLE_COUNTER)840840- val = ARMV7_CNTENS_C;841841- else842842- val = ARMV7_CNTENS_P(idx);843843-844844- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));845845-857857+ counter = ARMV7_IDX_TO_COUNTER(idx);858858+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter)));846859 return idx;847860}848861849849-static inline u32 armv7_pmnc_disable_counter(unsigned int idx)862862+static inline int armv7_pmnc_disable_counter(int idx)850863{851851- u32 val;864864+ u32 counter;852865853853-854854- if ((idx != ARMV7_CYCLE_COUNTER) &&855855- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {856856- pr_err("CPU%u disabling wrong PMNC counter"857857- " %d\n", smp_processor_id(), idx);858858- return -1;866866+ if (!armv7_pmnc_counter_valid(idx)) {867867+ pr_err("CPU%u disabling wrong PMNC counter %d\n",868868+ smp_processor_id(), idx);869869+ return -EINVAL;859870 }860871861861- if (idx == ARMV7_CYCLE_COUNTER)862862- val = ARMV7_CNTENC_C;863863- else864864- val = ARMV7_CNTENC_P(idx);865865-866866- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));867867-872872+ counter = ARMV7_IDX_TO_COUNTER(idx);873873+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter)));868874 return idx;869875}870876871871-static inline u32 armv7_pmnc_enable_intens(unsigned int idx)877877+static inline int armv7_pmnc_enable_intens(int idx)872878{873873- u32 val;879879+ u32 counter;874880875875- if ((idx != ARMV7_CYCLE_COUNTER) &&876876- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {877877- pr_err("CPU%u enabling wrong PMNC counter"878878- " interrupt enable %d\n", smp_processor_id(), idx);879879- return -1;881881+ if (!armv7_pmnc_counter_valid(idx)) {882882+ pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",883883+ smp_processor_id(), idx);884884+ return -EINVAL;880885 }881886882882- if (idx == ARMV7_CYCLE_COUNTER)883883- val = ARMV7_INTENS_C;884884- else885885- val = ARMV7_INTENS_P(idx);886886-887887- asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));888888-887887+ counter = ARMV7_IDX_TO_COUNTER(idx);888888+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter)));889889 return idx;890890}891891892892-static inline u32 armv7_pmnc_disable_intens(unsigned int idx)892892+static inline int armv7_pmnc_disable_intens(int idx)893893{894894- u32 val;894894+ u32 counter;895895896896- if ((idx != ARMV7_CYCLE_COUNTER) &&897897- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {898898- pr_err("CPU%u disabling wrong PMNC counter"899899- " interrupt enable %d\n", smp_processor_id(), idx);900900- return -1;896896+ if (!armv7_pmnc_counter_valid(idx)) {897897+ pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",898898+ smp_processor_id(), idx);899899+ return -EINVAL;901900 }902901903903- if (idx == ARMV7_CYCLE_COUNTER)904904- val = ARMV7_INTENC_C;905905- else906906- val = ARMV7_INTENC_P(idx);907907-908908- asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));909909-902902+ counter = ARMV7_IDX_TO_COUNTER(idx);903903+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));910904 return idx;911905}912906···921973 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));922974 printk(KERN_INFO "CCNT =0x%08x\n", val);923975924924- for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) {976976+ for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST; cnt++) {925977 armv7_pmnc_select_counter(cnt);926978 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));927979 printk(KERN_INFO "CNT[%d] count =0x%08x\n",928928- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);980980+ ARMV7_IDX_TO_COUNTER(cnt), val);929981 asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));930982 printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n",931931- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);983983+ ARMV7_IDX_TO_COUNTER(cnt), val);932984 }933985}934986#endif···936988static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)937989{938990 unsigned long flags;991991+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();939992940993 /*941994 * Enable counter and interrupt, and set the counter to count942995 * the event that we're interested in.943996 */944944- raw_spin_lock_irqsave(&pmu_lock, flags);997997+ raw_spin_lock_irqsave(&events->pmu_lock, flags);945998946999 /*9471000 * Disable counter···95110029521003 /*9531004 * Set event (if destined for PMNx counters)954954- * We don't need to set the event if it's a cycle count10051005+ * We only need to set the event for the cycle counter if we10061006+ * have the ability to perform event filtering.9551007 */956956- if (idx != ARMV7_CYCLE_COUNTER)10081008+ if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER)9571009 armv7_pmnc_write_evtsel(idx, hwc->config_base);95810109591011 /*···9671017 */9681018 armv7_pmnc_enable_counter(idx);9691019970970- raw_spin_unlock_irqrestore(&pmu_lock, flags);10201020+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);9711021}97210229731023static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)9741024{9751025 unsigned long flags;10261026+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();97610279771028 /*9781029 * Disable counter and interrupt9791030 */980980- raw_spin_lock_irqsave(&pmu_lock, flags);10311031+ raw_spin_lock_irqsave(&events->pmu_lock, flags);98110329821033 /*9831034 * Disable counter···9901039 */9911040 armv7_pmnc_disable_intens(idx);9921041993993- raw_spin_unlock_irqrestore(&pmu_lock, flags);10421042+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);9941043}99510449961045static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)9971046{998998- unsigned long pmnc;10471047+ u32 pmnc;9991048 struct perf_sample_data data;10001000- struct cpu_hw_events *cpuc;10491049+ struct pmu_hw_events *cpuc;10011050 struct pt_regs *regs;10021051 int idx;10031052···10201069 perf_sample_data_init(&data, 0);1021107010221071 cpuc = &__get_cpu_var(cpu_hw_events);10231023- for (idx = 0; idx <= armpmu->num_events; ++idx) {10721072+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {10241073 struct perf_event *event = cpuc->events[idx];10251074 struct hw_perf_event *hwc;10261026-10271027- if (!test_bit(idx, cpuc->active_mask))10281028- continue;1029107510301076 /*10311077 * We have a single interrupt for all counters. Check that···10381090 continue;1039109110401092 if (perf_event_overflow(event, &data, regs))10411041- armpmu->disable(hwc, idx);10931093+ cpu_pmu->disable(hwc, idx);10421094 }1043109510441096 /*···10561108static void armv7pmu_start(void)10571109{10581110 unsigned long flags;11111111+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();1059111210601060- raw_spin_lock_irqsave(&pmu_lock, flags);11131113+ raw_spin_lock_irqsave(&events->pmu_lock, flags);10611114 /* Enable all counters */10621115 armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E);10631063- raw_spin_unlock_irqrestore(&pmu_lock, flags);11161116+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);10641117}1065111810661119static void armv7pmu_stop(void)10671120{10681121 unsigned long flags;11221122+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();1069112310701070- raw_spin_lock_irqsave(&pmu_lock, flags);11241124+ raw_spin_lock_irqsave(&events->pmu_lock, flags);10711125 /* Disable all counters */10721126 armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E);10731073- raw_spin_unlock_irqrestore(&pmu_lock, flags);11271127+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);10741128}1075112910761076-static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,11301130+static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc,10771131 struct hw_perf_event *event)10781132{10791133 int idx;11341134+ unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT;1080113510811136 /* Always place a cycle counter into the cycle counter. */10821082- if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {10831083- if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask))11371137+ if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {11381138+ if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask))10841139 return -EAGAIN;1085114010861086- return ARMV7_CYCLE_COUNTER;10871087- } else {10881088- /*10891089- * For anything other than a cycle counter, try and use10901090- * the events counters10911091- */10921092- for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) {10931093- if (!test_and_set_bit(idx, cpuc->used_mask))10941094- return idx;10951095- }10961096-10971097- /* The counters are all in use. */10981098- return -EAGAIN;11411141+ return ARMV7_IDX_CYCLE_COUNTER;10991142 }11431143+11441144+ /*11451145+ * For anything other than a cycle counter, try and use11461146+ * the events counters11471147+ */11481148+ for (idx = ARMV7_IDX_COUNTER0; idx < cpu_pmu->num_events; ++idx) {11491149+ if (!test_and_set_bit(idx, cpuc->used_mask))11501150+ return idx;11511151+ }11521152+11531153+ /* The counters are all in use. */11541154+ return -EAGAIN;11551155+}11561156+11571157+/*11581158+ * Add an event filter to a given event. This will only work for PMUv2 PMUs.11591159+ */11601160+static int armv7pmu_set_event_filter(struct hw_perf_event *event,11611161+ struct perf_event_attr *attr)11621162+{11631163+ unsigned long config_base = 0;11641164+11651165+ if (attr->exclude_idle)11661166+ return -EPERM;11671167+ if (attr->exclude_user)11681168+ config_base |= ARMV7_EXCLUDE_USER;11691169+ if (attr->exclude_kernel)11701170+ config_base |= ARMV7_EXCLUDE_PL1;11711171+ if (!attr->exclude_hv)11721172+ config_base |= ARMV7_INCLUDE_HYP;11731173+11741174+ /*11751175+ * Install the filter into config_base as this is used to11761176+ * construct the event type.11771177+ */11781178+ event->config_base = config_base;11791179+11801180+ return 0;11001181}1101118211021183static void armv7pmu_reset(void *info)11031184{11041104- u32 idx, nb_cnt = armpmu->num_events;11851185+ u32 idx, nb_cnt = cpu_pmu->num_events;1105118611061187 /* The counter and interrupt enable registers are unknown at reset. */11071107- for (idx = 1; idx < nb_cnt; ++idx)11881188+ for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx)11081189 armv7pmu_disable_event(NULL, idx);1109119011101191 /* Initialize & Reset PMNC: C and P bits */11111192 armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);11931193+}11941194+11951195+static int armv7_a8_map_event(struct perf_event *event)11961196+{11971197+ return map_cpu_event(event, &armv7_a8_perf_map,11981198+ &armv7_a8_perf_cache_map, 0xFF);11991199+}12001200+12011201+static int armv7_a9_map_event(struct perf_event *event)12021202+{12031203+ return map_cpu_event(event, &armv7_a9_perf_map,12041204+ &armv7_a9_perf_cache_map, 0xFF);12051205+}12061206+12071207+static int armv7_a5_map_event(struct perf_event *event)12081208+{12091209+ return map_cpu_event(event, &armv7_a5_perf_map,12101210+ &armv7_a5_perf_cache_map, 0xFF);12111211+}12121212+12131213+static int armv7_a15_map_event(struct perf_event *event)12141214+{12151215+ return map_cpu_event(event, &armv7_a15_perf_map,12161216+ &armv7_a15_perf_cache_map, 0xFF);11121217}1113121811141219static struct arm_pmu armv7pmu = {···11741173 .start = armv7pmu_start,11751174 .stop = armv7pmu_stop,11761175 .reset = armv7pmu_reset,11771177- .raw_event_mask = 0xFF,11781176 .max_period = (1LLU << 32) - 1,11791177};11801178···11881188 return nb_cnt + 1;11891189}1190119011911191-static const struct arm_pmu *__init armv7_a8_pmu_init(void)11911191+static struct arm_pmu *__init armv7_a8_pmu_init(void)11921192{11931193 armv7pmu.id = ARM_PERF_PMU_ID_CA8;11941194 armv7pmu.name = "ARMv7 Cortex-A8";11951195- armv7pmu.cache_map = &armv7_a8_perf_cache_map;11961196- armv7pmu.event_map = &armv7_a8_perf_map;11951195+ armv7pmu.map_event = armv7_a8_map_event;11971196 armv7pmu.num_events = armv7_read_num_pmnc_events();11981197 return &armv7pmu;11991198}1200119912011201-static const struct arm_pmu *__init armv7_a9_pmu_init(void)12001200+static struct arm_pmu *__init armv7_a9_pmu_init(void)12021201{12031202 armv7pmu.id = ARM_PERF_PMU_ID_CA9;12041203 armv7pmu.name = "ARMv7 Cortex-A9";12051205- armv7pmu.cache_map = &armv7_a9_perf_cache_map;12061206- armv7pmu.event_map = &armv7_a9_perf_map;12041204+ armv7pmu.map_event = armv7_a9_map_event;12071205 armv7pmu.num_events = armv7_read_num_pmnc_events();12081206 return &armv7pmu;12091207}1210120812111211-static const struct arm_pmu *__init armv7_a5_pmu_init(void)12091209+static struct arm_pmu *__init armv7_a5_pmu_init(void)12121210{12131211 armv7pmu.id = ARM_PERF_PMU_ID_CA5;12141212 armv7pmu.name = "ARMv7 Cortex-A5";12151215- armv7pmu.cache_map = &armv7_a5_perf_cache_map;12161216- armv7pmu.event_map = &armv7_a5_perf_map;12131213+ armv7pmu.map_event = armv7_a5_map_event;12171214 armv7pmu.num_events = armv7_read_num_pmnc_events();12181215 return &armv7pmu;12191216}1220121712211221-static const struct arm_pmu *__init armv7_a15_pmu_init(void)12181218+static struct arm_pmu *__init armv7_a15_pmu_init(void)12221219{12231220 armv7pmu.id = ARM_PERF_PMU_ID_CA15;12241221 armv7pmu.name = "ARMv7 Cortex-A15";12251225- armv7pmu.cache_map = &armv7_a15_perf_cache_map;12261226- armv7pmu.event_map = &armv7_a15_perf_map;12221222+ armv7pmu.map_event = armv7_a15_map_event;12271223 armv7pmu.num_events = armv7_read_num_pmnc_events();12241224+ armv7pmu.set_event_filter = armv7pmu_set_event_filter;12281225 return &armv7pmu;12291226}12301227#else12311231-static const struct arm_pmu *__init armv7_a8_pmu_init(void)12281228+static struct arm_pmu *__init armv7_a8_pmu_init(void)12321229{12331230 return NULL;12341231}1235123212361236-static const struct arm_pmu *__init armv7_a9_pmu_init(void)12331233+static struct arm_pmu *__init armv7_a9_pmu_init(void)12371234{12381235 return NULL;12391236}1240123712411241-static const struct arm_pmu *__init armv7_a5_pmu_init(void)12381238+static struct arm_pmu *__init armv7_a5_pmu_init(void)12421239{12431240 return NULL;12441241}1245124212461246-static const struct arm_pmu *__init armv7_a15_pmu_init(void)12431243+static struct arm_pmu *__init armv7_a15_pmu_init(void)12471244{12481245 return NULL;12491246}