diff options
Diffstat (limited to 'arch/mips/mm/tlb-r4k.c')
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 88 |
1 files changed, 49 insertions, 39 deletions
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index eeaf50f5df2..3914e27456f 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -8,6 +8,7 @@ * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. */ +#include <linux/cpu_pm.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/smp.h> @@ -25,28 +26,6 @@ extern void build_tlb_refill_handler(void); -/* Atomicity and interruptability */ -#ifdef CONFIG_MIPS_MT_SMTC - -#include <asm/smtc.h> -#include <asm/mipsmtregs.h> - -#define ENTER_CRITICAL(flags) \ - { \ - unsigned int mvpflags; \ - local_irq_save(flags);\ - mvpflags = dvpe() -#define EXIT_CRITICAL(flags) \ - evpe(mvpflags); \ - local_irq_restore(flags); \ - } -#else - -#define ENTER_CRITICAL(flags) local_irq_save(flags) -#define EXIT_CRITICAL(flags) local_irq_restore(flags) - -#endif /* CONFIG_MIPS_MT_SMTC */ - /* * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, * unfortunately, itlb is not totally transparent to software. @@ -75,7 +54,7 @@ void local_flush_tlb_all(void) unsigned long old_ctx; int entry, ftlbhighset; - ENTER_CRITICAL(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = read_c0_entryhi(); write_c0_entrylo0(0); @@ -112,7 +91,7 @@ void local_flush_tlb_all(void) tlbw_use_hazard(); write_c0_entryhi(old_ctx); flush_itlb(); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } EXPORT_SYMBOL(local_flush_tlb_all); @@ -142,7 +121,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, if (cpu_context(cpu, mm) != 0) { unsigned long size, flags; - ENTER_CRITICAL(flags); + local_irq_save(flags); start = round_down(start, PAGE_SIZE << 1); end = round_up(end, PAGE_SIZE << 1); size = (end - start) >> (PAGE_SHIFT + 1); @@ -176,7 +155,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, drop_mmu_context(mm, cpu); } flush_itlb(); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } } @@ -184,7 +163,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { unsigned long size, flags; - ENTER_CRITICAL(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if (size <= (current_cpu_data.tlbsizeftlbsets ? @@ -220,7 +199,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) local_flush_tlb_all(); } flush_itlb(); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) @@ -233,7 +212,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) newpid = cpu_asid(cpu, vma->vm_mm); page &= (PAGE_MASK << 1); - ENTER_CRITICAL(flags); + local_irq_save(flags); oldpid = read_c0_entryhi(); write_c0_entryhi(page | newpid); mtc0_tlbw_hazard(); @@ -253,7 +232,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); + local_irq_restore(flags); } } @@ -266,7 +245,7 @@ void local_flush_tlb_one(unsigned long page) unsigned long flags; int oldpid, idx; - ENTER_CRITICAL(flags); + local_irq_save(flags); oldpid = read_c0_entryhi(); page &= (PAGE_MASK << 1); write_c0_entryhi(page); @@ -285,7 +264,7 @@ void local_flush_tlb_one(unsigned long page) } write_c0_entryhi(oldpid); flush_itlb(); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } /* @@ -308,7 +287,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) if (current->active_mm != vma->vm_mm) return; - ENTER_CRITICAL(flags); + local_irq_save(flags); pid = read_c0_entryhi() & ASID_MASK; address &= (PAGE_MASK << 1); @@ -358,7 +337,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) } tlbw_use_hazard(); flush_itlb_vm(vma); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, @@ -369,7 +348,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - ENTER_CRITICAL(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = read_c0_entryhi(); old_pagemask = read_c0_pagemask(); @@ -389,7 +368,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, tlbw_use_hazard(); /* What is the hazard here? */ write_c0_pagemask(old_pagemask); local_flush_tlb_all(); - EXIT_CRITICAL(flags); + local_irq_restore(flags); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE @@ -399,13 +378,13 @@ int __init has_transparent_hugepage(void) unsigned int mask; unsigned long flags; - ENTER_CRITICAL(flags); + local_irq_save(flags); write_c0_pagemask(PM_HUGE_MASK); back_to_back_c0_hazard(); mask = read_c0_pagemask(); write_c0_pagemask(PM_DEFAULT_MASK); - EXIT_CRITICAL(flags); + local_irq_restore(flags); return mask == PM_HUGE_MASK; } @@ -421,7 +400,10 @@ static int __init set_ntlb(char *str) __setup("ntlb=", set_ntlb); -void tlb_init(void) +/* + * Configure TLB (for init or after a CPU has been powered off). + */ +static void r4k_tlb_configure(void) { /* * You should never change this register: @@ -453,6 +435,11 @@ void tlb_init(void) local_flush_tlb_all(); /* Did I tell you that ARC SUCKS? */ +} + +void tlb_init(void) +{ + r4k_tlb_configure(); if (ntlb) { if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) { @@ -466,3 +453,26 @@ void tlb_init(void) build_tlb_refill_handler(); } + +static int r4k_tlb_pm_notifier(struct notifier_block *self, unsigned long cmd, + void *v) +{ + switch (cmd) { + case CPU_PM_ENTER_FAILED: + case CPU_PM_EXIT: + r4k_tlb_configure(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block r4k_tlb_pm_notifier_block = { + .notifier_call = r4k_tlb_pm_notifier, +}; + +static int __init r4k_tlb_init_pm(void) +{ + return cpu_pm_register_notifier(&r4k_tlb_pm_notifier_block); +} +arch_initcall(r4k_tlb_init_pm); |