2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
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 as
6 * published by the Free Software Foundation.
10 #include <linux/module.h>
14 #define NUM_REGIONS 256
15 #define REGION_SIZE (64*1024)
16 #define REGION_DEBUG 1
21 #define PMEVCNTSR0 0x0150
22 #define PMCCNTRSR 0x0190
25 #define PMSR_REQ 0x01B8
26 #define PMSR_CLR 0x01C0
29 #define DT_CONFIG 0x0300
30 #define DT_CONTROL 0x0370
33 #define PMU_EVENT_SEL 0x0600
37 #define CNTMAX (CCNT + 1)
39 #define get_pmu_event_id(event) (((event) >> 0) & 0xFF)
40 #define get_node_type(event) (((event) >> 8) & 0xFF)
41 #define get_region(event) (((event) >> 16) & 0xFF)
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
45 // From kernel/params.c
46 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
47 int param_set_##name(const char *val, struct kernel_param *kp) \
52 if (!val) return -EINVAL; \
53 ret = strtolfn(val, 0, &l); \
54 if (ret == -EINVAL || ((type)l != l)) \
56 *((type *)kp->arg) = l; \
59 int param_get_##name(char *buffer, struct kernel_param *kp) \
61 return sprintf(buffer, format, *((type *)kp->arg)); \
66 // From kernel/params.c
67 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
68 int param_set_##name(const char *val, const struct kernel_param *kp) \
73 ret = strtolfn(val, 0, &l); \
74 if (ret < 0 || ((type)l != l)) \
75 return ret < 0 ? ret : -EINVAL; \
76 *((type *)kp->arg) = l; \
79 int param_get_##name(char *buffer, const struct kernel_param *kp) \
81 return scnprintf(buffer, PAGE_SIZE, format, \
82 *((type *)kp->arg)); \
84 struct kernel_param_ops param_ops_##name = { \
85 .set = param_set_##name, \
86 .get = param_get_##name, \
88 EXPORT_SYMBOL(param_set_##name); \
89 EXPORT_SYMBOL(param_get_##name); \
90 EXPORT_SYMBOL(param_ops_##name)
94 STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull);
96 // From include/linux/moduleparam.h
97 #define param_check_u64(name, p) __param_check(name, p, u64)
99 MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address");
100 static u64 ccn504_addr = 0;
101 module_param(ccn504_addr, u64, 0444);
103 static void __iomem *gator_events_ccn504_base;
104 static bool gator_events_ccn504_global_enabled;
105 static unsigned long gator_events_ccn504_enabled[CNTMAX];
106 static unsigned long gator_events_ccn504_event[CNTMAX];
107 static unsigned long gator_events_ccn504_key[CNTMAX];
108 static int gator_events_ccn504_buffer[2*CNTMAX];
109 static int gator_events_ccn504_prev[CNTMAX];
111 static void gator_events_ccn504_create_shutdown(void)
113 if (gator_events_ccn504_base != NULL) {
114 iounmap(gator_events_ccn504_base);
118 static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
124 for (i = 0; i < CNTMAX; ++i) {
126 snprintf(buf, sizeof(buf), "CCN-504_ccnt");
128 snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
130 dir = gatorfs_mkdir(sb, root, buf);
135 gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
137 gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
139 gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
145 static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
149 dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
150 dt_config |= (value + event_num) << (4*event_num);
151 writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
154 static int gator_events_ccn504_start(void)
158 gator_events_ccn504_global_enabled = 0;
159 for (i = 0; i < CNTMAX; ++i) {
160 if (gator_events_ccn504_enabled[i]) {
161 gator_events_ccn504_global_enabled = 1;
166 if (!gator_events_ccn504_global_enabled) {
170 memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev));
172 // Disable INTREQ on overflow
173 // [6] ovfl_intr_en = 0
176 // No register paring
178 // Enable PMU features
180 writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR);
183 for (i = 0; i < NUM_XPS; ++i) {
186 // Pass on all events
187 writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
189 // Enable PMU capability
191 dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
193 writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
196 // Assume no other pmu_event_sel registers are set
198 // cycle counter does not need to be enabled
199 for (i = 0; i < CCNT; ++i) {
208 if (!gator_events_ccn504_enabled[i]) {
212 pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]);
213 node_type = get_node_type(gator_events_ccn504_event[i]);
214 region = get_region(gator_events_ccn504_event[i]);
216 // Verify the node_type
217 oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID);
218 oly_id = oly_id_whole & 0x1F;
219 node_id = (oly_id_whole >> 8) & 0x7F;
220 if ((oly_id != node_type) ||
221 ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) {
222 printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type);
226 // Set the control register
227 pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
230 pmu_event_sel |= pmu_event_id << (7*i);
231 gator_events_ccn504_set_dt_config(node_id, i, 0x4);
236 pmu_event_sel |= pmu_event_id << (4*i);
237 gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
240 writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
246 static void gator_events_ccn504_stop(void)
250 if (!gator_events_ccn504_global_enabled) {
254 // cycle counter does not need to be disabled
255 for (i = 0; i < CCNT; ++i) {
258 if (!gator_events_ccn504_enabled[i]) {
262 region = get_region(gator_events_ccn504_event[i]);
264 writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
268 for (i = 0; i < NUM_XPS; ++i) {
269 writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
273 static int gator_events_ccn504_read(int **buffer)
279 if (!on_primary_core() || !gator_events_ccn504_global_enabled) {
283 // Verify the pmsr register is zero
284 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0);
286 // Request a PMU snapshot
287 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
289 // Wait for the snapshot
290 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0);
292 // Read the shadow registers
293 for (i = 0; i < CNTMAX; ++i) {
294 if (!gator_events_ccn504_enabled[i]) {
298 value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
299 if (gator_events_ccn504_prev[i] != 0x80808080) {
300 gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
301 gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i];
303 gator_events_ccn504_prev[i] = value;
305 // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
308 // Clear the PMU snapshot status
309 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
312 *buffer = gator_events_ccn504_buffer;
317 static struct gator_interface gator_events_ccn504_interface = {
318 .shutdown = gator_events_ccn504_create_shutdown,
319 .create_files = gator_events_ccn504_create_files,
320 .start = gator_events_ccn504_start,
321 .stop = gator_events_ccn504_stop,
322 .read = gator_events_ccn504_read,
325 int gator_events_ccn504_init(void)
329 if (ccn504_addr == 0) {
333 gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
334 if (gator_events_ccn504_base == NULL) {
335 printk(KERN_ERR "gator: ioremap returned NULL\n");
339 for (i = 0; i < CNTMAX; ++i) {
340 gator_events_ccn504_enabled[i] = 0;
341 gator_events_ccn504_event[i] = 0;
342 gator_events_ccn504_key[i] = gator_events_get_key();
345 return gator_events_install(&gator_events_ccn504_interface);