diff options
Diffstat (limited to 'include/asm-mips')
48 files changed, 1560 insertions, 228 deletions
diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h index 42520cc84b0..1386af1cb7d 100644 --- a/include/asm-mips/addrspace.h +++ b/include/asm-mips/addrspace.h @@ -129,6 +129,7 @@ #if defined (CONFIG_CPU_R4300) \ || defined (CONFIG_CPU_R4X00) \ || defined (CONFIG_CPU_R5000) \ + || defined (CONFIG_CPU_RM7000) \ || defined (CONFIG_CPU_NEVADA) \ || defined (CONFIG_CPU_TX49XX) \ || defined (CONFIG_CPU_MIPS64) diff --git a/include/asm-mips/asmmacro.h b/include/asm-mips/asmmacro.h index 30b18ea6cb1..f54aa147ec1 100644 --- a/include/asm-mips/asmmacro.h +++ b/include/asm-mips/asmmacro.h @@ -17,7 +17,26 @@ #ifdef CONFIG_64BIT #include <asm/asmmacro-64.h> #endif +#ifdef CONFIG_MIPS_MT_SMTC +#include <asm/mipsmtregs.h> +#endif +#ifdef CONFIG_MIPS_MT_SMTC + .macro local_irq_enable reg=t0 + mfc0 \reg, CP0_TCSTATUS + ori \reg, \reg, TCSTATUS_IXMT + xori \reg, \reg, TCSTATUS_IXMT + mtc0 \reg, CP0_TCSTATUS + ehb + .endm + + .macro local_irq_disable reg=t0 + mfc0 \reg, CP0_TCSTATUS + ori \reg, \reg, TCSTATUS_IXMT + mtc0 \reg, CP0_TCSTATUS + ehb + .endm +#else .macro local_irq_enable reg=t0 mfc0 \reg, CP0_STATUS ori \reg, \reg, 1 @@ -32,6 +51,7 @@ mtc0 \reg, CP0_STATUS irq_disable_hazard .endm +#endif /* CONFIG_MIPS_MT_SMTC */ #ifdef CONFIG_CPU_SB1 .macro fpu_enable_hazard @@ -48,4 +68,31 @@ .endm #endif +/* + * Temporary until all gas have MT ASE support + */ + .macro DMT reg=0 + .word (0x41600bc1 | (\reg << 16)) + .endm + + .macro EMT reg=0 + .word (0x41600be1 | (\reg << 16)) + .endm + + .macro DVPE reg=0 + .word (0x41600001 | (\reg << 16)) + .endm + + .macro EVPE reg=0 + .word (0x41600021 | (\reg << 16)) + .endm + + .macro MFTR rt=0, rd=0, u=0, sel=0 + .word (0x41000000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)) + .endm + + .macro MTTR rt=0, rd=0, u=0, sel=0 + .word (0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)) + .endm + #endif /* _ASM_ASMMACRO_H */ diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index a1728f8c070..d2f444537e4 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -467,64 +467,56 @@ static inline unsigned long __ffs(unsigned long word) } /* - * ffs - find first bit set. + * fls - find last bit set. * @word: The word to search * - * Returns 1..SZLONG - * Returns 0 if no bit exists + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. */ - -static inline unsigned long ffs(unsigned long word) +static inline int fls(int word) { - if (!word) - return 0; + __asm__ ("clz %0, %1" : "=r" (word) : "r" (word)); - return __ffs(word) + 1; + return 32 - word; } -/* - * ffz - find first zero in word. - * @word: The word to search - * - * Undefined if no zero exists, so code should check against ~0UL first. - */ -static inline unsigned long ffz(unsigned long word) +#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64) +static inline int fls64(__u64 word) { - return __ffs (~word); + __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word)); + + return 64 - word; } +#else +#include <asm-generic/bitops/fls64.h> +#endif /* - * fls - find last bit set. + * ffs - find first bit set. * @word: The word to search * - * Returns 1..SZLONG - * Returns 0 if no bit exists + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). */ -static inline unsigned long fls(unsigned long word) +static inline int ffs(int word) { -#ifdef CONFIG_CPU_MIPS32 - __asm__ ("clz %0, %1" : "=r" (word) : "r" (word)); - - return 32 - word; -#endif - -#ifdef CONFIG_CPU_MIPS64 - __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word)); + if (!word) + return 0; - return 64 - word; -#endif + return fls(word & -word); } #else #include <asm-generic/bitops/__ffs.h> #include <asm-generic/bitops/ffs.h> -#include <asm-generic/bitops/ffz.h> #include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/fls64.h> #endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */ -#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/ffz.h> #include <asm-generic/bitops/find.h> #ifdef __KERNEL__ diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index aeae9fabf4a..47bc8f6c20d 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h @@ -74,6 +74,7 @@ static inline void copy_from_user_page(struct vm_area_struct *vma, extern void (*flush_cache_sigtramp)(unsigned long addr); extern void (*flush_icache_all)(void); +extern void (*local_flush_data_cache_page)(void * addr); extern void (*flush_data_cache_page)(unsigned long addr); /* diff --git a/include/asm-mips/cpu-features.h b/include/asm-mips/cpu-features.h index 3f2b6d9ac45..254e11ed247 100644 --- a/include/asm-mips/cpu-features.h +++ b/include/asm-mips/cpu-features.h @@ -40,7 +40,7 @@ #define cpu_has_sb1_cache (cpu_data[0].options & MIPS_CPU_SB1_CACHE) #endif #ifndef cpu_has_fpu -#define cpu_has_fpu (cpu_data[0].options & MIPS_CPU_FPU) +#define cpu_has_fpu (current_cpu_data.options & MIPS_CPU_FPU) #endif #ifndef cpu_has_32fpr #define cpu_has_32fpr (cpu_data[0].options & MIPS_CPU_32FPR) diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h index 140be1c67da..6572ac70366 100644 --- a/include/asm-mips/cpu-info.h +++ b/include/asm-mips/cpu-info.h @@ -73,6 +73,16 @@ struct cpuinfo_mips { struct cache_desc dcache; /* Primary D or combined I/D cache */ struct cache_desc scache; /* Secondary cache */ struct cache_desc tcache; /* Tertiary/split secondary cache */ +#if defined(CONFIG_MIPS_MT_SMTC) + /* + * In the MIPS MT "SMTC" model, each TC is considered + * to be a "CPU" for the purposes of scheduling, but + * exception resources, ASID spaces, etc, are common + * to all TCs within the same VPE. + */ + int vpe_id; /* Virtual Processor number */ + int tc_id; /* Thread Context number */ +#endif /* CONFIG_MIPS_MT */ void *data; /* Additional data */ } __attribute__((aligned(SMP_CACHE_BYTES))); diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h index 818b9a97e21..dff2a0a52f8 100644 --- a/include/asm-mips/cpu.h +++ b/include/asm-mips/cpu.h @@ -51,6 +51,7 @@ #define PRID_IMP_R4300 0x0b00 #define PRID_IMP_VR41XX 0x0c00 #define PRID_IMP_R12000 0x0e00 +#define PRID_IMP_R14000 0x0f00 #define PRID_IMP_R8000 0x1000 #define PRID_IMP_PR4450 0x1200 #define PRID_IMP_R4600 0x2000 @@ -87,6 +88,7 @@ #define PRID_IMP_24K 0x9300 #define PRID_IMP_34K 0x9500 #define PRID_IMP_24KE 0x9600 +#define PRID_IMP_74K 0x9700 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -196,7 +198,9 @@ #define CPU_34K 60 #define CPU_PR4450 61 #define CPU_SB1A 62 -#define CPU_LAST 62 +#define CPU_74K 63 +#define CPU_R14000 64 +#define CPU_LAST 64 /* * ISA Level encodings diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index 64dd45150f6..928f30f8c45 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -19,20 +19,22 @@ static inline void __delay(unsigned long loops) { if (sizeof(long) == 4) __asm__ __volatile__ ( - ".set\tnoreorder\n" - "1:\tbnez\t%0,1b\n\t" - "subu\t%0,1\n\t" - ".set\treorder" + " .set noreorder \n" + " .align 3 \n" + "1: bnez %0, 1b \n" + " subu %0, 1 \n" + " .set reorder \n" : "=r" (loops) : "0" (loops)); else if (sizeof(long) == 8) __asm__ __volatile__ ( - ".set\tnoreorder\n" - "1:\tbnez\t%0,1b\n\t" - "dsubu\t%0,1\n\t" - ".set\treorder" - :"=r" (loops) - :"0" (loops)); + " .set noreorder \n" + " .align 3 \n" + "1: bnez %0, 1b \n" + " dsubu %0, 1 \n" + " .set reorder \n" + : "=r" (loops) + : "0" (loops)); } diff --git a/include/asm-mips/ds1742.h b/include/asm-mips/ds1742.h new file mode 100644 index 00000000000..c2f2c32da63 --- /dev/null +++ b/include/asm-mips/ds1742.h @@ -0,0 +1,13 @@ +/* + * 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) 2006 by Ralf Baechle (ralf@linux-mips.org) + */ +#ifndef _ASM_DS1742_H +#define _ASM_DS1742_H + +#include <ds1742.h> + +#endif /* _ASM_DS1742_H */ diff --git a/include/asm-mips/elf.h b/include/asm-mips/elf.h index 851f013adad..bdc9de2df1e 100644 --- a/include/asm-mips/elf.h +++ b/include/asm-mips/elf.h @@ -119,8 +119,49 @@ #define SHT_MIPS_CONFLICT 0x70000002 #define SHT_MIPS_GPTAB 0x70000003 #define SHT_MIPS_UCODE 0x70000004 - -#define SHF_MIPS_GPREL 0x10000000 +#define SHT_MIPS_DEBUG 0x70000005 +#define SHT_MIPS_REGINFO 0x70000006 +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +#define SHF_MIPS_GPREL 0x10000000 +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRING 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPES 0x01000000 #ifndef ELF_ARCH /* ELF register definitions */ diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index 9c828b1f821..b0f50015e25 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h @@ -21,6 +21,10 @@ #include <asm/processor.h> #include <asm/current.h> +#ifdef CONFIG_MIPS_MT_FPAFF +#include <asm/mips_mt.h> +#endif + struct sigcontext; struct sigcontext32; diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index a554089991f..12d118f1bc9 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -7,6 +7,7 @@ #include <linux/futex.h> #include <asm/errno.h> #include <asm/uaccess.h> +#include <asm/war.h> #ifdef CONFIG_SMP #define __FUTEX_SMP_SYNC " sync \n" @@ -16,30 +17,58 @@ #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " .set mips3 \n" \ - "1: ll %1, (%3) # __futex_atomic_op1 \n" \ - " .set mips0 \n" \ - " " insn " \n" \ - " .set mips3 \n" \ - "2: sc $1, (%3) \n" \ - " beqzl $1, 1b \n" \ - __FUTEX_SMP_SYNC \ - "3: \n" \ - " .set pop \n" \ - " .set mips0 \n" \ - " .section .fixup,\"ax\" \n" \ - "4: li %0, %5 \n" \ - " j 2b \n" \ - " .previous \n" \ - " .section __ex_table,\"a\" \n" \ - " "__UA_ADDR "\t1b, 4b \n" \ - " "__UA_ADDR "\t2b, 4b \n" \ - " .previous \n" \ - : "=r" (ret), "=r" (oldval) \ - : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + if (cpu_has_llsc && R10000_LLSC_WAR) { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips3 \n" \ + "1: ll %1, (%3) # __futex_atomic_op \n" \ + " .set mips0 \n" \ + " " insn " \n" \ + " .set mips3 \n" \ + "2: sc $1, (%3) \n" \ + " beqzl $1, 1b \n" \ + __FUTEX_SMP_SYNC \ + "3: \n" \ + " .set pop \n" \ + " .set mips0 \n" \ + " .section .fixup,\"ax\" \n" \ + "4: li %0, %5 \n" \ + " j 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__UA_ADDR "\t1b, 4b \n" \ + " "__UA_ADDR "\t2b, 4b \n" \ + " .previous \n" \ + : "=r" (ret), "=r" (oldval) \ + : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + } else if (cpu_has_llsc) { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips3 \n" \ + "1: ll %1, (%3) # __futex_atomic_op \n" \ + " .set mips0 \n" \ + " " insn " \n" \ + " .set mips3 \n" \ + "2: sc $1, (%3) \n" \ + " beqz $1, 1b \n" \ + __FUTEX_SMP_SYNC \ + "3: \n" \ + " .set pop \n" \ + " .set mips0 \n" \ + " .section .fixup,\"ax\" \n" \ + "4: li %0, %5 \n" \ + " j 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__UA_ADDR "\t1b, 4b \n" \ + " "__UA_ADDR "\t2b, 4b \n" \ + " .previous \n" \ + : "=r" (ret), "=r" (oldval) \ + : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + } else \ + ret = -ENOSYS; \ } static inline int @@ -102,7 +131,69 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) { - return -ENOSYS; + int retval; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + if (cpu_has_llsc && R10000_LLSC_WAR) { + __asm__ __volatile__( + "# futex_atomic_cmpxchg_inatomic \n" + " .set push \n" + " .set noat \n" + " .set mips3 \n" + "1: ll %0, %2 \n" + " bne %0, %z3, 3f \n" + " .set mips0 \n" + " move $1, %z4 \n" + " .set mips3 \n" + "2: sc $1, %1 \n" + " beqzl $1, 1b \n" + __FUTEX_SMP_SYNC + "3: \n" + " .set pop \n" + " .section .fixup,\"ax\" \n" + "4: li %0, %5 \n" + " j 3b \n" + " .previous \n" + " .section __ex_table,\"a\" \n" + " "__UA_ADDR "\t1b, 4b \n" + " "__UA_ADDR "\t2b, 4b \n" + " .previous \n" + : "=&r" (retval), "=R" (*uaddr) + : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "memory"); + } else if (cpu_has_llsc) { + __asm__ __volatile__( + "# futex_atomic_cmpxchg_inatomic \n" + " .set push \n" + " .set noat \n" + " .set mips3 \n" + "1: ll %0, %2 \n" + " bne %0, %z3, 3f \n" + " .set mips0 \n" + " move $1, %z4 \n" + " .set mips3 \n" + "2: sc $1, %1 \n" + " beqz $1, 1b \n" + __FUTEX_SMP_SYNC + "3: \n" + " .set pop \n" + " .section .fixup,\"ax\" \n" + "4: li %0, %5 \n" + " j 3b \n" + " .previous \n" + " .section __ex_table,\"a\" \n" + " "__UA_ADDR "\t1b, 4b \n" + " "__UA_ADDR "\t2b, 4b \n" + " .previous \n" + : "=&r" (retval), "=R" (*uaddr) + : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "memory"); + } else + return -ENOSYS; + + return retval; } #endif diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h index feb29a79388..dadc05188db 100644 --- a/include/asm-mips/hazards.h +++ b/include/asm-mips/hazards.h @@ -284,6 +284,8 @@ do { \ #define instruction_hazard() do { } while (0) #endif +extern void mips_ihb(void); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_HAZARDS_H */ diff --git a/include/asm-mips/inst.h b/include/asm-mips/inst.h index e0745f4ff62..1ed8d0f6257 100644 --- a/include/asm-mips/inst.h +++ b/include/asm-mips/inst.h @@ -6,6 +6,7 @@ * for more details. * * Copyright (C) 1996, 2000 by Ralf Baechle + * Copyright (C) 2006 by Thiemo Seufer */ #ifndef _ASM_INST_H #define _ASM_INST_H @@ -21,14 +22,14 @@ enum major_op { cop0_op, cop1_op, cop2_op, cop1x_op, beql_op, bnel_op, blezl_op, bgtzl_op, daddi_op, daddiu_op, ldl_op, ldr_op, - major_1c_op, jalx_op, major_1e_op, major_1f_op, + spec2_op, jalx_op, mdmx_op, spec3_op, lb_op, lh_op, lwl_op, lw_op, lbu_op, lhu_op, lwr_op, lwu_op, sb_op, sh_op, swl_op, sw_op, sdl_op, sdr_op, swr_op, cache_op, ll_op, lwc1_op, lwc2_op, pref_op, lld_op, ldc1_op, ldc2_op, ld_op, - sc_op, swc1_op, swc2_op, rdhwr_op, + sc_op, swc1_op, swc2_op, major_3b_op, scd_op, sdc1_op, sdc2_op, sd_op }; @@ -37,7 +38,7 @@ enum major_op { */ enum spec_op { sll_op, movc_op, srl_op, sra_op, - sllv_op, srlv_op, srav_op, spec1_unused_op, /* Opcode 0x07 is unused */ + sllv_op, pmon_op, srlv_op, srav_op, jr_op, jalr_op, movz_op, movn_op, syscall_op, break_op, spim_op, sync_op, mfhi_op, mthi_op, mflo_op, mtlo_op, @@ -55,6 +56,28 @@ enum spec_op { }; /* + * func field of spec2 opcode. + */ +enum spec2_op { + madd_op, maddu_op, mul_op, spec2_3_unused_op, + msub_op, msubu_op, /* more unused ops */ + clz_op = 0x20, clo_op, + dclz_op = 0x24, dclo_op, + sdbpp_op = 0x3f +}; + +/* + * func field of spec3 opcode. + */ +enum spec3_op { + ext_op, dextm_op, dextu_op, dext_op, + ins_op, dinsm_op, dinsu_op, dins_op, + bshfl_op = 0x20, + dbshfl_op = 0x24, + rdhwr_op = 0x3f +}; + +/* * rt field of bcond opcodes. */ enum rt_op { @@ -151,8 +174,8 @@ enum cop1x_func { * func field for mad opcodes (MIPS IV). */ enum mad_func { - madd_op = 0x08, msub_op = 0x0a, - nmadd_op = 0x0c, nmsub_op = 0x0e + madd_fp_op = 0x08, msub_fp_op = 0x0a, + nmadd_fp_op = 0x0c, nmsub_fp_op = 0x0e }; /* diff --git a/include/asm-mips/interrupt.h b/include/asm-mips/interrupt.h index 774348734fa..4bb9c06f441 100644 --- a/include/asm-mips/interrupt.h +++ b/include/asm-mips/interrupt.h @@ -19,7 +19,12 @@ __asm__ ( " .set push \n" " .set reorder \n" " .set noat \n" -#ifdef CONFIG_CPU_MIPSR2 +#ifdef CONFIG_MIPS_MT_SMTC + " mfc0 $1, $2, 1 # SMTC - clear TCStatus.IXMT \n" + " ori $1, 0x400 \n" + " xori $1, 0x400 \n" + " mtc0 $1, $2, 1 \n" +#elif defined(CONFIG_CPU_MIPSR2) " ei \n" #else " mfc0 $1,$12 \n" @@ -62,7 +67,12 @@ __asm__ ( " .macro local_irq_disable\n" " .set push \n" " .set noat \n" -#ifdef CONFIG_CPU_MIPSR2 +#ifdef CONFIG_MIPS_MT_SMTC + " mfc0 $1, $2, 1 \n" + " ori $1, 0x400 \n" + " .set noreorder \n" + " mtc0 $1, $2, 1 \n" +#elif defined(CONFIG_CPU_MIPSR2) " di \n" #else " mfc0 $1,$12 \n" @@ -88,7 +98,11 @@ __asm__ ( " .macro local_save_flags flags \n" " .set push \n" " .set reorder \n" +#ifdef CONFIG_MIPS_MT_SMTC + " mfc0 \\flags, $2, 1 \n" +#else " mfc0 \\flags, $12 \n" +#endif " .set pop \n" " .endm \n"); @@ -102,7 +116,13 @@ __asm__ ( " .set push \n" " .set reorder \n" " .set noat \n" -#ifdef CONFIG_CPU_MIPSR2 +#ifdef CONFIG_MIPS_MT_SMTC + " mfc0 \\result, $2, 1 \n" + " ori $1, \\result, 0x400 \n" + " .set noreorder \n" + " mtc0 $1, $2, 1 \n" + " andi \\result, \\result, 0x400 \n" +#elif defined(CONFIG_CPU_MIPSR2) " di \\result \n" " andi \\result, 1 \n" #else @@ -128,7 +148,14 @@ __asm__ ( " .set push \n" " .set noreorder \n" " .set noat \n" -#if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) +#ifdef CONFIG_MIPS_MT_SMTC + "mfc0 $1, $2, 1 \n" + "andi \\flags, 0x400 \n" + "ori $1, 0x400 \n" + "xori $1, 0x400 \n" + "or \\flags, $1 \n" + "mtc0 \\flags, $2, 1 \n" +#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) /* * Slow, but doesn't suffer from a relativly unlikely race * condition we're having since days 1. @@ -167,11 +194,29 @@ do { \ : "memory"); \ } while(0) -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - !(flags & 1); \ -}) +static inline int irqs_disabled(void) +{ +#ifdef CONFIG_MIPS_MT_SMTC + /* + * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU + */ + unsigned long __result; + + __asm__ __volatile__( + " .set noreorder \n" + " mfc0 %0, $2, 1 \n" + " andi %0, 0x400 \n" + " slt %0, $0, %0 \n" + " .set reorder \n" + : "=r" (__result)); + + return __result; +#else + unsigned long flags; + local_save_flags(flags); + + return !(flags & 1); +#endif +} #endif /* _ASM_INTERRUPT_H */ diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index 8a342ccb34a..dde677f02bc 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -11,6 +11,9 @@ #include <linux/config.h> #include <linux/linkage.h> + +#include <asm/mipsmtregs.h> + #include <irq.h> #ifdef CONFIG_I8259 @@ -26,6 +29,23 @@ struct pt_regs; extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs); +#ifdef CONFIG_MIPS_MT_SMTC +/* + * Clear interrupt mask handling "backstop" if irq_hwmask + * entry so indicates. This implies that the ack() or end() + * functions will take over re-enabling the low-level mask. + * Otherwise it will be done on return from exception. + */ +#define __DO_IRQ_SMTC_HOOK() \ +do { \ + if (irq_hwmask[irq] & 0x0000ff00) \ + write_c0_tccontext(read_c0_tccontext() & \ + ~(irq_hwmask[irq] & 0x0000ff00)); \ +} while (0) +#else +#define __DO_IRQ_SMTC_HOOK() do { } while (0) +#endif + #ifdef CONFIG_PREEMPT /* @@ -39,6 +59,7 @@ extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs); #define do_IRQ(irq, regs) \ do { \ irq_enter(); \ + __DO_IRQ_SMTC_HOOK(); \ __do_IRQ((irq), (regs)); \ irq_exit(); \ } while (0) @@ -46,5 +67,14 @@ do { \ #endif extern void arch_init_irq(void); +extern void spurious_interrupt(struct pt_regs *regs); + +#ifdef CONFIG_MIPS_MT_SMTC +struct irqaction; + +extern unsigned long irq_hwmask[]; +extern int setup_irq_smtc(unsigned int irq, struct irqaction * new, + unsigned long hwmask); +#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* _ASM_IRQ_H */ diff --git a/include/asm-mips/kspd.h b/include/asm-mips/kspd.h new file mode 100644 index 00000000000..4e9e724c893 --- /dev/null +++ b/include/asm-mips/kspd.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef _ASM_KSPD_H +#define _ASM_KSPD_H + +struct kspd_notifications { + void (*kspd_sp_exit)(int sp_id); + + struct list_head list; +}; + +#ifdef CONFIG_MIPS_APSP_KSPD +extern void kspd_notify(struct kspd_notifications *notify); +#else +static inline void kspd_notify(struct kspd_notifications *notify) +{ +} +#endif + +#endif diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h index 550979a9ea9..e3315359500 100644 --- a/include/asm-mips/mach-generic/ide.h +++ b/include/asm-mips/mach-generic/ide.h @@ -104,65 +104,107 @@ static __inline__ unsigned long ide_default_io_base(int index) #endif /* MIPS port and memory-mapped I/O string operations. */ +static inline void __ide_flush_prologue(void) +{ +#ifdef CONFIG_SMP + if (cpu_has_dc_aliases) + preempt_disable(); +#endif +} + +static inline void __ide_flush_epilogue(void) +{ +#ifdef CONFIG_SMP + if (cpu_has_dc_aliases) + preempt_enable(); +#endif +} static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) { if (cpu_has_dc_aliases) { unsigned long end = addr + size; - for (; addr < end; addr += PAGE_SIZE) - flush_dcache_page(virt_to_page(addr)); + + while (addr < end) { + local_flush_data_cache_page((void *)addr); + addr += PAGE_SIZE; + } } } +/* + * insw() and gang might be called with interrupts disabled, so we can't + * send IPIs for flushing due to the potencial of deadlocks, see the comment + * above smp_call_function() in arch/mips/kernel/smp.c. We work around the + * problem by disabling preemption so we know we actually perform the flush + * on the processor that actually has the lines to be flushed which hopefully + * is even better for performance anyway. + */ static inline void __ide_insw(unsigned long port, void *addr, unsigned int count) { + __ide_flush_prologue(); insw(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 2); + __ide_flush_epilogue(); } static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) { + __ide_flush_prologue(); insl(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 4); + __ide_flush_epilogue(); } static inline void __ide_outsw(unsigned long port, const void *addr, unsigned long count) { + __ide_flush_prologue(); outsw(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 2); + __ide_flush_epilogue(); } static inline void __ide_outsl(unsigned long port, const void *addr, unsigned long count) { + __ide_flush_prologue(); outsl(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 4); + __ide_flush_epilogue(); } static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) { + __ide_flush_prologue(); readsw(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 2); + __ide_flush_epilogue(); } static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) { + __ide_flush_prologue(); readsl(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 4); + __ide_flush_epilogue(); } static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) { + __ide_flush_prologue(); writesw(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 2); + __ide_flush_epilogue(); } static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) { + __ide_flush_prologue(); writesl(port, addr, count); __ide_flush_dcache_range((unsigned long)addr, count * 4); + __ide_flush_epilogue(); } /* ide_insw calls insw, not __ide_insw. Why? */ diff --git a/include/asm-mips/mach-jmr3927/ds1742.h b/include/asm-mips/mach-jmr3927/ds1742.h index cff6192d4bd..8a8fef6d07f 100644 --- a/include/asm-mips/mach-jmr3927/ds1742.h +++ b/include/asm-mips/mach-jmr3927/ds1742.h @@ -3,14 +3,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003 by Ralf Baechle + * Copyright (C) 2003, 06 by Ralf Baechle */ #ifndef __ASM_MACH_JMR3927_DS1742_H #define __ASM_MACH_JMR3927_DS1742_H #include <asm/jmr3927/jmr3927.h> -#define rtc_read(reg) (jmr3927_nvram_in(addr)) +#define rtc_read(reg) (jmr3927_nvram_in(reg)) #define rtc_write(data, reg) (jmr3927_nvram_out((data),(reg))) #endif /* __ASM_MACH_JMR3927_DS1742_H */ diff --git a/include/asm-mips/mach-mips/param.h b/include/asm-mips/mach-mips/param.h new file mode 100644 index 00000000000..805ef6d27d3 --- /dev/null +++ b/include/asm-mips/mach-mips/param.h @@ -0,0 +1,13 @@ +/* + * 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) 2003 by Ralf Baechle + */ +#ifndef __ASM_MACH_MIPS_PARAM_H +#define __ASM_MACH_MIPS_PARAM_H + +#define HZ 100 /* Internal kernel timer frequency */ + +#endif /* __ASM_MACH_MIPS_PARAM_H */ diff --git a/include/asm-mips/marvell.h b/include/asm-mips/marvell.h index 9225b3397a4..6bb2125bb05 100644 --- a/include/asm-mips/marvell.h +++ b/include/asm-mips/marvell.h @@ -53,4 +53,6 @@ struct mv_pci_controller { unsigned long config_vreg; }; +extern void ll_mv64340_irq(struct pt_regs *regs); + #endif /* __ASM_MIPS_MARVELL_H */ diff --git a/include/asm-mips/mips-boards/atlas.h b/include/asm-mips/mips-boards/atlas.h index 0998151fb3a..a8ae12d120e 100644 --- a/include/asm-mips/mips-boards/atlas.h +++ b/include/asm-mips/mips-boards/atlas.h @@ -33,13 +33,29 @@ #define ATLAS_RTC_ADR_REG 0x1f000800 #define ATLAS_RTC_DAT_REG 0x1f000808 - /* * Atlas interrupt controller register base. */ #define ATLAS_ICTRL_REGS_BASE 0x1f000000 /* + * Atlas registers are memory mapped on 64-bit aligned boundaries and + * only word access are allowed. + */ +struct atlas_ictrl_regs { + volatile unsigned int intraw; + int dummy1; + volatile unsigned int intseten; + int dummy2; + volatile unsigned int intrsten; + int dummy3; + volatile unsigned int intenable; + int dummy4; + volatile unsigned int intstatus; + int dummy5; +}; + +/* * Atlas UART register base. */ #define ATLAS_UART_REGS_BASE 0x1f000900 diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h index bba35c183d0..fd7ebc54fa9 100644 --- a/include/asm-mips/mips-boards/atlasint.h +++ b/include/asm-mips/mips-boards/atlasint.h @@ -62,23 +62,4 @@ #define ATLASINT_RES31 (ATLASINT_BASE+31) #define ATLASINT_END (ATLASINT_BASE+31) -/* - * Atlas registers are memory mapped on 64-bit aligned boundaries and - * only word access are allowed. - */ -struct atlas_ictrl_regs { - volatile unsigned int intraw; - int dummy1; - volatile unsigned int intseten; - int dummy2; - volatile unsigned int intrsten; - int dummy3; - volatile unsigned int intenable; - int dummy4; - volatile unsigned int intstatus; - int dummy5; -}; - -extern void atlasint_init(void); - #endif /* !(_MIPS_ATLASINT_H) */ diff --git a/include/asm-mips/mips-boards/generic.h b/include/asm-mips/mips-boards/generic.h index 25b6ffc2662..fa8b913cc3e 100644 --- a/include/asm-mips/mips-boards/generic.h +++ b/include/asm-mips/mips-boards/generic.h @@ -67,6 +67,7 @@ #define MIPS_REVISION_CORID_CORE_FPGA2 7 #define MIPS_REVISION_CORID_CORE_FPGAR2 8 #define MIPS_REVISION_CORID_CORE_FPGA3 9 +#define MIPS_REVISION_CORID_CORE_24K 10 /**** Artificial corid defines ****/ /* diff --git a/include/asm-mips/mips_mt.h b/include/asm-mips/mips_mt.h new file mode 100644 index 00000000000..c31a312b978 --- /dev/null +++ b/include/asm-mips/mips_mt.h @@ -0,0 +1,15 @@ +/* + * Definitions and decalrations for MIPS MT support + * that are common between SMTC, VSMP, and/or AP/SP + * kernel models. + */ +#ifndef __ASM_MIPS_MT_H +#define __ASM_MIPS_MT_H + +extern cpumask_t mt_fpu_cpumask; +extern unsigned long mt_fpemul_threshold; + +extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value); +extern void mips_mt_set_cpuoptions(void); + +#endif /* __ASM_MIPS_MT_H */ diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h index a669c0702c6..f637ce70758 100644 --- a/include/asm-mips/mipsmtregs.h +++ b/include/asm-mips/mipsmtregs.h @@ -165,7 +165,7 @@ #ifndef __ASSEMBLY__ -extern void mips_mt_regdump(void); +extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value); static inline unsigned int dvpe(void) { @@ -234,7 +234,7 @@ static inline void __raw_emt(void) __asm__ __volatile__( " .set noreorder \n" " .set mips32r2 \n" - " emt \n" + " .word 0x41600be1 # emt \n" " ehb \n" " .set mips0 \n" " .set reorder"); @@ -282,8 +282,11 @@ static inline void ehb(void) \ __asm__ __volatile__( \ " .set push \n" \ + " .set noat \n" \ " .set mips32r2 \n" \ - " mftgpr %0," #rt " \n" \ + " # mftgpr $1," #rt " \n" \ + " .word 0x41000820 | (" #rt " << 16) \n" \ + " move %0, $1 \n" \ " .set pop \n" \ : "=r" (__res)); \ \ @@ -295,9 +298,7 @@ static inline void ehb(void) unsigned long __res; \ \ __asm__ __volatile__( \ - ".set noat\n\t" \ - "mftr\t%0, " #rt ", " #u ", " #sel "\n\t" \ - ".set at\n\t" \ + " mftr %0, " #rt ", " #u ", " #sel " \n" \ : "=r" (__res)); \ \ __res; \ @@ -364,6 +365,9 @@ do { \ #define read_vpe_c0_ebase() mftc0(15,1) #define write_vpe_c0_ebase(val) mttc0(15, 1, val) #define write_vpe_c0_compare(val) mttc0(11, 0, val) +#define read_vpe_c0_badvaddr() mftc0(8, 0) +#define read_vpe_c0_epc() mftc0(14, 0) +#define write_vpe_c0_epc(val) mttc0(14, 0, val) /* TC */ diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h index 035ba0a9b0d..5af7517fce8 100644 --- a/include/asm-mips/mipsregs.h +++ b/include/asm-mips/mipsregs.h @@ -291,7 +291,7 @@ #define ST0_DL (_ULCAST_(1) << 24) /* - * Enable the MIPS DSP ASE + * Enable the MIPS MDMX and DSP ASEs */ #define ST0_MX 0x01000000 @@ -836,6 +836,9 @@ do { \ #define read_c0_cache() __read_32bit_c0_register($7, 0) /* TX39xx */ #define write_c0_cache(val) __write_32bit_c0_register($7, 0, val) +#define read_c0_badvaddr() __read_ulong_c0_register($8, 0) +#define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) + #define read_c0_count() __read_32bit_c0_register($9, 0) #define write_c0_count(val) __write_32bit_c0_register($9, 0, val) @@ -858,7 +861,19 @@ do { \ #define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) #define read_c0_status() __read_32bit_c0_register($12, 0) +#ifdef CONFIG_MIPS_MT_SMTC +#define write_c0_status(val) \ +do { \ + __write_32bit_c0_register($12, 0, val); \ + __ehb(); \ +} while (0) +#else +/* + * Legacy non-SMTC code, which may be hazardous + * but which might not support EHB + */ #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) +#endif /* CONFIG_MIPS_MT_SMTC */ #define read_c0_cause() __read_32bit_c0_register($13, 0) #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) @@ -1001,6 +1016,9 @@ do { \ #define read_c0_taglo() __read_32bit_c0_register($28, 0) #define write_c0_taglo(val) __write_32bit_c0_register($28, 0, val) +#define read_c0_dtaglo() __read_32bit_c0_register($28, 2) +#define write_c0_dtaglo(val) __write_32bit_c0_register($28, 2, val) + #define read_c0_taghi() __read_32bit_c0_register($29, 0) #define write_c0_taghi(val) __write_32bit_c0_register($29, 0, val) @@ -1354,15 +1372,119 @@ static inline void tlb_write_random(void) /* * Manipulate bits in a c0 register. */ +#ifndef CONFIG_MIPS_MT_SMTC +/* + * SMTC Linux requires shutting-down microthread scheduling + * during CP0 register read-modify-write sequences. + */ +#define __BUILD_SET_C0(name) \ +static inline unsigned int \ +set_c0_##name(unsigned int set) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res |= set; \ + write_c0_##name(res); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +clear_c0_##name(unsigned int clear) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res &= ~clear; \ + write_c0_##name(res); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +change_c0_##name(unsigned int change, unsigned int new) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res &= ~change; \ + res |= (new & change); \ + write_c0_##name(res); \ + \ + return res; \ +} + +#else /* SMTC versions that manage MT scheduling */ + +#include <asm/interrupt.h> + +/* + * This is a duplicate of dmt() in mipsmtregs.h to avoid problems with + * header file recursion. + */ +static inline unsigned int __dmt(void) +{ + int res; + + __asm__ __volatile__( + " .set push \n" + " .set mips32r2 \n" + " .set noat \n" + " .word 0x41610BC1 # dmt $1 \n" + " ehb \n" + " move %0, $1 \n" + " .set pop \n" + : "=r" (res)); + + instruction_hazard(); + + return res; +} + +#define __VPECONTROL_TE_SHIFT 15 +#define __VPECONTROL_TE (1UL << __VPECONTROL_TE_SHIFT) + +#define __EMT_ENABLE __VPECONTROL_TE + +static inline void __emt(unsigned int previous) +{ + if ((previous & __EMT_ENABLE)) + __asm__ __volatile__( + " .set noreorder \n" + " .set mips32r2 \n" + " .word 0x41600be1 # emt \n" + " ehb \n" + " .set mips0 \n" + " .set reorder \n"); +} + +static inline void __ehb(void) +{ + __asm__ __volatile__( + " ehb \n"); +} + +/* + * Note that local_irq_save/restore affect TC-specific IXMT state, + * not Status.IE as in non-SMTC kernel. + */ + #define __BUILD_SET_C0(name) \ static inline unsigned int \ set_c0_##name(unsigned int set) \ { \ unsigned int res; \ + unsigned int omt; \ + unsigned int flags; \ \ + local_irq_save(flags); \ + omt = __dmt(); \ res = read_c0_##name(); \ res |= set; \ write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ \ return res; \ } \ @@ -1371,10 +1493,16 @@ static inline unsigned int \ clear_c0_##name(unsigned int clear) \ { \ unsigned int res; \ + unsigned int omt; \ + unsigned int flags; \ \ + local_irq_save(flags); \ + omt = __dmt(); \ res = read_c0_##name(); \ res &= ~clear; \ write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ \ return res; \ } \ @@ -1383,14 +1511,22 @@ static inline unsigned int \ change_c0_##name(unsigned int change, unsigned int new) \ { \ unsigned int res; \ + unsigned int omt; \ + unsigned int flags; \ \ + local_irq_save(flags); \ + \ + omt = __dmt(); \ res = read_c0_##name(); \ res &= ~change; \ res |= (new & change); \ write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ \ return res; \ } +#endif __BUILD_SET_C0(status) __BUILD_SET_C0(cause) diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index 61cf2258813..6e09f4c8721 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -17,6 +17,10 @@ #include <linux/slab.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> +#ifdef CONFIG_MIPS_MT_SMTC +#include <asm/mipsmtregs.h> +#include <asm/smtc.h> +#endif /* SMTC */ /* * For the fast tlb miss handlers, we keep a per cpu array of pointers @@ -54,6 +58,14 @@ extern unsigned long pgd_current[]; #define ASID_INC 0x1 #define ASID_MASK 0xfff +/* SMTC/34K debug hack - but maybe we'll keep it */ +#elif defined(CONFIG_MIPS_MT_SMTC) + +#define ASID_INC 0x1 +extern unsigned long smtc_asid_mask; +#define ASID_MASK (smtc_asid_mask) +#define HW_ASID_MASK 0xff +/* End SMTC/34K debug hack */ #else /* FIXME: not correct for R6000 */ #define ASID_INC 0x1 @@ -76,6 +88,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) #define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) #define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) +#ifndef CONFIG_MIPS_MT_SMTC +/* Normal, classic MIPS get_new_mmu_context */ static inline void get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) { @@ -91,6 +105,12 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) cpu_context(cpu, mm) = asid_cache(cpu) = asid; } +#else /* CONFIG_MIPS_MT_SMTC */ + +#define get_new_mmu_context(mm,cpu) smtc_get_new_mmu_context((mm),(cpu)) + +#endif /* CONFIG_MIPS_MT_SMTC */ + /* * Initialize the context related info for a new mm_struct * instance. @@ -111,14 +131,46 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { unsigned int cpu = smp_processor_id(); unsigned long flags; - +#ifdef CONFIG_MIPS_MT_SMTC + unsigned long oldasid; + unsigned long mtflags; + int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; local_irq_save(flags); + mtflags = dvpe(); +#else /* Not SMTC */ + local_irq_save(flags); +#endif /* CONFIG_MIPS_MT_SMTC */ /* Check if our ASID is of an older version and thus invalid */ if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) get_new_mmu_context(next, cpu); - +#ifdef CONFIG_MIPS_MT_SMTC + /* + * If the EntryHi ASID being replaced happens to be + * the value flagged at ASID recycling time as having + * an extended life, clear the bit showing it being + * in use by this "CPU", and if that's the last bit, + * free up the ASID value for use and flush any old + * instances of it from the TLB. + */ + oldasid = (read_c0_entryhi() & ASID_MASK); + if(smtc_live_asid[mytlb][oldasid]) { + smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); + if(smtc_live_asid[mytlb][oldasid] == 0) + smtc_flush_tlb_asid(oldasid); + } + /* + * Tread softly on EntryHi, and so long as we support + * having ASID_MASK smaller than the hardware maximum, + * make sure no "soft" bits become "hard"... + */ + write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) + | (cpu_context(cpu, next) & ASID_MASK)); + ehb(); /* Make sure it propagates to TCStatus */ + evpe(mtflags); +#else write_c0_entryhi(cpu_context(cpu, next)); +#endif /* CONFIG_MIPS_MT_SMTC */ TLBMISS_HANDLER_SETUP_PGD(next->pgd); /* @@ -151,12 +203,34 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next) unsigned long flags; unsigned int cpu = smp_processor_id(); +#ifdef CONFIG_MIPS_MT_SMTC + unsigned long oldasid; + unsigned long mtflags; + int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; +#endif /* CONFIG_MIPS_MT_SMTC */ + local_irq_save(flags); /* Unconditionally get a new ASID. */ get_new_mmu_context(next, cpu); +#ifdef CONFIG_MIPS_MT_SMTC + /* See comments for similar code above */ + mtflags = dvpe(); + oldasid = read_c0_entryhi() & ASID_MASK; + if(smtc_live_asid[mytlb][oldasid]) { + smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); + if(smtc_live_asid[mytlb][oldasid] == 0) + smtc_flush_tlb_asid(oldasid); + } + /* See comments for similar code above */ + write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | + (cpu_context(cpu, next) & ASID_MASK)); + ehb(); /* Make sure it propagates to TCStatus */ + evpe(mtflags); +#else write_c0_entryhi(cpu_context(cpu, next)); +#endif /* CONFIG_MIPS_MT_SMTC */ TLBMISS_HANDLER_SETUP_PGD(next->pgd); /* mark mmu ownership change */ @@ -174,17 +248,49 @@ static inline void drop_mmu_context(struct mm_struct *mm, unsigned cpu) { unsigned long flags; +#ifdef CONFIG_MIPS_MT_SMTC + unsigned long oldasid; + /* Can't use spinlock because called from TLB flush within DVPE */ + unsigned int prevvpe; + int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; +#endif /* CONFIG_MIPS_MT_SMTC */ local_irq_save(flags); if (cpu_isset(cpu, mm->cpu_vm_mask)) { get_new_mmu_context(mm, cpu); +#ifdef CONFIG_MIPS_MT_SMTC + /* See comments for similar code above */ + prevvpe = dvpe(); + oldasid = (read_c0_entryhi() & ASID_MASK); + if(smtc_live_asid[mytlb][oldasid]) { + smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); + if(smtc_live_asid[mytlb][oldasid] == 0) + smtc_flush_tlb_asid(oldasid); + } + /* See comments for similar code above */ + write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) + | cpu_asid(cpu, mm)); + ehb(); /* Make sure it propagates to TCStatus */ + evpe(prevvpe); +#else /* not CONFIG_MIPS_MT_SMTC */ write_c0_entryhi(cpu_asid(cpu, mm)); +#endif /* CONFIG_MIPS_MT_SMTC */ } else { /* will get a new context next time */ +#ifndef CONFIG_MIPS_MT_SMTC cpu_context(cpu, mm) = 0; +#else /* SMTC */ + int i; + + /* SMTC shares the TLB (and ASIDs) across VPEs */ + for (i = 0; i < num_online_cpus(); i++) { + if((smtc_status & SMTC_TLB_SHARED) + || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id)) + cpu_context(i, mm) = 0; + } +#endif /* CONFIG_MIPS_MT_SMTC */ } - local_irq_restore(flags); } diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index a1eab136ff6..4035ec79ecd 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -139,9 +139,11 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) +#ifndef CONFIG_SPARSEMEM #ifndef CONFIG_NEED_MULTIPLE_NODES #define pfn_valid(pfn) ((pfn) < max_mapnr) #endif +#endif #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h index 4d6bc45df59..087c2076925 100644 --- a/include/asm-mips/pgtable-32.h +++ b/include/asm-mips/pgtable-32.h @@ -177,48 +177,67 @@ pfn_pte(unsigned long pfn, pgprot_t prot) ((swp_entry_t) { ((type) << 10) | ((offset) << 15) }) /* - * Bits 0, 1, 2, 9 and 10 are taken, split up the 27 bits of offset - * into this range: + * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range: */ -#define PTE_FILE_MAX_BITS 27 +#define PTE_FILE_MAX_BITS 28 -#define pte_to_pgoff(_pte) \ - ((((_pte).pte >> 3) & 0x3f ) + (((_pte).pte >> 11) << 8 )) +#define pte_to_pgoff(_pte) ((((_pte).pte >> 1 ) & 0x07) | \ + (((_pte).pte >> 2 ) & 0x38) | \ + (((_pte).pte >> 10) << 6 )) -#define pgoff_to_pte(off) \ - ((pte_t) { (((off) & 0x3f) << 3) + (((off) >> 8) << 11) + _PAGE_FILE }) +#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x07) << 1 ) | \ + (((off) & 0x38) << 2 ) | \ + (((off) >> 6 ) << 10) | \ + _PAGE_FILE }) #else /* Swap entries must have VALID and GLOBAL bits cleared. */ +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#define __swp_type(x) (((x).val >> 2) & 0x1f) +#define __swp_offset(x) ((x).val >> 7) +#define __swp_entry(type,offset) \ + ((swp_entry_t) { ((type) << 2) | ((offset) << 7) }) +#else #define __swp_type(x) (((x).val >> 8) & 0x1f) -#define __swp_offset(x) ((x).val >> 13) +#define __swp_offset(x) ((x).val >> 13) #define __swp_entry(type,offset) \ - ((swp_entry_t) { ((type) << 8) | ((offset) << 13) }) + ((swp_entry_t) { ((type) << 8) | ((offset) << 13) }) +#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */ +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) /* - * Bits 0, 1, 2, 7 and 8 are taken, split up the 27 bits of offset - * into this range: + * Bits 0 and 1 of pte_high are taken, use the rest for the page offset... */ -#define PTE_FILE_MAX_BITS 27 +#define PTE_FILE_MAX_BITS 30 -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) - /* fixme */ -#define pte_to_pgoff(_pte) (((_pte).pte_high >> 6) + ((_pte).pte_high & 0x3f)) -#define pgoff_to_pte(off) \ - ((pte_t){(((off) & 0x3f) + ((off) << 6) + _PAGE_FILE)}) +#define pte_to_pgoff(_pte) ((_pte).pte_high >> 2) +#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) << 2 }) #else -#define pte_to_pgoff(_pte) \ - ((((_pte).pte >> 3) & 0x1f ) + (((_pte).pte >> 9) << 6 )) +/* + * Bits 0, 4, 6, and 7 are taken, split up 28 bits of offset into this range: + */ +#define PTE_FILE_MAX_BITS 28 + +#define pte_to_pgoff(_pte) ((((_pte).pte >> 1) & 0x7) | \ + (((_pte).pte >> 2) & 0x8) | \ + (((_pte).pte >> 8) << 4)) -#define pgoff_to_pte(off) \ - ((pte_t) { (((off) & 0x1f) << 3) + (((off) >> 6) << 9) + _PAGE_FILE }) +#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7) << 1) | \ + (((off) & 0x8) << 2) | \ + (((off) >> 4) << 8) | \ + _PAGE_FILE }) #endif #endif +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) +#define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) +#else #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) +#endif #endif /* _ASM_PGTABLE_32_H */ diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index 82166b254b2..2faf5c9ff12 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h @@ -224,15 +224,12 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) /* - * Bits 0, 1, 2, 7 and 8 are taken, split up the 32 bits of offset - * into this range: + * Bits 0, 4, 6, and 7 are taken. Let's leave bits 1, 2, 3, and 5 alone to + * make things easier, and only use the upper 56 bits for the page offset... */ -#define PTE_FILE_MAX_BITS 32 +#define PTE_FILE_MAX_BITS 56 -#define pte_to_pgoff(_pte) \ - ((((_pte).pte >> 3) & 0x1f ) + (((_pte).pte >> 9) << 6 )) - -#define pgoff_to_pte(off) \ - ((pte_t) { (((off) & 0x1f) << 3) + (((off) >> 6) << 9) + _PAGE_FILE }) +#define pte_to_pgoff(_pte) ((_pte).pte >> 8) +#define pgoff_to_pte(off) ((pte_t) { ((off) << 8) | _PAGE_FILE }) #endif /* _ASM_PGTABLE_64_H */ diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index 702a28fa7a3..d0af2a3b015 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -70,7 +70,15 @@ extern unsigned long zero_page_mask; #define ZERO_PAGE(vaddr) \ (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) -#define __HAVE_ARCH_MULTIPLE_ZERO_PAGE +#define __HAVE_ARCH_MOVE_PTE +#define move_pte(pte, prot, old_addr, new_addr) \ +({ \ + pte_t newpte = (pte); \ + if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \ + pte_page(pte) == ZERO_PAGE(old_addr)) \ + newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \ + newpte; \ +}) extern void paging_init(void); @@ -82,10 +90,11 @@ extern void paging_init(void); #define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT)) #define pmd_page_kernel(pmd) pmd_val(pmd) -#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) -#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) - #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) + +#define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) +#define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT) + static inline void set_pte(pte_t *ptep, pte_t pte) { ptep->pte_high = pte.pte_high; @@ -93,27 +102,35 @@ static inline void set_pte(pte_t *ptep, pte_t pte) ptep->pte_low = pte.pte_low; //printk("pte_high %x pte_low %x\n", ptep->pte_high, ptep->pte_low); - if (pte_val(pte) & _PAGE_GLOBAL) { + if (pte.pte_low & _PAGE_GLOBAL) { pte_t *buddy = ptep_buddy(ptep); /* * Make sure the buddy is global too (if it's !none, * it better already be global) */ - if (pte_none(*buddy)) - buddy->pte_low |= _PAGE_GLOBAL; + if (pte_none(*buddy)) { + buddy->pte_low |= _PAGE_GLOBAL; + buddy->pte_high |= _PAGE_GLOBAL; + } } } #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { + pte_t null = __pte(0); + /* Preserve global status for the pair */ - if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) - set_pte_at(mm, addr, ptep, __pte(_PAGE_GLOBAL)); - else - set_pte_at(mm, addr, ptep, __pte(0)); + if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL) + null.pte_low = null.pte_high = _PAGE_GLOBAL; + + set_pte_at(mm, addr, ptep, null); } #else + +#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) +#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) + /* * Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following @@ -174,75 +191,76 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; */ static inline int pte_user(pte_t pte) { BUG(); return 0; } #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) -static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_READ; } -static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_WRITE; } -static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_MODIFIED; } -static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; } +static inline int pte_read(pte_t pte) { return pte.pte_low & _PAGE_READ; } +static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; } +static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; } +static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; } +static inline int pte_file(pte_t pte) { return pte.pte_low & _PAGE_FILE; } + static inline pte_t pte_wrprotect(pte_t pte) { - (pte).pte_low &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); - (pte).pte_high &= ~_PAGE_SILENT_WRITE; + pte.pte_low &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); + pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } static inline pte_t pte_rdprotect(pte_t pte) { - (pte).pte_low &= ~(_PAGE_READ | _PAGE_SILENT_READ); - (pte).pte_high &= ~_PAGE_SILENT_READ; + pte.pte_low &= ~(_PAGE_READ | _PAGE_SILENT_READ); + pte.pte_high &= ~_PAGE_SILENT_READ; return pte; } static inline pte_t pte_mkclean(pte_t pte) { - (pte).pte_low &= ~(_PAGE_MODIFIED|_PAGE_SILENT_WRITE); - (pte).pte_high &= ~_PAGE_SILENT_WRITE; + pte.pte_low &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); + pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } static inline pte_t pte_mkold(pte_t pte) { - (pte).pte_low &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ); - (pte).pte_high &= ~_PAGE_SILENT_READ; + pte.pte_low &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); + pte.pte_high &= ~_PAGE_SILENT_READ; return pte; } static inline pte_t pte_mkwrite(pte_t pte) { - (pte).pte_low |= _PAGE_WRITE; - if ((pte).pte_low & _PAGE_MODIFIED) { - (pte).pte_low |= _PAGE_SILENT_WRITE; - (pte).pte_high |= _PAGE_SILENT_WRITE; + pte.pte_low |= _PAGE_WRITE; + if (pte.pte_low & _PAGE_MODIFIED) { + pte.pte_low |= _PAGE_SILENT_WRITE; + pte.pte_high |= _PAGE_SILENT_WRITE; } return pte; } static inline pte_t pte_mkread(pte_t pte) { - (pte).pte_low |= _PAGE_READ; - if ((pte).pte_low & _PAGE_ACCESSED) { - (pte).pte_low |= _PAGE_SILENT_READ; - (pte).pte_high |= _PAGE_SILENT_READ; + pte.pte_low |= _PAGE_READ; + if (pte.pte_low & _PAGE_ACCESSED) { + pte.pte_low |= _PAGE_SILENT_READ; + pte.pte_high |= _PAGE_SILENT_READ; } return pte; } static inline pte_t pte_mkdirty(pte_t pte) { - (pte).pte_low |= _PAGE_MODIFIED; - if ((pte).pte_low & _PAGE_WRITE) { - (pte).pte_low |= _PAGE_SILENT_WRITE; - (pte).pte_high |= _PAGE_SILENT_WRITE; + pte.pte_low |= _PAGE_MODIFIED; + if (pte.pte_low & _PAGE_WRITE) { + pte.pte_low |= _PAGE_SILENT_WRITE; + pte.pte_high |= _PAGE_SILENT_WRITE; } return pte; } static inline pte_t pte_mkyoung(pte_t pte) { - (pte).pte_low |= _PAGE_ACCESSED; - if ((pte).pte_low & _PAGE_READ) - (pte).pte_low |= _PAGE_SILENT_READ; - (pte).pte_high |= _PAGE_SILENT_READ; + pte.pte_low |= _PAGE_ACCESSED; + if (pte.pte_low & _PAGE_READ) + pte.pte_low |= _PAGE_SILENT_READ; + pte.pte_high |= _PAGE_SILENT_READ; return pte; } #else @@ -335,8 +353,9 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { - pte.pte_low &= _PAGE_CHG_MASK; - pte.pte_low |= pgprot_val(newprot); + pte.pte_low &= _PAGE_CHG_MASK; + pte.pte_high &= ~0x3f; + pte.pte_low |= pgprot_val(newprot); pte.pte_high |= pgprot_val(newprot) & 0x3f; return pte; } diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index 39d2bd50fec..0fb75f0762e 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -12,6 +12,7 @@ #define _ASM_PROCESSOR_H #include <linux/config.h> +#include <linux/cpumask.h> #include <linux/threads.h> #include <asm/cachectl.h> @@ -107,6 +108,10 @@ struct mips_dsp_state { #define INIT_DSP {{0,},} +#define INIT_CPUMASK { \ + {0,} \ +} + typedef struct { unsigned long seg; } mm_segment_t; @@ -129,6 +134,12 @@ struct thread_struct { /* Saved fpu/fpu emulator stuff. */ union mips_fpu_union fpu; +#ifdef CONFIG_MIPS_MT_FPAFF + /* Emulated instruction count */ + unsigned long emulated_fp; + /* Saved per-thread scheduler affinity mask */ + cpumask_t user_cpus_allowed; +#endif /* CONFIG_MIPS_MT_FPAFF */ /* Saved state of the DSP ASE, if available. */ struct mips_dsp_state dsp; @@ -142,6 +153,7 @@ struct thread_struct { #define MF_LOGADE 2 /* Log address errors to syslog */ #define MF_32BIT_REGS 4 /* also implies 16/32 fprs */ #define MF_32BIT_ADDR 8 /* 32-bit address space (o32/n32) */ +#define MF_FPUBOUND 0x10 /* thread bound to FPU-full CPU set */ unsigned long mflags; unsigned long irix_trampoline; /* Wheee... */ unsigned long irix_oldctx; @@ -153,6 +165,12 @@ struct thread_struct { #define MF_N32 MF_32BIT_ADDR #define MF_N64 0 +#ifdef CONFIG_MIPS_MT_FPAFF +#define FPAFF_INIT 0, INIT_CPUMASK, +#else +#define FPAFF_INIT +#endif /* CONFIG_MIPS_MT_FPAFF */ + #define INIT_THREAD { \ /* \ * saved main processor registers \ @@ -168,6 +186,10 @@ struct thread_struct { */ \ INIT_FPU, \ /* \ + * fpu affinity state (null if not FPAFF) \ + */ \ + FPAFF_INIT \ + /* \ * saved dsp/dsp emulator stuff \ */ \ INIT_DSP, \ diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h index 95c5839ac46..fa9d8713c12 100644 --- a/include/asm-mips/ptrace.h +++ b/include/asm-mips/ptrace.h @@ -45,6 +45,10 @@ struct pt_regs { unsigned long cp0_badvaddr; unsigned long cp0_cause; unsigned long cp0_epc; +#ifdef CONFIG_MIPS_MT_SMTC + unsigned long cp0_tcstatus; + unsigned long smtc_pad; +#endif /* CONFIG_MIPS_MT_SMTC */ }; /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ diff --git a/include/asm-mips/r4kcache.h b/include/asm-mips/r4kcache.h index 90c37470097..3c8e3c8d1a9 100644 --- a/include/asm-mips/r4kcache.h +++ b/include/asm-mips/r4kcache.h @@ -15,6 +15,7 @@ #include <asm/asm.h> #include <asm/cacheops.h> #include <asm/cpu-features.h> +#include <asm/mipsmtregs.h> /* * This macro return a properly sign-extended address suitable as base address @@ -37,16 +38,120 @@ " cache %0, %1 \n" \ " .set pop \n" \ : \ - : "i" (op), "m" (*(unsigned char *)(addr))) + : "i" (op), "R" (*(unsigned char *)(addr))) + +#ifdef CONFIG_MIPS_MT +/* + * Temporary hacks for SMTC debug. Optionally force single-threaded + * execution during I-cache flushes. + */ + +#define PROTECT_CACHE_FLUSHES 1 + +#ifdef PROTECT_CACHE_FLUSHES + +extern int mt_protiflush; +extern int mt_protdflush; +extern void mt_cflush_lockdown(void); +extern void mt_cflush_release(void); + +#define BEGIN_MT_IPROT \ + unsigned long flags = 0; \ + unsigned long mtflags = 0; \ + if(mt_protiflush) { \ + local_irq_save(flags); \ + ehb(); \ + mtflags = dvpe(); \ + mt_cflush_lockdown(); \ + } + +#define END_MT_IPROT \ + if(mt_protiflush) { \ + mt_cflush_release(); \ + evpe(mtflags); \ + local_irq_restore(flags); \ + } + +#define BEGIN_MT_DPROT \ + unsigned long flags = 0; \ + unsigned long mtflags = 0; \ + if(mt_protdflush) { \ + local_irq_save(flags); \ + ehb(); \ + mtflags = dvpe(); \ + mt_cflush_lockdown(); \ + } + +#define END_MT_DPROT \ + if(mt_protdflush) { \ + mt_cflush_release(); \ + evpe(mtflags); \ + local_irq_restore(flags); \ + } + +#else + +#define BEGIN_MT_IPROT +#define BEGIN_MT_DPROT +#define END_MT_IPROT +#define END_MT_DPROT + +#endif /* PROTECT_CACHE_FLUSHES */ + +#define __iflush_prologue \ + unsigned long redundance; \ + extern int mt_n_iflushes; \ + BEGIN_MT_IPROT \ + for (redundance = 0; redundance < mt_n_iflushes; redundance++) { + +#define __iflush_epilogue \ + END_MT_IPROT \ + } + +#define __dflush_prologue \ + unsigned long redundance; \ + extern int mt_n_dflushes; \ + BEGIN_MT_DPROT \ + for (redundance = 0; redundance < mt_n_dflushes; redundance++) { + +#define __dflush_epilogue \ + END_MT_DPROT \ + } + +#define __inv_dflush_prologue __dflush_prologue +#define __inv_dflush_epilogue __dflush_epilogue +#define __sflush_prologue { +#define __sflush_epilogue } +#define __inv_sflush_prologue __sflush_prologue +#define __inv_sflush_epilogue __sflush_epilogue + +#else /* CONFIG_MIPS_MT */ + +#define __iflush_prologue { +#define __iflush_epilogue } +#define __dflush_prologue { +#define __dflush_epilogue } +#define __inv_dflush_prologue { +#define __inv_dflush_epilogue } +#define __sflush_prologue { +#define __sflush_epilogue } +#define __inv_sflush_prologue { +#define __inv_sflush_epilogue } + +#endif /* CONFIG_MIPS_MT */ static inline void flush_icache_line_indexed(unsigned long addr) { + __iflush_prologue cache_op(Index_Invalidate_I, addr); + __iflush_epilogue } static inline void flush_dcache_line_indexed(unsigned long addr) { + __dflush_prologue cache_op(Index_Writeback_Inv_D, addr); + __dflush_epilogue } static inline void flush_scache_line_indexed(unsigned long addr) @@ -56,17 +161,23 @@ static inline void flush_scache_line_indexed(unsigned long addr) static inline void flush_icache_line(unsigned long addr) { + __iflush_prologue cache_op(Hit_Invalidate_I, addr); + __iflush_epilogue } static inline void flush_dcache_line(unsigned long addr) { + __dflush_prologue cache_op(Hit_Writeback_Inv_D, addr); + __dflush_epilogue } static inline void invalidate_dcache_line(unsigned long addr) { + __dflush_prologue cache_op(Hit_Invalidate_D, addr); + __dflush_epilogue } static inline void invalidate_scache_line(unsigned long addr) @@ -239,9 +350,13 @@ static inline void blast_##pfx##cache##lsize(void) \ current_cpu_data.desc.waybit; \ unsigned long ws, addr; \ \ + __##pfx##flush_prologue \ + \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ cache##lsize##_unroll32(addr|ws,indexop); \ + \ + __##pfx##flush_epilogue \ } \ \ static inline void blast_##pfx##cache##lsize##_page(unsigned long page) \ @@ -249,10 +364,14 @@ static inline void blast_##pfx##cache##lsize##_page(unsigned long page) \ unsigned long start = page; \ unsigned long end = page + PAGE_SIZE; \ \ + __##pfx##flush_prologue \ + \ do { \ cache##lsize##_unroll32(start,hitop); \ start += lsize * 32; \ } while (start < end); \ + \ + __##pfx##flush_epilogue \ } \ \ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page) \ @@ -265,9 +384,13 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page) current_cpu_data.desc.waybit; \ unsigned long ws, addr; \ \ + __##pfx##flush_prologue \ + \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ cache##lsize##_unroll32(addr|ws,indexop); \ + \ + __##pfx##flush_epilogue \ } __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16) @@ -288,12 +411,17 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ unsigned long lsize = cpu_##desc##_line_size(); \ unsigned long addr = start & ~(lsize - 1); \ unsigned long aend = (end - 1) & ~(lsize - 1); \ + \ + __##pfx##flush_prologue \ + \ while (1) { \ prot##cache_op(hitop, addr); \ if (addr == aend) \ break; \ addr += lsize; \ } \ + \ + __##pfx##flush_epilogue \ } __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_) diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h index a2abc4572b6..82ad401c7dc 100644 --- a/include/asm-mips/rtc.h +++ b/include/asm-mips/rtc.h @@ -32,7 +32,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) { unsigned long nowtime; - nowtime = rtc_get_time(); + nowtime = rtc_mips_get_time(); to_tm(nowtime, time); time->tm_year -= 1900; @@ -47,7 +47,7 @@ static inline int set_rtc_time(struct rtc_time *time) nowtime = mktime(time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); - ret = rtc_set_time(nowtime); + ret = rtc_mips_set_time(nowtime); return ret; } diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h index 1298c3fdf6c..76cd51c6be3 100644 --- a/include/asm-mips/rtlx.h +++ b/include/asm-mips/rtlx.h @@ -3,32 +3,46 @@ * */ -#ifndef _RTLX_H -#define _RTLX_H_ +#ifndef __ASM_RTLX_H +#define __ASM_RTLX_H_ #define LX_NODE_BASE 10 #define MIPSCPU_INT_BASE 16 #define MIPS_CPU_RTLX_IRQ 0 -#define RTLX_VERSION 1 +#define RTLX_VERSION 2 #define RTLX_xID 0x12345600 #define RTLX_ID (RTLX_xID | RTLX_VERSION) #define RTLX_CHANNELS 8 -#define RTLX_BUFFER_SIZE 1024 +#define RTLX_CHANNEL_STDIO 0 +#define RTLX_CHANNEL_DBG 1 +#define RTLX_CHANNEL_SYSIO 2 -/* - * lx_state bits - */ -#define RTLX_STATE_OPENED 1UL +extern int rtlx_open(int index, int can_sleep); +extern int rtlx_release(int index); +extern ssize_t rtlx_read(int index, void *buff, size_t count, int user); +extern ssize_t rtlx_write(int index, void *buffer, size_t count, int user); +extern unsigned int rtlx_read_poll(int index, int can_sleep); +extern unsigned int rtlx_write_poll(int index); + +enum rtlx_state { + RTLX_STATE_UNUSED, + RTLX_STATE_INITIALISED, + RTLX_STATE_REMOTE_READY, + RTLX_STATE_OPENED +}; + +#define RTLX_BUFFER_SIZE 1024 /* each channel supports read and write. linux (vpe0) reads lx_buffer and writes rt_buffer SP (vpe1) reads rt_buffer and writes lx_buffer */ struct rtlx_channel { - unsigned long lx_state; + enum rtlx_state rt_state; + enum rtlx_state lx_state; int buffer_size; @@ -38,15 +52,13 @@ struct rtlx_channel { int lx_write, lx_read; char *lx_buffer; - - void *queues; - }; struct rtlx_info { unsigned long id; + enum rtlx_state state; struct rtlx_channel channel[RTLX_CHANNELS]; }; -#endif /* _RTLX_H_ */ +#endif /* __ASM_RTLX_H_ */ diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index 7b236641220..7196ceb0e94 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h @@ -77,15 +77,15 @@ #include <asm/it8712.h> #define ITE_SERIAL_PORT_DEFNS \ { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \ - .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .type = 0x3 }, \ + .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ { .baud_base = (24000000/(16*13)), .port = (IT8172_PCI_IO_BASE + IT8712_UART1_PORT), \ - .irq = IT8172_SERIRQ_4, .flags = STD_COM_FLAGS, .type = 0x3 }, \ + .irq = IT8172_SERIRQ_4, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ /* Smart Card Reader 0 */ \ { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR0_BASE), \ - .irq = IT8172_SCR0_IRQ, .flags = STD_COM_FLAGS, .type = 0x3 }, \ + .irq = IT8172_SCR0_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ /* Smart Card Reader 1 */ \ { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ - .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .type = 0x3 }, + .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, #else #define ITE_SERIAL_PORT_DEFNS #endif @@ -95,10 +95,10 @@ #include <asm/it8172/it8172_int.h> #define IVR_SERIAL_PORT_DEFNS \ { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \ - .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .type = 0x3 }, \ + .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ /* Smart Card Reader 1 */ \ { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ - .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .type = 0x3 }, + .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, #else #define IVR_SERIAL_PORT_DEFNS #endif diff --git a/include/asm-mips/sigcontext.h b/include/asm-mips/sigcontext.h index 8edabb0be23..cefa657dd04 100644 --- a/include/asm-mips/sigcontext.h +++ b/include/asm-mips/sigcontext.h @@ -55,8 +55,14 @@ struct sigcontext { struct sigcontext { unsigned long sc_regs[32]; unsigned long sc_fpregs[32]; - unsigned long sc_hi[4]; - unsigned long sc_lo[4]; + unsigned long sc_mdhi; + unsigned long sc_hi1; + unsigned long sc_hi2; + unsigned long sc_hi3; + unsigned long sc_mdlo; + unsigned long sc_lo1; + unsigned long sc_lo2; + unsigned long sc_lo3; unsigned long sc_pc; unsigned int sc_fpc_csr; unsigned int sc_used_math; diff --git a/include/asm-mips/smp.h b/include/asm-mips/smp.h index 75c6fe7c212..e14e4b69de2 100644 --- a/include/asm-mips/smp.h +++ b/include/asm-mips/smp.h @@ -48,7 +48,6 @@ extern struct call_data_struct *call_data; #define SMP_CALL_FUNCTION 0x2 extern cpumask_t phys_cpu_present_map; -extern cpumask_t cpu_online_map; #define cpu_possible_map phys_cpu_present_map extern cpumask_t cpu_callout_map; @@ -86,9 +85,9 @@ extern void prom_init_secondary(void); extern void plat_smp_setup(void); /* - * Called after init_IRQ but before __cpu_up. + * Called in smp_prepare_cpus. */ -extern void prom_prepare_cpus(unsigned int max_cpus); +extern void plat_prepare_cpus(unsigned int max_cpus); /* * Last chance for the board code to finish SMP initialization before diff --git a/include/asm-mips/smtc.h b/include/asm-mips/smtc.h new file mode 100644 index 00000000000..e1941d1b872 --- /dev/null +++ b/include/asm-mips/smtc.h @@ -0,0 +1,55 @@ +#ifndef _ASM_SMTC_MT_H +#define _ASM_SMTC_MT_H + +/* + * Definitions for SMTC multitasking on MIPS MT cores + */ + +#include <asm/mips_mt.h> + +/* + * System-wide SMTC status information + */ + +extern unsigned int smtc_status; + +#define SMTC_TLB_SHARED 0x00000001 +#define SMTC_MTC_ACTIVE 0x00000002 + +/* + * TLB/ASID Management information + */ + +#define MAX_SMTC_TLBS 2 +#define MAX_SMTC_ASIDS 256 +#if NR_CPUS <= 8 +typedef char asiduse; +#else +#if NR_CPUS <= 16 +typedef short asiduse; +#else +typedef long asiduse; +#endif +#endif + +extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; + +void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu); + +void smtc_flush_tlb_asid(unsigned long asid); +extern int mipsmt_build_cpu_map(int startslot); +extern void mipsmt_prepare_cpus(void); +extern void smtc_smp_finish(void); +extern void smtc_boot_secondary(int cpu, struct task_struct *t); + +/* + * Sharing the TLB between multiple VPEs means that the + * "random" index selection function is not allowed to + * select the current value of the Index register. To + * avoid additional TLB pressure, the Index registers + * are "parked" with an non-Valid value. + */ + +#define PARKED_INDEX ((unsigned int)0x80000000) + +#endif /* _ASM_SMTC_MT_H */ diff --git a/include/asm-mips/smtc_ipi.h b/include/asm-mips/smtc_ipi.h new file mode 100644 index 00000000000..f22c3e2f993 --- /dev/null +++ b/include/asm-mips/smtc_ipi.h @@ -0,0 +1,118 @@ +/* + * Definitions used in MIPS MT SMTC "Interprocessor Interrupt" code. + */ +#ifndef __ASM_SMTC_IPI_H +#define __ASM_SMTC_IPI_H + +//#define SMTC_IPI_DEBUG + +#ifdef SMTC_IPI_DEBUG +#include <asm/mipsregs.h> +#include <asm/mipsmtregs.h> +#endif /* SMTC_IPI_DEBUG */ + +/* + * An IPI "message" + */ + +struct smtc_ipi { + struct smtc_ipi *flink; + int type; + void *arg; + int dest; +#ifdef SMTC_IPI_DEBUG + int sender; + long stamp; +#endif /* SMTC_IPI_DEBUG */ +}; + +/* + * Defined IPI Types + */ + +#define LINUX_SMP_IPI 1 +#define SMTC_CLOCK_TICK 2 + +/* + * A queue of IPI messages + */ + +struct smtc_ipi_q { + struct smtc_ipi *head; + spinlock_t lock; + struct smtc_ipi *tail; + int depth; +}; + +extern struct smtc_ipi_q IPIQ[NR_CPUS]; +extern struct smtc_ipi_q freeIPIq; + +static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p) +{ + long flags; + + spin_lock_irqsave(&q->lock, flags); + if (q->head == NULL) + q->head = q->tail = p; + else + q->tail->flink = p; + p->flink = NULL; + q->tail = p; + q->depth++; +#ifdef SMTC_IPI_DEBUG + p->sender = read_c0_tcbind(); + p->stamp = read_c0_count(); +#endif /* SMTC_IPI_DEBUG */ + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline struct smtc_ipi *smtc_ipi_dq(struct smtc_ipi_q *q) +{ + struct smtc_ipi *p; + long flags; + + spin_lock_irqsave(&q->lock, flags); + if (q->head == NULL) + p = NULL; + else { + p = q->head; + q->head = q->head->flink; + q->depth--; + /* Arguably unnecessary, but leaves queue cleaner */ + if (q->head == NULL) + q->tail = NULL; + } + spin_unlock_irqrestore(&q->lock, flags); + return p; +} + +static inline void smtc_ipi_req(struct smtc_ipi_q *q, struct smtc_ipi *p) +{ + long flags; + + spin_lock_irqsave(&q->lock, flags); + if (q->head == NULL) { + q->head = q->tail = p; + p->flink = NULL; + } else { + p->flink = q->head; + q->head = p; + } + q->depth++; + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline int smtc_ipi_qdepth(struct smtc_ipi_q *q) +{ + long flags; + int retval; + + spin_lock_irqsave(&q->lock, flags); + retval = q->depth; + spin_unlock_irqrestore(&q->lock, flags); + return retval; +} + +extern void smtc_send_ipi(int cpu, int type, unsigned int action); + +#endif /* __ASM_SMTC_IPI_H */ diff --git a/include/asm-mips/smtc_proc.h b/include/asm-mips/smtc_proc.h new file mode 100644 index 00000000000..25da651f1f5 --- /dev/null +++ b/include/asm-mips/smtc_proc.h @@ -0,0 +1,23 @@ +/* + * Definitions for SMTC /proc entries + * Copyright(C) 2005 MIPS Technologies Inc. + */ +#ifndef __ASM_SMTC_PROC_H +#define __ASM_SMTC_PROC_H + +/* + * per-"CPU" statistics + */ + +struct smtc_cpu_proc { + unsigned long timerints; + unsigned long selfipis; +}; + +extern struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS]; + +/* Count of number of recoveries of "stolen" FPU access rights on 34K */ + +extern atomic_t smtc_fpu_recoveries; + +#endif /* __ASM_SMTC_PROC_H */ diff --git a/include/asm-mips/sparsemem.h b/include/asm-mips/sparsemem.h new file mode 100644 index 00000000000..795ac6c2320 --- /dev/null +++ b/include/asm-mips/sparsemem.h @@ -0,0 +1,14 @@ +#ifndef _MIPS_SPARSEMEM_H +#define _MIPS_SPARSEMEM_H +#ifdef CONFIG_SPARSEMEM + +/* + * SECTION_SIZE_BITS 2^N: how big each section will be + * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space + */ +#define SECTION_SIZE_BITS 28 +#define MAX_PHYSMEM_BITS 35 + +#endif /* CONFIG_SPARSEMEM */ +#endif /* _MIPS_SPARSEMEM_H */ + diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 2acf3e844f0..c4856a87496 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -14,9 +14,14 @@ #include <linux/threads.h> #include <asm/asm.h> +#include <asm/asmmacro.h> #include <asm/mipsregs.h> #include <asm/asm-offsets.h> +#ifdef CONFIG_MIPS_MT_SMTC +#include <asm/mipsmtregs.h> +#endif /* CONFIG_MIPS_MT_SMTC */ + .macro SAVE_AT .set push .set noat @@ -57,13 +62,30 @@ #ifdef CONFIG_SMP .macro get_saved_sp /* SMP variation */ #ifdef CONFIG_32BIT +#ifdef CONFIG_MIPS_MT_SMTC + .set mips32 + mfc0 k0, CP0_TCBIND; + .set mips0 + lui k1, %hi(kernelsp) + srl k0, k0, 19 + /* No need to shift down and up to clear bits 0-1 */ +#else mfc0 k0, CP0_CONTEXT lui k1, %hi(kernelsp) srl k0, k0, 23 +#endif addu k1, k0 LONG_L k1, %lo(kernelsp)(k1) #endif #ifdef CONFIG_64BIT +#ifdef CONFIG_MIPS_MT_SMTC + .set mips64 + mfc0 k0, CP0_TCBIND; + .set mips0 + lui k0, %highest(kernelsp) + dsrl k1, 19 + /* No need to shift down and up to clear bits 0-2 */ +#else MFC0 k1, CP0_CONTEXT lui k0, %highest(kernelsp) dsrl k1, 23 @@ -71,20 +93,31 @@ dsll k0, k0, 16 daddiu k0, %hi(kernelsp) dsll k0, k0, 16 +#endif /* CONFIG_MIPS_MT_SMTC */ daddu k1, k1, k0 LONG_L k1, %lo(kernelsp)(k1) -#endif +#endif /* CONFIG_64BIT */ .endm .macro set_saved_sp stackp temp temp2 #ifdef CONFIG_32BIT +#ifdef CONFIG_MIPS_MT_SMTC + mfc0 \temp, CP0_TCBIND + srl \temp, 19 +#else mfc0 \temp, CP0_CONTEXT srl \temp, 23 #endif +#endif #ifdef CONFIG_64BIT +#ifdef CONFIG_MIPS_MT_SMTC + mfc0 \temp, CP0_TCBIND + dsrl \temp, 19 +#else MFC0 \temp, CP0_CONTEXT dsrl \temp, 23 #endif +#endif LONG_S \stackp, kernelsp(\temp) .endm #else @@ -122,10 +155,25 @@ PTR_SUBU sp, k1, PT_SIZE LONG_S k0, PT_R29(sp) LONG_S $3, PT_R3(sp) + /* + * You might think that you don't need to save $0, + * but the FPU emulator and gdb remote debug stub + * need it to operate correctly + */ LONG_S $0, PT_R0(sp) mfc0 v1, CP0_STATUS LONG_S $2, PT_R2(sp) LONG_S v1, PT_STATUS(sp) +#ifdef CONFIG_MIPS_MT_SMTC + /* + * Ideally, these instructions would be shuffled in + * to cover the pipeline delay. + */ + .set mips32 + mfc0 v1, CP0_TCSTATUS + .set mips0 + LONG_S v1, PT_TCSTATUS(sp) +#endif /* CONFIG_MIPS_MT_SMTC */ LONG_S $4, PT_R4(sp) mfc0 v1, CP0_CAUSE LONG_S $5, PT_R5(sp) @@ -234,14 +282,36 @@ .endm #else +/* + * For SMTC kernel, global IE should be left set, and interrupts + * controlled exclusively via IXMT. + */ +#ifdef CONFIG_MIPS_MT_SMTC +#define STATMASK 0x1e +#else +#define STATMASK 0x1f +#endif .macro RESTORE_SOME .set push .set reorder .set noat +#ifdef CONFIG_MIPS_MT_SMTC + .set mips32r2 + /* + * This may not really be necessary if ints are already + * inhibited here. + */ + mfc0 v0, CP0_TCSTATUS + ori v0, TCSTATUS_IXMT + mtc0 v0, CP0_TCSTATUS + ehb + DMT 5 # dmt a1 + jal mips_ihb +#endif /* CONFIG_MIPS_MT_SMTC */ mfc0 a0, CP0_STATUS - ori a0, 0x1f - xori a0, 0x1f + ori a0, STATMASK + xori a0, STATMASK mtc0 a0, CP0_STATUS li v1, 0xff00 and a0, v1 @@ -250,6 +320,26 @@ and v0, v1 or v0, a0 mtc0 v0, CP0_STATUS +#ifdef CONFIG_MIPS_MT_SMTC +/* + * Only after EXL/ERL have been restored to status can we + * restore TCStatus.IXMT. + */ + LONG_L v1, PT_TCSTATUS(sp) + ehb + mfc0 v0, CP0_TCSTATUS + andi v1, TCSTATUS_IXMT + /* We know that TCStatua.IXMT should be set from above */ + xori v0, v0, TCSTATUS_IXMT + or v0, v0, v1 + mtc0 v0, CP0_TCSTATUS + ehb + andi a1, a1, VPECONTROL_TE + beqz a1, 1f + emt +1: + .set mips0 +#endif /* CONFIG_MIPS_MT_SMTC */ LONG_L v1, PT_EPC(sp) MTC0 v1, CP0_EPC LONG_L $31, PT_R31(sp) @@ -302,11 +392,33 @@ * Set cp0 enable bit as sign that we're running on the kernel stack */ .macro CLI +#if !defined(CONFIG_MIPS_MT_SMTC) mfc0 t0, CP0_STATUS li t1, ST0_CU0 | 0x1f or t0, t1 xori t0, 0x1f mtc0 t0, CP0_STATUS +#else /* CONFIG_MIPS_MT_SMTC */ + /* + * For SMTC, we need to set privilege + * and disable interrupts only for the + * current TC, using the TCStatus register. + */ + mfc0 t0,CP0_TCSTATUS + /* Fortunately CU 0 is in the same place in both registers */ + /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */ + li t1, ST0_CU0 | 0x08001c00 + or t0,t1 + /* Clear TKSU, leave IXMT */ + xori t0, 0x00001800 + mtc0 t0, CP0_TCSTATUS + ehb + /* We need to leave the global IE bit set, but clear EXL...*/ + mfc0 t0, CP0_STATUS + ori t0, ST0_EXL | ST0_ERL + xori t0, ST0_EXL | ST0_ERL + mtc0 t0, CP0_STATUS +#endif /* CONFIG_MIPS_MT_SMTC */ irq_disable_hazard .endm @@ -315,11 +427,35 @@ * Set cp0 enable bit as sign that we're running on the kernel stack */ .macro STI +#if !defined(CONFIG_MIPS_MT_SMTC) mfc0 t0, CP0_STATUS li t1, ST0_CU0 | 0x1f or t0, t1 xori t0, 0x1e mtc0 t0, CP0_STATUS +#else /* CONFIG_MIPS_MT_SMTC */ + /* + * For SMTC, we need to set privilege + * and enable interrupts only for the + * current TC, using the TCStatus register. + */ + ehb + mfc0 t0,CP0_TCSTATUS + /* Fortunately CU 0 is in the same place in both registers */ + /* Set TCU0, TKSU (for later inversion) and IXMT */ + li t1, ST0_CU0 | 0x08001c00 + or t0,t1 + /* Clear TKSU *and* IXMT */ + xori t0, 0x00001c00 + mtc0 t0, CP0_TCSTATUS + ehb + /* We need to leave the global IE bit set, but clear EXL...*/ + mfc0 t0, CP0_STATUS + ori t0, ST0_EXL + xori t0, ST0_EXL + mtc0 t0, CP0_STATUS + /* irq_enable_hazard below should expand to EHB for 24K/34K cpus */ +#endif /* CONFIG_MIPS_MT_SMTC */ irq_enable_hazard .endm @@ -328,11 +464,56 @@ * Set cp0 enable bit as sign that we're running on the kernel stack */ .macro KMODE +#ifdef CONFIG_MIPS_MT_SMTC + /* + * This gets baroque in SMTC. We want to + * protect the non-atomic clearing of EXL + * with DMT/EMT, but we don't want to take + * an interrupt while DMT is still in effect. + */ + + /* KMODE gets invoked from both reorder and noreorder code */ + .set push + .set mips32r2 + .set noreorder + mfc0 v0, CP0_TCSTATUS + andi v1, v0, TCSTATUS_IXMT + ori v0, TCSTATUS_IXMT + mtc0 v0, CP0_TCSTATUS + ehb + DMT 2 # dmt v0 + /* + * We don't know a priori if ra is "live" + */ + move t0, ra + jal mips_ihb + nop /* delay slot */ + move ra, t0 +#endif /* CONFIG_MIPS_MT_SMTC */ mfc0 t0, CP0_STATUS li t1, ST0_CU0 | 0x1e or t0, t1 xori t0, 0x1e mtc0 t0, CP0_STATUS +#ifdef CONFIG_MIPS_MT_SMTC + ehb + andi v0, v0, VPECONTROL_TE + beqz v0, 2f + nop /* delay slot */ + emt +2: + mfc0 v0, CP0_TCSTATUS + /* Clear IXMT, then OR in previous value */ + ori v0, TCSTATUS_IXMT + xori v0, TCSTATUS_IXMT + or v0, v1, v0 + mtc0 v0, CP0_TCSTATUS + /* + * irq_disable_hazard below should expand to EHB + * on 24K/34K CPUS + */ + .set pop +#endif /* CONFIG_MIPS_MT_SMTC */ irq_disable_hazard .endm diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 4097fac5ac3..261f71d16a0 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -155,6 +155,37 @@ extern asmlinkage void *resume(void *last, void *next, void *next_ti); struct task_struct; +#ifdef CONFIG_MIPS_MT_FPAFF + +/* + * Handle the scheduler resume end of FPU affinity management. We do this + * inline to try to keep the overhead down. If we have been forced to run on + * a "CPU" with an FPU because of a previous high level of FP computation, + * but did not actually use the FPU during the most recent time-slice (CU1 + * isn't set), we undo the restriction on cpus_allowed. + * + * We're not calling set_cpus_allowed() here, because we have no need to + * force prompt migration - we're already switching the current CPU to a + * different thread. + */ + +#define switch_to(prev,next,last) \ +do { \ + if (cpu_has_fpu && \ + (prev->thread.mflags & MF_FPUBOUND) && \ + (!(KSTK_STATUS(prev) & ST0_CU1))) { \ + prev->thread.mflags &= ~MF_FPUBOUND; \ + prev->cpus_allowed = prev->thread.user_cpus_allowed; \ + } \ + if (cpu_has_dsp) \ + __save_dsp(prev); \ + next->thread.emulated_fp = 0; \ + (last) = resume(prev, next, next->thread_info); \ + if (cpu_has_dsp) \ + __restore_dsp(current); \ +} while(0) + +#else #define switch_to(prev,next,last) \ do { \ if (cpu_has_dsp) \ @@ -163,6 +194,7 @@ do { \ if (cpu_has_dsp) \ __restore_dsp(current); \ } while(0) +#endif /* * On SMP systems, when the scheduler does migration-cost autodetection, @@ -440,8 +472,8 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, extern void set_handler (unsigned long offset, void *addr, unsigned long len); extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); extern void *set_vi_handler (int n, void *addr); -extern void *set_vi_srs_handler (int n, void *addr, int regset); extern void *set_except_vector(int n, void *addr); +extern unsigned long ebase; extern void per_cpu_trap_init(void); extern NORET_TYPE void die(const char *, struct pt_regs *); diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index b5c78a4a019..1068fe9a0a5 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -324,16 +324,18 @@ #define __NR_pselect6 (__NR_Linux + 301) #define __NR_ppoll (__NR_Linux + 302) #define __NR_unshare (__NR_Linux + 303) +#define __NR_splice (__NR_Linux + 304) +#define __NR_sync_file_range (__NR_Linux + 305) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 303 +#define __NR_Linux_syscalls 305 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 303 +#define __NR_O32_Linux_syscalls 305 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -604,16 +606,18 @@ #define __NR_pselect6 (__NR_Linux + 260) #define __NR_ppoll (__NR_Linux + 261) #define __NR_unshare (__NR_Linux + 262) +#define __NR_splice (__NR_Linux + 263) +#define __NR_sync_file_range (__NR_Linux + 264) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 262 +#define __NR_Linux_syscalls 264 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 262 +#define __NR_64_Linux_syscalls 264 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -888,16 +892,18 @@ #define __NR_pselect6 (__NR_Linux + 264) #define __NR_ppoll (__NR_Linux + 265) #define __NR_unshare (__NR_Linux + 266) +#define __NR_splice (__NR_Linux + 267) +#define __NR_sync_file_range (__NR_Linux + 268) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 266 +#define __NR_Linux_syscalls 268 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 266 +#define __NR_N32_Linux_syscalls 268 #ifndef __ASSEMBLY__ diff --git a/include/asm-mips/vpe.h b/include/asm-mips/vpe.h new file mode 100644 index 00000000000..c6e1b961537 --- /dev/null +++ b/include/asm-mips/vpe.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef _ASM_VPE_H +#define _ASM_VPE_H + +struct vpe_notifications { + void (*start)(int vpe); + void (*stop)(int vpe); + + struct list_head list; +}; + + +extern int vpe_notify(int index, struct vpe_notifications *notify); + +extern void *vpe_get_shared(int index); +extern int vpe_getuid(int index); +extern int vpe_getgid(int index); +extern char *vpe_getcwd(int index); + +#endif /* _ASM_VPE_H */ |