From 325f8a0a31df567dbafafc48f8e60f3c1f101a46 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 13:52:36 -0800 Subject: MIPS: Two-level pagetables for 64-bit kernels with 64KB pages. For 64-bit kernels with 64KB pages and two level page tables, there are 42 bits worth of virtual address space This is larger than the 40 bits of virtual address space obtained with the default 4KB Page size and three levels, so there are no draw backs for using two level tables with this configuration. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/761/ Signed-off-by: Ralf Baechle --- arch/mips/mm/init.c | 2 +- arch/mips/mm/pgtable-64.c | 44 +++++++++++++++++++++++++++----------------- arch/mips/mm/tlbex.c | 2 ++ 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 1651942f7fe..3c5b7de10af 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -477,7 +477,7 @@ unsigned long pgd_current[NR_CPUS]; * will officially be retired. */ pgd_t swapper_pg_dir[_PTRS_PER_PGD] __page_aligned(_PGD_ORDER); -#ifdef CONFIG_64BIT +#ifndef __PAGETABLE_PMD_FOLDED pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER); #endif pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER); diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c index 1121019fa45..78eaa4f0b0e 100644 --- a/arch/mips/mm/pgtable-64.c +++ b/arch/mips/mm/pgtable-64.c @@ -15,23 +15,31 @@ void pgd_init(unsigned long page) { unsigned long *p, *end; + unsigned long entry; + +#ifdef __PAGETABLE_PMD_FOLDED + entry = (unsigned long)invalid_pte_table; +#else + entry = (unsigned long)invalid_pmd_table; +#endif p = (unsigned long *) page; end = p + PTRS_PER_PGD; while (p < end) { - p[0] = (unsigned long) invalid_pmd_table; - p[1] = (unsigned long) invalid_pmd_table; - p[2] = (unsigned long) invalid_pmd_table; - p[3] = (unsigned long) invalid_pmd_table; - p[4] = (unsigned long) invalid_pmd_table; - p[5] = (unsigned long) invalid_pmd_table; - p[6] = (unsigned long) invalid_pmd_table; - p[7] = (unsigned long) invalid_pmd_table; + p[0] = entry; + p[1] = entry; + p[2] = entry; + p[3] = entry; + p[4] = entry; + p[5] = entry; + p[6] = entry; + p[7] = entry; p += 8; } } +#ifndef __PAGETABLE_PMD_FOLDED void pmd_init(unsigned long addr, unsigned long pagetable) { unsigned long *p, *end; @@ -40,17 +48,18 @@ void pmd_init(unsigned long addr, unsigned long pagetable) end = p + PTRS_PER_PMD; while (p < end) { - p[0] = (unsigned long)pagetable; - p[1] = (unsigned long)pagetable; - p[2] = (unsigned long)pagetable; - p[3] = (unsigned long)pagetable; - p[4] = (unsigned long)pagetable; - p[5] = (unsigned long)pagetable; - p[6] = (unsigned long)pagetable; - p[7] = (unsigned long)pagetable; + p[0] = pagetable; + p[1] = pagetable; + p[2] = pagetable; + p[3] = pagetable; + p[4] = pagetable; + p[5] = pagetable; + p[6] = pagetable; + p[7] = pagetable; p += 8; } } +#endif void __init pagetable_init(void) { @@ -59,8 +68,9 @@ void __init pagetable_init(void) /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); +#ifndef __PAGETABLE_PMD_FOLDED pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); - +#endif pgd_base = swapper_pg_dir; /* * Fixed mappings: diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index badcf5e8d69..eae45f0f9a1 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -549,11 +549,13 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3); uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */ +#ifndef __PAGETABLE_PMD_FOLDED uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */ uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */ uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */ uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3); uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */ +#endif } /* -- cgit From 2a880986d899f556f5a327bc77cc8760d5bb9c64 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 22 Jan 2010 14:41:14 -0800 Subject: MIPS: Remove probe_tlb(). The function probe_tlb() only does anything for processors that are not PRID_COMP_LEGACY. This is precisely the set of processors for which decode_configs() is called to do identical tlbsize probing calculations. Therefore probe_tlb() is completely redundant and may be removed. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/865/ Signed-off-by: Ralf Baechle --- arch/mips/mm/tlb-r4k.c | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index d73428b18b0..45b7c35950c 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -447,34 +447,6 @@ out: return ret; } -static void __cpuinit probe_tlb(unsigned long config) -{ - struct cpuinfo_mips *c = ¤t_cpu_data; - unsigned int reg; - - /* - * If this isn't a MIPS32 / MIPS64 compliant CPU. Config 1 register - * is not supported, we assume R4k style. Cpu probing already figured - * out the number of tlb entries. - */ - if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY) - return; -#ifdef CONFIG_MIPS_MT_SMTC - /* - * If TLB is shared in SMTC system, total size already - * has been calculated and written into cpu_data tlbsize - */ - if((smtc_status & SMTC_TLB_SHARED) == SMTC_TLB_SHARED) - return; -#endif /* CONFIG_MIPS_MT_SMTC */ - - reg = read_c0_config1(); - if (!((config >> 7) & 3)) - panic("No TLB present"); - - c->tlbsize = ((reg >> 25) & 0x3f) + 1; -} - static int __cpuinitdata ntlb; static int __init set_ntlb(char *str) { @@ -486,8 +458,6 @@ __setup("ntlb=", set_ntlb); void __cpuinit tlb_init(void) { - unsigned int config = read_c0_config(); - /* * You should never change this register: * - On R4600 1.7 the tlbp never hits for pages smaller than @@ -495,7 +465,6 @@ void __cpuinit tlb_init(void) * - The entire mm handling assumes the c0_pagemask register to * be set to fixed-size pages. */ - probe_tlb(config); write_c0_pagemask(PM_DEFAULT_MASK); write_c0_wired(0); if (current_cpu_type() == CPU_R10000 || -- cgit From e0e53dee69e07e9446eb16ceabd55a1116611696 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 27 Feb 2010 12:53:14 +0100 Subject: MIPS: Nuke trailing blank lines Recent git versions now warn about those and they've always been a bit of an annoyance. Signed-off-by: Ralf Baechle --- arch/mips/mm/c-octeon.c | 1 - arch/mips/mm/hugetlbpage.c | 1 - 2 files changed, 2 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index e06f1af760a..af85959e59f 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -305,4 +305,3 @@ asmlinkage void cache_parity_error_octeon_non_recoverable(void) { cache_parity_error_octeon(1); } - diff --git a/arch/mips/mm/hugetlbpage.c b/arch/mips/mm/hugetlbpage.c index 8c2834f5919..cd0660c51f2 100644 --- a/arch/mips/mm/hugetlbpage.c +++ b/arch/mips/mm/hugetlbpage.c @@ -97,4 +97,3 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); return page; } - -- cgit From 3482d713a91befb8c96722cb8d55aed36c212d9e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 28 Jan 2010 15:21:24 +0100 Subject: MIPS: Move arch/mips/mm/uasm.h to arch/mips/include/asm/uasm.h Signed-off-by: Florian Fainelli To: linux-mips@linux-mips.org To: David Daney Patchwork: http://patchwork.linux-mips.org/patch/887/ Signed-off-by: Ralf Baechle --- arch/mips/mm/page.c | 2 +- arch/mips/mm/tlbex.c | 3 +- arch/mips/mm/uasm.c | 3 +- arch/mips/mm/uasm.h | 191 --------------------------------------------------- 4 files changed, 3 insertions(+), 196 deletions(-) delete mode 100644 arch/mips/mm/uasm.h (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index f5c73754d66..36272f7d374 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -35,7 +35,7 @@ #include #endif -#include "uasm.h" +#include /* Registers used in the assembled routines. */ #define ZERO 0 diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index eae45f0f9a1..bcf30026d1f 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -29,8 +29,7 @@ #include #include - -#include "uasm.h" +#include static inline int r45k_bvahwbug(void) { diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 0a165c5179a..e3ca0f7ed01 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -19,8 +19,7 @@ #include #include #include - -#include "uasm.h" +#include enum fields { RS = 0x001, diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h deleted file mode 100644 index 3d153edaa51..00000000000 --- a/arch/mips/mm/uasm.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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) 2004, 2005, 2006, 2008 Thiemo Seufer - * Copyright (C) 2005 Maciej W. Rozycki - * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) - */ - -#include - -#define Ip_u1u2u3(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) - -#define Ip_u2u1u3(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) - -#define Ip_u3u1u2(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) - -#define Ip_u1u2s3(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) - -#define Ip_u2s3u1(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c) - -#define Ip_u2u1s3(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) - -#define Ip_u2u1msbu3(op) \ -void __cpuinit \ -uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \ - unsigned int d) - -#define Ip_u1u2(op) \ -void __cpuinit uasm_i##op(u32 **buf, unsigned int a, unsigned int b) - -#define Ip_u1s2(op) \ -void __cpuinit uasm_i##op(u32 **buf, unsigned int a, signed int b) - -#define Ip_u1(op) void __cpuinit uasm_i##op(u32 **buf, unsigned int a) - -#define Ip_0(op) void __cpuinit uasm_i##op(u32 **buf) - -Ip_u2u1s3(_addiu); -Ip_u3u1u2(_addu); -Ip_u2u1u3(_andi); -Ip_u3u1u2(_and); -Ip_u1u2s3(_beq); -Ip_u1u2s3(_beql); -Ip_u1s2(_bgez); -Ip_u1s2(_bgezl); -Ip_u1s2(_bltz); -Ip_u1s2(_bltzl); -Ip_u1u2s3(_bne); -Ip_u2s3u1(_cache); -Ip_u1u2u3(_dmfc0); -Ip_u1u2u3(_dmtc0); -Ip_u2u1s3(_daddiu); -Ip_u3u1u2(_daddu); -Ip_u2u1u3(_dsll); -Ip_u2u1u3(_dsll32); -Ip_u2u1u3(_dsra); -Ip_u2u1u3(_dsrl); -Ip_u2u1u3(_dsrl32); -Ip_u2u1u3(_drotr); -Ip_u3u1u2(_dsubu); -Ip_0(_eret); -Ip_u1(_j); -Ip_u1(_jal); -Ip_u1(_jr); -Ip_u2s3u1(_ld); -Ip_u2s3u1(_ll); -Ip_u2s3u1(_lld); -Ip_u1s2(_lui); -Ip_u2s3u1(_lw); -Ip_u1u2u3(_mfc0); -Ip_u1u2u3(_mtc0); -Ip_u2u1u3(_ori); -Ip_u2s3u1(_pref); -Ip_0(_rfe); -Ip_u2s3u1(_sc); -Ip_u2s3u1(_scd); -Ip_u2s3u1(_sd); -Ip_u2u1u3(_sll); -Ip_u2u1u3(_sra); -Ip_u2u1u3(_srl); -Ip_u3u1u2(_subu); -Ip_u2s3u1(_sw); -Ip_0(_tlbp); -Ip_0(_tlbwi); -Ip_0(_tlbwr); -Ip_u3u1u2(_xor); -Ip_u2u1u3(_xori); -Ip_u2u1msbu3(_dins); - -/* Handle labels. */ -struct uasm_label { - u32 *addr; - int lab; -}; - -void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid); -#ifdef CONFIG_64BIT -int uasm_in_compat_space_p(long addr); -#endif -int uasm_rel_hi(long val); -int uasm_rel_lo(long val); -void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr); -void UASM_i_LA(u32 **buf, unsigned int rs, long addr); - -#define UASM_L_LA(lb) \ -static inline void __cpuinit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ -{ \ - uasm_build_label(lab, addr, label##lb); \ -} - -/* convenience macros for instructions */ -#ifdef CONFIG_64BIT -# define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off) -# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off) -# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh) -# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh) -# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh) -# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd) -# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd) -# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val) -# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd) -# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) -# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) -# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) -#else -# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) -# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) -# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh) -# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh) -# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh) -# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd) -# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd) -# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val) -# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd) -# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) -# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) -# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) -#endif - -#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) -#define uasm_i_beqz(buf, rs, off) uasm_i_beq(buf, rs, 0, off) -#define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off) -#define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off) -#define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off) -#define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b) -#define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0) -#define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1) -#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3) - -/* Handle relocations. */ -struct uasm_reloc { - u32 *addr; - unsigned int type; - int lab; -}; - -/* This is zero so we can use zeroed label arrays. */ -#define UASM_LABEL_INVALID 0 - -void uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid); -void uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab); -void uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off); -void uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off); -void uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, - u32 *first, u32 *end, u32 *target); -int uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr); - -/* Convenience functions for labeled branches. */ -void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid); -void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, - unsigned int reg2, int lid); -void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -- cgit From b66bb6090d9aa36931911e34d3f069932934b6fe Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 2 Feb 2010 17:19:38 -0800 Subject: MIPS: Remove #if 0 r4k_update_mmu_cache_hwbug The function is #if 0ed out. There are no other occurrences of its name in the tree. It is safe to remove. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/936/ Signed-off-by: Ralf Baechle --- arch/mips/mm/tlb-r4k.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 45b7c35950c..21d04dfa11d 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -337,40 +337,6 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) EXIT_CRITICAL(flags); } -#if 0 -static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - unsigned int asid; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx; - - ENTER_CRITICAL(flags); - address &= (PAGE_MASK << 1); - asid = read_c0_entryhi() & ASID_MASK; - write_c0_entryhi(address | asid); - pgdp = pgd_offset(vma->vm_mm, address); - mtc0_tlbw_hazard(); - tlb_probe(); - tlb_probe_hazard(); - pmdp = pmd_offset(pgdp, address); - idx = read_c0_index(); - ptep = pte_offset_map(pmdp, address); - write_c0_entrylo0(pte_val(*ptep++) >> 6); - write_c0_entrylo1(pte_val(*ptep) >> 6); - mtc0_tlbw_hazard(); - if (idx < 0) - tlb_write_random(); - else - tlb_write_indexed(); - tlbw_use_hazard(); - EXIT_CRITICAL(flags); -} -#endif - void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { -- cgit From 9b8c38917b8e083a6343bb5a0c6bbaea78ebff7a Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 10 Feb 2010 15:12:44 -0800 Subject: MIPS: Use 64-bit stores to c0_entrylo on 64-bit kernels. 64-bit CPUs have 64-bit c0_entrylo{0,1} registers. We should use the 64-bit dmtc0 instruction to set them. This becomes important if we want to set the RI and XI bits present in some processors. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/954/ Signed-off-by: Ralf Baechle --- arch/mips/mm/tlbex.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index bcf30026d1f..4a2907c5956 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -460,14 +460,14 @@ static __cpuinit void build_huge_update_entries(u32 **p, uasm_i_lui(p, tmp, HPAGE_SIZE >> (7 + 16)); UASM_i_SRL(p, pte, pte, 6); /* convert to entrylo */ - uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* load it */ + UASM_i_MTC0(p, pte, C0_ENTRYLO0); /* load it */ /* convert to entrylo1 */ if (small_sequence) UASM_i_ADDIU(p, pte, pte, HPAGE_SIZE >> 7); else UASM_i_ADDU(p, pte, pte, tmp); - uasm_i_mtc0(p, pte, C0_ENTRYLO1); /* load it */ + UASM_i_MTC0(p, pte, C0_ENTRYLO1); /* load it */ } static __cpuinit void build_huge_handler_tail(u32 **p, @@ -686,18 +686,18 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, uasm_i_ld(p, tmp, 0, ptep); /* get even pte */ uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */ - uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */ - uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */ + UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ } else { int pte_off_even = sizeof(pte_t) / 2; int pte_off_odd = pte_off_even + sizeof(pte_t); /* The pte entries are pre-shifted */ uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */ - uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */ - uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */ + UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ } #else UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ @@ -706,14 +706,14 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, build_tlb_probe_entry(p); UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */ if (r4k_250MHZhwbug()) - uasm_i_mtc0(p, 0, C0_ENTRYLO0); - uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_MTC0(p, 0, C0_ENTRYLO0); + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */ if (r45k_bvahwbug()) uasm_i_mfc0(p, tmp, C0_INDEX); if (r4k_250MHZhwbug()) - uasm_i_mtc0(p, 0, C0_ENTRYLO1); - uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */ + UASM_i_MTC0(p, 0, C0_ENTRYLO1); + UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ #endif } -- cgit From 32546f38fab839eee6f62b3f06c2774eade4188a Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 10 Feb 2010 15:12:46 -0800 Subject: MIPS: Add TLBR and ROTR to uasm. The soon to follow Read Inhibit/eXecute Inhibit patch needs TLBR and ROTR support in uasm. We also add a UASM_i_ROTR macro. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/953/ Signed-off-by: Ralf Baechle --- arch/mips/mm/uasm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index e3ca0f7ed01..1581e985246 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -62,8 +62,9 @@ enum opcode { insn_dsrl32, insn_drotr, insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd, - insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw, - insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, insn_dins + insn_sd, insn_sll, insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, + insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, + insn_dins }; struct insn { @@ -125,9 +126,11 @@ static struct insn insn_table[] __cpuinitdata = { { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE }, + { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE }, { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, + { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 }, { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 }, { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, @@ -378,9 +381,11 @@ I_u2s3u1(_sd) I_u2u1u3(_sll) I_u2u1u3(_sra) I_u2u1u3(_srl) +I_u2u1u3(_rotr) I_u3u1u2(_subu) I_u2s3u1(_sw) I_0(_tlbp) +I_0(_tlbr) I_0(_tlbwi) I_0(_tlbwr) I_u3u1u2(_xor) -- cgit From 6dd9344cfc41bcc60a01cdc828cb278be7a10e01 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 10 Feb 2010 15:12:47 -0800 Subject: MIPS: Implement Read Inhibit/eXecute Inhibit The SmartMIPS ASE specifies how Read Inhibit (RI) and eXecute Inhibit (XI) bits in the page tables work. The upper two bits of EntryLo{0,1} are RI and XI when the feature is enabled in the PageGrain register. SmartMIPS only covers 32-bit systems. Cavium Octeon+ extends this to 64-bit systems by continuing to place the RI and XI bits in the top of EntryLo even when EntryLo is 64-bits wide. Because we need to carry the RI and XI bits in the PTE, the layout of the PTE is changed. There is a two instruction overhead in the TLB refill hot path to get the EntryLo bits into the proper position. Also the TLB load exception has to probe the TLB to check if RI or XI caused the exception. Also of note is that the layout of the PTE bits is done at compile and runtime rather than statically. In the 32-bit case this allows for the same number of PFN bits as before the patch as the _PAGE_HUGE is not supported in 32-bit kernels (we have _PAGE_NO_EXEC and _PAGE_NO_READ instead of _PAGE_READ and _PAGE_HUGE). The patch is tested on Cavium Octeon+, but should also work on 32-bit systems with the Smart-MIPS ASE. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/952/ Patchwork: http://patchwork.linux-mips.org/patch/956/ Patchwork: http://patchwork.linux-mips.org/patch/962/ Signed-off-by: Ralf Baechle --- arch/mips/mm/cache.c | 53 +++++++++++----- arch/mips/mm/fault.c | 27 +++++++- arch/mips/mm/init.c | 2 +- arch/mips/mm/tlb-r4k.c | 19 +++++- arch/mips/mm/tlbex.c | 169 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 220 insertions(+), 50 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index e716cafc346..be8627bc5b0 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -137,22 +137,43 @@ EXPORT_SYMBOL_GPL(_page_cachable_default); static inline void setup_protection_map(void) { - protection_map[0] = PAGE_NONE; - protection_map[1] = PAGE_READONLY; - protection_map[2] = PAGE_COPY; - protection_map[3] = PAGE_COPY; - protection_map[4] = PAGE_READONLY; - protection_map[5] = PAGE_READONLY; - protection_map[6] = PAGE_COPY; - protection_map[7] = PAGE_COPY; - protection_map[8] = PAGE_NONE; - protection_map[9] = PAGE_READONLY; - protection_map[10] = PAGE_SHARED; - protection_map[11] = PAGE_SHARED; - protection_map[12] = PAGE_READONLY; - protection_map[13] = PAGE_READONLY; - protection_map[14] = PAGE_SHARED; - protection_map[15] = PAGE_SHARED; + if (kernel_uses_smartmips_rixi) { + protection_map[0] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); + protection_map[1] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); + protection_map[2] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); + protection_map[3] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); + protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[5] = __pgprot(_page_cachable_default | _PAGE_PRESENT); + protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[7] = __pgprot(_page_cachable_default | _PAGE_PRESENT); + + protection_map[8] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); + protection_map[9] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); + protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ); + protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE); + protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT); + protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ); + protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); + + } else { + protection_map[0] = PAGE_NONE; + protection_map[1] = PAGE_READONLY; + protection_map[2] = PAGE_COPY; + protection_map[3] = PAGE_COPY; + protection_map[4] = PAGE_READONLY; + protection_map[5] = PAGE_READONLY; + protection_map[6] = PAGE_COPY; + protection_map[7] = PAGE_COPY; + protection_map[8] = PAGE_NONE; + protection_map[9] = PAGE_READONLY; + protection_map[10] = PAGE_SHARED; + protection_map[11] = PAGE_SHARED; + protection_map[12] = PAGE_READONLY; + protection_map[13] = PAGE_READONLY; + protection_map[14] = PAGE_SHARED; + protection_map[15] = PAGE_SHARED; + } } void __cpuinit cpu_cache_init(void) diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index e97a7a2fb2c..b78f7d913ca 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -99,8 +99,31 @@ good_area: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { - if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) - goto bad_area; + if (kernel_uses_smartmips_rixi) { + if (address == regs->cp0_epc && !(vma->vm_flags & VM_EXEC)) { +#if 0 + pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] XI violation\n", + raw_smp_processor_id(), + current->comm, current->pid, + field, address, write, + field, regs->cp0_epc); +#endif + goto bad_area; + } + if (!(vma->vm_flags & VM_READ)) { +#if 0 + pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n", + raw_smp_processor_id(), + current->comm, current->pid, + field, address, write, + field, regs->cp0_epc); +#endif + goto bad_area; + } + } else { + if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) + goto bad_area; + } } /* diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 3c5b7de10af..f34c26439a3 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -143,7 +143,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) entrylo = pte.pte_high; #else - entrylo = pte_val(pte) >> 6; + entrylo = pte_to_entrylo(pte_val(pte)); #endif ENTER_CRITICAL(flags); diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 21d04dfa11d..c618eed933a 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -303,7 +303,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) unsigned long lo; write_c0_pagemask(PM_HUGE_MASK); ptep = (pte_t *)pmdp; - lo = pte_val(*ptep) >> 6; + lo = pte_to_entrylo(pte_val(*ptep)); write_c0_entrylo0(lo); write_c0_entrylo1(lo + (HPAGE_SIZE >> 7)); @@ -323,8 +323,8 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) ptep++; write_c0_entrylo1(ptep->pte_high); #else - write_c0_entrylo0(pte_val(*ptep++) >> 6); - write_c0_entrylo1(pte_val(*ptep) >> 6); + write_c0_entrylo0(pte_to_entrylo(pte_val(*ptep++))); + write_c0_entrylo1(pte_to_entrylo(pte_val(*ptep))); #endif mtc0_tlbw_hazard(); if (idx < 0) @@ -437,6 +437,19 @@ void __cpuinit tlb_init(void) current_cpu_type() == CPU_R12000 || current_cpu_type() == CPU_R14000) write_c0_framemask(0); + + if (kernel_uses_smartmips_rixi) { + /* + * Enable the no read, no exec bits, and enable large virtual + * address. + */ + u32 pg = PG_RIE | PG_XIE; +#ifdef CONFIG_64BIT + pg |= PG_ELPA; +#endif + write_c0_pagegrain(pg); + } + temp_tlb_entry = current_cpu_data.tlbsize - 1; /* From this point on the ARC firmware is dead. */ diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 4a2907c5956..0de0e4127d6 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -76,6 +76,8 @@ enum label_id { label_vmalloc_done, label_tlbw_hazard, label_split, + label_tlbl_goaround1, + label_tlbl_goaround2, label_nopage_tlbl, label_nopage_tlbs, label_nopage_tlbm, @@ -92,6 +94,8 @@ UASM_L_LA(_vmalloc) UASM_L_LA(_vmalloc_done) UASM_L_LA(_tlbw_hazard) UASM_L_LA(_split) +UASM_L_LA(_tlbl_goaround1) +UASM_L_LA(_tlbl_goaround2) UASM_L_LA(_nopage_tlbl) UASM_L_LA(_nopage_tlbs) UASM_L_LA(_nopage_tlbm) @@ -396,36 +400,60 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, } } -#ifdef CONFIG_HUGETLB_PAGE -static __cpuinit void build_huge_tlb_write_entry(u32 **p, - struct uasm_label **l, - struct uasm_reloc **r, - unsigned int tmp, - enum tlb_write_entry wmode) +static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p, + unsigned int reg) { - /* Set huge page tlb entry size */ - uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); - uasm_i_ori(p, tmp, tmp, PM_HUGE_MASK & 0xffff); - uasm_i_mtc0(p, tmp, C0_PAGEMASK); + if (kernel_uses_smartmips_rixi) { + UASM_i_SRL(p, reg, reg, ilog2(_PAGE_NO_EXEC)); + UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); + } else { +#ifdef CONFIG_64BIT_PHYS_ADDR + uasm_i_dsrl(p, reg, reg, ilog2(_PAGE_GLOBAL)); +#else + UASM_i_SRL(p, reg, reg, ilog2(_PAGE_GLOBAL)); +#endif + } +} - build_tlb_write_entry(p, l, r, wmode); +#ifdef CONFIG_HUGETLB_PAGE +static __cpuinit void build_restore_pagemask(u32 **p, + struct uasm_reloc **r, + unsigned int tmp, + enum label_id lid) +{ /* Reset default page size */ if (PM_DEFAULT_MASK >> 16) { uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); - uasm_il_b(p, r, label_leave); + uasm_il_b(p, r, lid); uasm_i_mtc0(p, tmp, C0_PAGEMASK); } else if (PM_DEFAULT_MASK) { uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); - uasm_il_b(p, r, label_leave); + uasm_il_b(p, r, lid); uasm_i_mtc0(p, tmp, C0_PAGEMASK); } else { - uasm_il_b(p, r, label_leave); + uasm_il_b(p, r, lid); uasm_i_mtc0(p, 0, C0_PAGEMASK); } } +static __cpuinit void build_huge_tlb_write_entry(u32 **p, + struct uasm_label **l, + struct uasm_reloc **r, + unsigned int tmp, + enum tlb_write_entry wmode) +{ + /* Set huge page tlb entry size */ + uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); + uasm_i_ori(p, tmp, tmp, PM_HUGE_MASK & 0xffff); + uasm_i_mtc0(p, tmp, C0_PAGEMASK); + + build_tlb_write_entry(p, l, r, wmode); + + build_restore_pagemask(p, r, tmp, label_leave); +} + /* * Check if Huge PTE is present, if so then jump to LABEL. */ @@ -459,7 +487,7 @@ static __cpuinit void build_huge_update_entries(u32 **p, if (!small_sequence) uasm_i_lui(p, tmp, HPAGE_SIZE >> (7 + 16)); - UASM_i_SRL(p, pte, pte, 6); /* convert to entrylo */ + build_convert_pte_to_entrylo(p, pte); UASM_i_MTC0(p, pte, C0_ENTRYLO0); /* load it */ /* convert to entrylo1 */ if (small_sequence) @@ -685,9 +713,17 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, if (cpu_has_64bits) { uasm_i_ld(p, tmp, 0, ptep); /* get even pte */ uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ - uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */ - UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ - uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */ + if (kernel_uses_smartmips_rixi) { + UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_NO_EXEC)); + UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_NO_EXEC)); + UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); + } else { + uasm_i_dsrl(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */ + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ + uasm_i_dsrl(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */ + } UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ } else { int pte_off_even = sizeof(pte_t) / 2; @@ -704,13 +740,23 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ if (r45k_bvahwbug()) build_tlb_probe_entry(p); - UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */ - if (r4k_250MHZhwbug()) - UASM_i_MTC0(p, 0, C0_ENTRYLO0); - UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ - UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */ - if (r45k_bvahwbug()) - uasm_i_mfc0(p, tmp, C0_INDEX); + if (kernel_uses_smartmips_rixi) { + UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_NO_EXEC)); + UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_NO_EXEC)); + UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); + if (r4k_250MHZhwbug()) + UASM_i_MTC0(p, 0, C0_ENTRYLO0); + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); + } else { + UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */ + if (r4k_250MHZhwbug()) + UASM_i_MTC0(p, 0, C0_ENTRYLO0); + UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ + UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */ + if (r45k_bvahwbug()) + uasm_i_mfc0(p, tmp, C0_INDEX); + } if (r4k_250MHZhwbug()) UASM_i_MTC0(p, 0, C0_ENTRYLO1); UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ @@ -986,9 +1032,14 @@ static void __cpuinit build_pte_present(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, enum label_id lid) { - uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); - uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); - uasm_il_bnez(p, r, pte, lid); + if (kernel_uses_smartmips_rixi) { + uasm_i_andi(p, pte, pte, _PAGE_PRESENT); + uasm_il_beqz(p, r, pte, lid); + } else { + uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); + uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); + uasm_il_bnez(p, r, pte, lid); + } iPTE_LW(p, pte, ptr); } @@ -1273,6 +1324,34 @@ static void __cpuinit build_r4000_tlb_load_handler(void) build_pte_present(&p, &r, K0, K1, label_nopage_tlbl); if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); + + if (kernel_uses_smartmips_rixi) { + /* + * If the page is not _PAGE_VALID, RI or XI could not + * have triggered it. Skip the expensive test.. + */ + uasm_i_andi(&p, K0, K0, _PAGE_VALID); + uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1); + uasm_i_nop(&p); + + uasm_i_tlbr(&p); + /* Examine entrylo 0 or 1 based on ptr. */ + uasm_i_andi(&p, K0, K1, sizeof(pte_t)); + uasm_i_beqz(&p, K0, 8); + + UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ + UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ + /* + * If the entryLo (now in K0) is valid (bit 1), RI or + * XI must have triggered it. + */ + uasm_i_andi(&p, K0, K0, 2); + uasm_il_bnez(&p, &r, K0, label_nopage_tlbl); + + uasm_l_tlbl_goaround1(&l, p); + /* Reload the PTE value */ + iPTE_LW(&p, K0, K1); + } build_make_valid(&p, &r, K0, K1); build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); @@ -1285,6 +1364,40 @@ static void __cpuinit build_r4000_tlb_load_handler(void) iPTE_LW(&p, K0, K1); build_pte_present(&p, &r, K0, K1, label_nopage_tlbl); build_tlb_probe_entry(&p); + + if (kernel_uses_smartmips_rixi) { + /* + * If the page is not _PAGE_VALID, RI or XI could not + * have triggered it. Skip the expensive test.. + */ + uasm_i_andi(&p, K0, K0, _PAGE_VALID); + uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); + uasm_i_nop(&p); + + uasm_i_tlbr(&p); + /* Examine entrylo 0 or 1 based on ptr. */ + uasm_i_andi(&p, K0, K1, sizeof(pte_t)); + uasm_i_beqz(&p, K0, 8); + + UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ + UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ + /* + * If the entryLo (now in K0) is valid (bit 1), RI or + * XI must have triggered it. + */ + uasm_i_andi(&p, K0, K0, 2); + uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); + /* Reload the PTE value */ + iPTE_LW(&p, K0, K1); + + /* + * We clobbered C0_PAGEMASK, restore it. On the other branch + * it is restored in build_huge_tlb_write_entry. + */ + build_restore_pagemask(&p, &r, K0, label_nopage_tlbl); + + uasm_l_tlbl_goaround2(&l, p); + } uasm_i_ori(&p, K0, K0, (_PAGE_ACCESSED | _PAGE_VALID)); build_huge_handler_tail(&p, &r, &l, K0, K1); #endif -- cgit From 6f329468f3086e9d8f3832930fdb09ab3769176b Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 10 Feb 2010 15:12:48 -0800 Subject: MIPS: Give Octeon+ CPUs their own cputype. This allows us to treat them differently at runtime. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/951/ Patchwork: http://patchwork.linux-mips.org/patch/987/ Signed-off-by: Ralf Baechle --- arch/mips/mm/c-octeon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/mips/mm') diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index af85959e59f..0f9c488044d 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -183,6 +183,7 @@ static void __cpuinit probe_octeon(void) switch (c->cputype) { case CPU_CAVIUM_OCTEON: + case CPU_CAVIUM_OCTEON_PLUS: config1 = read_c0_config1(); c->icache.linesz = 2 << ((config1 >> 19) & 7); c->icache.sets = 64 << ((config1 >> 22) & 7); @@ -192,10 +193,10 @@ static void __cpuinit probe_octeon(void) c->icache.sets * c->icache.ways * c->icache.linesz; c->icache.waybit = ffs(icache_size / c->icache.ways) - 1; c->dcache.linesz = 128; - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) - c->dcache.sets = 1; /* CN3XXX has one Dcache set */ - else + if (c->cputype == CPU_CAVIUM_OCTEON_PLUS) c->dcache.sets = 2; /* CN5XXX has two Dcache sets */ + else + c->dcache.sets = 1; /* CN3XXX has one Dcache set */ c->dcache.ways = 64; dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz; -- cgit