diff options
Diffstat (limited to 'target/linux/lantiq/patches-3.3/0015-VPE-extensions.patch')
-rw-r--r-- | target/linux/lantiq/patches-3.3/0015-VPE-extensions.patch | 1221 |
1 files changed, 0 insertions, 1221 deletions
diff --git a/target/linux/lantiq/patches-3.3/0015-VPE-extensions.patch b/target/linux/lantiq/patches-3.3/0015-VPE-extensions.patch deleted file mode 100644 index 2b04769098..0000000000 --- a/target/linux/lantiq/patches-3.3/0015-VPE-extensions.patch +++ /dev/null @@ -1,1221 +0,0 @@ -From 1a3548545403c8f7cc02317643b616db6d0c9a4b Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 20:30:40 +0200 -Subject: [PATCH 15/25] VPE extensions - ---- - arch/mips/Kconfig | 22 +++ - arch/mips/include/asm/mipsmtregs.h | 54 +++++++ - arch/mips/kernel/Makefile | 3 +- - arch/mips/kernel/mips-mt.c | 97 +++++++++++-- - arch/mips/kernel/mtsched_proc.c | 279 ++++++++++++++++++++++++++++++++++++ - arch/mips/kernel/perf_proc.c | 191 ++++++++++++++++++++++++ - arch/mips/kernel/proc.c | 17 +++ - arch/mips/kernel/smtc.c | 7 + - arch/mips/kernel/vpe.c | 250 ++++++++++++++++++++++++++++++++- - 9 files changed, 905 insertions(+), 15 deletions(-) - create mode 100644 arch/mips/kernel/mtsched_proc.c - create mode 100644 arch/mips/kernel/perf_proc.c - -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index 0e2ce5d..e152c85 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -1948,6 +1948,28 @@ config MIPS_VPE_LOADER - 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 --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h -index c9420aa..04bfb4b 100644 ---- a/arch/mips/include/asm/mipsmtregs.h -+++ b/arch/mips/include/asm/mipsmtregs.h -@@ -28,14 +28,34 @@ - #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2) - #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, 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 -@@ -74,6 +94,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 -@@ -84,6 +106,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 -@@ -121,9 +145,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) -+ - /* TCStatus fields (per TC) */ - #define TCSTATUS_TASID (_ULCAST_(0xff)) - #define TCSTATUS_IXMT_SHIFT 10 -@@ -350,6 +390,14 @@ do { \ - #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) - #define read_vpe_c0_vpeconf0() mftc0(1, 2) - #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, 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) -@@ -381,6 +429,12 @@ do { \ - #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 --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile -index cacc340..477bcc3 100644 ---- a/arch/mips/kernel/Makefile -+++ b/arch/mips/kernel/Makefile -@@ -90,7 +90,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o - - 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 --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c -index c23d11f..11d6489 100644 ---- a/arch/mips/kernel/mips-mt.c -+++ b/arch/mips/kernel/mips-mt.c -@@ -21,26 +21,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. -@@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpctl) - 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 */ - } - } -@@ -287,6 +357,9 @@ void mips_mt_set_cpuoptions(void) - printk("Mapped %ld ITC cells starting at 0x%08x\n", - ((itcblkgrn & 0x7fe00000) >> 20), itc_base); - } -+#ifdef CONFIG_IFX_VPE_EXT -+ configure_tlb(); -+#endif - } - - /* -diff --git a/arch/mips/kernel/mtsched_proc.c b/arch/mips/kernel/mtsched_proc.c -new file mode 100644 -index 0000000..4dafded ---- /dev/null -+++ b/arch/mips/kernel/mtsched_proc.c -@@ -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 --git a/arch/mips/kernel/perf_proc.c b/arch/mips/kernel/perf_proc.c -new file mode 100644 -index 0000000..7eec015 ---- /dev/null -+++ b/arch/mips/kernel/perf_proc.c -@@ -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(); -+ if ((long)snapshot < 0) { -+ extencount[2] += -+ (unsigned long long)((unsigned)read_c0_perfcntr2()); -+ write_c0_perfcntr2(0); -+ } -+ snapshot = read_c0_perfcntr3(); -+ if ((long)snapshot < 0) { -+ extencount[3] += -+ (unsigned long long)((unsigned)read_c0_perfcntr3()); -+ write_c0_perfcntr3(0); -+ } -+ return 0; -+} -+ -+static int __init init_perf_proc(void) -+{ -+ extern struct proc_dir_entry *get_mips_proc_dir(void); -+ -+ struct proc_dir_entry *mips_proc_dir = get_mips_proc_dir(); -+ -+ write_c0_perfcntr0(0); -+ write_c0_perfcntr1(0); -+ write_c0_perfcntr2(0); -+ write_c0_perfcntr3(0); -+ perf_proc = create_proc_entry("perf", 0644, mips_proc_dir); -+ perf_proc->read_proc = proc_read_perf; -+ perf_proc->write_proc = proc_write_perf; -+ perf_irq = perf_proc_irq; -+ -+ return 0; -+} -+ -+/* Automagically create the entry */ -+module_init(init_perf_proc); -diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c -index e309665..2de204f 100644 ---- a/arch/mips/kernel/proc.c -+++ b/arch/mips/kernel/proc.c -@@ -7,6 +7,7 @@ - #include <linux/kernel.h> - #include <linux/sched.h> - #include <linux/seq_file.h> -+#include <linux/proc_fs.h> - #include <asm/bootinfo.h> - #include <asm/cpu.h> - #include <asm/cpu-features.h> -@@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op = { - .stop = c_stop, - .show = show_cpuinfo, - }; -+ -+/* -+ * Support for MIPS/local /proc hooks in /proc/mips/ -+ */ -+ -+static struct proc_dir_entry *mips_proc = NULL; -+ -+struct proc_dir_entry *get_mips_proc_dir(void) -+{ -+ /* -+ * This ought not to be preemptable. -+ */ -+ if(mips_proc == NULL) -+ mips_proc = proc_mkdir("mips", NULL); -+ return(mips_proc); -+} -diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c -index 0a42ff3..41f5258 100644 ---- a/arch/mips/kernel/smtc.c -+++ b/arch/mips/kernel/smtc.c -@@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) - asid = asid_cache(cpu); - - do { -+#ifdef CONFIG_IFX_VPE_EXT -+ /* If TLB is shared between AP and RP (AP is running SMTC), -+ leave out max ASID i.e., ASID_MASK for RP -+ */ -+ if (!nostlb && ((asid & ASID_MASK) == (ASID_MASK - 1))) -+ asid++; -+#endif - if (!((asid += ASID_INC) & ASID_MASK) ) { - if (cpu_has_vtag_icache) - flush_icache_all(); -diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c -index bfa12a4..e338ba5 100644 ---- a/arch/mips/kernel/vpe.c -+++ b/arch/mips/kernel/vpe.c -@@ -75,6 +75,58 @@ static struct kspd_notifications kspd_events; - static int kspd_events_reqd; - #endif - -+#ifdef CONFIG_IFX_VPE_EXT -+static int is_sdepgm; -+extern int stlb; -+extern int vpe0_wired; -+extern int vpe1_wired; -+unsigned int vpe1_load_addr; -+ -+static int __init load_address(char *str) -+{ -+ get_option(&str, &vpe1_load_addr); -+ return 1; -+} -+__setup("vpe1_load_addr=", load_address); -+ -+#include <asm/mipsmtregs.h> -+#define write_vpe_c0_wired(val) mttc0(6, 0, val) -+ -+#ifndef COMMAND_LINE_SIZE -+# define COMMAND_LINE_SIZE 512 -+#endif -+ -+char command_line[COMMAND_LINE_SIZE * 2]; -+ -+static unsigned int vpe1_mem; -+static int __init vpe1mem(char *str) -+{ -+ vpe1_mem = memparse(str, &str); -+ return 1; -+} -+__setup("vpe1_mem=", vpe1mem); -+ -+uint32_t vpe1_wdog_ctr; -+static int __init wdog_ctr(char *str) -+{ -+ get_option(&str, &vpe1_wdog_ctr); -+ return 1; -+} -+ -+__setup("vpe1_wdog_ctr_addr=", wdog_ctr); -+EXPORT_SYMBOL(vpe1_wdog_ctr); -+ -+uint32_t vpe1_wdog_timeout; -+static int __init wdog_timeout(char *str) -+{ -+ get_option(&str, &vpe1_wdog_timeout); -+ return 1; -+} -+ -+__setup("vpe1_wdog_timeout=", wdog_timeout); -+EXPORT_SYMBOL(vpe1_wdog_timeout); -+ -+#endif - /* grab the likely amount of memory we will need. */ - #ifdef CONFIG_MIPS_VPE_LOADER_TOM - #define P_SIZE (2 * 1024 * 1024) -@@ -267,6 +319,13 @@ static void *alloc_progmem(unsigned long len) - void *addr; - - #ifdef CONFIG_MIPS_VPE_LOADER_TOM -+#ifdef CONFIG_IFX_VPE_EXT -+ if (vpe1_load_addr) { -+ memset((void *)vpe1_load_addr, 0, len); -+ return (void *)vpe1_load_addr; -+ } -+#endif -+ - /* - * This means you must tell Linux to use less memory than you - * physically have, for example by passing a mem= boot argument. -@@ -745,6 +804,12 @@ static int vpe_run(struct vpe * v) - } - - /* Write the address we want it to start running from in the TCPC register. */ -+#if defined(CONFIG_IFX_VPE_EXT) && 0 -+ if (stlb) -+ write_vpe_c0_wired(vpe0_wired + vpe1_wired); -+ else -+ write_vpe_c0_wired(vpe1_wired); -+#endif - write_tc_c0_tcrestart((unsigned long)v->__start); - write_tc_c0_tccontext((unsigned long)0); - -@@ -758,6 +823,20 @@ static int vpe_run(struct vpe * v) - - write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); - -+#if defined(CONFIG_IFX_VPE_EXT) && 0 -+ /* -+ * $a2 & $a3 are used to pass command line parameters to VPE1. $a2 -+ * points to the start of the command line string and $a3 points to -+ * the end of the string. This convention is identical to the Linux -+ * kernel boot parameter passing mechanism. Please note that $a3 is -+ * used to pass physical memory size or 0 in SDE tool kit. So, if you -+ * are passing comand line parameters through $a2 & $a3 SDE programs -+ * don't work as desired. -+ */ -+ mttgpr(6, command_line); -+ mttgpr(7, (command_line + strlen(command_line))); -+ if (is_sdepgm) -+#endif - /* - * The sde-kit passes 'memsize' to __start in $a3, so set something - * here... Or set $a3 to zero and define DFLT_STACK_SIZE and -@@ -832,6 +911,9 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, - if ( (v->__start == 0) || (v->shared_ptr == NULL)) - return -1; - -+#ifdef CONFIG_IFX_VPE_EXT -+ is_sdepgm = 1; -+#endif - return 0; - } - -@@ -993,6 +1075,15 @@ static int vpe_elfload(struct vpe * v) - (unsigned long)v->load_addr + v->len); - - if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { -+#ifdef CONFIG_IFX_VPE_EXT -+ if (vpe1_load_addr) { -+ /* Conversion to KSEG1 is required ??? */ -+ v->__start = KSEG1ADDR(vpe1_load_addr); -+ is_sdepgm = 0; -+ return 0; -+ } -+#endif -+ - if (v->__start == 0) { - printk(KERN_WARNING "VPE loader: program does not contain " - "a __start symbol\n"); -@@ -1063,6 +1154,9 @@ static int vpe_open(struct inode *inode, struct file *filp) - struct vpe_notifications *not; - struct vpe *v; - int ret; -+#ifdef CONFIG_IFX_VPE_EXT -+ int progsize; -+#endif - - if (minor != iminor(inode)) { - /* assume only 1 device at the moment. */ -@@ -1088,7 +1182,12 @@ static int vpe_open(struct inode *inode, struct file *filp) - release_progmem(v->load_addr); - cleanup_tc(get_tc(tclimit)); - } -- -+#ifdef CONFIG_IFX_VPE_EXT -+ progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; -+ //printk("progsize = %x\n", progsize); -+ v->pbuffer = vmalloc(progsize); -+ v->plen = progsize; -+#else - /* this of-course trashes what was there before... */ - v->pbuffer = vmalloc(P_SIZE); - if (!v->pbuffer) { -@@ -1096,11 +1195,14 @@ static int vpe_open(struct inode *inode, struct file *filp) - return -ENOMEM; - } - v->plen = P_SIZE; -+#endif - v->load_addr = NULL; - v->len = 0; - -+#if 0 - v->uid = filp->f_cred->fsuid; - v->gid = filp->f_cred->fsgid; -+#endif - - #ifdef CONFIG_MIPS_APSP_KSPD - /* get kspd to tell us when a syscall_exit happens */ -@@ -1348,6 +1450,133 @@ static void kspd_sp_exit( int sp_id) - cleanup_tc(get_tc(sp_id)); - } - #endif -+#ifdef CONFIG_IFX_VPE_EXT -+int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags) -+{ -+ enum vpe_state state; -+ struct vpe *v = get_vpe(tclimit); -+ struct vpe_notifications *not; -+ -+ if (tcmask || flags) { -+ printk(KERN_WARNING "Currently tcmask and flags should be 0.\ -+ other values not supported\n"); -+ return -1; -+ } -+ -+ state = xchg(&v->state, VPE_STATE_INUSE); -+ if (state != VPE_STATE_UNUSED) { -+ vpe_stop(v); -+ -+ list_for_each_entry(not, &v->notify, list) { -+ not->stop(tclimit); -+ } -+ } -+ -+ v->__start = (unsigned long)sw_start_addr; -+ is_sdepgm = 0; -+ -+ if (!vpe_run(v)) { -+ printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n"); -+ return 0; -+ } -+ return -1; -+} -+ -+EXPORT_SYMBOL(vpe1_sw_start); -+ -+int32_t vpe1_sw_stop(uint32_t flags) -+{ -+ struct vpe *v = get_vpe(tclimit); -+ -+ if (!vpe_free(v)) { -+ printk(KERN_DEBUG "RP Stopped\n"); -+ return 0; -+ } -+ else -+ return -1; -+} -+ -+EXPORT_SYMBOL(vpe1_sw_stop); -+ -+uint32_t vpe1_get_load_addr (uint32_t flags) -+{ -+ return vpe1_load_addr; -+} -+ -+EXPORT_SYMBOL(vpe1_get_load_addr); -+ -+uint32_t vpe1_get_max_mem (uint32_t flags) -+{ -+ if (!vpe1_mem) -+ return P_SIZE; -+ else -+ return vpe1_mem; -+} -+ -+EXPORT_SYMBOL(vpe1_get_max_mem); -+ -+void* vpe1_get_cmdline_argument(void) -+{ -+ return saved_command_line; -+} -+ -+EXPORT_SYMBOL(vpe1_get_cmdline_argument); -+ -+int32_t vpe1_set_boot_param(char *field, char *value, char flags) -+{ -+ char *ptr, string[64]; -+ int start_off, end_off; -+ if (!field) -+ return -1; -+ strcpy(string, field); -+ if (value) { -+ strcat(string, "="); -+ strcat(string, value); -+ strcat(command_line, " "); -+ strcat(command_line, string); -+ } -+ else { -+ ptr = strstr(command_line, string); -+ if (ptr) { -+ start_off = ptr - command_line; -+ ptr += strlen(string); -+ while ((*ptr != ' ') && (*ptr != '\0')) -+ ptr++; -+ end_off = ptr - command_line; -+ command_line[start_off] = '\0'; -+ strcat (command_line, command_line+end_off); -+ } -+ } -+ return 0; -+} -+ -+EXPORT_SYMBOL(vpe1_set_boot_param); -+ -+int32_t vpe1_get_boot_param(char *field, char **value, char flags) -+{ -+ char *ptr, string[64]; -+ int i = 0; -+ if (!field) -+ return -1; -+ if ((ptr = strstr(command_line, field))) { -+ ptr += strlen(field) + 1; /* including = */ -+ while ((*ptr != ' ') && (*ptr != '\0')) -+ string[i++] = *ptr++; -+ string[i] = '\0'; -+ *value = kmalloc((strlen(string) + 1), GFP_KERNEL); -+ if (*value != NULL) -+ strcpy(*value, string); -+ } -+ else -+ *value = NULL; -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL(vpe1_get_boot_param); -+ -+extern void configure_tlb(void); -+#endif - - static ssize_t store_kill(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -@@ -1429,6 +1658,18 @@ static int __init vpe_module_init(void) - printk("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } -+#ifdef CONFIG_IFX_VPE_EXT -+#ifndef CONFIG_MIPS_MT_SMTC -+ configure_tlb(); -+#endif -+#endif -+ -+#ifndef CONFIG_MIPS_MT_SMTC -+ if (!vpelimit) -+ vpelimit = 1; -+ if (!tclimit) -+ tclimit = 1; -+#endif - - if (vpelimit == 0) { - printk(KERN_WARNING "No VPEs reserved for AP/SP, not " -@@ -1473,10 +1714,12 @@ static int __init vpe_module_init(void) - mtflags = dmt(); - vpflags = dvpe(); - -+ back_to_back_c0_hazard(); -+ - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - -- /* dump_mtregs(); */ -+ dump_mtregs(); - - val = read_c0_mvpconf0(); - hw_tcs = (val & MVPCONF0_PTC) + 1; -@@ -1488,6 +1731,7 @@ static int __init vpe_module_init(void) - * reschedule send IPIs or similar we might hang. - */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); -+ back_to_back_c0_hazard(); - evpe(vpflags); - emt(mtflags); - local_irq_restore(flags); -@@ -1513,6 +1757,7 @@ static int __init vpe_module_init(void) - } - - v->ntcs = hw_tcs - tclimit; -+ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); - - /* add the tc to the list of this vpe's tc's. */ - list_add(&t->tc, &v->tc); -@@ -1581,6 +1826,7 @@ static int __init vpe_module_init(void) - out_reenable: - /* release config state */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); -+ back_to_back_c0_hazard(); - - evpe(vpflags); - emt(mtflags); --- -1.7.9.1 - |