[OpenWrt-Devel] [PATCH 03/11] BB: lantiq: falcon/vr9 - add support for vpe1

Eddi De Pieri eddi at depieri.net
Fri Oct 31 09:08:54 EDT 2014


(required not-distributable firmware blob - dump it by yourself from original firmware)

Signed-off-by: Eddi De Pieri <eddi at depieri.net>
---
 .../lantiq/patches-3.10/0152-VPE-extensions.patch  | 1358 ++++++++++++++++++++
 1 file changed, 1358 insertions(+)
 create mode 100644 target/linux/lantiq/patches-3.10/0152-VPE-extensions.patch

diff --git a/target/linux/lantiq/patches-3.10/0152-VPE-extensions.patch b/target/linux/lantiq/patches-3.10/0152-VPE-extensions.patch
new file mode 100644
index 0000000..2ecd461
--- /dev/null
+++ b/target/linux/lantiq/patches-3.10/0152-VPE-extensions.patch
@@ -0,0 +1,1358 @@
+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();
++	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 -u -N -r linux-3.10.49.orig/arch/mips/kernel/proc.c linux-3.10.49/arch/mips/kernel/proc.c
+--- linux-3.10.49.orig/arch/mips/kernel/proc.c	2014-10-15 21:41:48.000000000 +0200
++++ linux-3.10.49/arch/mips/kernel/proc.c	2014-10-15 21:44:25.000000000 +0200
+@@ -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>
+@@ -142,3 +143,19 @@
+ 	.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 -u -N -r linux-3.10.49.orig/arch/mips/kernel/prom.c linux-3.10.49/arch/mips/kernel/prom.c
+--- linux-3.10.49.orig/arch/mips/kernel/prom.c	2014-10-15 21:41:48.000000000 +0200
++++ linux-3.10.49/arch/mips/kernel/prom.c	2014-10-15 21:45:47.000000000 +0200
+@@ -39,6 +39,8 @@
+ 	return mips_machine_name;
+ }
+ 
++unsigned long physical_memsize = 0L;
++
+ #ifdef CONFIG_OF
+ int __init early_init_dt_scan_memory_arch(unsigned long node,
+ 					  const char *uname, int depth,
+@@ -50,6 +52,7 @@
+ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+ {
+ 	return add_memory_region(base, size, BOOT_MEM_RAM);
++	physical_memsize = size;
+ }
+ 
+ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/smtc.c linux-3.10.49/arch/mips/kernel/smtc.c
+--- linux-3.10.49.orig/arch/mips/kernel/smtc.c	2014-10-15 21:41:48.000000000 +0200
++++ linux-3.10.49/arch/mips/kernel/smtc.c	2014-10-15 21:44:25.000000000 +0200
+@@ -1394,6 +1394,13 @@
+ 	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 -u -N -r linux-3.10.49.orig/arch/mips/kernel/vpe.c linux-3.10.49/arch/mips/kernel/vpe.c
+--- linux-3.10.49.orig/arch/mips/kernel/vpe.c	2014-10-15 21:41:48.000000000 +0200
++++ linux-3.10.49/arch/mips/kernel/vpe.c	2014-10-15 21:54:34.000000000 +0200
+@@ -68,6 +68,58 @@
+ static int major;
+ static const int minor = 1;	/* fixed for now  */
+ 
++#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)
+@@ -260,6 +312,13 @@
+ 	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.
+@@ -729,6 +788,12 @@
+ 	}
+ 
+ 	/* 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);
+ 
+@@ -742,6 +807,20 @@
+ 
+ 	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
+@@ -816,6 +895,9 @@
+ 	if ( (v->__start == 0) || (v->shared_ptr == NULL))
+ 		return -1;
+ 
++#ifdef CONFIG_IFX_VPE_EXT
++	is_sdepgm = 1;
++#endif
+ 	return 0;
+ }
+ 
+@@ -977,6 +1059,15 @@
+ 			   (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");
+@@ -1047,6 +1138,9 @@
+ 	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. */
+@@ -1072,7 +1166,12 @@
+ 		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) {
+@@ -1080,11 +1179,14 @@
+ 		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
+ 
+ 	v->cwd[0] = 0;
+ 	ret = getcwd(v->cwd, VPE_PATH_MAX);
+@@ -1318,6 +1420,134 @@
+ 
+ EXPORT_SYMBOL(vpe_getcwd);
+ 
++#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)
+ {
+@@ -1398,6 +1628,18 @@
+ 		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 "
+@@ -1442,10 +1684,12 @@
+ 	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;
+@@ -1457,6 +1701,7 @@
+ 		 * 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);
+@@ -1482,6 +1727,7 @@
+ 			}
+ 
+ 			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);
+@@ -1550,6 +1796,7 @@
+ out_reenable:
+ 	/* release config state */
+ 	clear_c0_mvpcontrol(MVPCONTROL_VPC);
++	back_to_back_c0_hazard();
+ 
+ 	evpe(vpflags);
+ 	emt(mtflags);
+diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/vpe.c.patched linux-3.10.49/arch/mips/kernel/vpe.c.patched
+diff -u -N -r linux-3.10.49.orig/arch/mips/kernel/vpe.h linux-3.10.49/arch/mips/kernel/vpe.h
+--- linux-3.10.49.orig/arch/mips/kernel/vpe.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.49/arch/mips/kernel/vpe.h	2014-10-15 21:44:25.000000000 +0200
+@@ -0,0 +1,130 @@
++/*
++ * 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) 2005 MIPS Technologies, Inc.  All rights reserved.
++ * Copyright (C) 2013 Imagination Technologies Ltd.
++ */
++#ifndef _ASM_VPE_H
++#define _ASM_VPE_H
++
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/smp.h>
++#include <linux/spinlock.h>
++
++#define VPE_MODULE_NAME "vpe"
++#define VPE_MODULE_MINOR 1
++
++/* grab the likely amount of memory we will need. */
++#ifdef CONFIG_MIPS_VPE_LOADER_TOM
++#define P_SIZE (2 * 1024 * 1024)
++#else
++/* add an overhead to the max kmalloc size for non-striped symbols/etc */
++#define P_SIZE (256 * 1024)
++#endif
++
++#define MAX_VPES 16
++#define VPE_PATH_MAX 256
++
++static inline int aprp_cpu_index(void)
++{
++#ifdef CONFIG_MIPS_CMP
++	return setup_max_cpus;
++#else
++	extern int tclimit;
++	return tclimit;
++#endif
++}
++
++enum vpe_state {
++	VPE_STATE_UNUSED = 0,
++	VPE_STATE_INUSE,
++	VPE_STATE_RUNNING
++};
++
++enum tc_state {
++	TC_STATE_UNUSED = 0,
++	TC_STATE_INUSE,
++	TC_STATE_RUNNING,
++	TC_STATE_DYNAMIC
++};
++
++struct vpe {
++	enum vpe_state state;
++
++	/* (device) minor associated with this vpe */
++	int minor;
++
++	/* elfloader stuff */
++	void *load_addr;
++	unsigned long len;
++	char *pbuffer;
++	unsigned long plen;
++	char cwd[VPE_PATH_MAX];
++
++	unsigned long __start;
++
++	/* tc's associated with this vpe */
++	struct list_head tc;
++
++	/* The list of vpe's */
++	struct list_head list;
++
++	/* shared symbol address */
++	void *shared_ptr;
++
++	/* the list of who wants to know when something major happens */
++	struct list_head notify;
++
++	unsigned int ntcs;
++};
++
++struct tc {
++	enum tc_state state;
++	int index;
++
++	struct vpe *pvpe;	/* parent VPE */
++	struct list_head tc;	/* The list of TC's with this VPE */
++	struct list_head list;	/* The global list of tc's */
++};
++
++struct vpe_notifications {
++	void (*start)(int vpe);
++	void (*stop)(int vpe);
++
++	struct list_head list;
++};
++
++struct vpe_control {
++	spinlock_t vpe_list_lock;
++	struct list_head vpe_list;      /* Virtual processing elements */
++	spinlock_t tc_list_lock;
++	struct list_head tc_list;       /* Thread contexts */
++};
++
++extern unsigned long physical_memsize;
++extern struct vpe_control vpecontrol;
++extern const struct file_operations vpe_fops;
++
++int vpe_notify(int index, struct vpe_notifications *notify);
++
++void *vpe_get_shared(int index);
++char *vpe_getcwd(int index);
++
++struct vpe *get_vpe(int minor);
++struct tc *get_tc(int index);
++struct vpe *alloc_vpe(int minor);
++struct tc *alloc_tc(int index);
++void release_vpe(struct vpe *v);
++
++void *alloc_progmem(unsigned long len);
++void release_progmem(void *ptr);
++
++int __weak vpe_run(struct vpe *v);
++void cleanup_tc(struct tc *tc);
++
++int __init vpe_module_init(void);
++void __exit vpe_module_exit(void);
++#endif /* _ASM_VPE_H */
+diff -u -N -r linux-3.10.49.orig/arch/mips/lantiq/prom.c linux-3.10.49/arch/mips/lantiq/prom.c
+--- linux-3.10.49.orig/arch/mips/lantiq/prom.c	2014-10-15 21:41:48.000000000 +0200
++++ linux-3.10.49/arch/mips/lantiq/prom.c	2014-10-15 21:44:39.000000000 +0200
+@@ -30,6 +30,10 @@
+  */
+ static struct ltq_soc_info soc_info;
+ 
++/* for Multithreading (APRP), vpe.c will use it */
++//unsigned long physical_memsize = 0;
++unsigned long cp0_memsize = 0;
++
+ const char *get_system_type(void)
+ {
+ 	return soc_info.sys_type;
-- 
1.7.10.4
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list