Path: blob/master/arch/arm/kernel/perf_event_xscale.c
10817 views
/*1* ARMv5 [xscale] Performance counter handling code.2*3* Copyright (C) 2010, ARM Ltd., Will Deacon <[email protected]>4*5* Based on the previous xscale OProfile code.6*7* There are two variants of the xscale PMU that we support:8* - xscale1pmu: 2 event counters and a cycle counter9* - xscale2pmu: 4 event counters and a cycle counter10* The two variants share event definitions, but have different11* PMU structures.12*/1314#ifdef CONFIG_CPU_XSCALE15enum xscale_perf_types {16XSCALE_PERFCTR_ICACHE_MISS = 0x00,17XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01,18XSCALE_PERFCTR_DATA_STALL = 0x02,19XSCALE_PERFCTR_ITLB_MISS = 0x03,20XSCALE_PERFCTR_DTLB_MISS = 0x04,21XSCALE_PERFCTR_BRANCH = 0x05,22XSCALE_PERFCTR_BRANCH_MISS = 0x06,23XSCALE_PERFCTR_INSTRUCTION = 0x07,24XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08,25XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09,26XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A,27XSCALE_PERFCTR_DCACHE_MISS = 0x0B,28XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C,29XSCALE_PERFCTR_PC_CHANGED = 0x0D,30XSCALE_PERFCTR_BCU_REQUEST = 0x10,31XSCALE_PERFCTR_BCU_FULL = 0x11,32XSCALE_PERFCTR_BCU_DRAIN = 0x12,33XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14,34XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15,35XSCALE_PERFCTR_RMW = 0x16,36/* XSCALE_PERFCTR_CCNT is not hardware defined */37XSCALE_PERFCTR_CCNT = 0xFE,38XSCALE_PERFCTR_UNUSED = 0xFF,39};4041enum xscale_counters {42XSCALE_CYCLE_COUNTER = 1,43XSCALE_COUNTER0,44XSCALE_COUNTER1,45XSCALE_COUNTER2,46XSCALE_COUNTER3,47};4849static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = {50[PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT,51[PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION,52[PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,53[PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,54[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH,55[PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS,56[PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,57};5859static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]60[PERF_COUNT_HW_CACHE_OP_MAX]61[PERF_COUNT_HW_CACHE_RESULT_MAX] = {62[C(L1D)] = {63[C(OP_READ)] = {64[C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,65[C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,66},67[C(OP_WRITE)] = {68[C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,69[C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,70},71[C(OP_PREFETCH)] = {72[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,73[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,74},75},76[C(L1I)] = {77[C(OP_READ)] = {78[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,79[C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,80},81[C(OP_WRITE)] = {82[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,83[C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,84},85[C(OP_PREFETCH)] = {86[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,87[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,88},89},90[C(LL)] = {91[C(OP_READ)] = {92[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,93[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,94},95[C(OP_WRITE)] = {96[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,97[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,98},99[C(OP_PREFETCH)] = {100[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,101[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,102},103},104[C(DTLB)] = {105[C(OP_READ)] = {106[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,107[C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,108},109[C(OP_WRITE)] = {110[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,111[C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,112},113[C(OP_PREFETCH)] = {114[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,115[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,116},117},118[C(ITLB)] = {119[C(OP_READ)] = {120[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,121[C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,122},123[C(OP_WRITE)] = {124[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,125[C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,126},127[C(OP_PREFETCH)] = {128[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,129[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,130},131},132[C(BPU)] = {133[C(OP_READ)] = {134[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,135[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,136},137[C(OP_WRITE)] = {138[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,139[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,140},141[C(OP_PREFETCH)] = {142[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,143[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,144},145},146};147148#define XSCALE_PMU_ENABLE 0x001149#define XSCALE_PMN_RESET 0x002150#define XSCALE_CCNT_RESET 0x004151#define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET)152#define XSCALE_PMU_CNT64 0x008153154#define XSCALE1_OVERFLOWED_MASK 0x700155#define XSCALE1_CCOUNT_OVERFLOW 0x400156#define XSCALE1_COUNT0_OVERFLOW 0x100157#define XSCALE1_COUNT1_OVERFLOW 0x200158#define XSCALE1_CCOUNT_INT_EN 0x040159#define XSCALE1_COUNT0_INT_EN 0x010160#define XSCALE1_COUNT1_INT_EN 0x020161#define XSCALE1_COUNT0_EVT_SHFT 12162#define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT)163#define XSCALE1_COUNT1_EVT_SHFT 20164#define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT)165166static inline u32167xscale1pmu_read_pmnc(void)168{169u32 val;170asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));171return val;172}173174static inline void175xscale1pmu_write_pmnc(u32 val)176{177/* upper 4bits and 7, 11 are write-as-0 */178val &= 0xffff77f;179asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));180}181182static inline int183xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,184enum xscale_counters counter)185{186int ret = 0;187188switch (counter) {189case XSCALE_CYCLE_COUNTER:190ret = pmnc & XSCALE1_CCOUNT_OVERFLOW;191break;192case XSCALE_COUNTER0:193ret = pmnc & XSCALE1_COUNT0_OVERFLOW;194break;195case XSCALE_COUNTER1:196ret = pmnc & XSCALE1_COUNT1_OVERFLOW;197break;198default:199WARN_ONCE(1, "invalid counter number (%d)\n", counter);200}201202return ret;203}204205static irqreturn_t206xscale1pmu_handle_irq(int irq_num, void *dev)207{208unsigned long pmnc;209struct perf_sample_data data;210struct cpu_hw_events *cpuc;211struct pt_regs *regs;212int idx;213214/*215* NOTE: there's an A stepping erratum that states if an overflow216* bit already exists and another occurs, the previous217* Overflow bit gets cleared. There's no workaround.218* Fixed in B stepping or later.219*/220pmnc = xscale1pmu_read_pmnc();221222/*223* Write the value back to clear the overflow flags. Overflow224* flags remain in pmnc for use below. We also disable the PMU225* while we process the interrupt.226*/227xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);228229if (!(pmnc & XSCALE1_OVERFLOWED_MASK))230return IRQ_NONE;231232regs = get_irq_regs();233234perf_sample_data_init(&data, 0);235236cpuc = &__get_cpu_var(cpu_hw_events);237for (idx = 0; idx <= armpmu->num_events; ++idx) {238struct perf_event *event = cpuc->events[idx];239struct hw_perf_event *hwc;240241if (!test_bit(idx, cpuc->active_mask))242continue;243244if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))245continue;246247hwc = &event->hw;248armpmu_event_update(event, hwc, idx, 1);249data.period = event->hw.last_period;250if (!armpmu_event_set_period(event, hwc, idx))251continue;252253if (perf_event_overflow(event, 0, &data, regs))254armpmu->disable(hwc, idx);255}256257irq_work_run();258259/*260* Re-enable the PMU.261*/262pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE;263xscale1pmu_write_pmnc(pmnc);264265return IRQ_HANDLED;266}267268static void269xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)270{271unsigned long val, mask, evt, flags;272273switch (idx) {274case XSCALE_CYCLE_COUNTER:275mask = 0;276evt = XSCALE1_CCOUNT_INT_EN;277break;278case XSCALE_COUNTER0:279mask = XSCALE1_COUNT0_EVT_MASK;280evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) |281XSCALE1_COUNT0_INT_EN;282break;283case XSCALE_COUNTER1:284mask = XSCALE1_COUNT1_EVT_MASK;285evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) |286XSCALE1_COUNT1_INT_EN;287break;288default:289WARN_ONCE(1, "invalid counter number (%d)\n", idx);290return;291}292293raw_spin_lock_irqsave(&pmu_lock, flags);294val = xscale1pmu_read_pmnc();295val &= ~mask;296val |= evt;297xscale1pmu_write_pmnc(val);298raw_spin_unlock_irqrestore(&pmu_lock, flags);299}300301static void302xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)303{304unsigned long val, mask, evt, flags;305306switch (idx) {307case XSCALE_CYCLE_COUNTER:308mask = XSCALE1_CCOUNT_INT_EN;309evt = 0;310break;311case XSCALE_COUNTER0:312mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK;313evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT;314break;315case XSCALE_COUNTER1:316mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK;317evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT;318break;319default:320WARN_ONCE(1, "invalid counter number (%d)\n", idx);321return;322}323324raw_spin_lock_irqsave(&pmu_lock, flags);325val = xscale1pmu_read_pmnc();326val &= ~mask;327val |= evt;328xscale1pmu_write_pmnc(val);329raw_spin_unlock_irqrestore(&pmu_lock, flags);330}331332static int333xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc,334struct hw_perf_event *event)335{336if (XSCALE_PERFCTR_CCNT == event->config_base) {337if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))338return -EAGAIN;339340return XSCALE_CYCLE_COUNTER;341} else {342if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask))343return XSCALE_COUNTER1;344345if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask))346return XSCALE_COUNTER0;347348return -EAGAIN;349}350}351352static void353xscale1pmu_start(void)354{355unsigned long flags, val;356357raw_spin_lock_irqsave(&pmu_lock, flags);358val = xscale1pmu_read_pmnc();359val |= XSCALE_PMU_ENABLE;360xscale1pmu_write_pmnc(val);361raw_spin_unlock_irqrestore(&pmu_lock, flags);362}363364static void365xscale1pmu_stop(void)366{367unsigned long flags, val;368369raw_spin_lock_irqsave(&pmu_lock, flags);370val = xscale1pmu_read_pmnc();371val &= ~XSCALE_PMU_ENABLE;372xscale1pmu_write_pmnc(val);373raw_spin_unlock_irqrestore(&pmu_lock, flags);374}375376static inline u32377xscale1pmu_read_counter(int counter)378{379u32 val = 0;380381switch (counter) {382case XSCALE_CYCLE_COUNTER:383asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));384break;385case XSCALE_COUNTER0:386asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));387break;388case XSCALE_COUNTER1:389asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));390break;391}392393return val;394}395396static inline void397xscale1pmu_write_counter(int counter, u32 val)398{399switch (counter) {400case XSCALE_CYCLE_COUNTER:401asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));402break;403case XSCALE_COUNTER0:404asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));405break;406case XSCALE_COUNTER1:407asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));408break;409}410}411412static const struct arm_pmu xscale1pmu = {413.id = ARM_PERF_PMU_ID_XSCALE1,414.name = "xscale1",415.handle_irq = xscale1pmu_handle_irq,416.enable = xscale1pmu_enable_event,417.disable = xscale1pmu_disable_event,418.read_counter = xscale1pmu_read_counter,419.write_counter = xscale1pmu_write_counter,420.get_event_idx = xscale1pmu_get_event_idx,421.start = xscale1pmu_start,422.stop = xscale1pmu_stop,423.cache_map = &xscale_perf_cache_map,424.event_map = &xscale_perf_map,425.raw_event_mask = 0xFF,426.num_events = 3,427.max_period = (1LLU << 32) - 1,428};429430static const struct arm_pmu *__init xscale1pmu_init(void)431{432return &xscale1pmu;433}434435#define XSCALE2_OVERFLOWED_MASK 0x01f436#define XSCALE2_CCOUNT_OVERFLOW 0x001437#define XSCALE2_COUNT0_OVERFLOW 0x002438#define XSCALE2_COUNT1_OVERFLOW 0x004439#define XSCALE2_COUNT2_OVERFLOW 0x008440#define XSCALE2_COUNT3_OVERFLOW 0x010441#define XSCALE2_CCOUNT_INT_EN 0x001442#define XSCALE2_COUNT0_INT_EN 0x002443#define XSCALE2_COUNT1_INT_EN 0x004444#define XSCALE2_COUNT2_INT_EN 0x008445#define XSCALE2_COUNT3_INT_EN 0x010446#define XSCALE2_COUNT0_EVT_SHFT 0447#define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT)448#define XSCALE2_COUNT1_EVT_SHFT 8449#define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT)450#define XSCALE2_COUNT2_EVT_SHFT 16451#define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT)452#define XSCALE2_COUNT3_EVT_SHFT 24453#define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT)454455static inline u32456xscale2pmu_read_pmnc(void)457{458u32 val;459asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));460/* bits 1-2 and 4-23 are read-unpredictable */461return val & 0xff000009;462}463464static inline void465xscale2pmu_write_pmnc(u32 val)466{467/* bits 4-23 are write-as-0, 24-31 are write ignored */468val &= 0xf;469asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));470}471472static inline u32473xscale2pmu_read_overflow_flags(void)474{475u32 val;476asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val));477return val;478}479480static inline void481xscale2pmu_write_overflow_flags(u32 val)482{483asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val));484}485486static inline u32487xscale2pmu_read_event_select(void)488{489u32 val;490asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val));491return val;492}493494static inline void495xscale2pmu_write_event_select(u32 val)496{497asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));498}499500static inline u32501xscale2pmu_read_int_enable(void)502{503u32 val;504asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val));505return val;506}507508static void509xscale2pmu_write_int_enable(u32 val)510{511asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val));512}513514static inline int515xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,516enum xscale_counters counter)517{518int ret = 0;519520switch (counter) {521case XSCALE_CYCLE_COUNTER:522ret = of_flags & XSCALE2_CCOUNT_OVERFLOW;523break;524case XSCALE_COUNTER0:525ret = of_flags & XSCALE2_COUNT0_OVERFLOW;526break;527case XSCALE_COUNTER1:528ret = of_flags & XSCALE2_COUNT1_OVERFLOW;529break;530case XSCALE_COUNTER2:531ret = of_flags & XSCALE2_COUNT2_OVERFLOW;532break;533case XSCALE_COUNTER3:534ret = of_flags & XSCALE2_COUNT3_OVERFLOW;535break;536default:537WARN_ONCE(1, "invalid counter number (%d)\n", counter);538}539540return ret;541}542543static irqreturn_t544xscale2pmu_handle_irq(int irq_num, void *dev)545{546unsigned long pmnc, of_flags;547struct perf_sample_data data;548struct cpu_hw_events *cpuc;549struct pt_regs *regs;550int idx;551552/* Disable the PMU. */553pmnc = xscale2pmu_read_pmnc();554xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);555556/* Check the overflow flag register. */557of_flags = xscale2pmu_read_overflow_flags();558if (!(of_flags & XSCALE2_OVERFLOWED_MASK))559return IRQ_NONE;560561/* Clear the overflow bits. */562xscale2pmu_write_overflow_flags(of_flags);563564regs = get_irq_regs();565566perf_sample_data_init(&data, 0);567568cpuc = &__get_cpu_var(cpu_hw_events);569for (idx = 0; idx <= armpmu->num_events; ++idx) {570struct perf_event *event = cpuc->events[idx];571struct hw_perf_event *hwc;572573if (!test_bit(idx, cpuc->active_mask))574continue;575576if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))577continue;578579hwc = &event->hw;580armpmu_event_update(event, hwc, idx, 1);581data.period = event->hw.last_period;582if (!armpmu_event_set_period(event, hwc, idx))583continue;584585if (perf_event_overflow(event, 0, &data, regs))586armpmu->disable(hwc, idx);587}588589irq_work_run();590591/*592* Re-enable the PMU.593*/594pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE;595xscale2pmu_write_pmnc(pmnc);596597return IRQ_HANDLED;598}599600static void601xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)602{603unsigned long flags, ien, evtsel;604605ien = xscale2pmu_read_int_enable();606evtsel = xscale2pmu_read_event_select();607608switch (idx) {609case XSCALE_CYCLE_COUNTER:610ien |= XSCALE2_CCOUNT_INT_EN;611break;612case XSCALE_COUNTER0:613ien |= XSCALE2_COUNT0_INT_EN;614evtsel &= ~XSCALE2_COUNT0_EVT_MASK;615evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT;616break;617case XSCALE_COUNTER1:618ien |= XSCALE2_COUNT1_INT_EN;619evtsel &= ~XSCALE2_COUNT1_EVT_MASK;620evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT;621break;622case XSCALE_COUNTER2:623ien |= XSCALE2_COUNT2_INT_EN;624evtsel &= ~XSCALE2_COUNT2_EVT_MASK;625evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT;626break;627case XSCALE_COUNTER3:628ien |= XSCALE2_COUNT3_INT_EN;629evtsel &= ~XSCALE2_COUNT3_EVT_MASK;630evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT;631break;632default:633WARN_ONCE(1, "invalid counter number (%d)\n", idx);634return;635}636637raw_spin_lock_irqsave(&pmu_lock, flags);638xscale2pmu_write_event_select(evtsel);639xscale2pmu_write_int_enable(ien);640raw_spin_unlock_irqrestore(&pmu_lock, flags);641}642643static void644xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)645{646unsigned long flags, ien, evtsel;647648ien = xscale2pmu_read_int_enable();649evtsel = xscale2pmu_read_event_select();650651switch (idx) {652case XSCALE_CYCLE_COUNTER:653ien &= ~XSCALE2_CCOUNT_INT_EN;654break;655case XSCALE_COUNTER0:656ien &= ~XSCALE2_COUNT0_INT_EN;657evtsel &= ~XSCALE2_COUNT0_EVT_MASK;658evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;659break;660case XSCALE_COUNTER1:661ien &= ~XSCALE2_COUNT1_INT_EN;662evtsel &= ~XSCALE2_COUNT1_EVT_MASK;663evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;664break;665case XSCALE_COUNTER2:666ien &= ~XSCALE2_COUNT2_INT_EN;667evtsel &= ~XSCALE2_COUNT2_EVT_MASK;668evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;669break;670case XSCALE_COUNTER3:671ien &= ~XSCALE2_COUNT3_INT_EN;672evtsel &= ~XSCALE2_COUNT3_EVT_MASK;673evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;674break;675default:676WARN_ONCE(1, "invalid counter number (%d)\n", idx);677return;678}679680raw_spin_lock_irqsave(&pmu_lock, flags);681xscale2pmu_write_event_select(evtsel);682xscale2pmu_write_int_enable(ien);683raw_spin_unlock_irqrestore(&pmu_lock, flags);684}685686static int687xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc,688struct hw_perf_event *event)689{690int idx = xscale1pmu_get_event_idx(cpuc, event);691if (idx >= 0)692goto out;693694if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask))695idx = XSCALE_COUNTER3;696else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask))697idx = XSCALE_COUNTER2;698out:699return idx;700}701702static void703xscale2pmu_start(void)704{705unsigned long flags, val;706707raw_spin_lock_irqsave(&pmu_lock, flags);708val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;709val |= XSCALE_PMU_ENABLE;710xscale2pmu_write_pmnc(val);711raw_spin_unlock_irqrestore(&pmu_lock, flags);712}713714static void715xscale2pmu_stop(void)716{717unsigned long flags, val;718719raw_spin_lock_irqsave(&pmu_lock, flags);720val = xscale2pmu_read_pmnc();721val &= ~XSCALE_PMU_ENABLE;722xscale2pmu_write_pmnc(val);723raw_spin_unlock_irqrestore(&pmu_lock, flags);724}725726static inline u32727xscale2pmu_read_counter(int counter)728{729u32 val = 0;730731switch (counter) {732case XSCALE_CYCLE_COUNTER:733asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));734break;735case XSCALE_COUNTER0:736asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));737break;738case XSCALE_COUNTER1:739asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));740break;741case XSCALE_COUNTER2:742asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));743break;744case XSCALE_COUNTER3:745asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));746break;747}748749return val;750}751752static inline void753xscale2pmu_write_counter(int counter, u32 val)754{755switch (counter) {756case XSCALE_CYCLE_COUNTER:757asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));758break;759case XSCALE_COUNTER0:760asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));761break;762case XSCALE_COUNTER1:763asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));764break;765case XSCALE_COUNTER2:766asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));767break;768case XSCALE_COUNTER3:769asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));770break;771}772}773774static const struct arm_pmu xscale2pmu = {775.id = ARM_PERF_PMU_ID_XSCALE2,776.name = "xscale2",777.handle_irq = xscale2pmu_handle_irq,778.enable = xscale2pmu_enable_event,779.disable = xscale2pmu_disable_event,780.read_counter = xscale2pmu_read_counter,781.write_counter = xscale2pmu_write_counter,782.get_event_idx = xscale2pmu_get_event_idx,783.start = xscale2pmu_start,784.stop = xscale2pmu_stop,785.cache_map = &xscale_perf_cache_map,786.event_map = &xscale_perf_map,787.raw_event_mask = 0xFF,788.num_events = 5,789.max_period = (1LLU << 32) - 1,790};791792static const struct arm_pmu *__init xscale2pmu_init(void)793{794return &xscale2pmu;795}796#else797static const struct arm_pmu *__init xscale1pmu_init(void)798{799return NULL;800}801802static const struct arm_pmu *__init xscale2pmu_init(void)803{804return NULL;805}806#endif /* CONFIG_CPU_XSCALE */807808809