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

