blob: 2ad36df9216709cf7e030a50f92fb99e84799d90 [file] [log] [blame]
Ashwin Chaugule7530b452012-06-11 17:41:59 -04001/*
2 * Copyright (c) 2011, 2012 Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#include <linux/irq.h>
14#include <asm/pmu.h>
15#include <linux/platform_device.h>
Ashwin Chauguled2337c32012-06-19 14:37:36 -040016#include <linux/spinlock.h>
Ashwin Chaugule7530b452012-06-11 17:41:59 -040017
18
Ashwin Chaugule4362c742012-06-28 15:24:18 -040019#define MAX_SCORPION_L2_CTRS 10
20
Ashwin Chaugule7530b452012-06-11 17:41:59 -040021#define SCORPION_L2CYCLE_CTR_BIT 31
Ashwin Chaugule7530b452012-06-11 17:41:59 -040022#define SCORPION_L2CYCLE_CTR_RAW_CODE 0xfe
23#define SCORPIONL2_PMNC_E (1 << 0) /* Enable all counters */
24#define SCORPION_L2_EVT_PREFIX 3
25#define SCORPION_MAX_L2_REG 4
26
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -040027#define L2_EVT_MASK 0xfffff
28#define L2_EVT_PREFIX_MASK 0xf0000
29#define L2_EVT_PREFIX_SHIFT 16
30#define L2_SLAVE_EVT_PREFIX 4
31
Ashwin Chaugule4362c742012-06-28 15:24:18 -040032#define PMCR_NUM_EV_SHIFT 11
33#define PMCR_NUM_EV_MASK 0x1f
Ashwin Chauguled2337c32012-06-19 14:37:36 -040034
35/*
36 * The L2 PMU is shared between all CPU's, so protect
37 * its bitmap access.
38 */
39struct pmu_constraints {
40 u64 pmu_bitmap;
41 raw_spinlock_t lock;
42} l2_pmu_constraints = {
43 .pmu_bitmap = 0,
44 .lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock),
45};
46
Ashwin Chaugule795bf7b2012-06-20 16:23:08 -040047/* NRCCG format for perf RAW codes. */
48PMU_FORMAT_ATTR(l2_prefix, "config:16-19");
49PMU_FORMAT_ATTR(l2_reg, "config:12-15");
50PMU_FORMAT_ATTR(l2_code, "config:4-11");
51PMU_FORMAT_ATTR(l2_grp, "config:0-3");
52
53static struct attribute *msm_l2_ev_formats[] = {
54 &format_attr_l2_prefix.attr,
55 &format_attr_l2_reg.attr,
56 &format_attr_l2_code.attr,
57 &format_attr_l2_grp.attr,
58 NULL,
59};
60
61/*
62 * Format group is essential to access PMU's from userspace
63 * via their .name field.
64 */
65static struct attribute_group msm_l2_pmu_format_group = {
66 .name = "format",
67 .attrs = msm_l2_ev_formats,
68};
69
70static const struct attribute_group *msm_l2_pmu_attr_grps[] = {
71 &msm_l2_pmu_format_group,
72 NULL,
73};
74
Ashwin Chaugule4362c742012-06-28 15:24:18 -040075static u32 total_l2_ctrs;
76static u32 l2_cycle_ctr_idx;
77
Ashwin Chaugule7530b452012-06-11 17:41:59 -040078static u32 pmu_type;
79
80static struct arm_pmu scorpion_l2_pmu;
81
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -040082static u32 l2_orig_filter_prefix = 0x000f0030;
83
84/* L2 slave port traffic filtering */
85static u32 l2_slv_filter_prefix = 0x000f0010;
86
Ashwin Chaugule7530b452012-06-11 17:41:59 -040087static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
88static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
89
90static struct pmu_hw_events scorpion_l2_pmu_hw_events = {
91 .events = l2_events,
92 .used_mask = l2_used_mask,
93 .pmu_lock =
94 __RAW_SPIN_LOCK_UNLOCKED(scorpion_l2_pmu_hw_events.pmu_lock),
95};
96
97struct scorpion_l2_scorp_evt {
98 u32 evt_type;
99 u32 val;
100 u8 grp;
101 u32 evt_type_act;
102};
103
104enum scorpion_perf_types {
105 SCORPIONL2_TOTAL_BANK_REQ = 0x90,
106 SCORPIONL2_DSIDE_READ = 0x91,
107 SCORPIONL2_DSIDE_WRITE = 0x92,
108 SCORPIONL2_ISIDE_READ = 0x93,
109 SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
110 SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
111 SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
112 SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
113 SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
114 SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
115 SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
116 SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
117 SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
118 SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
119 SCORPIONL2_BARRIERS = 0x9e,
120 SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
121 SCORPIONL2_MVA_POC = 0xa0,
122 SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
123 SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
124 SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
125 SCORPIONL2_ISIDE_READ_HITS = 0xa4,
126 SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
127 SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
128 SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
129 SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
130 SCORPIONL2_L2LINE_LOCKED = 0xa9,
131 SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
132 SCORPIONL2_CACHE_MVA_POC = 0xab,
133 SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
134 SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
135 SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
136 SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
137 SCORPIONL2_PMBUS_MPAAF = 0xb0,
138 SCORPIONL2_PMBUS_MPWDAF = 0xb1,
139 SCORPIONL2_PMBUS_MPBRT = 0xb2,
140 SCORPIONL2_CPU0_GRANT = 0xb3,
141 SCORPIONL2_CPU1_GRANT = 0xb4,
142 SCORPIONL2_CPU0_NOGRANT = 0xb5,
143 SCORPIONL2_CPU1_NOGRANT = 0xb6,
144 SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
145 SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
146 SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
147 SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
148 SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
149 SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
150 SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
151 SCORPIONL2_L2EM_STREX_PASS = 0xbe,
152 SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
153 SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
154 SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
155 SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
156 SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
157 SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
158 SCORPIONL2_CPU0_CLAMPED = 0xc5,
159 SCORPIONL2_CPU1_CLAMPED = 0xc6,
160 SCORPIONL2_CPU0_WAIT = 0xc7,
161 SCORPIONL2_CPU1_WAIT = 0xc8,
162 SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
163 SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
164 SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
165 SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
166 SCORPIONL2_AXI_READ = 0xcd,
167 SCORPIONL2_AXI_WRITE = 0xce,
168
169 SCORPIONL2_1BEAT_WRITE = 0xcf,
170 SCORPIONL2_2BEAT_WRITE = 0xd0,
171 SCORPIONL2_4BEAT_WRITE = 0xd1,
172 SCORPIONL2_8BEAT_WRITE = 0xd2,
173 SCORPIONL2_12BEAT_WRITE = 0xd3,
174 SCORPIONL2_16BEAT_WRITE = 0xd4,
175 SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
176 SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
177 SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
178 SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
179 SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
180 SCORPIONL2_CSYS_READ_2BEAT = 0xda,
181 SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
182 SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
183 SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
184 SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
185 SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
186 SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
187 SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
188 SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
189 SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
190 SCORPIONL2_LDREX_REQ = 0xe4,
191 SCORPIONL2_STREX_PASS = 0xe5,
192 SCORPIONL2_STREX_FAIL = 0xe6,
193 SCORPIONL2_CPREAD = 0xe7,
194 SCORPIONL2_CPWRITE = 0xe8,
195 SCORPIONL2_BARRIER_REQ = 0xe9,
196 SCORPIONL2_AXI_READ_SLVPORT = 0xea,
197 SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
198 SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
199 SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
200 SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
201 SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
202 SCORPIONL2_SNOOPED_IC = 0xf0,
203 SCORPIONL2_SNOOPED_BP = 0xf1,
204 SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
205 SCORPIONL2_SNOOPED_TLB = 0xf3,
206 SCORPION_L2_MAX_EVT,
207};
208
209static const struct scorpion_l2_scorp_evt sc_evt[] = {
210 {SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
211 {SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
212 {SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
213 {SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
214 {SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
215 {SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
216 {SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
217 {SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
218 {SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
219 {SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
220 {SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
221 {SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
222 {SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
223 {SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
224 {SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
225 {SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
226 {SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
227 {SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
228 {SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
229 {SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
230 {SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
231 {SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
232 {SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
233 {SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
234 {SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
235 {SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
236 {SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
237 {SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
238 {SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
239 {SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
240 {SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
241 {SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
242 {SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
243 {SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
244 {SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
245
246 {SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
247 {SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
248 {SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
249 {SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
250 {SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
251 {SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
252 {SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
253 {SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
254 {SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
255 {SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
256 {SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
257 {SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
258 {SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
259 {SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
260 {SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
261 {SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
262 {SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
263 {SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
264 {SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
265 {SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
266 {SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
267 {SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
268 {SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
269 {SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
270 {SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
271 {SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
272
273 {SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
274 {SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
275 {SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
276 {SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
277 {SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
278 {SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
279 {SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
280 {SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
281 {SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
282 {SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
283 {SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
284 {SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
285 {SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
286 {SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
287 {SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
288 {SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
289 {SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
290 {SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
291 {SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
292 {SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
293 {SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
294 {SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
295 {SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
296 {SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
297 {SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
298 {SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
299 {SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
300 {SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
301 {SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
302
303 {SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
304 {SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
305 {SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
306 {SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
307
308 {SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
309 {SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
310 {SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
311 {SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
312 {SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
313 {SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
314};
315
316static struct pmu_hw_events *scorpion_l2_get_hw_events(void)
317{
318 return &scorpion_l2_pmu_hw_events;
319}
320static u32 scorpion_l2_read_l2pm0(void)
321{
322 u32 val;
323 asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
324 return val;
325}
326
327static void scorpion_l2_write_l2pm0(u32 val)
328{
329 asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
330}
331
332static u32 scorpion_l2_read_l2pm1(void)
333{
334 u32 val;
335 asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
336 return val;
337}
338
339static void scorpion_l2_write_l2pm1(u32 val)
340{
341 asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
342}
343
344static u32 scorpion_l2_read_l2pm2(void)
345{
346 u32 val;
347 asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
348 return val;
349}
350
351static void scorpion_l2_write_l2pm2(u32 val)
352{
353 asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
354}
355
356static u32 scorpion_l2_read_l2pm3(void)
357{
358 u32 val;
359 asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
360 return val;
361}
362
363static void scorpion_l2_write_l2pm3(u32 val)
364{
365 asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
366}
367
368static u32 scorpion_l2_read_l2pm4(void)
369{
370 u32 val;
371 asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
372 return val;
373}
374
375static void scorpion_l2_write_l2pm4(u32 val)
376{
377 asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
378}
379
380struct scorpion_scorpion_access_funcs {
381 u32(*read) (void);
382 void (*write) (u32);
383 void (*pre) (void);
384 void (*post) (void);
385};
386
387struct scorpion_scorpion_access_funcs scorpion_l2_func[] = {
388 {scorpion_l2_read_l2pm0, scorpion_l2_write_l2pm0, NULL, NULL},
389 {scorpion_l2_read_l2pm1, scorpion_l2_write_l2pm1, NULL, NULL},
390 {scorpion_l2_read_l2pm2, scorpion_l2_write_l2pm2, NULL, NULL},
391 {scorpion_l2_read_l2pm3, scorpion_l2_write_l2pm3, NULL, NULL},
392 {scorpion_l2_read_l2pm4, scorpion_l2_write_l2pm4, NULL, NULL},
393};
394
395#define COLMN0MASK 0x000000ff
396#define COLMN1MASK 0x0000ff00
397#define COLMN2MASK 0x00ff0000
398
399static u32 scorpion_l2_get_columnmask(u32 setval)
400{
401 if (setval & COLMN0MASK)
402 return 0xffffff00;
403 else if (setval & COLMN1MASK)
404 return 0xffff00ff;
405 else if (setval & COLMN2MASK)
406 return 0xff00ffff;
407 else
408 return 0x80ffffff;
409}
410
411static void scorpion_l2_evt_setup(u32 gr, u32 setval)
412{
413 u32 val;
414 if (scorpion_l2_func[gr].pre)
415 scorpion_l2_func[gr].pre();
416 val = scorpion_l2_get_columnmask(setval) & scorpion_l2_func[gr].read();
417 val = val | setval;
418 scorpion_l2_func[gr].write(val);
419 if (scorpion_l2_func[gr].post)
420 scorpion_l2_func[gr].post();
421}
422
423#define SCORPION_L2_EVT_START_IDX 0x90
424#define SCORPION_L2_INV_EVTYPE 0
425
426static unsigned int get_scorpion_l2_evtinfo(unsigned int evt_type,
427 struct scorpion_l2_scorp_evt *evtinfo)
428{
429 u32 idx;
430 u8 prefix;
431 u8 reg;
432 u8 code;
433 u8 group;
434
435 prefix = (evt_type & 0xF0000) >> 16;
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400436 if (prefix == SCORPION_L2_EVT_PREFIX ||
437 prefix == L2_SLAVE_EVT_PREFIX) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400438 reg = (evt_type & 0x0F000) >> 12;
439 code = (evt_type & 0x00FF0) >> 4;
440 group = evt_type & 0x0000F;
441
442 if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
443 return SCORPION_L2_INV_EVTYPE;
444
445 evtinfo->val = 0x80000000 | (code << (group * 8));
446 evtinfo->grp = reg;
447 evtinfo->evt_type_act = group | (reg << 2);
448 return evtinfo->evt_type_act;
449 }
450
451 if (evt_type < SCORPION_L2_EVT_START_IDX
452 || evt_type >= SCORPION_L2_MAX_EVT)
453 return SCORPION_L2_INV_EVTYPE;
454
455 idx = evt_type - SCORPION_L2_EVT_START_IDX;
456
457 if (sc_evt[idx].evt_type == evt_type) {
458 evtinfo->val = sc_evt[idx].val;
459 evtinfo->grp = sc_evt[idx].grp;
460 evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
461 return sc_evt[idx].evt_type_act;
462 }
463 return SCORPION_L2_INV_EVTYPE;
464}
465
466static inline void scorpion_l2_pmnc_write(unsigned long val)
467{
468 val &= 0xff;
469 asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
470}
471
472static inline unsigned long scorpion_l2_pmnc_read(void)
473{
474 u32 val;
475 asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
476 return val;
477}
478
479static void scorpion_l2_set_evcntcr(void)
480{
481 u32 val = 0x0;
482 asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
483}
484
485static inline void scorpion_l2_set_evtyper(int ctr, int val)
486{
487 /* select ctr */
488 asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
489
490 /* write into EVTYPER */
491 asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
492}
493
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400494static void scorpion_l2_set_evfilter_task_mode(unsigned int is_slv)
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400495{
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400496 u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
497
498 if (is_slv)
499 filter_val = l2_slv_filter_prefix;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400500
501 asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
502}
503
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400504static void scorpion_l2_set_evfilter_sys_mode(unsigned int is_slv)
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400505{
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400506 u32 filter_val = l2_orig_filter_prefix | 0xf;
507
508 if (is_slv)
509 filter_val = l2_slv_filter_prefix;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400510
511 asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
512}
513
514static void scorpion_l2_enable_intenset(u32 idx)
515{
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400516 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400517 asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
518 (1 << SCORPION_L2CYCLE_CTR_BIT));
519 } else {
520 asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
521 }
522}
523
524static void scorpion_l2_disable_intenclr(u32 idx)
525{
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400526 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400527 asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
528 (1 << SCORPION_L2CYCLE_CTR_BIT));
529 } else {
530 asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
531 }
532}
533
534static void scorpion_l2_enable_counter(u32 idx)
535{
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400536 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400537 asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
538 (1 << SCORPION_L2CYCLE_CTR_BIT));
539 } else {
540 asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
541 }
542}
543
544static void scorpion_l2_disable_counter(u32 idx)
545{
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400546 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400547 asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
548 (1 << SCORPION_L2CYCLE_CTR_BIT));
549 } else {
550 asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
551 }
552}
553
554static u32 scorpion_l2_read_counter(int idx)
555{
556 u32 val;
557 unsigned long iflags;
558
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400559 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400560 asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
561 } else {
562 raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
563 iflags);
564 asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
565
566 /* read val from counter */
567 asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
568 raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
569 iflags);
570 }
571
572 return val;
573}
574
575static void scorpion_l2_write_counter(int idx, u32 val)
576{
577 unsigned long iflags;
578
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400579 if (idx == l2_cycle_ctr_idx) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400580 asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
581 } else {
582 raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
583 iflags);
584
585 /* select counter */
586 asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
587
588 /* write val into counter */
589 asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
590 raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
591 iflags);
592 }
593}
594
595static void scorpion_l2_stop_counter(struct hw_perf_event *hwc, int idx)
596{
597 scorpion_l2_disable_intenclr(idx);
598 scorpion_l2_disable_counter(idx);
599 pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
600 hwc->config_base, idx);
601}
602
603static void scorpion_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
604{
605 struct scorpion_l2_scorp_evt evtinfo;
606 int evtype = hwc->config_base;
607 int ev_typer;
608 unsigned long iflags;
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400609 unsigned int is_slv = 0;
610 unsigned int evt_prefix;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400611
612 raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
613
614 if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
615 goto out;
616
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400617 /* Check if user requested any special origin filtering. */
618 evt_prefix = (hwc->config_base &
619 L2_EVT_PREFIX_MASK) >> L2_EVT_PREFIX_SHIFT;
620
621 if (evt_prefix == L2_SLAVE_EVT_PREFIX)
622 is_slv = 1;
623
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400624 memset(&evtinfo, 0, sizeof(evtinfo));
625
626 ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
627
628 scorpion_l2_set_evtyper(idx, ev_typer);
629
630 scorpion_l2_set_evcntcr();
631
632 if (cpu < 0)
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400633 scorpion_l2_set_evfilter_task_mode(is_slv);
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400634 else
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400635 scorpion_l2_set_evfilter_sys_mode(is_slv);
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400636
637 scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
638
639out:
640
641 scorpion_l2_enable_intenset(idx);
642
643 scorpion_l2_enable_counter(idx);
644
645 raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
646
647 pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
648 __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
649}
650
651static void scorpion_l2_disable(struct hw_perf_event *hwc, int idx)
652{
653 unsigned long iflags;
654
655 raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
656
657 scorpion_l2_stop_counter(hwc, idx);
658
659 raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
660
661 pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
662}
663
664static int scorpion_l2_get_event_idx(struct pmu_hw_events *cpuc,
665 struct hw_perf_event *hwc)
666{
667 int ctr = 0;
668
669 if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) {
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400670 if (!test_and_set_bit(l2_cycle_ctr_idx,
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400671 cpuc->used_mask))
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400672 return l2_cycle_ctr_idx;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400673 }
674
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400675 for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) {
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400676 if (!test_and_set_bit(ctr, cpuc->used_mask))
677 return ctr;
678 }
679
680 return -EAGAIN;
681}
682
683static void scorpion_l2_start(void)
684{
685 isb();
686 /* Enable all counters */
687 scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() | SCORPIONL2_PMNC_E);
688}
689
690static void scorpion_l2_stop(void)
691{
692 /* Disable all counters */
693 scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
694 isb();
695}
696
697static inline u32 scorpion_l2_get_reset_pmovsr(void)
698{
699 u32 val;
700
701 /* Read */
702 asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
703
704 /* Write to clear flags */
705 val &= 0xffffffff;
706 asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
707
708 return val;
709}
710
711static irqreturn_t scorpion_l2_handle_irq(int irq_num, void *dev)
712{
713 unsigned long pmovsr;
714 struct perf_sample_data data;
715 struct pt_regs *regs;
716 struct perf_event *event;
717 struct hw_perf_event *hwc;
718 int bitp;
719 int idx = 0;
720
721 pmovsr = scorpion_l2_get_reset_pmovsr();
722
723 if (!(pmovsr & 0xffffffff))
724 return IRQ_NONE;
725
726 regs = get_irq_regs();
727
728 perf_sample_data_init(&data, 0);
729
730 while (pmovsr) {
731 bitp = __ffs(pmovsr);
732
733 if (bitp == SCORPION_L2CYCLE_CTR_BIT)
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400734 idx = l2_cycle_ctr_idx;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400735 else
736 idx = bitp;
737
738 event = scorpion_l2_pmu_hw_events.events[idx];
739
740 if (!event)
741 goto next;
742
743 if (!test_bit(idx, scorpion_l2_pmu_hw_events.used_mask))
744 goto next;
745
746 hwc = &event->hw;
747
748 armpmu_event_update(event, hwc, idx);
749
750 data.period = event->hw.last_period;
751
752 if (!armpmu_event_set_period(event, hwc, idx))
753 goto next;
754
755 if (perf_event_overflow(event, &data, regs))
756 scorpion_l2_disable_counter(hwc->idx);
757next:
758 pmovsr &= (pmovsr - 1);
759 }
760
761 irq_work_run();
762
763 return IRQ_HANDLED;
764}
765
766static int scorpion_l2_map_event(struct perf_event *event)
767{
768 if (pmu_type > 0 && pmu_type == event->attr.type)
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400769 return event->attr.config & L2_EVT_MASK;
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400770 else
771 return -ENOENT;
772}
773
774static int
775scorpion_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
776{
777 return request_irq(irq, *handle_irq,
778 IRQF_DISABLED | IRQF_NOBALANCING,
779 "scorpion-l2-armpmu", NULL);
780}
781
782static void
783scorpion_l2_pmu_generic_free_irq(int irq)
784{
785 if (irq >= 0)
786 free_irq(irq, NULL);
787}
788
Ashwin Chauguled2337c32012-06-19 14:37:36 -0400789static int msm_l2_test_set_ev_constraint(struct perf_event *event)
790{
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400791 u32 evt_type = event->attr.config & L2_EVT_MASK;
Ashwin Chauguled2337c32012-06-19 14:37:36 -0400792 u8 prefix = (evt_type & 0xF0000) >> 16;
793 u8 reg = (evt_type & 0x0F000) >> 12;
794 u8 group = evt_type & 0x0000F;
795 unsigned long flags;
796 u32 err = 0;
797 u64 bitmap_t;
798
799 if (!prefix)
800 return 0;
801
802 raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
803
804 bitmap_t = 1 << ((reg * 4) + group);
805
806 if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) {
807 l2_pmu_constraints.pmu_bitmap |= bitmap_t;
808 goto out;
809 }
810
811 /* Bit is already set. Constraint failed. */
812 err = -EPERM;
813
814out:
815 raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
816 return err;
817}
818
819static int msm_l2_clear_ev_constraint(struct perf_event *event)
820{
Ashwin Chaugulefcd66aa2012-06-27 13:09:38 -0400821 u32 evt_type = event->attr.config & L2_EVT_MASK;
Ashwin Chauguled2337c32012-06-19 14:37:36 -0400822 u8 prefix = (evt_type & 0xF0000) >> 16;
823 u8 reg = (evt_type & 0x0F000) >> 12;
824 u8 group = evt_type & 0x0000F;
825 unsigned long flags;
826 u64 bitmap_t;
827
828 if (!prefix)
829 return 0;
830
831 raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
832
833 bitmap_t = 1 << ((reg * 4) + group);
834
835 /* Clear constraint bit. */
836 l2_pmu_constraints.pmu_bitmap &= ~bitmap_t;
837
838 raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
839 return 1;
840}
841
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400842static int get_num_events(void)
843{
844 int val;
845
846 val = scorpion_l2_pmnc_read();
847 /*
848 * Read bits 15:11 of the L2PMCR and add 1
849 * for the cycle counter.
850 */
851 return ((val >> PMCR_NUM_EV_SHIFT) & PMCR_NUM_EV_MASK) + 1;
852}
853
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400854static struct arm_pmu scorpion_l2_pmu = {
855 .id = ARM_PERF_PMU_ID_SCORPIONMP_L2,
856 .type = ARM_PMU_DEVICE_L2CC,
857 .name = "Scorpion L2CC PMU",
858 .start = scorpion_l2_start,
859 .stop = scorpion_l2_stop,
860 .handle_irq = scorpion_l2_handle_irq,
861 .request_pmu_irq = scorpion_l2_pmu_generic_request_irq,
862 .free_pmu_irq = scorpion_l2_pmu_generic_free_irq,
863 .enable = scorpion_l2_enable,
864 .disable = scorpion_l2_disable,
865 .read_counter = scorpion_l2_read_counter,
866 .get_event_idx = scorpion_l2_get_event_idx,
867 .write_counter = scorpion_l2_write_counter,
868 .map_event = scorpion_l2_map_event,
869 .max_period = (1LLU << 32) - 1,
870 .get_hw_events = scorpion_l2_get_hw_events,
Ashwin Chauguled2337c32012-06-19 14:37:36 -0400871 .test_set_event_constraints = msm_l2_test_set_ev_constraint,
872 .clear_event_constraints = msm_l2_clear_ev_constraint,
Ashwin Chaugule795bf7b2012-06-20 16:23:08 -0400873 .pmu.attr_groups = msm_l2_pmu_attr_grps,
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400874};
875
876static int __devinit scorpion_l2_pmu_device_probe(struct platform_device *pdev)
877{
878 scorpion_l2_pmu.plat_device = pdev;
879
Ashwin Chaugulef4a533d2012-07-19 18:27:03 -0400880 if (!armpmu_register(&scorpion_l2_pmu, "msm-l2", -1))
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400881 pmu_type = scorpion_l2_pmu.pmu.type;
882
883 return 0;
884}
885
886static struct platform_driver scorpion_l2_pmu_driver = {
887 .driver = {
888 .name = "l2-arm-pmu",
889 },
890 .probe = scorpion_l2_pmu_device_probe,
891};
892
893static int __init register_scorpion_l2_pmu_driver(void)
894{
895 /* Avoid spurious interrupt if any */
896 scorpion_l2_get_reset_pmovsr();
897
Ashwin Chaugule4362c742012-06-28 15:24:18 -0400898 total_l2_ctrs = get_num_events();
899 scorpion_l2_pmu.num_events = total_l2_ctrs;
900
901 pr_info("Detected %d counters on the L2CC PMU.\n",
902 total_l2_ctrs);
903
904 /*
905 * The L2 cycle counter index in the used_mask
906 * bit stream is always after the other counters.
907 * Counter indexes begin from 0 to keep it consistent
908 * with the h/w.
909 */
910 l2_cycle_ctr_idx = total_l2_ctrs - 1;
911
Ashwin Chaugule7530b452012-06-11 17:41:59 -0400912 return platform_driver_register(&scorpion_l2_pmu_driver);
913}
914device_initcall(register_scorpion_l2_pmu_driver);