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 + + 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 : <0/1> \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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * /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 + #include + #include ++#include + #include + #include + #include +@@ -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 ++#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 ++#include ++#include ++#include ++ ++#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;