~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/avr32/oprofile/op_model_avr32.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 19 #include <asm/sysreg.h>
 20 
 21 #define AVR32_PERFCTR_IRQ_GROUP 0
 22 #define AVR32_PERFCTR_IRQ_LINE  1
 23 
 24 void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
 25 
 26 enum { PCCNT, PCNT0, PCNT1, NR_counter };
 27 
 28 struct 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 
 40 static 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 
 53 static 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 
 63 static 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 
100 static int avr32_perf_counter_create_files(struct super_block *sb,
101                 struct dentry *root)
102 {
103         struct dentry *dir;
104         unsigned int i;
105         char filename[4];
106 
107         for (i = 0; i < NR_counter; i++) {
108                 snprintf(filename, sizeof(filename), "%u", i);
109                 dir = oprofilefs_mkdir(sb, root, filename);
110 
111                 oprofilefs_create_ulong(sb, dir, "enabled",
112                                 &counter[i].enabled);
113                 oprofilefs_create_ulong(sb, dir, "event",
114                                 &counter[i].event);
115                 oprofilefs_create_ulong(sb, dir, "count",
116                                 &counter[i].count);
117 
118                 /* Dummy entries */
119                 oprofilefs_create_ulong(sb, dir, "kernel",
120                                 &counter[i].kernel);
121                 oprofilefs_create_ulong(sb, dir, "user",
122                                 &counter[i].user);
123                 oprofilefs_create_ulong(sb, dir, "unit_mask",
124                                 &counter[i].unit_mask);
125         }
126 
127         return 0;
128 }
129 
130 static int avr32_perf_counter_setup(void)
131 {
132         struct avr32_perf_counter *ctr;
133         u32 pccr;
134         int ret;
135         int i;
136 
137         pr_debug("avr32_perf_counter_setup\n");
138 
139         if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
140                 printk(KERN_ERR
141                         "oprofile: setup: perf counter already enabled\n");
142                 return -EBUSY;
143         }
144 
145         ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
146                         avr32_perf_counter_interrupt, IRQF_SHARED,
147                         "oprofile", counter);
148         if (ret)
149                 return ret;
150 
151         avr32_perf_counter_reset();
152 
153         pccr = 0;
154         for (i = PCCNT; i < NR_counter; i++) {
155                 ctr = &counter[i];
156                 if (!ctr->enabled)
157                         continue;
158 
159                 pr_debug("enabling counter %d...\n", i);
160 
161                 pccr |= ctr->ie_mask;
162 
163                 switch (i) {
164                 case PCCNT:
165                         /* PCCNT always counts cycles, so no events */
166                         sysreg_write(PCCNT, -ctr->count);
167                         break;
168                 case PCNT0:
169                         pccr |= SYSREG_BF(CONF0, ctr->event);
170                         sysreg_write(PCNT0, -ctr->count);
171                         break;
172                 case PCNT1:
173                         pccr |= SYSREG_BF(CONF1, ctr->event);
174                         sysreg_write(PCNT1, -ctr->count);
175                         break;
176                 }
177         }
178 
179         pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
180 
181         sysreg_write(PCCR, pccr);
182 
183         return 0;
184 }
185 
186 static void avr32_perf_counter_shutdown(void)
187 {
188         pr_debug("avr32_perf_counter_shutdown\n");
189 
190         avr32_perf_counter_reset();
191         free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
192 }
193 
194 static int avr32_perf_counter_start(void)
195 {
196         pr_debug("avr32_perf_counter_start\n");
197 
198         sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
199 
200         return 0;
201 }
202 
203 static void avr32_perf_counter_stop(void)
204 {
205         pr_debug("avr32_perf_counter_stop\n");
206 
207         sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
208 }
209 
210 static struct oprofile_operations avr32_perf_counter_ops __initdata = {
211         .create_files   = avr32_perf_counter_create_files,
212         .setup          = avr32_perf_counter_setup,
213         .shutdown       = avr32_perf_counter_shutdown,
214         .start          = avr32_perf_counter_start,
215         .stop           = avr32_perf_counter_stop,
216         .cpu_type       = "avr32",
217 };
218 
219 int __init oprofile_arch_init(struct oprofile_operations *ops)
220 {
221         if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
222                 return -ENODEV;
223 
224         memcpy(ops, &avr32_perf_counter_ops,
225                         sizeof(struct oprofile_operations));
226 
227         ops->backtrace = avr32_backtrace;
228 
229         printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
230 
231         return 0;
232 }
233 
234 void oprofile_arch_exit(void)
235 {
236 
237 }
238 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp