diff -uNr src/arch/mips/godson/lm2e/irq.c pmc/arch/mips/godson/lm2e/irq.c --- src/arch/mips/godson/lm2e/irq.c 2006-12-01 18:10:11.000000000 +0800 +++ pmc/arch/mips/godson/lm2e/irq.c 2007-04-29 10:30:24.000000000 +0800 @@ -113,6 +113,8 @@ if (pending & CAUSEF_IP7) { do_IRQ(63, regs); + } else if (pending & CAUSEF_IP6) { + do_IRQ(62, regs); } else if (pending & CAUSEF_IP5) { i8259_irqdispatch(regs); } else if (pending & CAUSEF_IP2) { @@ -168,8 +170,10 @@ /* bonito irq at IP2 */ setup_irq(56 + 2, &cascade_irqaction); - /* 8259 irq at IP7 */ + /* 8259 irq at IP5 */ setup_irq(56 + 5, &cascade_irqaction); + /* performance counter overflowe at IP6 */ + printk("init_IRQ done.\n"); } diff -uNr src/arch/mips/kernel/unaligned.c pmc/arch/mips/kernel/unaligned.c --- src/arch/mips/kernel/unaligned.c 2006-09-20 11:42:06.000000000 +0800 +++ pmc/arch/mips/kernel/unaligned.c 2007-05-15 18:30:33.000000000 +0800 @@ -239,7 +239,7 @@ break; case lwu_op: -#ifdef CONFIG_64BIT +#if (defined (CONFIG_64BIT) || defined (CONFIG_CPU_GODSON2) ) /* * A 32-bit kernel might be running on a 64-bit processor. But * if we're on a 32-bit processor and an i-cache incoherency @@ -283,7 +283,7 @@ goto sigill; case ld_op: -#ifdef CONFIG_64BIT +#if (defined (CONFIG_64BIT) || defined (CONFIG_CPU_GODSON2) ) /* * A 32-bit kernel might be running on a 64-bit processor. But * if we're on a 32-bit processor and an i-cache incoherency @@ -293,6 +293,7 @@ */ if (!access_ok(VERIFY_READ, addr, 8)) goto sigbus; + //printk(KERN_EMERG "ld after access\n"); __asm__ __volatile__ ( #ifdef __BIG_ENDIAN @@ -391,7 +392,7 @@ break; case sd_op: -#ifdef CONFIG_64BIT +#if (defined (CONFIG_64BIT) || defined (CONFIG_CPU_GODSON2) ) /* * A 32-bit kernel might be running on a 64-bit processor. But * if we're on a 32-bit processor and an i-cache incoherency diff -uNr src/arch/mips/oprofile/Makefile pmc/arch/mips/oprofile/Makefile --- src/arch/mips/oprofile/Makefile 2006-09-20 11:42:06.000000000 +0800 +++ pmc/arch/mips/oprofile/Makefile 2007-04-27 17:18:23.000000000 +0800 @@ -14,3 +14,5 @@ oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_SB1) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_RM9000) += op_model_rm9000.o +oprofile-$(CONFIG_CPU_GODSON2) += op_model_godson2e.o + diff -uNr src/arch/mips/oprofile/common.c pmc/arch/mips/oprofile/common.c --- src/arch/mips/oprofile/common.c 2006-09-20 11:42:06.000000000 +0800 +++ pmc/arch/mips/oprofile/common.c 2007-04-27 17:17:54.000000000 +0800 @@ -16,6 +16,7 @@ extern struct op_mips_model op_model_mipsxx_ops __attribute__((weak)); extern struct op_mips_model op_model_rm9000_ops __attribute__((weak)); +extern struct op_mips_model op_model_godson2e_ops __attribute__((weak)); static struct op_mips_model *model; @@ -89,6 +90,11 @@ case CPU_RM9000: lmodel = &op_model_rm9000_ops; break; + + case CPU_GODSON2: + lmodel = &op_model_godson2e_ops; + break; + }; if (!lmodel) diff -uNr src/arch/mips/oprofile/op_model_godson2e.c pmc/arch/mips/oprofile/op_model_godson2e.c --- src/arch/mips/oprofile/op_model_godson2e.c 1970-01-01 08:00:00.000000000 +0800 +++ pmc/arch/mips/oprofile/op_model_godson2e.c 2007-05-25 14:59:54.000000000 +0800 @@ -0,0 +1,171 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2007 by comcat + */ + +#include +#include +#include +#include + +#include "op_impl.h" + +#define GODSON2E_PERFCTL_EXL (1UL << 0) +#define GODSON2E_PERFCTL_KERNEL (1UL << 1) +#define GODSON2E_PERFCTL_SUPERVISOR (1UL << 2) +#define GODSON2E_PERFCTL_USER (1UL << 3) +#define GODSON2E_PERFCTL_INTERRUPT_ENABLE (1UL << 4) +#define GODSON2E_PERFCTL_OVERFLOW (1ULL << 31) + +#define GODSON2E_COUNTER1_EVENT(event) ((event) << 5) +#define GODSON2E_COUNTER2_EVENT(event) ((event) << 9) + + +/* IP6 --- performance counter overflow */ +static int godson2e_pmc_irq = 56 + 6; + + +static struct godson2e_register_config { + unsigned int control; + unsigned int reset_counter1; + unsigned int reset_counter2; + int c1_enabled; + int c2_enabled; +} reg; + +/* Compute all of the registers in preparation for enabling profiling. */ + +static void godson2e_reg_setup(struct op_counter_config *ctr) +{ + unsigned int control = 0; + + /* Compute the performance counter control word. */ + /* For now count kernel and user mode */ + if (ctr[0].enabled) + control |= GODSON2E_COUNTER1_EVENT(ctr[0].event) | + GODSON2E_PERFCTL_INTERRUPT_ENABLE; + else + control |= GODSON2E_COUNTER1_EVENT(0xe); + + if (ctr[1].enabled) + control |= GODSON2E_COUNTER2_EVENT(ctr[1].event) | + GODSON2E_PERFCTL_INTERRUPT_ENABLE; + else + control |= GODSON2E_COUNTER2_EVENT(0x3); + + if (ctr[0].kernel || ctr[1].kernel) + control |= GODSON2E_PERFCTL_KERNEL; + else + control &= ~GODSON2E_PERFCTL_KERNEL; + + if (ctr[0].user || ctr[1].user) + control |= GODSON2E_PERFCTL_USER; + else + control &= ~GODSON2E_PERFCTL_USER; + + if (ctr[0].exl || ctr[1].exl) + control |= GODSON2E_PERFCTL_EXL; + else + control &= ~GODSON2E_PERFCTL_EXL; + + reg.control = control; + + reg.c1_enabled = ctr[0].enabled; + reg.c2_enabled = ctr[1].enabled; + reg.reset_counter1 = ctr[0].count ? 0x80000000 - ctr[0].count : 0; + reg.reset_counter2 = ctr[1].count ? 0x80000000 - ctr[1].count : 0; +} + +static void godson2e_cpu_setup (void *args) +{ + uint64_t perfcount; + + perfcount = ((uint64_t) reg.reset_counter2 << 32) | reg.reset_counter1; + write_c0_pmc_count(perfcount); +} + +static void godson2e_cpu_start(void *args) +{ + /* Start all counters */ + write_c0_pmc_control(reg.control); +} + +static void godson2e_cpu_stop(void *args) +{ + /* Stop all counters */ + write_c0_pmc_control(0); +} + + +static irqreturn_t godson2e_pmc_handler(int irq, void * dev_id, + struct pt_regs *regs) +{ + uint32_t counter1, counter2; + uint64_t counters; + uint64_t tmp = 0x0; + + /* + * Godson2e combines two 32-bit performance counters into a single + * 64-bit coprocessor zero register. To avoid a race updating the + * registers we need to stop the counters while we're messing with + * them ... + */ + + write_c0_pmc_control(tmp); + + counters = read_c0_pmc_count(); + counter1 = counters; + counter2 = counters >> 32; + + if (reg.c2_enabled && counter2 & GODSON2E_PERFCTL_OVERFLOW) { + oprofile_add_sample(regs, 1); + counter2 = reg.reset_counter2; + } + + if (reg.c1_enabled && counter1 & GODSON2E_PERFCTL_OVERFLOW) { + oprofile_add_sample(regs, 0); + counter1 = reg.reset_counter1; + } + + counters = ((uint64_t)counter2 << 32) | counter1; + + write_c0_pmc_count(counters); + write_c0_pmc_control(reg.control); + + return IRQ_HANDLED; +} + +static int __init godson2e_init(void) +{ + uint64_t tmp = 0; + write_c0_pmc_control(0); + write_c0_pmc_count(tmp); + + return request_irq(godson2e_pmc_irq, godson2e_pmc_handler, + IRQF_DISABLED, "Perfcounter", NULL); +} + +static void godson2e_exit(void) +{ + uint64_t tmp = 0; + write_c0_pmc_control(0); + write_c0_pmc_count(tmp); + + free_irq(godson2e_pmc_irq, NULL); +} + +struct op_mips_model op_model_godson2e_ops = { + .reg_setup = godson2e_reg_setup, + .cpu_setup = godson2e_cpu_setup, + .init = godson2e_init, + .exit = godson2e_exit, + .cpu_start = godson2e_cpu_start, + .cpu_stop = godson2e_cpu_stop, + .cpu_type = "mips/godson2e", + .num_counters = 2 +}; + + diff -uNr src/include/asm-mips/mipsregs.h pmc/include/asm-mips/mipsregs.h --- src/include/asm-mips/mipsregs.h 2006-09-20 11:42:06.000000000 +0800 +++ pmc/include/asm-mips/mipsregs.h 2007-05-22 16:01:48.000000000 +0800 @@ -650,6 +650,57 @@ /* + * Macros to access the godson2e system control coprocessor + */ +#define __read_64bit_c0_pmc_split(source, sel) \ +({ \ + unsigned long long val; \ + unsigned long flags; \ + \ + local_irq_save(flags); \ + if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%M0, " #source "\n\t" \ + "dsll\t%L0, %M0, 32\n\t" \ + "dsra\t%M0, %M0, 32\n\t" \ + "dsra\t%L0, %L0, 32\n\t" \ + ".set\tmips0" \ + : "=r" (val)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%M0, " #source ", " #sel "\n\t" \ + "dsll\t%L0, %M0, 32\n\t" \ + "dsra\t%M0, %M0, 32\n\t" \ + "dsra\t%L0, %L0, 32\n\t" \ + ".set\tmips0" \ + : "=r" (val)); \ + local_irq_restore(flags); \ + \ + val; \ +}) + +#define __read_64bit_c0_pmc(source, sel) \ +({ unsigned long long __res; \ + if (sizeof(unsigned long) == 4) \ + __res = __read_64bit_c0_pmc_split(source, sel); \ + else if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips3\n\t" \ + "dmfc0\t%0, " #source "\n\t" \ + ".set\tmips0" \ + : "=r" (__res)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%0, " #source ", " #sel "\n\t" \ + ".set\tmips0" \ + : "=r" (__res)); \ + __res; \ +}) + +/* * Macros to access the system control coprocessor */ @@ -951,6 +1002,14 @@ #define read_c0_framemask() __read_32bit_c0_register($21, 0) #define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val) +/* Godson2e PMC control register */ +#define read_c0_pmc_control() __read_32bit_c0_register($24, 0) +#define write_c0_pmc_control(val) __write_32bit_c0_register($24, 0, val) + +/* Godson2e PMC counter register */ +#define read_c0_pmc_count() __read_64bit_c0_pmc($25, 0) +#define write_c0_pmc_count(val) __write_64bit_c0_register($25, 0, val) + /* RM9000 PerfControl performance counter control register */ #define read_c0_perfcontrol() __read_32bit_c0_register($22, 0) #define write_c0_perfcontrol(val) __write_32bit_c0_register($22, 0, val) diff -uNr src/drivers/oprofile/cpu_buffer.c pmc/drivers/oprofile/cpu_buffer.c --- src/drivers/oprofile/cpu_buffer.c 2006-09-20 11:42:06.000000000 +0800 +++ pmc/drivers/oprofile/cpu_buffer.c 2007-04-30 15:39:23.000000000 +0800 @@ -148,6 +148,10 @@ unsigned long pc, unsigned long event) { struct op_sample * entry = &cpu_buf->buffer[cpu_buf->head_pos]; + + if(!entry) + return; + entry->eip = pc; entry->event = event; increment_head(cpu_buf); diff -uNr src/drivers/oprofile/oprof.c pmc/drivers/oprofile/oprof.c --- src/drivers/oprofile/oprof.c 2006-09-20 11:42:06.000000000 +0800 +++ pmc/drivers/oprofile/oprof.c 2007-04-29 15:18:35.000000000 +0800 @@ -186,3 +186,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Levon "); MODULE_DESCRIPTION("OProfile system profiler"); + +