]> Pileus Git - ~andy/linux/blobdiff - arch/sparc/mm/fault_32.c
Merge tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd
[~andy/linux] / arch / sparc / mm / fault_32.c
index df3155a179918e0ad5e9741eceab601ae93d8abb..f46cf6be3370ac7d9cc9aa233e436e09e75d1a0e 100644 (file)
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/memreg.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/smp.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
 
-extern int prom_node_root;
-
 int show_unhandled_signals = 1;
 
 /* At boot time we determine these two values necessary for setting
  * up the segment maps and page table entries (pte's).
  */
 
-int num_segmaps, num_contexts;
-int invalid_segment;
-
-/* various Virtual Address Cache parameters we find at boot time... */
-
-int vac_size, vac_linesize, vac_do_hw_vac_flushes;
-int vac_entries_per_context, vac_entries_per_segment;
-int vac_entries_per_page;
+int num_contexts;
 
 /* Return how much physical memory we have.  */
 unsigned long probe_memory(void)
@@ -60,55 +50,36 @@ unsigned long probe_memory(void)
        return total;
 }
 
-extern void sun4c_complete_all_stores(void);
-
-/* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
-asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
-                               unsigned long svaddr, unsigned long aerr,
-                               unsigned long avaddr)
-{
-       sun4c_complete_all_stores();
-       printk("FAULT: NMI received\n");
-       printk("SREGS: Synchronous Error %08lx\n", serr);
-       printk("       Synchronous Vaddr %08lx\n", svaddr);
-       printk("      Asynchronous Error %08lx\n", aerr);
-       printk("      Asynchronous Vaddr %08lx\n", avaddr);
-       if (sun4c_memerr_reg)
-               printk("     Memory Parity Error %08lx\n", *sun4c_memerr_reg);
-       printk("REGISTER DUMP:\n");
-       show_regs(regs);
-       prom_halt();
-}
-
 static void unhandled_fault(unsigned long, struct task_struct *,
                struct pt_regs *) __attribute__ ((noreturn));
 
-static void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                     struct pt_regs *regs)
+static void __noreturn unhandled_fault(unsigned long address,
+                                      struct task_struct *tsk,
+                                      struct pt_regs *regs)
 {
-       if((unsigned long) address < PAGE_SIZE) {
+       if ((unsigned long) address < PAGE_SIZE) {
                printk(KERN_ALERT
                    "Unable to handle kernel NULL pointer dereference\n");
        } else {
-               printk(KERN_ALERT "Unable to handle kernel paging request "
-                      "at virtual address %08lx\n", address);
+               printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n",
+                      address);
        }
        printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
                (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
        printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
                (tsk->mm ? (unsigned long) tsk->mm->pgd :
-                       (unsigned long) tsk->active_mm->pgd));
+                       (unsigned long) tsk->active_mm->pgd));
        die_if_kernel("Oops", regs);
 }
 
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
                            unsigned long address)
 {
        struct pt_regs regs;
        unsigned long g2;
        unsigned int insn;
        int i;
-       
+
        i = search_extables_range(ret_pc, &g2);
        switch (i) {
        case 3:
@@ -128,14 +99,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
                /* for _from_ macros */
                insn = *((unsigned int *) pc);
                if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
-                       return 2; 
-               break; 
+                       return 2;
+               break;
 
        default:
                break;
        }
 
-       memset(&regs, 0, sizeof (regs));
+       memset(&regs, 0, sizeof(regs));
        regs.pc = pc;
        regs.npc = pc + 4;
        __asm__ __volatile__(
@@ -198,11 +169,10 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
        if (text_fault)
                return regs->pc;
 
-       if (regs->psr & PSR_PS) {
+       if (regs->psr & PSR_PS)
                insn = *(unsigned int *) regs->pc;
-       } else {
+       else
                __get_user(insn, (unsigned int *) regs->pc);
-       }
 
        return safe_compute_effective_address(regs, insn);
 }
@@ -228,7 +198,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
                              (write ? FAULT_FLAG_WRITE : 0));
 
-       if(text_fault)
+       if (text_fault)
                address = regs->pc;
 
        /*
@@ -241,36 +211,32 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
         * nothing more.
         */
        code = SEGV_MAPERR;
-       if (!ARCH_SUN4C && address >= TASK_SIZE)
+       if (address >= TASK_SIZE)
                goto vmalloc_fault;
 
        /*
         * If we're in an interrupt or have no user
         * context, we must not take the fault..
         */
-        if (in_atomic() || !mm)
-                goto no_context;
+       if (in_atomic() || !mm)
+               goto no_context;
 
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 retry:
        down_read(&mm->mmap_sem);
 
-       /*
-        * The kernel referencing a bad kernel pointer can lock up
-        * a sun4c machine completely, so we must attempt recovery.
-        */
-       if(!from_user && address >= PAGE_OFFSET)
+       if (!from_user && address >= PAGE_OFFSET)
                goto bad_area;
 
        vma = find_vma(mm, address);
-       if(!vma)
+       if (!vma)
                goto bad_area;
-       if(vma->vm_start <= address)
+       if (vma->vm_start <= address)
                goto good_area;
-       if(!(vma->vm_flags & VM_GROWSDOWN))
+       if (!(vma->vm_flags & VM_GROWSDOWN))
                goto bad_area;
-       if(expand_stack(vma, address))
+       if (expand_stack(vma, address))
                goto bad_area;
        /*
         * Ok, we have a good vm_area for this memory access, so
@@ -278,12 +244,12 @@ retry:
         */
 good_area:
        code = SEGV_ACCERR;
-       if(write) {
-               if(!(vma->vm_flags & VM_WRITE))
+       if (write) {
+               if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
        } else {
                /* Allow reads even for write-only mappings */
-               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
 
@@ -349,14 +315,16 @@ no_context:
        g2 = regs->u_regs[UREG_G2];
        if (!from_user) {
                fixup = search_extables_range(regs->pc, &g2);
-               if (fixup > 10) { /* Values below are reserved for other things */
+               /* Values below 10 are reserved for other things */
+               if (fixup > 10) {
                        extern const unsigned __memset_start[];
                        extern const unsigned __memset_end[];
                        extern const unsigned __csum_partial_copy_start[];
                        extern const unsigned __csum_partial_copy_end[];
 
 #ifdef DEBUG_EXCEPTIONS
-                       printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
+                       printk("Exception: PC<%08lx> faddr<%08lx>\n",
+                              regs->pc, address);
                        printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
                                regs->pc, fixup, g2);
 #endif
@@ -364,7 +332,7 @@ no_context:
                             regs->pc < (unsigned long)__memset_end) ||
                            (regs->pc >= (unsigned long)__csum_partial_copy_start &&
                             regs->pc < (unsigned long)__csum_partial_copy_end)) {
-                               regs->u_regs[UREG_I4] = address;
+                               regs->u_regs[UREG_I4] = address;
                                regs->u_regs[UREG_I5] = regs->pc;
                        }
                        regs->u_regs[UREG_G2] = g2;
@@ -373,8 +341,8 @@ no_context:
                        return;
                }
        }
-       
-       unhandled_fault (address, tsk, regs);
+
+       unhandled_fault(address, tsk, regs);
        do_exit(SIGKILL);
 
 /*
@@ -420,97 +388,12 @@ vmalloc_fault:
 
                if (pmd_present(*pmd) || !pmd_present(*pmd_k))
                        goto bad_area_nosemaphore;
+
                *pmd = *pmd_k;
                return;
        }
 }
 
-asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
-                              unsigned long address)
-{
-       extern void sun4c_update_mmu_cache(struct vm_area_struct *,
-                                          unsigned long,pte_t *);
-       extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       pgd_t *pgdp;
-       pte_t *ptep;
-
-       if (text_fault) {
-               address = regs->pc;
-       } else if (!write &&
-                  !(regs->psr & PSR_PS)) {
-               unsigned int insn, __user *ip;
-
-               ip = (unsigned int __user *)regs->pc;
-               if (!get_user(insn, ip)) {
-                       if ((insn & 0xc1680000) == 0xc0680000)
-                               write = 1;
-               }
-       }
-
-       if (!mm) {
-               /* We are oopsing. */
-               do_sparc_fault(regs, text_fault, write, address);
-               BUG();  /* P3 Oops already, you bitch */
-       }
-
-       pgdp = pgd_offset(mm, address);
-       ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address);
-
-       if (pgd_val(*pgdp)) {
-           if (write) {
-               if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
-                                  == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
-                       unsigned long flags;
-
-                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
-                                     _SUN4C_PAGE_MODIFIED |
-                                     _SUN4C_PAGE_VALID |
-                                     _SUN4C_PAGE_DIRTY);
-
-                       local_irq_save(flags);
-                       if (sun4c_get_segmap(address) != invalid_segment) {
-                               sun4c_put_pte(address, pte_val(*ptep));
-                               local_irq_restore(flags);
-                               return;
-                       }
-                       local_irq_restore(flags);
-               }
-           } else {
-               if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
-                                  == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
-                       unsigned long flags;
-
-                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
-                                     _SUN4C_PAGE_VALID);
-
-                       local_irq_save(flags);
-                       if (sun4c_get_segmap(address) != invalid_segment) {
-                               sun4c_put_pte(address, pte_val(*ptep));
-                               local_irq_restore(flags);
-                               return;
-                       }
-                       local_irq_restore(flags);
-               }
-           }
-       }
-
-       /* This conditional is 'interesting'. */
-       if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
-           && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
-               /* Note: It is safe to not grab the MMAP semaphore here because
-                *       we know that update_mmu_cache() will not sleep for
-                *       any reason (at least not in the current implementation)
-                *       and therefore there is no danger of another thread getting
-                *       on the CPU and doing a shrink_mmap() on this vma.
-                */
-               sun4c_update_mmu_cache (find_vma(current->mm, address), address,
-                                       ptep);
-       else
-               do_sparc_fault(regs, text_fault, write, address);
-}
-
 /* This always deals with user addresses. */
 static void force_user_fault(unsigned long address, int write)
 {
@@ -523,21 +406,21 @@ static void force_user_fault(unsigned long address, int write)
 
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
-       if(!vma)
+       if (!vma)
                goto bad_area;
-       if(vma->vm_start <= address)
+       if (vma->vm_start <= address)
                goto good_area;
-       if(!(vma->vm_flags & VM_GROWSDOWN))
+       if (!(vma->vm_flags & VM_GROWSDOWN))
                goto bad_area;
-       if(expand_stack(vma, address))
+       if (expand_stack(vma, address))
                goto bad_area;
 good_area:
        code = SEGV_ACCERR;
-       if(write) {
-               if(!(vma->vm_flags & VM_WRITE))
+       if (write) {
+               if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
        } else {
-               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
        switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) {
@@ -568,7 +451,7 @@ void window_overflow_fault(void)
        unsigned long sp;
 
        sp = current_thread_info()->rwbuf_stkptrs[0];
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+       if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 1);
        force_user_fault(sp, 1);
 
@@ -577,7 +460,7 @@ void window_overflow_fault(void)
 
 void window_underflow_fault(unsigned long sp)
 {
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+       if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 0);
        force_user_fault(sp, 0);
 
@@ -589,7 +472,7 @@ void window_ret_fault(struct pt_regs *regs)
        unsigned long sp;
 
        sp = regs->u_regs[UREG_FP];
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+       if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 0);
        force_user_fault(sp, 0);