diff options
author | David Daney <ddaney@caviumnetworks.com> | 2009-05-27 20:47:44 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-06-17 06:06:30 -0400 |
commit | fd062c847a8cea2821347d7e18165dfa658f7dce (patch) | |
tree | 95410c5460f7d153a9c9b15184ea52e2059427c3 /arch/mips/mm/tlb-r4k.c | |
parent | dd7943920b492d9d8a79080fe05e25ecd7e10bc3 (diff) |
MIPS: TLB support for hugetlbfs.
The TLB handlers need to check for huge pages and give them special
handling. Huge pages consist of two contiguous sub-pages of physical
memory.
* Loading entrylo0 and entrylo1 need to be handled specially.
* The page mask must be set for huge pages and then restored after
writing the TLB entries.
* The PTE for huge pages resides in the PMD, we halt traversal of the
tables there.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mm/tlb-r4k.c')
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 892be426787c..f60fe513eb60 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
14 | #include <linux/hugetlb.h> | ||
14 | 15 | ||
15 | #include <asm/cpu.h> | 16 | #include <asm/cpu.h> |
16 | #include <asm/bootinfo.h> | 17 | #include <asm/bootinfo.h> |
@@ -295,21 +296,41 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
295 | pudp = pud_offset(pgdp, address); | 296 | pudp = pud_offset(pgdp, address); |
296 | pmdp = pmd_offset(pudp, address); | 297 | pmdp = pmd_offset(pudp, address); |
297 | idx = read_c0_index(); | 298 | idx = read_c0_index(); |
298 | ptep = pte_offset_map(pmdp, address); | 299 | #ifdef CONFIG_HUGETLB_PAGE |
300 | /* this could be a huge page */ | ||
301 | if (pmd_huge(*pmdp)) { | ||
302 | unsigned long lo; | ||
303 | write_c0_pagemask(PM_HUGE_MASK); | ||
304 | ptep = (pte_t *)pmdp; | ||
305 | lo = pte_val(*ptep) >> 6; | ||
306 | write_c0_entrylo0(lo); | ||
307 | write_c0_entrylo1(lo + (HPAGE_SIZE >> 7)); | ||
308 | |||
309 | mtc0_tlbw_hazard(); | ||
310 | if (idx < 0) | ||
311 | tlb_write_random(); | ||
312 | else | ||
313 | tlb_write_indexed(); | ||
314 | write_c0_pagemask(PM_DEFAULT_MASK); | ||
315 | } else | ||
316 | #endif | ||
317 | { | ||
318 | ptep = pte_offset_map(pmdp, address); | ||
299 | 319 | ||
300 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) | 320 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) |
301 | write_c0_entrylo0(ptep->pte_high); | 321 | write_c0_entrylo0(ptep->pte_high); |
302 | ptep++; | 322 | ptep++; |
303 | write_c0_entrylo1(ptep->pte_high); | 323 | write_c0_entrylo1(ptep->pte_high); |
304 | #else | 324 | #else |
305 | write_c0_entrylo0(pte_val(*ptep++) >> 6); | 325 | write_c0_entrylo0(pte_val(*ptep++) >> 6); |
306 | write_c0_entrylo1(pte_val(*ptep) >> 6); | 326 | write_c0_entrylo1(pte_val(*ptep) >> 6); |
307 | #endif | 327 | #endif |
308 | mtc0_tlbw_hazard(); | 328 | mtc0_tlbw_hazard(); |
309 | if (idx < 0) | 329 | if (idx < 0) |
310 | tlb_write_random(); | 330 | tlb_write_random(); |
311 | else | 331 | else |
312 | tlb_write_indexed(); | 332 | tlb_write_indexed(); |
333 | } | ||
313 | tlbw_use_hazard(); | 334 | tlbw_use_hazard(); |
314 | FLUSH_ITLB_VM(vma); | 335 | FLUSH_ITLB_VM(vma); |
315 | EXIT_CRITICAL(flags); | 336 | EXIT_CRITICAL(flags); |