summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-2.6.18/avr32-oprofile.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-2.6.18/avr32-oprofile.patch')
-rw-r--r--recipes/linux/linux-2.6.18/avr32-oprofile.patch610
1 files changed, 610 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.18/avr32-oprofile.patch b/recipes/linux/linux-2.6.18/avr32-oprofile.patch
new file mode 100644
index 0000000000..5fbc9855aa
--- /dev/null
+++ b/recipes/linux/linux-2.6.18/avr32-oprofile.patch
@@ -0,0 +1,610 @@
+From nobody Mon Sep 17 00:00:00 2001
+From: Haavard Skinnemoen <hskinnemoen@atmel.com>
+Date: Wed Jan 4 17:26:23 2006 +0100
+Subject: [PATCH] AVR32 oprofile implementation
+
+This adds support for oprofile on the AVR32 architecture.
+---
+
+ arch/avr32/Kconfig | 2
+ arch/avr32/Makefile | 1
+ arch/avr32/oprofile/Kconfig | 23 +++
+ arch/avr32/oprofile/Makefile | 10 +
+ arch/avr32/oprofile/common.c | 169 +++++++++++++++++++++++++++
+ arch/avr32/oprofile/init.c | 29 ++++
+ arch/avr32/oprofile/op_avr32_model.h | 25 +++
+ arch/avr32/oprofile/op_counter.h | 29 ++++
+ arch/avr32/oprofile/op_model_avr32.c | 219 +++++++++++++++++++++++++++++++++++
+ arch/avr32/oprofile/op_model_avr32.h | 21 +++
+ 10 files changed, 528 insertions(+)
+
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/Kconfig 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,23 @@
++
++menu "Profiling support"
++ depends on EXPERIMENTAL
++
++config PROFILING
++ bool "Profiling support (EXPERIMENTAL)"
++ help
++ Say Y here to enable the extended profiling support mechanisms used
++ by profilers such as OProfile.
++
++
++config OPROFILE
++ tristate "OProfile system profiling (EXPERIMENTAL)"
++ depends on PROFILING
++ help
++ OProfile is a profiling system capable of profiling the
++ whole system, including the kernel, kernel modules, libraries,
++ and applications.
++
++ If unsure, say N.
++
++endmenu
++
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/Makefile 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,10 @@
++obj-$(CONFIG_OPROFILE) += oprofile.o
++
++DRIVER_OBJS = $(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 := $(DRIVER_OBJS) init.o common.o
++oprofile-y += op_model_avr32.o
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/common.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/common.c 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2005-2006 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
++ */
++
++#define DEBUG
++#include <linux/init.h>
++#include <linux/oprofile.h>
++#include <linux/errno.h>
++#include <asm/semaphore.h>
++#include <linux/sysdev.h>
++
++#include "op_avr32_model.h"
++#include "op_counter.h"
++
++static struct op_avr32_model_spec *pc_model;
++static int pc_enabled = 0;
++static struct semaphore pc_sem;
++
++
++static int pc_start(void);
++static int pc_setup(void);
++static void pc_stop(void);
++static int pc_create_files(struct super_block *, struct dentry *);
++
++
++struct op_counter_config counter_config[OP_MAX_COUNTER];
++
++static int pc_suspend(struct sys_device *dev, u32 state)
++{
++ if (pc_enabled)
++ pc_stop();
++ return 0;
++}
++
++static int pc_resume(struct sys_device *dev)
++{
++ if (pc_enabled)
++ pc_start();
++ return 0;
++}
++
++static struct sysdev_class oprofile_sysclass = {
++ set_kset_name("oprofile"),
++ .resume = pc_resume,
++ .suspend = pc_suspend,
++};
++
++static struct sys_device device_oprofile = {
++ .id = 0,
++ .cls = &oprofile_sysclass,
++};
++
++static int __init init_driverfs(void)
++{
++ int ret;
++
++ if (!(ret = sysdev_class_register(&oprofile_sysclass)))
++ ret = sysdev_register(&device_oprofile);
++
++ return ret;
++}
++
++static void exit_driverfs(void)
++{
++ sysdev_unregister(&device_oprofile);
++ sysdev_class_unregister(&oprofile_sysclass);
++}
++
++static int pc_create_files(struct super_block *sb, struct dentry *root)
++{
++ unsigned int i;
++
++ pr_debug("AVR32 Peformance Counters: create files\n");
++ for (i = 0; i < pc_model->num_counters; i++) {
++ struct dentry *dir;
++ char buf[2];
++
++ snprintf(buf, sizeof buf, "%d", i);
++ dir = oprofilefs_mkdir(sb, root, buf);
++ oprofilefs_create_ulong(sb, dir, "enabled",
++ &counter_config[i].enabled);
++ oprofilefs_create_ulong(sb, dir, "event",
++ &counter_config[i].event);
++ oprofilefs_create_ulong(sb, dir, "count",
++ &counter_config[i].count);
++ oprofilefs_create_ulong(sb, dir, "unit_mask",
++ &counter_config[i].unit_mask);
++ oprofilefs_create_ulong(sb, dir, "kernel",
++ &counter_config[i].kernel);
++ oprofilefs_create_ulong(sb, dir, "user",
++ &counter_config[i].user);
++ }
++
++ return 0;
++}
++
++static int pc_setup(void)
++{
++ int ret;
++
++ spin_lock(&oprofilefs_lock);
++ pr_debug("AVR32 Peformance Counters: setup\n");
++ ret = pc_model->setup_ctrs();
++ spin_unlock(&oprofilefs_lock);
++ return ret;
++}
++
++static int pc_start(void)
++{
++ int ret = -EBUSY;
++
++ down(&pc_sem);
++ if (!pc_enabled) {
++ pr_debug("AVR32 Peformance Counters: start\n");
++ ret = pc_model->start();
++ pc_enabled = !ret;
++ }
++ up(&pc_sem);
++ return ret;
++}
++
++static void pc_stop(void)
++{
++ down(&pc_sem);
++ pr_debug("AVR32 Peformance Counters: stop\n");
++ if (pc_enabled)
++ pc_model->stop();
++ pc_enabled = 0;
++ up(&pc_sem);
++}
++
++int __init pc_init(struct oprofile_operations *ops,
++ struct op_avr32_model_spec *spec)
++{
++ init_MUTEX(&pc_sem);
++
++ if ( spec->init )
++ if (spec->init() < 0)
++ return -ENODEV;
++
++ pc_model = spec;
++ init_driverfs();
++ ops->create_files = pc_create_files;
++ ops->setup = pc_setup;
++ ops->shutdown = pc_stop;
++ ops->start = pc_start;
++ ops->stop = pc_stop;
++ ops->cpu_type = pc_model->name;
++ printk(KERN_INFO "oprofile: using %s Performance Counters\n",
++ spec->name);
++ pr_debug("AVR32 Peformance Counters: pc_init\n");
++
++ return 0;
++}
++
++void pc_exit(void)
++{
++ if (pc_model) {
++ pr_debug("AVR32 Peformance Counters: exit\n");
++ exit_driverfs();
++ pc_model = NULL;
++ }
++}
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/init.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/init.c 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2005-2006 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/oprofile.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include "op_avr32_model.h"
++#include "op_model_avr32.h"
++
++int __init oprofile_arch_init(struct oprofile_operations *ops)
++{
++ int ret = -ENODEV;
++
++ ret = pc_init(ops, &op_avr32_spec);
++
++ return ret;
++}
++
++void oprofile_arch_exit(void)
++{
++ pc_exit();
++}
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/op_avr32_model.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/op_avr32_model.h 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * interface to AVR32 machine specific operations
++ *
++ * Copyright (C) 2005-2006 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
++ */
++
++#ifndef OP_AVR32_MODEL_H
++#define OP_AVR32_MODEL_H
++
++struct op_avr32_model_spec {
++ int (*init)(void);
++ unsigned int num_counters;
++ int (*setup_ctrs)(void);
++ int (*start)(void);
++ void (*stop)(void);
++ char *name;
++};
++
++#endif /* OP_AVR32_MODEL_H */
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/op_counter.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/op_counter.h 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2005-2006 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
++ */
++#ifndef OP_COUNTER_H
++#define OP_COUNTER_H
++
++#define OP_MAX_COUNTER 3
++
++/* Per performance monitor configuration as set via
++ * oprofilefs.
++ */
++struct op_counter_config {
++ unsigned long count;
++ unsigned long enabled;
++ unsigned long event;
++ unsigned long unit_mask;
++ unsigned long kernel;
++ unsigned long user;
++};
++
++extern struct op_counter_config counter_config[];
++
++#endif /* OP_COUNTER_H */
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/op_model_avr32.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/op_model_avr32.c 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,219 @@
++/*
++ * AVR32 Performance Counter Driver
++ *
++ * Copyright (C) 2005-2006 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
++ */
++
++#define DEBUG
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/oprofile.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/sysreg.h>
++
++#include "op_counter.h"
++#include "op_avr32_model.h"
++
++
++#define PC_ENABLE 0x001 /* Enable counters */
++#define PCNT_RESET 0x002 /* Reset event counters */
++#define CCNT_RESET 0x004 /* Reset clock counter */
++#define PC_RESET (CCNT_RESET | PCNT_RESET)
++#define PC_CNT64 0x008 /* Make CCNT count every 64th cycle */
++
++
++#define EVT_UNUSED 0xFF
++
++struct pc_counter {
++ volatile unsigned long ovf;
++ unsigned long reset_counter;
++};
++
++enum { PCCNT, PCNT0, PCNT1, MAX_COUNTERS };
++
++#define PCCNT_IE (1 << 4)
++#define PCNT0_IE (1 << 5)
++#define PCNT1_IE (1 << 6)
++
++#define PCCNT_F (1 << 8)
++#define PCNT0_F (1 << 9)
++#define PCNT1_F (1 << 10)
++
++#define AVR32_PC_IRQ 1
++
++static const u32 int_mask[MAX_COUNTERS] = { PCCNT_IE, PCNT0_IE, PCNT1_IE };
++static const u32 ovf_mask[MAX_COUNTERS] = { PCCNT_F, PCNT0_F, PCNT1_F };
++
++static struct pc_counter results[MAX_COUNTERS];
++
++static void write_pccr(u32 val)
++{
++ __builtin_mtsr(SYSREG_PCCR, val);
++}
++
++static u32 read_pccr(void)
++{
++ return __builtin_mfsr(SYSREG_PCCR);
++}
++
++static u32 read_counter(int counter)
++{
++ switch (counter) {
++ case PCCNT:
++ return __builtin_mfsr(SYSREG_PCCNT);
++ case PCNT0:
++ return __builtin_mfsr(SYSREG_PCNT0);
++ case PCNT1:
++ return __builtin_mfsr(SYSREG_PCNT0);
++ default:
++ return 0;
++ }
++}
++
++
++static void write_counter(int counter, u32 val)
++{
++ switch (counter) {
++ case PCCNT:
++ __builtin_mtsr(SYSREG_PCCNT, val);
++ case PCNT0:
++ __builtin_mtsr(SYSREG_PCNT0, val);
++ case PCNT1:
++ __builtin_mtsr(SYSREG_PCNT0, val);
++ default:
++ break;
++ }
++}
++
++static int avr32_setup_ctrs(void)
++{
++ u32 pccr;
++ int i;
++
++ for (i = PCCNT; i < MAX_COUNTERS; i++) {
++ if (counter_config[i].enabled)
++ continue;
++
++ counter_config[i].event = EVT_UNUSED;
++ }
++
++ pccr = ((counter_config[PCNT1].event << 18)
++ | (counter_config[PCNT0].event << 12));
++ pr_debug("avr32_setup_ctrs: pccr: %#08x\n", pccr);
++ write_pccr(pccr);
++
++ for (i = PCCNT; i < MAX_COUNTERS; i++) {
++ if (counter_config[i].event == EVT_UNUSED) {
++ counter_config[i].event = 0;
++ continue;
++ }
++
++ results[i].reset_counter = counter_config[i].count;
++ write_counter(i, -(u32)counter_config[i].count);
++ pr_debug("avr32_setup_ctrs: counter%d %#08x from %#08lx\n",
++ i, read_counter(i), counter_config[i].count);
++ }
++
++ return 0;
++}
++
++static void inline check_ctrs(void)
++{
++ int i;
++ u32 pccr = read_pccr();
++
++ /* Writeback clears overflow flag */
++ write_pccr(pccr & ~PC_ENABLE);
++
++ for (i = PCCNT; i < MAX_COUNTERS; i++) {
++ if (!(int_mask[i] & pccr))
++ continue;
++
++ if (pccr & ovf_mask[i])
++ results[i].ovf++;
++ }
++}
++
++
++static irqreturn_t avr32_pc_interrupt(int irq, void *arg,
++ struct pt_regs *regs)
++{
++ int i;
++
++ check_ctrs();
++
++ for (i = PCCNT; i < MAX_COUNTERS; i++) {
++ if (!results[i].ovf)
++ continue;
++
++ write_counter(i, -(u32)results[i].reset_counter);
++ oprofile_add_sample(regs, i);
++ results[i].ovf--;
++ }
++
++ /* Enable Performance Counter */
++ write_pccr(read_pccr() | PC_ENABLE);
++
++ return IRQ_HANDLED;
++}
++
++static void avr32_pc_stop(void)
++{
++ write_pccr(read_pccr() & ~PC_ENABLE);
++
++ free_irq(AVR32_PC_IRQ, results);
++}
++
++static int avr32_pc_start(void)
++{
++ int i, ret;
++ u32 pccr = read_pccr();
++
++ ret = request_irq(AVR32_PC_IRQ, avr32_pc_interrupt, SA_INTERRUPT,
++ "AVR32 Performance Counter", (void *)results);
++
++ if (ret < 0) {
++ printk(KERN_ERR
++ "oprofile: unable to request IRQ%d for AVR32"
++ " Performance Counter\n",
++ AVR32_PC_IRQ);
++ return ret;
++ }
++
++ /* Enable interrupts */
++ for (i = PCCNT; i < MAX_COUNTERS; i++) {
++ if (counter_config[i].enabled)
++ pccr |= int_mask[i];
++ }
++
++ /* Disable scaler */
++ pccr &= ~PC_CNT64;
++
++ /* Enable Performance Counter */
++ pccr |= PC_ENABLE;
++
++ write_pccr(pccr);
++ pr_debug("avr32_pc_start: pc: %#08x\n", pccr);
++ return 0;
++}
++
++
++struct op_avr32_model_spec op_avr32_spec = {
++ .init = 0,
++ .setup_ctrs = avr32_setup_ctrs,
++ .start = avr32_pc_start,
++ .stop = avr32_pc_stop,
++ .num_counters = MAX_COUNTERS,
++ .name = "avr32",
++};
++
+Index: linux-2.6.18-avr32/arch/avr32/oprofile/op_model_avr32.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18-avr32/arch/avr32/oprofile/op_model_avr32.h 2006-10-20 14:08:20.000000000 +0200
+@@ -0,0 +1,21 @@
++/**
++ * AVR32 Machine Specific Operations
++ *
++ * Copyright (C) 2005-2006 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
++ */
++#ifndef OP_MODEL_AVR32_H
++#define OP_MODEL_AVR32_H
++
++extern struct op_avr32_model_spec op_avr32_spec;
++extern int pc_init(struct oprofile_operations *ops,
++ struct op_avr32_model_spec *spec);
++extern void pc_exit(void);
++
++
++#endif
+Index: linux-2.6.18-avr32/arch/avr32/Kconfig
+===================================================================
+--- linux-2.6.18-avr32.orig/arch/avr32/Kconfig 2006-10-20 14:04:43.000000000 +0200
++++ linux-2.6.18-avr32/arch/avr32/Kconfig 2006-10-20 14:08:20.000000000 +0200
+@@ -190,6 +190,8 @@ source "drivers/Kconfig"
+
+ source "fs/Kconfig"
+
++source "arch/avr32/oprofile/Kconfig"
++
+ source "arch/avr32/Kconfig.debug"
+
+ source "security/Kconfig"
+Index: linux-2.6.18-avr32/arch/avr32/Makefile
+===================================================================
+--- linux-2.6.18-avr32.orig/arch/avr32/Makefile 2006-10-20 14:04:54.000000000 +0200
++++ linux-2.6.18-avr32/arch/avr32/Makefile 2006-10-20 14:09:10.000000000 +0200
+@@ -30,6 +30,7 @@ core-$(CONFIG_BOARD_ATSTK1000) += arch/
+ 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