Commit 79472c02 authored by blogic's avatar blogic

BB: lantiq: falcon/vr9 - add support for vpe1

(required not-distributable firmware blob - dump it by yourself from original firmware)
Signed-off-by: default avatarEddi De Pieri <eddi@depieri.net>

git-svn-id: svn://svn.openwrt.org/openwrt/branches/barrier_breaker@43158 3c298f89-4303-0410-b956-a3cf2f4a3e73
parent eb0ce572
diff -u -N -r linux-3.10.49.orig/arch/mips/include/asm/mipsmtregs.h linux-3.10.49/arch/mips/include/asm/mipsmtregs.h
--- linux-3.10.49.orig/arch/mips/include/asm/mipsmtregs.h 2014-10-15 21:41:48.000000000 +0200
+++ linux-3.10.49/arch/mips/include/asm/mipsmtregs.h 2014-10-15 21:44:25.000000000 +0200
@@ -31,14 +31,34 @@
#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3)
#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val)
+#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3)
+#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val)
+
+#define read_c0_vpeschedule() __read_32bit_c0_register($1, 5)
+#define write_c0_vpeschedule(val) __write_32bit_c0_register($1, 5, val)
+
+#define read_c0_vpeschefback() __read_32bit_c0_register($1, 6)
+#define write_c0_vpeschefback(val) __write_32bit_c0_register($1, 6, val)
+
+#define read_c0_vpeopt() __read_32bit_c0_register($1, 7)
+#define write_c0_vpeopt(val) __write_32bit_c0_register($1, 7, val)
+
#define read_c0_tcstatus() __read_32bit_c0_register($2, 1)
#define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val)
#define read_c0_tcbind() __read_32bit_c0_register($2, 2)
+#define write_c0_tcbind(val) __write_32bit_c0_register($2, 2, val)
#define read_c0_tccontext() __read_32bit_c0_register($2, 5)
#define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val)
+#define read_c0_tcschedule() __read_32bit_c0_register($2, 6)
+#define write_c0_tcschedule(val) __write_32bit_c0_register($2, 6, val)
+
+#define read_c0_tcschefback() __read_32bit_c0_register($2, 7)
+#define write_c0_tcschefback(val) __write_32bit_c0_register($2, 7, val)
+
+
#else /* Assembly */
/*
* Macros for use in assembly language code
@@ -77,6 +97,8 @@
#define MVPCONTROL_STLB_SHIFT 2
#define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT)
+#define MVPCONTROL_CPA_SHIFT 3
+#define MVPCONTROL_CPA (_ULCAST_(1) << MVPCONTROL_CPA_SHIFT)
/* MVPConf0 fields */
#define MVPCONF0_PTC_SHIFT 0
@@ -87,6 +109,8 @@
#define MVPCONF0_TCA ( _ULCAST_(1) << MVPCONF0_TCA_SHIFT)
#define MVPCONF0_PTLBE_SHIFT 16
#define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT)
+#define MVPCONF0_PCP_SHIFT 27
+#define MVPCONF0_PCP (_ULCAST_(1) << MVPCONF0_PCP_SHIFT)
#define MVPCONF0_TLBS_SHIFT 29
#define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT)
#define MVPCONF0_M_SHIFT 31
@@ -124,9 +148,25 @@
#define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT)
#define VPECONF0_MVP_SHIFT 1
#define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT)
+#define VPECONF0_ICS_SHIFT 16
+#define VPECONF0_ICS (_ULCAST_(1) << VPECONF0_ICS_SHIFT)
+#define VPECONF0_DCS_SHIFT 17
+#define VPECONF0_DCS (_ULCAST_(1) << VPECONF0_DCS_SHIFT)
#define VPECONF0_XTC_SHIFT 21
#define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT)
+/* VPEOpt fields */
+#define VPEOPT_DWX_SHIFT 0
+#define VPEOPT_IWX_SHIFT 8
+#define VPEOPT_IWX0 ( _ULCAST_(0x1) << VPEOPT_IWX_SHIFT)
+#define VPEOPT_IWX1 ( _ULCAST_(0x2) << VPEOPT_IWX_SHIFT)
+#define VPEOPT_IWX2 ( _ULCAST_(0x4) << VPEOPT_IWX_SHIFT)
+#define VPEOPT_IWX3 ( _ULCAST_(0x8) << VPEOPT_IWX_SHIFT)
+#define VPEOPT_DWX0 ( _ULCAST_(0x1) << VPEOPT_DWX_SHIFT)
+#define VPEOPT_DWX1 ( _ULCAST_(0x2) << VPEOPT_DWX_SHIFT)
+#define VPEOPT_DWX2 ( _ULCAST_(0x4) << VPEOPT_DWX_SHIFT)
+#define VPEOPT_DWX3 ( _ULCAST_(0x8) << VPEOPT_DWX_SHIFT)
+
/* VPEConf1 fields (per VPE) */
#define VPECONF1_NCP1_SHIFT 0
#define VPECONF1_NCP1 (_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT)
@@ -363,6 +403,14 @@
#define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val)
#define read_vpe_c0_vpeconf1() mftc0(1, 3)
#define write_vpe_c0_vpeconf1(val) mttc0(1, 3, val)
+#define read_vpe_c0_vpeschedule() mftc0(1, 5)
+#define write_vpe_c0_vpeschedule(val) mttc0(1, 5, val)
+#define read_vpe_c0_vpeschefback() mftc0(1, 6)
+#define write_vpe_c0_vpeschefback(val) mttc0(1, 6, val)
+#define read_vpe_c0_vpeopt() mftc0(1, 7)
+#define write_vpe_c0_vpeopt(val) mttc0(1, 7, val)
+#define read_vpe_c0_wired() mftc0(6, 0)
+#define write_vpe_c0_wired(val) mttc0(6, 0, val)
#define read_vpe_c0_count() mftc0(9, 0)
#define write_vpe_c0_count(val) mttc0(9, 0, val)
#define read_vpe_c0_status() mftc0(12, 0)
@@ -394,6 +442,12 @@
#define write_tc_c0_tchalt(val) mttc0(2, 4, val)
#define read_tc_c0_tccontext() mftc0(2, 5)
#define write_tc_c0_tccontext(val) mttc0(2, 5, val)
+#define read_tc_c0_tcschedule() mftc0(2, 6)
+#define write_tc_c0_tcschedule(val) mttc0(2, 6, val)
+#define read_tc_c0_tcschefback() mftc0(2, 7)
+#define write_tc_c0_tcschefback(val) mttc0(2, 7, val)
+#define read_tc_c0_entryhi() mftc0(10, 0)
+#define write_tc_c0_entryhi(val) mttc0(10, 0, val)
/* GPR */
#define read_tc_gpr_sp() mftgpr(29)
diff -u -N -r linux-3.10.49.orig/arch/mips/Kconfig linux-3.10.49/arch/mips/Kconfig
--- linux-3.10.49.orig/arch/mips/Kconfig 2014-10-15 21:41:48.000000000 +0200
+++ linux-3.10.49/arch/mips/Kconfig 2014-10-15 21:44:25.000000000 +0200
@@ -1992,6 +1992,28 @@
Includes a loader for loading an elf relocatable object
onto another VPE and running it.
+config IFX_VPE_EXT
+ bool "IFX APRP Extensions"
+ depends on MIPS_VPE_LOADER
+ default y
+ help
+ IFX included extensions in APRP
+
+config PERFCTRS
+ bool "34K Performance counters"
+ depends on MIPS_MT && PROC_FS
+ default n
+ help
+ 34K Performance counter through /proc
+
+config MTSCHED
+ bool "Support mtsched priority configuration for TCs"
+ depends on MIPS_MT && PROC_FS
+ default y
+ help
+ Support for mtsched priority configuration for TCs through
+ /proc/mips/mtsched
+
config MIPS_MT_SMTC_IM_BACKSTOP
bool "Use per-TC register bits as backstop for inhibited IM bits"
depends on MIPS_MT_SMTC
diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/Makefile linux-3.10.49/arch/mips/kernel/Makefile
--- linux-3.10.49.orig/arch/mips/kernel/Makefile 2014-10-15 21:41:48.000000000 +0200
+++ linux-3.10.49/arch/mips/kernel/Makefile 2014-10-15 21:44:25.000000000 +0200
@@ -74,7 +74,8 @@
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_PROC_FS) += proc.o
-
+obj-$(CONFIG_MTSCHED) += mtsched_proc.o
+obj-$(CONFIG_PERFCTRS) += perf_proc.o
obj-$(CONFIG_64BIT) += cpu-bugs64.o
obj-$(CONFIG_I8253) += i8253.o
diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/mips-mt.c linux-3.10.49/arch/mips/kernel/mips-mt.c
--- linux-3.10.49.orig/arch/mips/kernel/mips-mt.c 2014-10-15 21:41:48.000000000 +0200
+++ linux-3.10.49/arch/mips/kernel/mips-mt.c 2014-10-15 21:44:25.000000000 +0200
@@ -20,26 +20,96 @@
#include <asm/cacheflush.h>
int vpelimit;
-
static int __init maxvpes(char *str)
{
get_option(&str, &vpelimit);
-
return 1;
}
-
__setup("maxvpes=", maxvpes);
int tclimit;
-
static int __init maxtcs(char *str)
{
get_option(&str, &tclimit);
+ return 1;
+}
+__setup("maxtcs=", maxtcs);
+#ifdef CONFIG_IFX_VPE_EXT
+int stlb;
+static int __init istlbshared(char *str)
+{
+ get_option(&str, &stlb);
return 1;
}
+__setup("vpe_tlb_shared=", istlbshared);
-__setup("maxtcs=", maxtcs);
+int vpe0_wired;
+static int __init vpe0wired(char *str)
+{
+ get_option(&str, &vpe0_wired);
+ return 1;
+}
+__setup("vpe0_wired_tlb_entries=", vpe0wired);
+
+int vpe1_wired;
+static int __init vpe1wired(char *str)
+{
+ get_option(&str, &vpe1_wired);
+ return 1;
+}
+__setup("vpe1_wired_tlb_entries=", vpe1wired);
+
+#ifdef CONFIG_MIPS_MT_SMTC
+extern int nostlb;
+#endif
+void configure_tlb(void)
+{
+ int vpeflags, tcflags, tlbsiz;
+ unsigned int config1val;
+ vpeflags = dvpe();
+ tcflags = dmt();
+ write_c0_vpeconf0((read_c0_vpeconf0() | VPECONF0_MVP));
+ write_c0_mvpcontrol((read_c0_mvpcontrol() | MVPCONTROL_VPC));
+ mips_ihb();
+ //printk("stlb = %d, vpe0_wired = %d vpe1_wired=%d\n", stlb,vpe0_wired, vpe1_wired);
+ if (stlb) {
+ if (!(read_c0_mvpconf0() & MVPCONF0_TLBS)) {
+ emt(tcflags);
+ evpe(vpeflags);
+ return;
+ }
+
+ write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB);
+ write_c0_wired(vpe0_wired + vpe1_wired);
+ if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) {
+ config1val = read_vpe_c0_config1();
+ tlbsiz = (((config1val >> 25) & 0x3f) + 1);
+ if (tlbsiz > 64)
+ tlbsiz = 64;
+ cpu_data[0].tlbsize = tlbsiz;
+ current_cpu_data.tlbsize = tlbsiz;
+ }
+
+ }
+ else {
+ write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_STLB);
+ write_c0_wired(vpe0_wired);
+ }
+
+ ehb();
+ write_c0_mvpcontrol((read_c0_mvpcontrol() & ~MVPCONTROL_VPC));
+ ehb();
+ local_flush_tlb_all();
+
+ printk("Wired TLB entries for Linux read_c0_wired() = %d\n", read_c0_wired());
+#ifdef CONFIG_MIPS_MT_SMTC
+ nostlb = !stlb;
+#endif
+ emt(tcflags);
+ evpe(vpeflags);
+}
+#endif
/*
* Dump new MIPS MT state for the core. Does not leave TCs halted.
@@ -77,18 +147,18 @@
if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) {
printk(" VPE %d\n", i);
printk(" VPEControl : %08lx\n",
- read_vpe_c0_vpecontrol());
+ read_vpe_c0_vpecontrol());
printk(" VPEConf0 : %08lx\n",
- read_vpe_c0_vpeconf0());
+ read_vpe_c0_vpeconf0());
printk(" VPE%d.Status : %08lx\n",
- i, read_vpe_c0_status());
+ i, read_vpe_c0_status());
printk(" VPE%d.EPC : %08lx %pS\n",
- i, read_vpe_c0_epc(),
- (void *) read_vpe_c0_epc());
+ i, read_vpe_c0_epc(),
+ (void *) read_vpe_c0_epc());
printk(" VPE%d.Cause : %08lx\n",
- i, read_vpe_c0_cause());
+ i, read_vpe_c0_cause());
printk(" VPE%d.Config7 : %08lx\n",
- i, read_vpe_c0_config7());
+ i, read_vpe_c0_config7());
break; /* Next VPE */
}
}
@@ -286,6 +356,9 @@
printk("Mapped %ld ITC cells starting at 0x%08x\n",
((itcblkgrn & 0x7fe00000) >> 20), itc_base);
}
+#ifdef CONFIG_IFX_VPE_EXT
+ configure_tlb();
+#endif
}
/*
diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/mtsched_proc.c linux-3.10.49/arch/mips/kernel/mtsched_proc.c
--- linux-3.10.49.orig/arch/mips/kernel/mtsched_proc.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-3.10.49/arch/mips/kernel/mtsched_proc.c 2014-10-15 21:44:25.000000000 +0200
@@ -0,0 +1,279 @@
+/*
+ * /proc hooks for MIPS MT scheduling policy management for 34K cores
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Copyright (C) 2006 Mips Technologies, Inc
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *mtsched_proc;
+
+#ifndef CONFIG_MIPS_MT_SMTC
+#define NTCS 2
+#else
+#define NTCS NR_CPUS
+#endif
+#define NVPES 2
+
+int lastvpe = 1;
+int lasttc = 8;
+
+static int proc_read_mtsched(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int totalen = 0;
+ int len;
+
+ int i;
+ int vpe;
+ int mytc;
+ unsigned long flags;
+ unsigned int mtflags;
+ unsigned int haltstate;
+ unsigned int vpes_checked[NVPES];
+ unsigned int vpeschedule[NVPES];
+ unsigned int vpeschefback[NVPES];
+ unsigned int tcschedule[NTCS];
+ unsigned int tcschefback[NTCS];
+
+ /* Dump the state of the MIPS MT scheduling policy manager */
+ /* Inititalize control state */
+ for(i = 0; i < NVPES; i++) {
+ vpes_checked[i] = 0;
+ vpeschedule[i] = 0;
+ vpeschefback[i] = 0;
+ }
+ for(i = 0; i < NTCS; i++) {
+ tcschedule[i] = 0;
+ tcschefback[i] = 0;
+ }
+
+ /* Disable interrupts and multithreaded issue */
+ local_irq_save(flags);
+ mtflags = dvpe();
+
+ /* Then go through the TCs, halt 'em, and extract the values */
+ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
+ for(i = 0; i < NTCS; i++) {
+ if(i == mytc) {
+ /* No need to halt ourselves! */
+ tcschedule[i] = read_c0_tcschedule();
+ tcschefback[i] = read_c0_tcschefback();
+ /* If VPE bound to TC hasn't been checked, do it */
+ vpe = read_c0_tcbind() & TCBIND_CURVPE;
+ if(!vpes_checked[vpe]) {
+ vpeschedule[vpe] = read_c0_vpeschedule();
+ vpeschefback[vpe] = read_c0_vpeschefback();
+ vpes_checked[vpe] = 1;
+ }
+ } else {
+ settc(i);
+ haltstate = read_tc_c0_tchalt();
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ tcschedule[i] = read_tc_c0_tcschedule();
+ tcschefback[i] = read_tc_c0_tcschefback();
+ /* If VPE bound to TC hasn't been checked, do it */
+ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE;
+ if(!vpes_checked[vpe]) {
+ vpeschedule[vpe] = read_vpe_c0_vpeschedule();
+ vpeschefback[vpe] = read_vpe_c0_vpeschefback();
+ vpes_checked[vpe] = 1;
+ }
+ if(!haltstate) write_tc_c0_tchalt(0);
+ }
+ }
+ /* Re-enable MT and interrupts */
+ evpe(mtflags);
+ local_irq_restore(flags);
+
+ for(vpe=0; vpe < NVPES; vpe++) {
+ len = sprintf(page, "VPE[%d].VPEschedule = 0x%08x\n",
+ vpe, vpeschedule[vpe]);
+ totalen += len;
+ page += len;
+ len = sprintf(page, "VPE[%d].VPEschefback = 0x%08x\n",
+ vpe, vpeschefback[vpe]);
+ totalen += len;
+ page += len;
+ }
+ for(i=0; i < NTCS; i++) {
+ len = sprintf(page, "TC[%d].TCschedule = 0x%08x\n",
+ i, tcschedule[i]);
+ totalen += len;
+ page += len;
+ len = sprintf(page, "TC[%d].TCschefback = 0x%08x\n",
+ i, tcschefback[i]);
+ totalen += len;
+ page += len;
+ }
+ return totalen;
+}
+
+/*
+ * Write to perf counter registers based on text input
+ */
+
+#define TXTBUFSZ 100
+
+static int proc_write_mtsched(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int len = 0;
+ char mybuf[TXTBUFSZ];
+ /* At most, we will set up 9 TCs and 2 VPEs, 11 entries in all */
+ char entity[1]; //, entity1[1];
+ int number[1];
+ unsigned long value[1];
+ int nparsed = 0 , index = 0;
+ unsigned long flags;
+ unsigned int mtflags;
+ unsigned int haltstate;
+ unsigned int tcbindval;
+
+ if(count >= TXTBUFSZ) len = TXTBUFSZ-1;
+ else len = count;
+ memset(mybuf,0,TXTBUFSZ);
+ if(copy_from_user(mybuf, buffer, len)) return -EFAULT;
+
+ nparsed = sscanf(mybuf, "%c%d %lx",
+ &entity[0] ,&number[0], &value[0]);
+
+ /*
+ * Having acquired the inputs, which might have
+ * generated exceptions and preemptions,
+ * program the registers.
+ */
+ /* Disable interrupts and multithreaded issue */
+ local_irq_save(flags);
+ mtflags = dvpe();
+
+ if(entity[index] == 't' ) {
+ /* Set TCSchedule or TCScheFBack of specified TC */
+ if(number[index] > NTCS) goto skip;
+ /* If it's our own TC, do it direct */
+ if(number[index] ==
+ ((read_c0_tcbind() & TCBIND_CURTC)
+ >> TCBIND_CURTC_SHIFT)) {
+ if(entity[index] == 't')
+ write_c0_tcschedule(value[index]);
+ else
+ write_c0_tcschefback(value[index]);
+ } else {
+ /* Otherwise, we do it via MTTR */
+ settc(number[index]);
+ haltstate = read_tc_c0_tchalt();
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ if(entity[index] == 't')
+ write_tc_c0_tcschedule(value[index]);
+ else
+ write_tc_c0_tcschefback(value[index]);
+ mips_ihb();
+ if(!haltstate) write_tc_c0_tchalt(0);
+ }
+ } else if(entity[index] == 'v') {
+ /* Set VPESchedule of specified VPE */
+ if(number[index] > NVPES) goto skip;
+ tcbindval = read_c0_tcbind();
+ /* Are we doing this to our current VPE? */
+ if((tcbindval & TCBIND_CURVPE) == number[index]) {
+ /* Then life is simple */
+ write_c0_vpeschedule(value[index]);
+ } else {
+ /*
+ * Bind ourselves to the other VPE long enough
+ * to program the bind value.
+ */
+ write_c0_tcbind((tcbindval & ~TCBIND_CURVPE)
+ | number[index]);
+ mips_ihb();
+ write_c0_vpeschedule(value[index]);
+ mips_ihb();
+ /* Restore previous binding */
+ write_c0_tcbind(tcbindval);
+ mips_ihb();
+ }
+ }
+
+ else if(entity[index] == 'r') {
+ unsigned int vpes_checked[2], vpe ,i , mytc;
+ vpes_checked[0] = vpes_checked[1] = 0;
+
+ /* Then go through the TCs, halt 'em, and extract the values */
+ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
+
+ for(i = 0; i < NTCS; i++) {
+ if(i == mytc) {
+ /* No need to halt ourselves! */
+ write_c0_vpeschefback(0);
+ write_c0_tcschefback(0);
+ } else {
+ settc(i);
+ haltstate = read_tc_c0_tchalt();
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ write_tc_c0_tcschefback(0);
+ /* If VPE bound to TC hasn't been checked, do it */
+ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE;
+ if(!vpes_checked[vpe]) {
+ write_vpe_c0_vpeschefback(0);
+ vpes_checked[vpe] = 1;
+ }
+ if(!haltstate) write_tc_c0_tchalt(0);
+ }
+ }
+ }
+ else {
+ printk ("\n Usage : <t/v><0/1> <Hex Value>\n Example : t0 0x01\n");
+ }
+
+skip:
+ /* Re-enable MT and interrupts */
+ evpe(mtflags);
+ local_irq_restore(flags);
+ return (len);
+}
+
+static int __init init_mtsched_proc(void)
+{
+ extern struct proc_dir_entry *get_mips_proc_dir(void);
+ struct proc_dir_entry *mips_proc_dir;
+
+ if (!cpu_has_mipsmt) {
+ printk("mtsched: not a MIPS MT capable processor\n");
+ return -ENODEV;
+ }
+
+ mips_proc_dir = get_mips_proc_dir();
+
+ mtsched_proc = create_proc_entry("mtsched", 0644, mips_proc_dir);
+ mtsched_proc->read_proc = proc_read_mtsched;
+ mtsched_proc->write_proc = proc_write_mtsched;
+
+ return 0;
+}
+
+/* Automagically create the entry */
+module_init(init_mtsched_proc);
diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/perf_proc.c linux-3.10.49/arch/mips/kernel/perf_proc.c
--- linux-3.10.49.orig/arch/mips/kernel/perf_proc.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-3.10.49/arch/mips/kernel/perf_proc.c 2014-10-15 21:44:25.000000000 +0200
@@ -0,0 +1,191 @@
+/*
+ * /proc hooks for CPU performance counter support for SMTC kernel
+ * (and ultimately others)
+ * Copyright (C) 2006 Mips Technologies, Inc
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/mipsregs.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+/*
+ * /proc diagnostic and statistics hooks
+ */
+
+
+/* Internal software-extended event counters */
+
+static unsigned long long extencount[4] = {0,0,0,0};
+
+static struct proc_dir_entry *perf_proc;
+
+static int proc_read_perf(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int totalen = 0;
+ int len;
+
+ len = sprintf(page, "PerfCnt[0].Ctl : 0x%08x\n", read_c0_perfctrl0());
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[0].Cnt : %Lu\n",
+ extencount[0] + (unsigned long long)((unsigned)read_c0_perfcntr0()));
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[1].Ctl : 0x%08x\n", read_c0_perfctrl1());
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[1].Cnt : %Lu\n",
+ extencount[1] + (unsigned long long)((unsigned)read_c0_perfcntr1()));
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[2].Ctl : 0x%08x\n", read_c0_perfctrl2());
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[2].Cnt : %Lu\n",
+ extencount[2] + (unsigned long long)((unsigned)read_c0_perfcntr2()));
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[3].Ctl : 0x%08x\n", read_c0_perfctrl3());
+ totalen += len;
+ page += len;
+ len = sprintf(page, "PerfCnt[3].Cnt : %Lu\n",
+ extencount[3] + (unsigned long long)((unsigned)read_c0_perfcntr3()));
+ totalen += len;
+ page += len;
+
+ return totalen;
+}
+
+/*
+ * Write to perf counter registers based on text input
+ */
+
+#define TXTBUFSZ 100
+
+static int proc_write_perf(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int len;
+ int nparsed;
+ int index;
+ char mybuf[TXTBUFSZ];
+
+ int which[4];
+ unsigned long control[4];
+ long long ctrdata[4];
+
+ if(count >= TXTBUFSZ) len = TXTBUFSZ-1;
+ else len = count;
+ memset(mybuf,0,TXTBUFSZ);
+ if(copy_from_user(mybuf, buffer, len)) return -EFAULT;
+
+ nparsed = sscanf(mybuf,
+ "%d %lx %Ld %d %lx %Ld %d %lx %Ld %d %lx %Ld",
+ &which[0], &control[0], &ctrdata[0],
+ &which[1], &control[1], &ctrdata[1],
+ &which[2], &control[2], &ctrdata[2],
+ &which[3], &control[3], &ctrdata[3]);
+
+ for(index = 0; nparsed >= 3; index++) {
+ switch (which[index]) {
+ case 0:
+ write_c0_perfctrl0(control[index]);
+ if(ctrdata[index] != -1) {
+ extencount[0] = (unsigned long long)ctrdata[index];
+ write_c0_perfcntr0((unsigned long)0);
+ }
+ break;
+ case 1:
+ write_c0_perfctrl1(control[index]);
+ if(ctrdata[index] != -1) {
+ extencount[1] = (unsigned long long)ctrdata[index];
+ write_c0_perfcntr1((unsigned long)0);
+ }
+ break;
+ case 2:
+ write_c0_perfctrl2(control[index]);
+ if(ctrdata[index] != -1) {
+ extencount[2] = (unsigned long long)ctrdata[index];
+ write_c0_perfcntr2((unsigned long)0);
+ }
+ break;
+ case 3:
+ write_c0_perfctrl3(control[index]);
+ if(ctrdata[index] != -1) {
+ extencount[3] = (unsigned long long)ctrdata[index];
+ write_c0_perfcntr3((unsigned long)0);
+ }
+ break;
+ }
+ nparsed -= 3;
+ }
+ return (len);
+}
+
+extern int (*perf_irq)(void);
+
+/*
+ * Invoked when timer interrupt vector picks up a perf counter overflow
+ */
+
+static int perf_proc_irq(void)
+{
+ unsigned long snapshot;
+
+ /*
+ * It would be nice to do this as a loop, but we don't have
+ * indirect access to CP0 registers.
+ */
+ snapshot = read_c0_perfcntr0();
+ if ((long)snapshot < 0) {
+ extencount[0] +=
+ (unsigned long long)((unsigned)read_c0_perfcntr0());
+ write_c0_perfcntr0(0);
+ }
+ snapshot = read_c0_perfcntr1();
+ if ((long)snapshot < 0) {
+ extencount[1] +=
+ (unsigned long long)((unsigned)read_c0_perfcntr1());
+ write_c0_perfcntr1(0);
+ }
+ snapshot = read_c0_perfcntr2();