Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 76075
b: refs/heads/master
c: 2853ce5
h: refs/heads/master
i:
  76073: 1189488
  76071: a0e6aa2
v: v3
  • Loading branch information
Haavard Skinnemoen committed Jan 25, 2008
1 parent d82a59f commit d9c497a
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a7f5bf9b95ace39cd8b61e8c9ca1035966779ed1
refs/heads/master: 2853ce5ecefe9d9ca119f33db0c23a3f075e35d9
3 changes: 3 additions & 0 deletions trunk/arch/avr32/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
def_bool n

config ARCH_SUPPORTS_OPROFILE
def_bool y

config GENERIC_HWEIGHT
def_bool y

Expand Down
1 change: 1 addition & 0 deletions trunk/arch/avr32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ core-$(CONFIG_BOARD_ATNGW100) += arch/avr32/boards/atngw100/
core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/
core-y += arch/avr32/kernel/
core-y += arch/avr32/mm/
drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/
libs-y += arch/avr32/lib/

archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap
Expand Down
8 changes: 8 additions & 0 deletions trunk/arch/avr32/oprofile/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
obj-$(CONFIG_OPROFILE) += oprofile.o

oprofile-y := $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o)
oprofile-y += op_model_avr32.o
235 changes: 235 additions & 0 deletions trunk/arch/avr32/oprofile/op_model_avr32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
/*
* AVR32 Performance Counter Driver
*
* Copyright (C) 2005-2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Author: Ronny Pedersen
*/
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/types.h>

#include <asm/intc.h>
#include <asm/sysreg.h>
#include <asm/system.h>

#define AVR32_PERFCTR_IRQ_GROUP 0
#define AVR32_PERFCTR_IRQ_LINE 1

enum { PCCNT, PCNT0, PCNT1, NR_counter };

struct avr32_perf_counter {
unsigned long enabled;
unsigned long event;
unsigned long count;
unsigned long unit_mask;
unsigned long kernel;
unsigned long user;

u32 ie_mask;
u32 flag_mask;
};

static struct avr32_perf_counter counter[NR_counter] = {
{
.ie_mask = SYSREG_BIT(IEC),
.flag_mask = SYSREG_BIT(FC),
}, {
.ie_mask = SYSREG_BIT(IE0),
.flag_mask = SYSREG_BIT(F0),
}, {
.ie_mask = SYSREG_BIT(IE1),
.flag_mask = SYSREG_BIT(F1),
},
};

static void avr32_perf_counter_reset(void)
{
/* Reset all counter and disable/clear all interrupts */
sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
| SYSREG_BIT(PCCR_C)
| SYSREG_BIT(FC)
| SYSREG_BIT(F0)
| SYSREG_BIT(F1)));
}

static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
{
struct avr32_perf_counter *ctr = dev_id;
struct pt_regs *regs;
u32 pccr;

if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
& (1 << AVR32_PERFCTR_IRQ_LINE))))
return IRQ_NONE;

regs = get_irq_regs();
pccr = sysreg_read(PCCR);

/* Clear the interrupt flags we're about to handle */
sysreg_write(PCCR, pccr);

/* PCCNT */
if (ctr->enabled && (pccr & ctr->flag_mask)) {
sysreg_write(PCCNT, -ctr->count);
oprofile_add_sample(regs, PCCNT);
}
ctr++;
/* PCNT0 */
if (ctr->enabled && (pccr & ctr->flag_mask)) {
sysreg_write(PCNT0, -ctr->count);
oprofile_add_sample(regs, PCNT0);
}
ctr++;
/* PCNT1 */
if (ctr->enabled && (pccr & ctr->flag_mask)) {
sysreg_write(PCNT1, -ctr->count);
oprofile_add_sample(regs, PCNT1);
}

return IRQ_HANDLED;
}

static int avr32_perf_counter_create_files(struct super_block *sb,
struct dentry *root)
{
struct dentry *dir;
unsigned int i;
char filename[4];

for (i = 0; i < NR_counter; i++) {
snprintf(filename, sizeof(filename), "%u", i);
dir = oprofilefs_mkdir(sb, root, filename);

oprofilefs_create_ulong(sb, dir, "enabled",
&counter[i].enabled);
oprofilefs_create_ulong(sb, dir, "event",
&counter[i].event);
oprofilefs_create_ulong(sb, dir, "count",
&counter[i].count);

/* Dummy entries */
oprofilefs_create_ulong(sb, dir, "kernel",
&counter[i].kernel);
oprofilefs_create_ulong(sb, dir, "user",
&counter[i].user);
oprofilefs_create_ulong(sb, dir, "unit_mask",
&counter[i].unit_mask);
}

return 0;
}

static int avr32_perf_counter_setup(void)
{
struct avr32_perf_counter *ctr;
u32 pccr;
int ret;
int i;

pr_debug("avr32_perf_counter_setup\n");

if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
printk(KERN_ERR
"oprofile: setup: perf counter already enabled\n");
return -EBUSY;
}

ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
avr32_perf_counter_interrupt, IRQF_SHARED,
"oprofile", counter);
if (ret)
return ret;

avr32_perf_counter_reset();

pccr = 0;
for (i = PCCNT; i < NR_counter; i++) {
ctr = &counter[i];
if (!ctr->enabled)
continue;

pr_debug("enabling counter %d...\n", i);

pccr |= ctr->ie_mask;

switch (i) {
case PCCNT:
/* PCCNT always counts cycles, so no events */
sysreg_write(PCCNT, -ctr->count);
break;
case PCNT0:
pccr |= SYSREG_BF(CONF0, ctr->event);
sysreg_write(PCNT0, -ctr->count);
break;
case PCNT1:
pccr |= SYSREG_BF(CONF1, ctr->event);
sysreg_write(PCNT1, -ctr->count);
break;
}
}

pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);

sysreg_write(PCCR, pccr);

return 0;
}

static void avr32_perf_counter_shutdown(void)
{
pr_debug("avr32_perf_counter_shutdown\n");

avr32_perf_counter_reset();
free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
}

static int avr32_perf_counter_start(void)
{
pr_debug("avr32_perf_counter_start\n");

sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));

return 0;
}

static void avr32_perf_counter_stop(void)
{
pr_debug("avr32_perf_counter_stop\n");

sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
}

static struct oprofile_operations avr32_perf_counter_ops __initdata = {
.create_files = avr32_perf_counter_create_files,
.setup = avr32_perf_counter_setup,
.shutdown = avr32_perf_counter_shutdown,
.start = avr32_perf_counter_start,
.stop = avr32_perf_counter_stop,
.cpu_type = "avr32",
};

int __init oprofile_arch_init(struct oprofile_operations *ops)
{
if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
return -ENODEV;

memcpy(ops, &avr32_perf_counter_ops,
sizeof(struct oprofile_operations));

printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");

return 0;
}

void oprofile_arch_exit(void)
{

}

0 comments on commit d9c497a

Please sign in to comment.