oprofilefs_mkdir() doesn't need superblock argument
[deliverable/linux.git] / arch / avr32 / oprofile / op_model_avr32.c
CommitLineData
2853ce5e
HS
1/*
2 * AVR32 Performance Counter Driver
3 *
4 * Copyright (C) 2005-2007 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Author: Ronny Pedersen
11 */
12#include <linux/errno.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/oprofile.h>
16#include <linux/sched.h>
17#include <linux/types.h>
18
2853ce5e 19#include <asm/sysreg.h>
2853ce5e
HS
20
21#define AVR32_PERFCTR_IRQ_GROUP 0
22#define AVR32_PERFCTR_IRQ_LINE 1
23
3d256151
NV
24void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
25
2853ce5e
HS
26enum { PCCNT, PCNT0, PCNT1, NR_counter };
27
28struct avr32_perf_counter {
29 unsigned long enabled;
30 unsigned long event;
31 unsigned long count;
32 unsigned long unit_mask;
33 unsigned long kernel;
34 unsigned long user;
35
36 u32 ie_mask;
37 u32 flag_mask;
38};
39
40static struct avr32_perf_counter counter[NR_counter] = {
41 {
42 .ie_mask = SYSREG_BIT(IEC),
43 .flag_mask = SYSREG_BIT(FC),
44 }, {
45 .ie_mask = SYSREG_BIT(IE0),
46 .flag_mask = SYSREG_BIT(F0),
47 }, {
48 .ie_mask = SYSREG_BIT(IE1),
49 .flag_mask = SYSREG_BIT(F1),
50 },
51};
52
53static void avr32_perf_counter_reset(void)
54{
55 /* Reset all counter and disable/clear all interrupts */
56 sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
57 | SYSREG_BIT(PCCR_C)
58 | SYSREG_BIT(FC)
59 | SYSREG_BIT(F0)
60 | SYSREG_BIT(F1)));
61}
62
63static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
64{
65 struct avr32_perf_counter *ctr = dev_id;
66 struct pt_regs *regs;
67 u32 pccr;
68
69 if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
70 & (1 << AVR32_PERFCTR_IRQ_LINE))))
71 return IRQ_NONE;
72
73 regs = get_irq_regs();
74 pccr = sysreg_read(PCCR);
75
76 /* Clear the interrupt flags we're about to handle */
77 sysreg_write(PCCR, pccr);
78
79 /* PCCNT */
80 if (ctr->enabled && (pccr & ctr->flag_mask)) {
81 sysreg_write(PCCNT, -ctr->count);
82 oprofile_add_sample(regs, PCCNT);
83 }
84 ctr++;
85 /* PCNT0 */
86 if (ctr->enabled && (pccr & ctr->flag_mask)) {
87 sysreg_write(PCNT0, -ctr->count);
88 oprofile_add_sample(regs, PCNT0);
89 }
90 ctr++;
91 /* PCNT1 */
92 if (ctr->enabled && (pccr & ctr->flag_mask)) {
93 sysreg_write(PCNT1, -ctr->count);
94 oprofile_add_sample(regs, PCNT1);
95 }
96
97 return IRQ_HANDLED;
98}
99
ef7bca14 100static int avr32_perf_counter_create_files(struct dentry *root)
2853ce5e
HS
101{
102 struct dentry *dir;
103 unsigned int i;
104 char filename[4];
105
106 for (i = 0; i < NR_counter; i++) {
107 snprintf(filename, sizeof(filename), "%u", i);
ecde2823 108 dir = oprofilefs_mkdir(root, filename);
2853ce5e 109
ef7bca14 110 oprofilefs_create_ulong(root->d_sb, dir, "enabled",
2853ce5e 111 &counter[i].enabled);
ef7bca14 112 oprofilefs_create_ulong(root->d_sb, dir, "event",
2853ce5e 113 &counter[i].event);
ef7bca14 114 oprofilefs_create_ulong(root->d_sb, dir, "count",
2853ce5e
HS
115 &counter[i].count);
116
117 /* Dummy entries */
ef7bca14 118 oprofilefs_create_ulong(root->d_sb, dir, "kernel",
2853ce5e 119 &counter[i].kernel);
ef7bca14 120 oprofilefs_create_ulong(root->d_sb, dir, "user",
2853ce5e 121 &counter[i].user);
ef7bca14 122 oprofilefs_create_ulong(root->d_sb, dir, "unit_mask",
2853ce5e
HS
123 &counter[i].unit_mask);
124 }
125
126 return 0;
127}
128
129static int avr32_perf_counter_setup(void)
130{
131 struct avr32_perf_counter *ctr;
132 u32 pccr;
133 int ret;
134 int i;
135
136 pr_debug("avr32_perf_counter_setup\n");
137
138 if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
139 printk(KERN_ERR
140 "oprofile: setup: perf counter already enabled\n");
141 return -EBUSY;
142 }
143
144 ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
145 avr32_perf_counter_interrupt, IRQF_SHARED,
146 "oprofile", counter);
147 if (ret)
148 return ret;
149
150 avr32_perf_counter_reset();
151
152 pccr = 0;
153 for (i = PCCNT; i < NR_counter; i++) {
154 ctr = &counter[i];
155 if (!ctr->enabled)
156 continue;
157
158 pr_debug("enabling counter %d...\n", i);
159
160 pccr |= ctr->ie_mask;
161
162 switch (i) {
163 case PCCNT:
164 /* PCCNT always counts cycles, so no events */
165 sysreg_write(PCCNT, -ctr->count);
166 break;
167 case PCNT0:
168 pccr |= SYSREG_BF(CONF0, ctr->event);
169 sysreg_write(PCNT0, -ctr->count);
170 break;
171 case PCNT1:
172 pccr |= SYSREG_BF(CONF1, ctr->event);
173 sysreg_write(PCNT1, -ctr->count);
174 break;
175 }
176 }
177
178 pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
179
180 sysreg_write(PCCR, pccr);
181
182 return 0;
183}
184
185static void avr32_perf_counter_shutdown(void)
186{
187 pr_debug("avr32_perf_counter_shutdown\n");
188
189 avr32_perf_counter_reset();
190 free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
191}
192
193static int avr32_perf_counter_start(void)
194{
195 pr_debug("avr32_perf_counter_start\n");
196
197 sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
198
199 return 0;
200}
201
202static void avr32_perf_counter_stop(void)
203{
204 pr_debug("avr32_perf_counter_stop\n");
205
206 sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
207}
208
209static struct oprofile_operations avr32_perf_counter_ops __initdata = {
210 .create_files = avr32_perf_counter_create_files,
211 .setup = avr32_perf_counter_setup,
212 .shutdown = avr32_perf_counter_shutdown,
213 .start = avr32_perf_counter_start,
214 .stop = avr32_perf_counter_stop,
215 .cpu_type = "avr32",
216};
217
218int __init oprofile_arch_init(struct oprofile_operations *ops)
219{
220 if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
221 return -ENODEV;
222
223 memcpy(ops, &avr32_perf_counter_ops,
224 sizeof(struct oprofile_operations));
225
3d256151
NV
226 ops->backtrace = avr32_backtrace;
227
2853ce5e
HS
228 printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
229
230 return 0;
231}
232
233void oprofile_arch_exit(void)
234{
235
236}
This page took 0.371652 seconds and 5 git commands to generate.