diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/Kconfig | 22 | ||||
-rw-r--r-- | arch/mips/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 13 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 8 | ||||
-rw-r--r-- | arch/mips/kernel/proc.c | 1 | ||||
-rw-r--r-- | arch/mips/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 54 | ||||
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 23 | ||||
-rw-r--r-- | arch/mips/mm/tlbex.c | 8 |
10 files changed, 122 insertions, 10 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 624c31c..c8d954d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -894,6 +894,16 @@ choice prompt "CPU type" default CPU_R4X00 +config CPU_LOONGSON2 + bool "Loongson 2" + depends on SYS_HAS_CPU_LOONGSON2 + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + help + The Loongson 2E processor implements the MIPS III instruction set + with many extensions. + config CPU_MIPS32_R1 bool "MIPS32 Release 1" depends on SYS_HAS_CPU_MIPS32_R1 @@ -1104,6 +1114,9 @@ config CPU_SB1 endchoice +config SYS_HAS_CPU_LOONGSON2 + bool + config SYS_HAS_CPU_MIPS32_R1 bool @@ -1438,6 +1451,15 @@ config CPU_HAS_SMARTMIPS config CPU_HAS_WB bool +config 64BIT_CONTEXT + bool "Save 64bit integer registers" + depends on 32BIT && CPU_LOONGSON2 + help + Loongson2 CPU is 64bit , when used in 32BIT mode, its integer + registers can still be accessed as 64bit, mainly for multimedia + instructions. We must have all 64bit save/restored to make sure + those instructions to get correct result. + # # Vectored interrupt mode is an R2 feature # diff --git a/arch/mips/Makefile b/arch/mips/Makefile index fc09769..1e4579c 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -118,6 +118,7 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2) += -march=r4600 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ -Wa,-mips32 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index bb25dd8..73983ee 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -14,14 +14,15 @@ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o +obj-$(CONFIG_CPU_LOONGSON2) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o -obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o -obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4000) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4300) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R4X00) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R5000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R5432) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R8000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_RM7000) += r4k_fpu.o r4k_switch.o @@ -29,9 +30,9 @@ obj-$(CONFIG_CPU_RM9000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o +obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 27fc184..23d8a3b 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -485,6 +485,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) MIPS_CPU_LLSC; c->tlbsize = 64; break; + case PRID_IMP_LOONGSON2: + c->cputype = CPU_LOONGSON2; + c->isa_level = MIPS_CPU_ISA_III; + c->options = R4K_OPTS | + MIPS_CPU_FPU | MIPS_CPU_LLSC | + MIPS_CPU_32FPR; + c->tlbsize = 64; + break; } } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index eb7730d..ec04f5a 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -83,6 +83,7 @@ static const char *cpu_name[] = { [CPU_VR4181A] = "NEC VR4181A", [CPU_SR71000] = "Sandcraft SR71000", [CPU_PR4450] = "Philips PR4450", + [CPU_LOONGSON2] = "ICT Loongson-2", }; diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 1a484e4..91ed1eb 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -8,6 +8,7 @@ lib-y += csum_partial.o memcpy.o memcpy-inatomic.o memset.o strlen_user.o \ obj-y += iomap.o obj-$(CONFIG_PCI) += iomap-pci.o +obj-$(CONFIG_CPU_LOONGSON2) += dump_tlb.o obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o obj-$(CONFIG_CPU_NEVADA) += dump_tlb.o diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 293697b..19a0e54 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index df04a31..be96231 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -335,6 +335,10 @@ static void r4k_flush_cache_all(void) static inline void local_r4k___flush_cache_all(void * args) { +#if defined(CONFIG_CPU_LOONGSON2) + r4k_blast_scache(); + return; +#endif r4k_blast_dcache(); r4k_blast_icache(); @@ -848,6 +852,24 @@ static void __init probe_pcache(void) c->options |= MIPS_CPU_PREFETCH; break; + case CPU_LOONGSON2: + icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); + c->icache.linesz = 16 << ((config & CONF_IB) >> 5); + if (prid & 0x3) + c->icache.ways = 4; + else + c->icache.ways = 2; + c->icache.waybit = 0; + + dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); + c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); + if (prid & 0x3) + c->dcache.ways = 4; + else + c->dcache.ways = 2; + c->dcache.waybit = 0; + break; + default: if (!(config & MIPS_CONF_M)) panic("Don't know how to probe P-caches on this cpu."); @@ -963,6 +985,14 @@ static void __init probe_pcache(void) break; } +#ifdef CONFIG_CPU_LOONGSON2 + /* + * LOONGSON2 has 4 way icache, but when using indexed cache op, + * one op will act on all 4 ways + */ + c->icache.ways = 1; +#endif + printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n", icache_size >> 10, cpu_has_vtag_icache ? "virtually tagged" : "physically tagged", @@ -1036,6 +1066,24 @@ static int __init probe_scache(void) return 1; } +#if defined(CONFIG_CPU_LOONGSON2) +static void __init loongson2_sc_init(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + + scache_size = 512*1024; + c->scache.linesz = 32; + c->scache.ways = 4; + c->scache.waybit = 0; + c->scache.waysize = scache_size / (c->scache.ways); + c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways); + pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n", + scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); + + c->options |= MIPS_CPU_INCLUSIVE_CACHES; +} +#endif + extern int r5k_sc_init(void); extern int rm7k_sc_init(void); extern int mips_sc_init(void); @@ -1085,6 +1133,12 @@ static void __init setup_scache(void) #endif return; +#if defined(CONFIG_CPU_LOONGSON2) + case CPU_LOONGSON2: + loongson2_sc_init(); + return; +#endif + default: if (c->isa_level == MIPS_CPU_ISA_M32R1 || c->isa_level == MIPS_CPU_ISA_M32R2 || diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 65160d4..dcd6913 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -48,6 +48,22 @@ extern void build_tlb_refill_handler(void); #endif /* CONFIG_MIPS_MT_SMTC */ +#if defined(CONFIG_CPU_LOONGSON2) +/* + * LOONGSON2 has a 4 entry itlb which is a subset of dtlb, + * unfortrunately, itlb is not totally transparent to software. + */ +#define FLUSH_ITLB write_c0_diag(4); + +#define FLUSH_ITLB_VM(vma) { if ((vma)->vm_flags & VM_EXEC) write_c0_diag(4); } + +#else + +#define FLUSH_ITLB +#define FLUSH_ITLB_VM(vma) + +#endif + void local_flush_tlb_all(void) { unsigned long flags; @@ -73,6 +89,7 @@ void local_flush_tlb_all(void) } tlbw_use_hazard(); write_c0_entryhi(old_ctx); + FLUSH_ITLB; EXIT_CRITICAL(flags); } @@ -136,6 +153,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, } else { drop_mmu_context(mm, cpu); } + FLUSH_ITLB; EXIT_CRITICAL(flags); } } @@ -178,6 +196,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) } else { local_flush_tlb_all(); } + FLUSH_ITLB; EXIT_CRITICAL(flags); } @@ -210,6 +229,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: write_c0_entryhi(oldpid); + FLUSH_ITLB_VM(vma); EXIT_CRITICAL(flags); } } @@ -241,7 +261,7 @@ void local_flush_tlb_one(unsigned long page) tlbw_use_hazard(); } write_c0_entryhi(oldpid); - + FLUSH_ITLB; EXIT_CRITICAL(flags); } @@ -293,6 +313,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) else tlb_write_indexed(); tlbw_use_hazard(); + FLUSH_ITLB_VM(vma); EXIT_CRITICAL(flags); } diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index e714929..4ec0964 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -893,6 +893,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, case CPU_4KSC: case CPU_20KC: case CPU_25KF: + case CPU_LOONGSON2: tlbw(p); break; @@ -1276,7 +1277,8 @@ static void __init build_r4000_tlb_refill_handler(void) * need three, with the second nop'ed and the third being * unused. */ -#ifdef CONFIG_32BIT + /* Loongson2 ebase is different than r4k, we have more space */ +#if defined(CONFIG_32BIT) || defined(CONFIG_CPU_LOONGSON2) if ((p - tlb_handler) > 64) panic("TLB refill handler space exceeded"); #else @@ -1289,7 +1291,7 @@ static void __init build_r4000_tlb_refill_handler(void) /* * Now fold the handler in the TLB refill handler space. */ -#ifdef CONFIG_32BIT +#if defined(CONFIG_32BIT) || defined(CONFIG_CPU_LOONGSON2) f = final_handler; /* Simplest case, just copy the handler. */ copy_handler(relocs, labels, tlb_handler, p, f); @@ -1336,7 +1338,7 @@ static void __init build_r4000_tlb_refill_handler(void) final_len); f = final_handler; -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) && !defined(CONFIG_CPU_LOONGSON2) if (final_len > 32) final_len = 64; else |