]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
powerpc: Rename files to have consistent _32/_64 suffixes
authorPaul Mackerras <paulus@samba.org>
Mon, 10 Oct 2005 11:52:43 +0000 (21:52 +1000)
committerPaul Mackerras <paulus@samba.org>
Mon, 10 Oct 2005 11:52:43 +0000 (21:52 +1000)
This doesn't change any code, just renames things so we consistently
have foo_32.c and foo_64.c where we have separate 32- and 64-bit
versions.

Signed-off-by: Paul Mackerras <paulus@samba.org>
42 files changed:
arch/powerpc/Makefile
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/head.S [deleted file]
arch/powerpc/kernel/head_32.S [new file with mode: 0644]
arch/powerpc/kernel/setup.c [deleted file]
arch/powerpc/kernel/setup_32.c [new file with mode: 0644]
arch/powerpc/lib/Makefile
arch/powerpc/lib/checksum.S [deleted file]
arch/powerpc/lib/checksum64.S [deleted file]
arch/powerpc/lib/checksum_32.S [new file with mode: 0644]
arch/powerpc/lib/checksum_64.S [new file with mode: 0644]
arch/powerpc/lib/copy32.S [deleted file]
arch/powerpc/lib/copy_32.S [new file with mode: 0644]
arch/powerpc/lib/copypage.S [deleted file]
arch/powerpc/lib/copypage_64.S [new file with mode: 0644]
arch/powerpc/lib/copyuser.S [deleted file]
arch/powerpc/lib/copyuser_64.S [new file with mode: 0644]
arch/powerpc/lib/mem_64.S [new file with mode: 0644]
arch/powerpc/lib/memcpy.S [deleted file]
arch/powerpc/lib/memcpy_64.S [new file with mode: 0644]
arch/powerpc/lib/usercopy.c [deleted file]
arch/powerpc/lib/usercopy_64.c [new file with mode: 0644]
arch/powerpc/mm/Makefile
arch/powerpc/mm/hash_32.S [deleted file]
arch/powerpc/mm/hash_low_32.S [new file with mode: 0644]
arch/powerpc/mm/init.c [deleted file]
arch/powerpc/mm/init64.c [deleted file]
arch/powerpc/mm/init_32.c [new file with mode: 0644]
arch/powerpc/mm/init_64.c [new file with mode: 0644]
arch/powerpc/mm/mem64.c [deleted file]
arch/powerpc/mm/mmu_context.c [deleted file]
arch/powerpc/mm/mmu_context64.c [deleted file]
arch/powerpc/mm/mmu_context_32.c [new file with mode: 0644]
arch/powerpc/mm/mmu_context_64.c [new file with mode: 0644]
arch/powerpc/mm/pgtable.c [deleted file]
arch/powerpc/mm/pgtable64.c [deleted file]
arch/powerpc/mm/pgtable_32.c [new file with mode: 0644]
arch/powerpc/mm/pgtable_64.c [new file with mode: 0644]
arch/powerpc/mm/ppc_mmu.c [deleted file]
arch/powerpc/mm/ppc_mmu_32.c [new file with mode: 0644]
arch/powerpc/mm/tlb.c [deleted file]
arch/powerpc/mm/tlb_32.c [new file with mode: 0644]

index eb1224c24e3ec576d35d22158e7a010ccebc39d1..06486406575388f804c1a937036846a0c5b0c9b7 100644 (file)
@@ -112,7 +112,7 @@ CFLAGS += $(cpu-as-y)
 # Default to the common case.
 KBUILD_DEFCONFIG := common_defconfig
 
-head-y                         := arch/powerpc/kernel/head.o
+head-y                         := arch/powerpc/kernel/head_32.o
 head-$(CONFIG_PPC64)           := arch/powerpc/kernel/head_64.o
 head-$(CONFIG_8xx)             := arch/powerpc/kernel/head_8xx.o
 head-$(CONFIG_4xx)             := arch/powerpc/kernel/head_4xx.o
index 06d618e52f8e80b4e0620413ec9ee30332f667b5..344cab678c6a9e569b42224929b1b16fa8c0f3bf 100644 (file)
@@ -10,7 +10,7 @@ CFLAGS_prom_init.o      += -fPIC
 CFLAGS_btext.o         += -fPIC
 endif
 
-extra-$(CONFIG_PPC_STD_MMU)    := head.o
+extra-$(CONFIG_PPC_STD_MMU)    := head_32.o
 extra-$(CONFIG_PPC64)          := head_64.o
 extra-$(CONFIG_40x)            := head_4xx.o
 extra-$(CONFIG_44x)            := head_44x.o
@@ -21,7 +21,7 @@ extra-$(CONFIG_PPC_FPU)               += fpu.o
 extra-y                                += vmlinux.lds
 
 obj-y                          := traps.o prom.o semaphore.o
-obj-$(CONFIG_PPC32)            += setup.o process.o
+obj-$(CONFIG_PPC32)            += setup_32.o process.o
 obj-$(CONFIG_PPC64)            += idle_power4.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_PPC_OF)           += prom_init.o of_device.o
diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S
deleted file mode 100644 (file)
index d9dbbd4..0000000
+++ /dev/null
@@ -1,1399 +0,0 @@
-/*
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC platform, including trap and interrupt dispatch.
- *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/cputable.h>
-#include <asm/cache.h>
-#include <asm/thread_info.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-
-#ifdef CONFIG_APUS
-#include <asm/amigappc.h>
-#endif
-
-/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
-#define LOAD_BAT(n, reg, RA, RB)       \
-       /* see the comment for clear_bats() -- Cort */ \
-       li      RA,0;                   \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       mtspr   SPRN_DBAT##n##U,RA;     \
-       lwz     RA,(n*16)+0(reg);       \
-       lwz     RB,(n*16)+4(reg);       \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       mtspr   SPRN_IBAT##n##L,RB;     \
-       beq     1f;                     \
-       lwz     RA,(n*16)+8(reg);       \
-       lwz     RB,(n*16)+12(reg);      \
-       mtspr   SPRN_DBAT##n##U,RA;     \
-       mtspr   SPRN_DBAT##n##L,RB;     \
-1:
-
-       .text
-       .stabs  "arch/ppc/kernel/",N_SO,0,0,0f
-       .stabs  "head.S",N_SO,0,0,0f
-0:
-       .globl  _stext
-_stext:
-
-/*
- * _start is defined this way because the XCOFF loader in the OpenFirmware
- * on the powermac expects the entry point to be a procedure descriptor.
- */
-       .text
-       .globl  _start
-_start:
-       /*
-        * These are here for legacy reasons, the kernel used to
-        * need to look like a coff function entry for the pmac
-        * but we're always started by some kind of bootloader now.
-        *  -- Cort
-        */
-       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
-       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
-       nop
-
-/* PMAC
- * Enter here with the kernel text, data and bss loaded starting at
- * 0, running with virtual == physical mapping.
- * r5 points to the prom entry point (the client interface handler
- * address).  Address translation is turned on, with the prom
- * managing the hash table.  Interrupts are disabled.  The stack
- * pointer (r1) points to just below the end of the half-meg region
- * from 0x380000 - 0x400000, which is mapped in already.
- *
- * If we are booted from MacOS via BootX, we enter with the kernel
- * image loaded somewhere, and the following values in registers:
- *  r3: 'BooX' (0x426f6f58)
- *  r4: virtual address of boot_infos_t
- *  r5: 0
- *
- * APUS
- *   r3: 'APUS'
- *   r4: physical address of memory base
- *   Linux/m68k style BootInfo structure at &_end.
- *
- * PREP
- * This is jumped to on prep systems right after the kernel is relocated
- * to its proper place in memory by the boot loader.  The expected layout
- * of the regs is:
- *   r3: ptr to residual data
- *   r4: initrd_start or if no initrd then 0
- *   r5: initrd_end - unused if r4 is 0
- *   r6: Start of command line string
- *   r7: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort
- */
-
-       .globl  __start
-__start:
-/*
- * We have to do any OF calls before we map ourselves to KERNELBASE,
- * because OF may have I/O devices mapped into that area
- * (particularly on CHRP).
- */
-       cmpwi   0,r5,0
-       beq     1f
-       bl      prom_init
-       trap
-
-1:     mr      r31,r3                  /* save parameters */
-       mr      r30,r4
-       li      r24,0                   /* cpu # */
-
-/*
- * early_init() does the early machine identification and does
- * the necessary low-level setup and clears the BSS
- *  -- Cort <cort@fsmlabs.com>
- */
-       bl      early_init
-
-#ifdef CONFIG_APUS
-/* On APUS the __va/__pa constants need to be set to the correct
- * values before continuing.
- */
-       mr      r4,r30
-       bl      fix_mem_constants
-#endif /* CONFIG_APUS */
-
-/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
- * the physical address we are running at, returned by early_init()
- */
-       bl      mmu_off
-__after_mmu_off:
-       bl      clear_bats
-       bl      flush_tlbs
-
-       bl      initial_bats
-#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
-       bl      setup_disp_bat
-#endif
-
-/*
- * Call setup_cpu for CPU 0 and initialize 6xx Idle
- */
-       bl      reloc_offset
-       li      r24,0                   /* cpu# */
-       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
-#ifdef CONFIG_6xx
-       bl      reloc_offset
-       bl      init_idle_6xx
-#endif /* CONFIG_6xx */
-
-
-#ifndef CONFIG_APUS
-/*
- * We need to run with _start at physical address 0.
- * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
- * the exception vectors at 0 (and therefore this copy
- * overwrites OF's exception vectors with our own).
- * The MMU is off at this point.
- */
-       bl      reloc_offset
-       mr      r26,r3
-       addis   r4,r3,KERNELBASE@h      /* current address of _start */
-       cmpwi   0,r4,0                  /* are we already running at 0? */
-       bne     relocate_kernel
-#endif /* CONFIG_APUS */
-/*
- * we now have the 1st 16M of ram mapped with the bats.
- * prep needs the mmu to be turned on here, but pmac already has it on.
- * this shouldn't bother the pmac since it just gets turned on again
- * as we jump to our code at KERNELBASE. -- Cort
- * Actually no, pmac doesn't have it on any more. BootX enters with MMU
- * off, and in other cases, we now turn it off before changing BATs above.
- */
-turn_on_mmu:
-       mfmsr   r0
-       ori     r0,r0,MSR_DR|MSR_IR
-       mtspr   SPRN_SRR1,r0
-       lis     r0,start_here@h
-       ori     r0,r0,start_here@l
-       mtspr   SPRN_SRR0,r0
-       SYNC
-       RFI                             /* enables MMU */
-
-/*
- * We need __secondary_hold as a place to hold the other cpus on
- * an SMP machine, even when we are running a UP kernel.
- */
-       . = 0xc0                        /* for prep bootloader */
-       li      r3,1                    /* MTX only has 1 cpu */
-       .globl  __secondary_hold
-__secondary_hold:
-       /* tell the master we're here */
-       stw     r3,4(0)
-#ifdef CONFIG_SMP
-100:   lwz     r4,0(0)
-       /* wait until we're told to start */
-       cmpw    0,r4,r3
-       bne     100b
-       /* our cpu # was at addr 0 - go */
-       mr      r24,r3                  /* cpu # */
-       b       __secondary_start
-#else
-       b       .
-#endif /* CONFIG_SMP */
-
-/*
- * Exception entry code.  This code runs with address translation
- * turned off, i.e. using physical addresses.
- * We assume sprg3 has the physical address of the current
- * task's thread_struct.
- */
-#define EXCEPTION_PROLOG       \
-       mtspr   SPRN_SPRG0,r10; \
-       mtspr   SPRN_SPRG1,r11; \
-       mfcr    r10;            \
-       EXCEPTION_PROLOG_1;     \
-       EXCEPTION_PROLOG_2
-
-#define EXCEPTION_PROLOG_1     \
-       mfspr   r11,SPRN_SRR1;          /* check whether user or kernel */ \
-       andi.   r11,r11,MSR_PR; \
-       tophys(r11,r1);                 /* use tophys(r1) if kernel */ \
-       beq     1f;             \
-       mfspr   r11,SPRN_SPRG3; \
-       lwz     r11,THREAD_INFO-THREAD(r11);    \
-       addi    r11,r11,THREAD_SIZE;    \
-       tophys(r11,r11);        \
-1:     subi    r11,r11,INT_FRAME_SIZE  /* alloc exc. frame */
-
-
-#define EXCEPTION_PROLOG_2     \
-       CLR_TOP32(r11);         \
-       stw     r10,_CCR(r11);          /* save registers */ \
-       stw     r12,GPR12(r11); \
-       stw     r9,GPR9(r11);   \
-       mfspr   r10,SPRN_SPRG0; \
-       stw     r10,GPR10(r11); \
-       mfspr   r12,SPRN_SPRG1; \
-       stw     r12,GPR11(r11); \
-       mflr    r10;            \
-       stw     r10,_LINK(r11); \
-       mfspr   r12,SPRN_SRR0;  \
-       mfspr   r9,SPRN_SRR1;   \
-       stw     r1,GPR1(r11);   \
-       stw     r1,0(r11);      \
-       tovirt(r1,r11);                 /* set new kernel sp */ \
-       li      r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
-       MTMSRD(r10);                    /* (except for mach check in rtas) */ \
-       stw     r0,GPR0(r11);   \
-       SAVE_4GPRS(3, r11);     \
-       SAVE_2GPRS(7, r11)
-
-/*
- * Note: code which follows this uses cr0.eq (set if from kernel),
- * r11, r12 (SRR0), and r9 (SRR1).
- *
- * Note2: once we have set r1 we are in a position to take exceptions
- * again, and we could thus set MSR:RI at that point.
- */
-
-/*
- * Exception vectors.
- */
-#define EXCEPTION(n, label, hdlr, xfer)                \
-       . = n;                                  \
-label:                                         \
-       EXCEPTION_PROLOG;                       \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;     \
-       xfer(n, hdlr)
-
-#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret)    \
-       li      r10,trap;                                       \
-       stw     r10,TRAP(r11);                                  \
-       li      r10,MSR_KERNEL;                                 \
-       copyee(r10, r9);                                        \
-       bl      tfer;                                           \
-i##n:                                                          \
-       .long   hdlr;                                           \
-       .long   ret
-
-#define COPY_EE(d, s)          rlwimi d,s,0,16,16
-#define NOCOPY(d, s)
-
-#define EXC_XFER_STD(n, hdlr)          \
-       EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \
-                         ret_from_except_full)
-
-#define EXC_XFER_LITE(n, hdlr)         \
-       EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
-                         ret_from_except)
-
-#define EXC_XFER_EE(n, hdlr)           \
-       EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
-                         ret_from_except_full)
-
-#define EXC_XFER_EE_LITE(n, hdlr)      \
-       EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
-                         ret_from_except)
-
-/* System reset */
-/* core99 pmac starts the seconary here by changing the vector, and
-   putting it back to what it was (unknown_exception) when done.  */
-#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
-       . = 0x100
-       b       __secondary_start_gemini
-#else
-       EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-#endif
-
-/* Machine check */
-/*
- * On CHRP, this is complicated by the fact that we could get a
- * machine check inside RTAS, and we have no guarantee that certain
- * critical registers will have the values we expect.  The set of
- * registers that might have bad values includes all the GPRs
- * and all the BATs.  We indicate that we are in RTAS by putting
- * a non-zero value, the address of the exception frame to use,
- * in SPRG2.  The machine check handler checks SPRG2 and uses its
- * value if it is non-zero.  If we ever needed to free up SPRG2,
- * we could use a field in the thread_info or thread_struct instead.
- * (Other exception handlers assume that r1 is a valid kernel stack
- * pointer when we take an exception from supervisor mode.)
- *     -- paulus.
- */
-       . = 0x200
-       mtspr   SPRN_SPRG0,r10
-       mtspr   SPRN_SPRG1,r11
-       mfcr    r10
-#ifdef CONFIG_PPC_CHRP
-       mfspr   r11,SPRN_SPRG2
-       cmpwi   0,r11,0
-       bne     7f
-#endif /* CONFIG_PPC_CHRP */
-       EXCEPTION_PROLOG_1
-7:     EXCEPTION_PROLOG_2
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-#ifdef CONFIG_PPC_CHRP
-       mfspr   r4,SPRN_SPRG2
-       cmpwi   cr1,r4,0
-       bne     cr1,1f
-#endif
-       EXC_XFER_STD(0x200, machine_check_exception)
-#ifdef CONFIG_PPC_CHRP
-1:     b       machine_check_in_rtas
-#endif
-
-/* Data access exception. */
-       . = 0x300
-DataAccess:
-       EXCEPTION_PROLOG
-       mfspr   r10,SPRN_DSISR
-       andis.  r0,r10,0xa470           /* weird error? */
-       bne     1f                      /* if not, try to put a PTE */
-       mfspr   r4,SPRN_DAR             /* into the hash table */
-       rlwinm  r3,r10,32-15,21,21      /* DSISR_STORE -> _PAGE_RW */
-       bl      hash_page
-1:     stw     r10,_DSISR(r11)
-       mr      r5,r10
-       mfspr   r4,SPRN_DAR
-       EXC_XFER_EE_LITE(0x300, handle_page_fault)
-
-
-/* Instruction access exception. */
-       . = 0x400
-InstructionAccess:
-       EXCEPTION_PROLOG
-       andis.  r0,r9,0x4000            /* no pte found? */
-       beq     1f                      /* if so, try to put a PTE */
-       li      r3,0                    /* into the hash table */
-       mr      r4,r12                  /* SRR0 is fault address */
-       bl      hash_page
-1:     mr      r4,r12
-       mr      r5,r9
-       EXC_XFER_EE_LITE(0x400, handle_page_fault)
-
-/* External interrupt */
-       EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
-
-/* Alignment exception */
-       . = 0x600
-Alignment:
-       EXCEPTION_PROLOG
-       mfspr   r4,SPRN_DAR
-       stw     r4,_DAR(r11)
-       mfspr   r5,SPRN_DSISR
-       stw     r5,_DSISR(r11)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_EE(0x600, alignment_exception)
-
-/* Program check exception */
-       EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
-
-/* Floating-point unavailable */
-       . = 0x800
-FPUnavailable:
-       EXCEPTION_PROLOG
-       bne     load_up_fpu             /* if from user, just load it up */
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
-
-/* Decrementer */
-       EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
-
-       EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
-
-/* System call */
-       . = 0xc00
-SystemCall:
-       EXCEPTION_PROLOG
-       EXC_XFER_EE_LITE(0xc00, DoSyscall)
-
-/* Single step - not used on 601 */
-       EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)
-       EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE)
-
-/*
- * The Altivec unavailable trap is at 0x0f20.  Foo.
- * We effectively remap it to 0x3000.
- * We include an altivec unavailable exception vector even if
- * not configured for Altivec, so that you can't panic a
- * non-altivec kernel running on a machine with altivec just
- * by executing an altivec instruction.
- */
-       . = 0xf00
-       b       Trap_0f
-
-       . = 0xf20
-       b       AltiVecUnavailable
-
-Trap_0f:
-       EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_EE(0xf00, unknown_exception)
-
-/*
- * Handle TLB miss for instruction on 603/603e.
- * Note: we get an alternate set of r0 - r3 to use automatically.
- */
-       . = 0x1000
-InstructionTLBMiss:
-/*
- * r0: stored ctr
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       mfctr   r0
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_IMISS
-       lis     r1,KERNELBASE@h         /* check if kernel address */
-       cmplw   0,r3,r1
-       mfspr   r2,SPRN_SPRG3
-       li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
-       lwz     r2,PGDIR(r2)
-       blt+    112f
-       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
-       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
-       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
-       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
-112:   tophys(r2,r2)
-       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    InstructionAddressInvalid       /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
-       bne-    InstructionAddressInvalid /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
-       /*
-        * NOTE! We are assuming this is not an SMP system, otherwise
-        * we would need to update the pte atomically with lwarx/stwcx.
-        */
-       stw     r3,0(r2)                /* update PTE (accessed bit) */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
-       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
-       and     r1,r1,r2                /* writable if _RW and _DIRTY */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r1,r1,0xe14             /* clear out reserved bits and M */
-       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
-       mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_IMISS
-       tlbli   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       rfi
-InstructionAddressInvalid:
-       mfspr   r3,SPRN_SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-
-       addis   r1,r1,0x2000
-       mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
-       mtctr   r0              /* Restore CTR */
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       or      r2,r2,r1
-       mtspr   SPRN_SRR1,r2
-       mfspr   r1,SPRN_IMISS   /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       rlwimi  r2,r2,1,30,30   /* change 1 -> 3 */
-       xor     r1,r1,r2
-       mtspr   SPRN_DAR,r1     /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       mtmsr   r0
-       b       InstructionAccess
-
-/*
- * Handle TLB miss for DATA Load operation on 603/603e
- */
-       . = 0x1100
-DataLoadTLBMiss:
-/*
- * r0: stored ctr
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       mfctr   r0
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_DMISS
-       lis     r1,KERNELBASE@h         /* check if kernel address */
-       cmplw   0,r3,r1
-       mfspr   r2,SPRN_SPRG3
-       li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
-       lwz     r2,PGDIR(r2)
-       blt+    112f
-       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
-       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
-       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
-       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
-112:   tophys(r2,r2)
-       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    DataAddressInvalid      /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
-       bne-    DataAddressInvalid      /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
-       /*
-        * NOTE! We are assuming this is not an SMP system, otherwise
-        * we would need to update the pte atomically with lwarx/stwcx.
-        */
-       stw     r3,0(r2)                /* update PTE (accessed bit) */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
-       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
-       and     r1,r1,r2                /* writable if _RW and _DIRTY */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r1,r1,0xe14             /* clear out reserved bits and M */
-       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
-       mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_DMISS
-       tlbld   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       rfi
-DataAddressInvalid:
-       mfspr   r3,SPRN_SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x2000
-       mtspr   SPRN_DSISR,r1
-       mtctr   r0              /* Restore CTR */
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       mtspr   SPRN_SRR1,r2
-       mfspr   r1,SPRN_DMISS   /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       beq     20f             /* Jump if big endian */
-       xori    r1,r1,3
-20:    mtspr   SPRN_DAR,r1     /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       mtmsr   r0
-       b       DataAccess
-
-/*
- * Handle TLB miss for DATA Store on 603/603e
- */
-       . = 0x1200
-DataStoreTLBMiss:
-/*
- * r0: stored ctr
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       mfctr   r0
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_DMISS
-       lis     r1,KERNELBASE@h         /* check if kernel address */
-       cmplw   0,r3,r1
-       mfspr   r2,SPRN_SPRG3
-       li      r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
-       lwz     r2,PGDIR(r2)
-       blt+    112f
-       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
-       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
-       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
-       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
-112:   tophys(r2,r2)
-       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    DataAddressInvalid      /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r3,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r3                /* check access & ~permission */
-       bne-    DataAddressInvalid      /* return if access not permitted */
-       ori     r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY
-       /*
-        * NOTE! We are assuming this is not an SMP system, otherwise
-        * we would need to update the pte atomically with lwarx/stwcx.
-        */
-       stw     r3,0(r2)                /* update PTE (accessed/dirty bits) */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
-       li      r1,0xe15                /* clear out reserved bits and M */
-       andc    r1,r3,r1                /* PP = user? 2: 0 */
-       mtspr   SPRN_RPA,r1
-       mfspr   r3,SPRN_DMISS
-       tlbld   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       rfi
-
-#ifndef CONFIG_ALTIVEC
-#define altivec_assist_exception       unknown_exception
-#endif
-
-       EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE)
-       EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
-       EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE)
-       EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
-       EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE)
-       EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE)
-       EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE)
-
-       .globl mol_trampoline
-       .set mol_trampoline, i0x2f00
-
-       . = 0x3000
-
-AltiVecUnavailable:
-       EXCEPTION_PROLOG
-#ifdef CONFIG_ALTIVEC
-       bne     load_up_altivec         /* if from user, just load it up */
-#endif /* CONFIG_ALTIVEC */
-       EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
-
-#ifdef CONFIG_ALTIVEC
-/* Note that the AltiVec support is closely modeled after the FP
- * support.  Changes to one are likely to be applicable to the
- * other!  */
-load_up_altivec:
-/*
- * Disable AltiVec for the task which had AltiVec previously,
- * and save its AltiVec registers in its thread_struct.
- * Enables AltiVec for use in the kernel on return.
- * On SMP we know the AltiVec units are free, since we give it up every
- * switch.  -- Kumar
- */
-       mfmsr   r5
-       oris    r5,r5,MSR_VEC@h
-       MTMSRD(r5)                      /* enable use of AltiVec now */
-       isync
-/*
- * For SMP, we don't do lazy AltiVec switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another.  Instead we call giveup_altivec in switch_to.
- */
-#ifndef CONFIG_SMP
-       tophys(r6,0)
-       addis   r3,r6,last_task_used_altivec@ha
-       lwz     r4,last_task_used_altivec@l(r3)
-       cmpwi   0,r4,0
-       beq     1f
-       add     r4,r4,r6
-       addi    r4,r4,THREAD    /* want THREAD of last_task_used_altivec */
-       SAVE_32VRS(0,r10,r4)
-       mfvscr  vr0
-       li      r10,THREAD_VSCR
-       stvx    vr0,r10,r4
-       lwz     r5,PT_REGS(r4)
-       add     r5,r5,r6
-       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       lis     r10,MSR_VEC@h
-       andc    r4,r4,r10       /* disable altivec for previous task */
-       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-       /* enable use of AltiVec after return */
-       oris    r9,r9,MSR_VEC@h
-       mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
-       li      r4,1
-       li      r10,THREAD_VSCR
-       stw     r4,THREAD_USED_VR(r5)
-       lvx     vr0,r10,r5
-       mtvscr  vr0
-       REST_32VRS(0,r10,r5)
-#ifndef CONFIG_SMP
-       subi    r4,r5,THREAD
-       sub     r4,r4,r6
-       stw     r4,last_task_used_altivec@l(r3)
-#endif /* CONFIG_SMP */
-       /* restore registers and return */
-       /* we haven't used ctr or xer or lr */
-       b       fast_exception_return
-
-/*
- * AltiVec unavailable trap from kernel - print a message, but let
- * the task use AltiVec in the kernel until it returns to user mode.
- */
-KernelAltiVec:
-       lwz     r3,_MSR(r1)
-       oris    r3,r3,MSR_VEC@h
-       stw     r3,_MSR(r1)     /* enable use of AltiVec after return */
-       lis     r3,87f@h
-       ori     r3,r3,87f@l
-       mr      r4,r2           /* current */
-       lwz     r5,_NIP(r1)
-       bl      printk
-       b       ret_from_except
-87:    .string "AltiVec used in kernel  (task=%p, pc=%x)  \n"
-       .align  4,0
-
-/*
- * giveup_altivec(tsk)
- * Disable AltiVec for the task given as the argument,
- * and save the AltiVec registers in its thread_struct.
- * Enables AltiVec for use in the kernel on return.
- */
-
-       .globl  giveup_altivec
-giveup_altivec:
-       mfmsr   r5
-       oris    r5,r5,MSR_VEC@h
-       SYNC
-       MTMSRD(r5)                      /* enable use of AltiVec now */
-       isync
-       cmpwi   0,r3,0
-       beqlr-                          /* if no previous owner, done */
-       addi    r3,r3,THREAD            /* want THREAD of task */
-       lwz     r5,PT_REGS(r3)
-       cmpwi   0,r5,0
-       SAVE_32VRS(0, r4, r3)
-       mfvscr  vr0
-       li      r4,THREAD_VSCR
-       stvx    vr0,r4,r3
-       beq     1f
-       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       lis     r3,MSR_VEC@h
-       andc    r4,r4,r3                /* disable AltiVec for previous task */
-       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
-       li      r5,0
-       lis     r4,last_task_used_altivec@ha
-       stw     r5,last_task_used_altivec@l(r4)
-#endif /* CONFIG_SMP */
-       blr
-#endif /* CONFIG_ALTIVEC */
-
-/*
- * This code is jumped to from the startup code to copy
- * the kernel image to physical address 0.
- */
-relocate_kernel:
-       addis   r9,r26,klimit@ha        /* fetch klimit */
-       lwz     r25,klimit@l(r9)
-       addis   r25,r25,-KERNELBASE@h
-       li      r3,0                    /* Destination base address */
-       li      r6,0                    /* Destination offset */
-       li      r5,0x4000               /* # bytes of memory to copy */
-       bl      copy_and_flush          /* copy the first 0x4000 bytes */
-       addi    r0,r3,4f@l              /* jump to the address of 4f */
-       mtctr   r0                      /* in copy and do the rest. */
-       bctr                            /* jump to the copy */
-4:     mr      r5,r25
-       bl      copy_and_flush          /* copy the rest */
-       b       turn_on_mmu
-
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- */
-copy_and_flush:
-       addi    r5,r5,-4
-       addi    r6,r6,-4
-4:     li      r0,L1_CACHE_LINE_SIZE/4
-       mtctr   r0
-3:     addi    r6,r6,4                 /* copy a cache line */
-       lwzx    r0,r6,r4
-       stwx    r0,r6,r3
-       bdnz    3b
-       dcbst   r6,r3                   /* write it to memory */
-       sync
-       icbi    r6,r3                   /* flush the icache line */
-       cmplw   0,r6,r5
-       blt     4b
-       sync                            /* additional sync needed on g4 */
-       isync
-       addi    r5,r5,4
-       addi    r6,r6,4
-       blr
-
-#ifdef CONFIG_APUS
-/*
- * On APUS the physical base address of the kernel is not known at compile
- * time, which means the __pa/__va constants used are incorrect. In the
- * __init section is recorded the virtual addresses of instructions using
- * these constants, so all that has to be done is fix these before
- * continuing the kernel boot.
- *
- * r4 = The physical address of the kernel base.
- */
-fix_mem_constants:
-       mr      r10,r4
-       addis   r10,r10,-KERNELBASE@h    /* virt_to_phys constant */
-       neg     r11,r10                  /* phys_to_virt constant */
-
-       lis     r12,__vtop_table_begin@h
-       ori     r12,r12,__vtop_table_begin@l
-       add     r12,r12,r10              /* table begin phys address */
-       lis     r13,__vtop_table_end@h
-       ori     r13,r13,__vtop_table_end@l
-       add     r13,r13,r10              /* table end phys address */
-       subi    r12,r12,4
-       subi    r13,r13,4
-1:     lwzu    r14,4(r12)               /* virt address of instruction */
-       add     r14,r14,r10              /* phys address of instruction */
-       lwz     r15,0(r14)               /* instruction, now insert top */
-       rlwimi  r15,r10,16,16,31         /* half of vp const in low half */
-       stw     r15,0(r14)               /* of instruction and restore. */
-       dcbst   r0,r14                   /* write it to memory */
-       sync
-       icbi    r0,r14                   /* flush the icache line */
-       cmpw    r12,r13
-       bne     1b
-       sync                            /* additional sync needed on g4 */
-       isync
-
-/*
- * Map the memory where the exception handlers will
- * be copied to when hash constants have been patched.
- */
-#ifdef CONFIG_APUS_FAST_EXCEPT
-       lis     r8,0xfff0
-#else
-       lis     r8,0
-#endif
-       ori     r8,r8,0x2               /* 128KB, supervisor */
-       mtspr   SPRN_DBAT3U,r8
-       mtspr   SPRN_DBAT3L,r8
-
-       lis     r12,__ptov_table_begin@h
-       ori     r12,r12,__ptov_table_begin@l
-       add     r12,r12,r10              /* table begin phys address */
-       lis     r13,__ptov_table_end@h
-       ori     r13,r13,__ptov_table_end@l
-       add     r13,r13,r10              /* table end phys address */
-       subi    r12,r12,4
-       subi    r13,r13,4
-1:     lwzu    r14,4(r12)               /* virt address of instruction */
-       add     r14,r14,r10              /* phys address of instruction */
-       lwz     r15,0(r14)               /* instruction, now insert top */
-       rlwimi  r15,r11,16,16,31         /* half of pv const in low half*/
-       stw     r15,0(r14)               /* of instruction and restore. */
-       dcbst   r0,r14                   /* write it to memory */
-       sync
-       icbi    r0,r14                   /* flush the icache line */
-       cmpw    r12,r13
-       bne     1b
-
-       sync                            /* additional sync needed on g4 */
-       isync                           /* No speculative loading until now */
-       blr
-
-/***********************************************************************
- *  Please note that on APUS the exception handlers are located at the
- *  physical address 0xfff0000. For this reason, the exception handlers
- *  cannot use relative branches to access the code below.
- ***********************************************************************/
-#endif /* CONFIG_APUS */
-
-#ifdef CONFIG_SMP
-#ifdef CONFIG_GEMINI
-       .globl  __secondary_start_gemini
-__secondary_start_gemini:
-        mfspr   r4,SPRN_HID0
-        ori     r4,r4,HID0_ICFI
-        li      r3,0
-        ori     r3,r3,HID0_ICE
-        andc    r4,r4,r3
-        mtspr   SPRN_HID0,r4
-        sync
-        b       __secondary_start
-#endif /* CONFIG_GEMINI */
-
-       .globl  __secondary_start_pmac_0
-__secondary_start_pmac_0:
-       /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
-       li      r24,0
-       b       1f
-       li      r24,1
-       b       1f
-       li      r24,2
-       b       1f
-       li      r24,3
-1:
-       /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
-          set to map the 0xf0000000 - 0xffffffff region */
-       mfmsr   r0
-       rlwinm  r0,r0,0,28,26           /* clear DR (0x10) */
-       SYNC
-       mtmsr   r0
-       isync
-
-       .globl  __secondary_start
-__secondary_start:
-       /* Copy some CPU settings from CPU 0 */
-       bl      __restore_cpu_setup
-
-       lis     r3,-KERNELBASE@h
-       mr      r4,r24
-       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
-#ifdef CONFIG_6xx
-       lis     r3,-KERNELBASE@h
-       bl      init_idle_6xx
-#endif /* CONFIG_6xx */
-
-       /* get current_thread_info and current */
-       lis     r1,secondary_ti@ha
-       tophys(r1,r1)
-       lwz     r1,secondary_ti@l(r1)
-       tophys(r2,r1)
-       lwz     r2,TI_TASK(r2)
-
-       /* stack */
-       addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
-       li      r0,0
-       tophys(r3,r1)
-       stw     r0,0(r3)
-
-       /* load up the MMU */
-       bl      load_up_mmu
-
-       /* ptr to phys current thread */
-       tophys(r4,r2)
-       addi    r4,r4,THREAD    /* phys address of our thread_struct */
-       CLR_TOP32(r4)
-       mtspr   SPRN_SPRG3,r4
-       li      r3,0
-       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
-
-       /* enable MMU and jump to start_secondary */
-       li      r4,MSR_KERNEL
-       FIX_SRR1(r4,r5)
-       lis     r3,start_secondary@h
-       ori     r3,r3,start_secondary@l
-       mtspr   SPRN_SRR0,r3
-       mtspr   SPRN_SRR1,r4
-       SYNC
-       RFI
-#endif /* CONFIG_SMP */
-
-/*
- * Those generic dummy functions are kept for CPUs not
- * included in CONFIG_6xx
- */
-#if !defined(CONFIG_6xx)
-_GLOBAL(__save_cpu_setup)
-       blr
-_GLOBAL(__restore_cpu_setup)
-       blr
-#endif /* !defined(CONFIG_6xx) */
-
-
-/*
- * Load stuff into the MMU.  Intended to be called with
- * IR=0 and DR=0.
- */
-load_up_mmu:
-       sync                    /* Force all PTE updates to finish */
-       isync
-       tlbia                   /* Clear all TLB entries */
-       sync                    /* wait for tlbia/tlbie to finish */
-       TLBSYNC                 /* ... on all CPUs */
-       /* Load the SDR1 register (hash table base & size) */
-       lis     r6,_SDR1@ha
-       tophys(r6,r6)
-       lwz     r6,_SDR1@l(r6)
-       mtspr   SPRN_SDR1,r6
-       li      r0,16           /* load up segment register values */
-       mtctr   r0              /* for context 0 */
-       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
-       li      r4,0
-3:     mtsrin  r3,r4
-       addi    r3,r3,0x111     /* increment VSID */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
-
-/* Load the BAT registers with the values set up by MMU_init.
-   MMU_init takes care of whether we're on a 601 or not. */
-       mfpvr   r3
-       srwi    r3,r3,16
-       cmpwi   r3,1
-       lis     r3,BATS@ha
-       addi    r3,r3,BATS@l
-       tophys(r3,r3)
-       LOAD_BAT(0,r3,r4,r5)
-       LOAD_BAT(1,r3,r4,r5)
-       LOAD_BAT(2,r3,r4,r5)
-       LOAD_BAT(3,r3,r4,r5)
-
-       blr
-
-/*
- * This is where the main kernel code starts.
- */
-start_here:
-       /* ptr to current */
-       lis     r2,init_task@h
-       ori     r2,r2,init_task@l
-       /* Set up for using our exception vectors */
-       /* ptr to phys current thread */
-       tophys(r4,r2)
-       addi    r4,r4,THREAD    /* init task's THREAD */
-       CLR_TOP32(r4)
-       mtspr   SPRN_SPRG3,r4
-       li      r3,0
-       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
-
-       /* stack */
-       lis     r1,init_thread_union@ha
-       addi    r1,r1,init_thread_union@l
-       li      r0,0
-       stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
-/*
- * Do early platform-specific initialization,
- * and set up the MMU.
- */
-       mr      r3,r31
-       mr      r4,r30
-       bl      machine_init
-       bl      MMU_init
-
-#ifdef CONFIG_APUS
-       /* Copy exception code to exception vector base on APUS. */
-       lis     r4,KERNELBASE@h
-#ifdef CONFIG_APUS_FAST_EXCEPT
-       lis     r3,0xfff0               /* Copy to 0xfff00000 */
-#else
-       lis     r3,0                    /* Copy to 0x00000000 */
-#endif
-       li      r5,0x4000               /* # bytes of memory to copy */
-       li      r6,0
-       bl      copy_and_flush          /* copy the first 0x4000 bytes */
-#endif  /* CONFIG_APUS */
-
-/*
- * Go back to running unmapped so we can load up new values
- * for SDR1 (hash table pointer) and the segment registers
- * and change to using our exception vectors.
- */
-       lis     r4,2f@h
-       ori     r4,r4,2f@l
-       tophys(r4,r4)
-       li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
-       FIX_SRR1(r3,r5)
-       mtspr   SPRN_SRR0,r4
-       mtspr   SPRN_SRR1,r3
-       SYNC
-       RFI
-/* Load up the kernel context */
-2:     bl      load_up_mmu
-
-#ifdef CONFIG_BDI_SWITCH
-       /* Add helper information for the Abatron bdiGDB debugger.
-        * We do this here because we know the mmu is disabled, and
-        * will be enabled for real in just a few instructions.
-        */
-       lis     r5, abatron_pteptrs@h
-       ori     r5, r5, abatron_pteptrs@l
-       stw     r5, 0xf0(r0)    /* This much match your Abatron config */
-       lis     r6, swapper_pg_dir@h
-       ori     r6, r6, swapper_pg_dir@l
-       tophys(r5, r5)
-       stw     r6, 0(r5)
-#endif /* CONFIG_BDI_SWITCH */
-
-/* Now turn on the MMU for real! */
-       li      r4,MSR_KERNEL
-       FIX_SRR1(r4,r5)
-       lis     r3,start_kernel@h
-       ori     r3,r3,start_kernel@l
-       mtspr   SPRN_SRR0,r3
-       mtspr   SPRN_SRR1,r4
-       SYNC
-       RFI
-
-/*
- * Set up the segment registers for a new context.
- */
-_GLOBAL(set_context)
-       mulli   r3,r3,897       /* multiply context by skew factor */
-       rlwinm  r3,r3,4,8,27    /* VSID = (context & 0xfffff) << 4 */
-       addis   r3,r3,0x6000    /* Set Ks, Ku bits */
-       li      r0,NUM_USER_SEGMENTS
-       mtctr   r0
-
-#ifdef CONFIG_BDI_SWITCH
-       /* Context switch the PTE pointer for the Abatron BDI2000.
-        * The PGDIR is passed as second argument.
-        */
-       lis     r5, KERNELBASE@h
-       lwz     r5, 0xf0(r5)
-       stw     r4, 0x4(r5)
-#endif
-       li      r4,0
-       isync
-3:
-       mtsrin  r3,r4
-       addi    r3,r3,0x111     /* next VSID */
-       rlwinm  r3,r3,0,8,3     /* clear out any overflow from VSID field */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
-       sync
-       isync
-       blr
-
-/*
- * An undocumented "feature" of 604e requires that the v bit
- * be cleared before changing BAT values.
- *
- * Also, newer IBM firmware does not clear bat3 and 4 so
- * this makes sure it's done.
- *  -- Cort
- */
-clear_bats:
-       li      r10,0
-       mfspr   r9,SPRN_PVR
-       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
-       cmpwi   r9, 1
-       beq     1f
-
-       mtspr   SPRN_DBAT0U,r10
-       mtspr   SPRN_DBAT0L,r10
-       mtspr   SPRN_DBAT1U,r10
-       mtspr   SPRN_DBAT1L,r10
-       mtspr   SPRN_DBAT2U,r10
-       mtspr   SPRN_DBAT2L,r10
-       mtspr   SPRN_DBAT3U,r10
-       mtspr   SPRN_DBAT3L,r10
-1:
-       mtspr   SPRN_IBAT0U,r10
-       mtspr   SPRN_IBAT0L,r10
-       mtspr   SPRN_IBAT1U,r10
-       mtspr   SPRN_IBAT1L,r10
-       mtspr   SPRN_IBAT2U,r10
-       mtspr   SPRN_IBAT2L,r10
-       mtspr   SPRN_IBAT3U,r10
-       mtspr   SPRN_IBAT3L,r10
-BEGIN_FTR_SECTION
-       /* Here's a tweak: at this point, CPU setup have
-        * not been called yet, so HIGH_BAT_EN may not be
-        * set in HID0 for the 745x processors. However, it
-        * seems that doesn't affect our ability to actually
-        * write to these SPRs.
-        */
-       mtspr   SPRN_DBAT4U,r10
-       mtspr   SPRN_DBAT4L,r10
-       mtspr   SPRN_DBAT5U,r10
-       mtspr   SPRN_DBAT5L,r10
-       mtspr   SPRN_DBAT6U,r10
-       mtspr   SPRN_DBAT6L,r10
-       mtspr   SPRN_DBAT7U,r10
-       mtspr   SPRN_DBAT7L,r10
-       mtspr   SPRN_IBAT4U,r10
-       mtspr   SPRN_IBAT4L,r10
-       mtspr   SPRN_IBAT5U,r10
-       mtspr   SPRN_IBAT5L,r10
-       mtspr   SPRN_IBAT6U,r10
-       mtspr   SPRN_IBAT6L,r10
-       mtspr   SPRN_IBAT7U,r10
-       mtspr   SPRN_IBAT7L,r10
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
-       blr
-
-flush_tlbs:
-       lis     r10, 0x40
-1:     addic.  r10, r10, -0x1000
-       tlbie   r10
-       blt     1b
-       sync
-       blr
-
-mmu_off:
-       addi    r4, r3, __after_mmu_off - _start
-       mfmsr   r3
-       andi.   r0,r3,MSR_DR|MSR_IR             /* MMU enabled? */
-       beqlr
-       andc    r3,r3,r0
-       mtspr   SPRN_SRR0,r4
-       mtspr   SPRN_SRR1,r3
-       sync
-       RFI
-
-/*
- * Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE.  From this point on we can't safely
- * call OF any more.
- */
-initial_bats:
-       lis     r11,KERNELBASE@h
-       mfspr   r9,SPRN_PVR
-       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
-       cmpwi   0,r9,1
-       bne     4f
-       ori     r11,r11,4               /* set up BAT registers for 601 */
-       li      r8,0x7f                 /* valid, block length = 8MB */
-       oris    r9,r11,0x800000@h       /* set up BAT reg for 2nd 8M */
-       oris    r10,r8,0x800000@h       /* set up BAT reg for 2nd 8M */
-       mtspr   SPRN_IBAT0U,r11         /* N.B. 601 has valid bit in */
-       mtspr   SPRN_IBAT0L,r8          /* lower BAT register */
-       mtspr   SPRN_IBAT1U,r9
-       mtspr   SPRN_IBAT1L,r10
-       isync
-       blr
-
-4:     tophys(r8,r11)
-#ifdef CONFIG_SMP
-       ori     r8,r8,0x12              /* R/W access, M=1 */
-#else
-       ori     r8,r8,2                 /* R/W access */
-#endif /* CONFIG_SMP */
-#ifdef CONFIG_APUS
-       ori     r11,r11,BL_8M<<2|0x2    /* set up 8MB BAT registers for 604 */
-#else
-       ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
-#endif /* CONFIG_APUS */
-
-       mtspr   SPRN_DBAT0L,r8          /* N.B. 6xx (not 601) have valid */
-       mtspr   SPRN_DBAT0U,r11         /* bit in upper BAT register */
-       mtspr   SPRN_IBAT0L,r8
-       mtspr   SPRN_IBAT0U,r11
-       isync
-       blr
-
-#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
-setup_disp_bat:
-       /*
-        * setup the display bat prepared for us in prom.c
-        */
-       mflr    r8
-       bl      reloc_offset
-       mtlr    r8
-       addis   r8,r3,disp_BAT@ha
-       addi    r8,r8,disp_BAT@l
-       lwz     r11,0(r8)
-       lwz     r8,4(r8)
-       mfspr   r9,SPRN_PVR
-       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
-       cmpwi   0,r9,1
-       beq     1f
-       mtspr   SPRN_DBAT3L,r8
-       mtspr   SPRN_DBAT3U,r11
-       blr
-1:     mtspr   SPRN_IBAT3L,r8
-       mtspr   SPRN_IBAT3U,r11
-       blr
-
-#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
-
-
-#ifdef CONFIG_8260
-/* Jump into the system reset for the rom.
- * We first disable the MMU, and then jump to the ROM reset address.
- *
- * r3 is the board info structure, r4 is the location for starting.
- * I use this for building a small kernel that can load other kernels,
- * rather than trying to write or rely on a rom monitor that can tftp load.
- */
-       .globl  m8260_gorom
-m8260_gorom:
-       mfmsr   r0
-       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
-       sync
-       mtmsr   r0
-       sync
-       mfspr   r11, SPRN_HID0
-       lis     r10, 0
-       ori     r10,r10,HID0_ICE|HID0_DCE
-       andc    r11, r11, r10
-       mtspr   SPRN_HID0, r11
-       isync
-       li      r5, MSR_ME|MSR_RI
-       lis     r6,2f@h
-       addis   r6,r6,-KERNELBASE@h
-       ori     r6,r6,2f@l
-       mtspr   SPRN_SRR0,r6
-       mtspr   SPRN_SRR1,r5
-       isync
-       sync
-       rfi
-2:
-       mtlr    r4
-       blr
-#endif
-
-
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
-       .data
-       .globl  sdata
-sdata:
-       .globl  empty_zero_page
-empty_zero_page:
-       .space  4096
-
-       .globl  swapper_pg_dir
-swapper_pg_dir:
-       .space  4096
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
-       .globl  cmd_line
-cmd_line:
-       .space  512
-
-       .globl intercept_table
-intercept_table:
-       .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700
-       .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0
-       .long 0, 0, 0, i0x1300, 0, 0, 0, 0
-       .long 0, 0, 0, 0, 0, 0, 0, 0
-       .long 0, 0, 0, 0, 0, 0, 0, 0
-       .long 0, 0, 0, 0, 0, 0, 0, 0
-
-/* Room for two PTE pointers, usually the kernel and current user pointers
- * to their respective root page table.
- */
-abatron_pteptrs:
-       .space  8
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
new file mode 100644 (file)
index 0000000..d9dbbd4
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC platform, including trap and interrupt dispatch.
+ *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+#ifdef CONFIG_APUS
+#include <asm/amigappc.h>
+#endif
+
+/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
+#define LOAD_BAT(n, reg, RA, RB)       \
+       /* see the comment for clear_bats() -- Cort */ \
+       li      RA,0;                   \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       lwz     RA,(n*16)+0(reg);       \
+       lwz     RB,(n*16)+4(reg);       \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_IBAT##n##L,RB;     \
+       beq     1f;                     \
+       lwz     RA,(n*16)+8(reg);       \
+       lwz     RB,(n*16)+12(reg);      \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##L,RB;     \
+1:
+
+       .text
+       .stabs  "arch/ppc/kernel/",N_SO,0,0,0f
+       .stabs  "head.S",N_SO,0,0,0f
+0:
+       .globl  _stext
+_stext:
+
+/*
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
+ */
+       .text
+       .globl  _start
+_start:
+       /*
+        * These are here for legacy reasons, the kernel used to
+        * need to look like a coff function entry for the pmac
+        * but we're always started by some kind of bootloader now.
+        *  -- Cort
+        */
+       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
+       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
+       nop
+
+/* PMAC
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address).  Address translation is turned on, with the prom
+ * managing the hash table.  Interrupts are disabled.  The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
+ *
+ * If we are booted from MacOS via BootX, we enter with the kernel
+ * image loaded somewhere, and the following values in registers:
+ *  r3: 'BooX' (0x426f6f58)
+ *  r4: virtual address of boot_infos_t
+ *  r5: 0
+ *
+ * APUS
+ *   r3: 'APUS'
+ *   r4: physical address of memory base
+ *   Linux/m68k style BootInfo structure at &_end.
+ *
+ * PREP
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader.  The expected layout
+ * of the regs is:
+ *   r3: ptr to residual data
+ *   r4: initrd_start or if no initrd then 0
+ *   r5: initrd_end - unused if r4 is 0
+ *   r6: Start of command line string
+ *   r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
+ */
+
+       .globl  __start
+__start:
+/*
+ * We have to do any OF calls before we map ourselves to KERNELBASE,
+ * because OF may have I/O devices mapped into that area
+ * (particularly on CHRP).
+ */
+       cmpwi   0,r5,0
+       beq     1f
+       bl      prom_init
+       trap
+
+1:     mr      r31,r3                  /* save parameters */
+       mr      r30,r4
+       li      r24,0                   /* cpu # */
+
+/*
+ * early_init() does the early machine identification and does
+ * the necessary low-level setup and clears the BSS
+ *  -- Cort <cort@fsmlabs.com>
+ */
+       bl      early_init
+
+#ifdef CONFIG_APUS
+/* On APUS the __va/__pa constants need to be set to the correct
+ * values before continuing.
+ */
+       mr      r4,r30
+       bl      fix_mem_constants
+#endif /* CONFIG_APUS */
+
+/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
+ * the physical address we are running at, returned by early_init()
+ */
+       bl      mmu_off
+__after_mmu_off:
+       bl      clear_bats
+       bl      flush_tlbs
+
+       bl      initial_bats
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+       bl      setup_disp_bat
+#endif
+
+/*
+ * Call setup_cpu for CPU 0 and initialize 6xx Idle
+ */
+       bl      reloc_offset
+       li      r24,0                   /* cpu# */
+       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
+#ifdef CONFIG_6xx
+       bl      reloc_offset
+       bl      init_idle_6xx
+#endif /* CONFIG_6xx */
+
+
+#ifndef CONFIG_APUS
+/*
+ * We need to run with _start at physical address 0.
+ * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
+ * the exception vectors at 0 (and therefore this copy
+ * overwrites OF's exception vectors with our own).
+ * The MMU is off at this point.
+ */
+       bl      reloc_offset
+       mr      r26,r3
+       addis   r4,r3,KERNELBASE@h      /* current address of _start */
+       cmpwi   0,r4,0                  /* are we already running at 0? */
+       bne     relocate_kernel
+#endif /* CONFIG_APUS */
+/*
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
+ * Actually no, pmac doesn't have it on any more. BootX enters with MMU
+ * off, and in other cases, we now turn it off before changing BATs above.
+ */
+turn_on_mmu:
+       mfmsr   r0
+       ori     r0,r0,MSR_DR|MSR_IR
+       mtspr   SPRN_SRR1,r0
+       lis     r0,start_here@h
+       ori     r0,r0,start_here@l
+       mtspr   SPRN_SRR0,r0
+       SYNC
+       RFI                             /* enables MMU */
+
+/*
+ * We need __secondary_hold as a place to hold the other cpus on
+ * an SMP machine, even when we are running a UP kernel.
+ */
+       . = 0xc0                        /* for prep bootloader */
+       li      r3,1                    /* MTX only has 1 cpu */
+       .globl  __secondary_hold
+__secondary_hold:
+       /* tell the master we're here */
+       stw     r3,4(0)
+#ifdef CONFIG_SMP
+100:   lwz     r4,0(0)
+       /* wait until we're told to start */
+       cmpw    0,r4,r3
+       bne     100b
+       /* our cpu # was at addr 0 - go */
+       mr      r24,r3                  /* cpu # */
+       b       __secondary_start
+#else
+       b       .
+#endif /* CONFIG_SMP */
+
+/*
+ * Exception entry code.  This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG       \
+       mtspr   SPRN_SPRG0,r10; \
+       mtspr   SPRN_SPRG1,r11; \
+       mfcr    r10;            \
+       EXCEPTION_PROLOG_1;     \
+       EXCEPTION_PROLOG_2
+
+#define EXCEPTION_PROLOG_1     \
+       mfspr   r11,SPRN_SRR1;          /* check whether user or kernel */ \
+       andi.   r11,r11,MSR_PR; \
+       tophys(r11,r1);                 /* use tophys(r1) if kernel */ \
+       beq     1f;             \
+       mfspr   r11,SPRN_SPRG3; \
+       lwz     r11,THREAD_INFO-THREAD(r11);    \
+       addi    r11,r11,THREAD_SIZE;    \
+       tophys(r11,r11);        \
+1:     subi    r11,r11,INT_FRAME_SIZE  /* alloc exc. frame */
+
+
+#define EXCEPTION_PROLOG_2     \
+       CLR_TOP32(r11);         \
+       stw     r10,_CCR(r11);          /* save registers */ \
+       stw     r12,GPR12(r11); \
+       stw     r9,GPR9(r11);   \
+       mfspr   r10,SPRN_SPRG0; \
+       stw     r10,GPR10(r11); \
+       mfspr   r12,SPRN_SPRG1; \
+       stw     r12,GPR11(r11); \
+       mflr    r10;            \
+       stw     r10,_LINK(r11); \
+       mfspr   r12,SPRN_SRR0;  \
+       mfspr   r9,SPRN_SRR1;   \
+       stw     r1,GPR1(r11);   \
+       stw     r1,0(r11);      \
+       tovirt(r1,r11);                 /* set new kernel sp */ \
+       li      r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
+       MTMSRD(r10);                    /* (except for mach check in rtas) */ \
+       stw     r0,GPR0(r11);   \
+       SAVE_4GPRS(3, r11);     \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r11, r12 (SRR0), and r9 (SRR1).
+ *
+ * Note2: once we have set r1 we are in a position to take exceptions
+ * again, and we could thus set MSR:RI at that point.
+ */
+
+/*
+ * Exception vectors.
+ */
+#define EXCEPTION(n, label, hdlr, xfer)                \
+       . = n;                                  \
+label:                                         \
+       EXCEPTION_PROLOG;                       \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;     \
+       xfer(n, hdlr)
+
+#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret)    \
+       li      r10,trap;                                       \
+       stw     r10,TRAP(r11);                                  \
+       li      r10,MSR_KERNEL;                                 \
+       copyee(r10, r9);                                        \
+       bl      tfer;                                           \
+i##n:                                                          \
+       .long   hdlr;                                           \
+       .long   ret
+
+#define COPY_EE(d, s)          rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)          \
+       EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)         \
+       EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
+                         ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)           \
+       EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)      \
+       EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
+                         ret_from_except)
+
+/* System reset */
+/* core99 pmac starts the seconary here by changing the vector, and
+   putting it back to what it was (unknown_exception) when done.  */
+#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
+       . = 0x100
+       b       __secondary_start_gemini
+#else
+       EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
+#endif
+
+/* Machine check */
+/*
+ * On CHRP, this is complicated by the fact that we could get a
+ * machine check inside RTAS, and we have no guarantee that certain
+ * critical registers will have the values we expect.  The set of
+ * registers that might have bad values includes all the GPRs
+ * and all the BATs.  We indicate that we are in RTAS by putting
+ * a non-zero value, the address of the exception frame to use,
+ * in SPRG2.  The machine check handler checks SPRG2 and uses its
+ * value if it is non-zero.  If we ever needed to free up SPRG2,
+ * we could use a field in the thread_info or thread_struct instead.
+ * (Other exception handlers assume that r1 is a valid kernel stack
+ * pointer when we take an exception from supervisor mode.)
+ *     -- paulus.
+ */
+       . = 0x200
+       mtspr   SPRN_SPRG0,r10
+       mtspr   SPRN_SPRG1,r11
+       mfcr    r10
+#ifdef CONFIG_PPC_CHRP
+       mfspr   r11,SPRN_SPRG2
+       cmpwi   0,r11,0
+       bne     7f
+#endif /* CONFIG_PPC_CHRP */
+       EXCEPTION_PROLOG_1
+7:     EXCEPTION_PROLOG_2
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_PPC_CHRP
+       mfspr   r4,SPRN_SPRG2
+       cmpwi   cr1,r4,0
+       bne     cr1,1f
+#endif
+       EXC_XFER_STD(0x200, machine_check_exception)
+#ifdef CONFIG_PPC_CHRP
+1:     b       machine_check_in_rtas
+#endif
+
+/* Data access exception. */
+       . = 0x300
+DataAccess:
+       EXCEPTION_PROLOG
+       mfspr   r10,SPRN_DSISR
+       andis.  r0,r10,0xa470           /* weird error? */
+       bne     1f                      /* if not, try to put a PTE */
+       mfspr   r4,SPRN_DAR             /* into the hash table */
+       rlwinm  r3,r10,32-15,21,21      /* DSISR_STORE -> _PAGE_RW */
+       bl      hash_page
+1:     stw     r10,_DSISR(r11)
+       mr      r5,r10
+       mfspr   r4,SPRN_DAR
+       EXC_XFER_EE_LITE(0x300, handle_page_fault)
+
+
+/* Instruction access exception. */
+       . = 0x400
+InstructionAccess:
+       EXCEPTION_PROLOG
+       andis.  r0,r9,0x4000            /* no pte found? */
+       beq     1f                      /* if so, try to put a PTE */
+       li      r3,0                    /* into the hash table */
+       mr      r4,r12                  /* SRR0 is fault address */
+       bl      hash_page
+1:     mr      r4,r12
+       mr      r5,r9
+       EXC_XFER_EE_LITE(0x400, handle_page_fault)
+
+/* External interrupt */
+       EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
+
+/* Alignment exception */
+       . = 0x600
+Alignment:
+       EXCEPTION_PROLOG
+       mfspr   r4,SPRN_DAR
+       stw     r4,_DAR(r11)
+       mfspr   r5,SPRN_DSISR
+       stw     r5,_DSISR(r11)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE(0x600, alignment_exception)
+
+/* Program check exception */
+       EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
+
+/* Floating-point unavailable */
+       . = 0x800
+FPUnavailable:
+       EXCEPTION_PROLOG
+       bne     load_up_fpu             /* if from user, just load it up */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
+
+/* Decrementer */
+       EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
+
+       EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
+
+/* System call */
+       . = 0xc00
+SystemCall:
+       EXCEPTION_PROLOG
+       EXC_XFER_EE_LITE(0xc00, DoSyscall)
+
+/* Single step - not used on 601 */
+       EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)
+       EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE)
+
+/*
+ * The Altivec unavailable trap is at 0x0f20.  Foo.
+ * We effectively remap it to 0x3000.
+ * We include an altivec unavailable exception vector even if
+ * not configured for Altivec, so that you can't panic a
+ * non-altivec kernel running on a machine with altivec just
+ * by executing an altivec instruction.
+ */
+       . = 0xf00
+       b       Trap_0f
+
+       . = 0xf20
+       b       AltiVecUnavailable
+
+Trap_0f:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE(0xf00, unknown_exception)
+
+/*
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
+ */
+       . = 0x1000
+InstructionTLBMiss:
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       mfctr   r0
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_IMISS
+       lis     r1,KERNELBASE@h         /* check if kernel address */
+       cmplw   0,r3,r1
+       mfspr   r2,SPRN_SPRG3
+       li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
+       lwz     r2,PGDIR(r2)
+       blt+    112f
+       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
+       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
+       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
+       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
+112:   tophys(r2,r2)
+       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    InstructionAddressInvalid       /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r3,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r3                /* check access & ~permission */
+       bne-    InstructionAddressInvalid /* return if access not permitted */
+       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
+       /*
+        * NOTE! We are assuming this is not an SMP system, otherwise
+        * we would need to update the pte atomically with lwarx/stwcx.
+        */
+       stw     r3,0(r2)                /* update PTE (accessed bit) */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
+       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
+       and     r1,r1,r2                /* writable if _RW and _DIRTY */
+       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r1,r1,0xe14             /* clear out reserved bits and M */
+       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
+       mtspr   SPRN_RPA,r1
+       mfspr   r3,SPRN_IMISS
+       tlbli   r3
+       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       rfi
+InstructionAddressInvalid:
+       mfspr   r3,SPRN_SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+
+       addis   r1,r1,0x2000
+       mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
+       mtctr   r0              /* Restore CTR */
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       or      r2,r2,r1
+       mtspr   SPRN_SRR1,r2
+       mfspr   r1,SPRN_IMISS   /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       rlwimi  r2,r2,1,30,30   /* change 1 -> 3 */
+       xor     r1,r1,r2
+       mtspr   SPRN_DAR,r1     /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       mtmsr   r0
+       b       InstructionAccess
+
+/*
+ * Handle TLB miss for DATA Load operation on 603/603e
+ */
+       . = 0x1100
+DataLoadTLBMiss:
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       mfctr   r0
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_DMISS
+       lis     r1,KERNELBASE@h         /* check if kernel address */
+       cmplw   0,r3,r1
+       mfspr   r2,SPRN_SPRG3
+       li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
+       lwz     r2,PGDIR(r2)
+       blt+    112f
+       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
+       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
+       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
+       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
+112:   tophys(r2,r2)
+       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    DataAddressInvalid      /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r3,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r3                /* check access & ~permission */
+       bne-    DataAddressInvalid      /* return if access not permitted */
+       ori     r3,r3,_PAGE_ACCESSED    /* set _PAGE_ACCESSED in pte */
+       /*
+        * NOTE! We are assuming this is not an SMP system, otherwise
+        * we would need to update the pte atomically with lwarx/stwcx.
+        */
+       stw     r3,0(r2)                /* update PTE (accessed bit) */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwinm  r1,r3,32-10,31,31       /* _PAGE_RW -> PP lsb */
+       rlwinm  r2,r3,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
+       and     r1,r1,r2                /* writable if _RW and _DIRTY */
+       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r3,r3,32-1,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r1,r1,0xe14             /* clear out reserved bits and M */
+       andc    r1,r3,r1                /* PP = user? (rw&dirty? 2: 3): 0 */
+       mtspr   SPRN_RPA,r1
+       mfspr   r3,SPRN_DMISS
+       tlbld   r3
+       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       rfi
+DataAddressInvalid:
+       mfspr   r3,SPRN_SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+       addis   r1,r1,0x2000
+       mtspr   SPRN_DSISR,r1
+       mtctr   r0              /* Restore CTR */
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       mtspr   SPRN_SRR1,r2
+       mfspr   r1,SPRN_DMISS   /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       beq     20f             /* Jump if big endian */
+       xori    r1,r1,3
+20:    mtspr   SPRN_DAR,r1     /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       mtmsr   r0
+       b       DataAccess
+
+/*
+ * Handle TLB miss for DATA Store on 603/603e
+ */
+       . = 0x1200
+DataStoreTLBMiss:
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       mfctr   r0
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_DMISS
+       lis     r1,KERNELBASE@h         /* check if kernel address */
+       cmplw   0,r3,r1
+       mfspr   r2,SPRN_SPRG3
+       li      r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
+       lwz     r2,PGDIR(r2)
+       blt+    112f
+       lis     r2,swapper_pg_dir@ha    /* if kernel address, use */
+       addi    r2,r2,swapper_pg_dir@l  /* kernel page table */
+       mfspr   r1,SPRN_SRR1            /* and MSR_PR bit from SRR1 */
+       rlwinm  r1,r1,32-12,29,29       /* shift MSR_PR to _PAGE_USER posn */
+112:   tophys(r2,r2)
+       rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    DataAddressInvalid      /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r3,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r3                /* check access & ~permission */
+       bne-    DataAddressInvalid      /* return if access not permitted */
+       ori     r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY
+       /*
+        * NOTE! We are assuming this is not an SMP system, otherwise
+        * we would need to update the pte atomically with lwarx/stwcx.
+        */
+       stw     r3,0(r2)                /* update PTE (accessed/dirty bits) */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwimi  r3,r3,32-1,30,30        /* _PAGE_USER -> PP msb */
+       li      r1,0xe15                /* clear out reserved bits and M */
+       andc    r1,r3,r1                /* PP = user? 2: 0 */
+       mtspr   SPRN_RPA,r1
+       mfspr   r3,SPRN_DMISS
+       tlbld   r3
+       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       rfi
+
+#ifndef CONFIG_ALTIVEC
+#define altivec_assist_exception       unknown_exception
+#endif
+
+       EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE)
+       EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
+       EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE)
+       EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
+       EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE)
+       EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE)
+
+       .globl mol_trampoline
+       .set mol_trampoline, i0x2f00
+
+       . = 0x3000
+
+AltiVecUnavailable:
+       EXCEPTION_PROLOG
+#ifdef CONFIG_ALTIVEC
+       bne     load_up_altivec         /* if from user, just load it up */
+#endif /* CONFIG_ALTIVEC */
+       EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
+
+#ifdef CONFIG_ALTIVEC
+/* Note that the AltiVec support is closely modeled after the FP
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_altivec:
+/*
+ * Disable AltiVec for the task which had AltiVec previously,
+ * and save its AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ * On SMP we know the AltiVec units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+       mfmsr   r5
+       oris    r5,r5,MSR_VEC@h
+       MTMSRD(r5)                      /* enable use of AltiVec now */
+       isync
+/*
+ * For SMP, we don't do lazy AltiVec switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_altivec in switch_to.
+ */
+#ifndef CONFIG_SMP
+       tophys(r6,0)
+       addis   r3,r6,last_task_used_altivec@ha
+       lwz     r4,last_task_used_altivec@l(r3)
+       cmpwi   0,r4,0
+       beq     1f
+       add     r4,r4,r6
+       addi    r4,r4,THREAD    /* want THREAD of last_task_used_altivec */
+       SAVE_32VRS(0,r10,r4)
+       mfvscr  vr0
+       li      r10,THREAD_VSCR
+       stvx    vr0,r10,r4
+       lwz     r5,PT_REGS(r4)
+       add     r5,r5,r6
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r10,MSR_VEC@h
+       andc    r4,r4,r10       /* disable altivec for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+       /* enable use of AltiVec after return */
+       oris    r9,r9,MSR_VEC@h
+       mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
+       li      r4,1
+       li      r10,THREAD_VSCR
+       stw     r4,THREAD_USED_VR(r5)
+       lvx     vr0,r10,r5
+       mtvscr  vr0
+       REST_32VRS(0,r10,r5)
+#ifndef CONFIG_SMP
+       subi    r4,r5,THREAD
+       sub     r4,r4,r6
+       stw     r4,last_task_used_altivec@l(r3)
+#endif /* CONFIG_SMP */
+       /* restore registers and return */
+       /* we haven't used ctr or xer or lr */
+       b       fast_exception_return
+
+/*
+ * AltiVec unavailable trap from kernel - print a message, but let
+ * the task use AltiVec in the kernel until it returns to user mode.
+ */
+KernelAltiVec:
+       lwz     r3,_MSR(r1)
+       oris    r3,r3,MSR_VEC@h
+       stw     r3,_MSR(r1)     /* enable use of AltiVec after return */
+       lis     r3,87f@h
+       ori     r3,r3,87f@l
+       mr      r4,r2           /* current */
+       lwz     r5,_NIP(r1)
+       bl      printk
+       b       ret_from_except
+87:    .string "AltiVec used in kernel  (task=%p, pc=%x)  \n"
+       .align  4,0
+
+/*
+ * giveup_altivec(tsk)
+ * Disable AltiVec for the task given as the argument,
+ * and save the AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ */
+
+       .globl  giveup_altivec
+giveup_altivec:
+       mfmsr   r5
+       oris    r5,r5,MSR_VEC@h
+       SYNC
+       MTMSRD(r5)                      /* enable use of AltiVec now */
+       isync
+       cmpwi   0,r3,0
+       beqlr-                          /* if no previous owner, done */
+       addi    r3,r3,THREAD            /* want THREAD of task */
+       lwz     r5,PT_REGS(r3)
+       cmpwi   0,r5,0
+       SAVE_32VRS(0, r4, r3)
+       mfvscr  vr0
+       li      r4,THREAD_VSCR
+       stvx    vr0,r4,r3
+       beq     1f
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r3,MSR_VEC@h
+       andc    r4,r4,r3                /* disable AltiVec for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+       li      r5,0
+       lis     r4,last_task_used_altivec@ha
+       stw     r5,last_task_used_altivec@l(r4)
+#endif /* CONFIG_SMP */
+       blr
+#endif /* CONFIG_ALTIVEC */
+
+/*
+ * This code is jumped to from the startup code to copy
+ * the kernel image to physical address 0.
+ */
+relocate_kernel:
+       addis   r9,r26,klimit@ha        /* fetch klimit */
+       lwz     r25,klimit@l(r9)
+       addis   r25,r25,-KERNELBASE@h
+       li      r3,0                    /* Destination base address */
+       li      r6,0                    /* Destination offset */
+       li      r5,0x4000               /* # bytes of memory to copy */
+       bl      copy_and_flush          /* copy the first 0x4000 bytes */
+       addi    r0,r3,4f@l              /* jump to the address of 4f */
+       mtctr   r0                      /* in copy and do the rest. */
+       bctr                            /* jump to the copy */
+4:     mr      r5,r25
+       bl      copy_and_flush          /* copy the rest */
+       b       turn_on_mmu
+
+/*
+ * Copy routine used to copy the kernel to start at physical address 0
+ * and flush and invalidate the caches as needed.
+ * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
+ * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
+ */
+copy_and_flush:
+       addi    r5,r5,-4
+       addi    r6,r6,-4
+4:     li      r0,L1_CACHE_LINE_SIZE/4
+       mtctr   r0
+3:     addi    r6,r6,4                 /* copy a cache line */
+       lwzx    r0,r6,r4
+       stwx    r0,r6,r3
+       bdnz    3b
+       dcbst   r6,r3                   /* write it to memory */
+       sync
+       icbi    r6,r3                   /* flush the icache line */
+       cmplw   0,r6,r5
+       blt     4b
+       sync                            /* additional sync needed on g4 */
+       isync
+       addi    r5,r5,4
+       addi    r6,r6,4
+       blr
+
+#ifdef CONFIG_APUS
+/*
+ * On APUS the physical base address of the kernel is not known at compile
+ * time, which means the __pa/__va constants used are incorrect. In the
+ * __init section is recorded the virtual addresses of instructions using
+ * these constants, so all that has to be done is fix these before
+ * continuing the kernel boot.
+ *
+ * r4 = The physical address of the kernel base.
+ */
+fix_mem_constants:
+       mr      r10,r4
+       addis   r10,r10,-KERNELBASE@h    /* virt_to_phys constant */
+       neg     r11,r10                  /* phys_to_virt constant */
+
+       lis     r12,__vtop_table_begin@h
+       ori     r12,r12,__vtop_table_begin@l
+       add     r12,r12,r10              /* table begin phys address */
+       lis     r13,__vtop_table_end@h
+       ori     r13,r13,__vtop_table_end@l
+       add     r13,r13,r10              /* table end phys address */
+       subi    r12,r12,4
+       subi    r13,r13,4
+1:     lwzu    r14,4(r12)               /* virt address of instruction */
+       add     r14,r14,r10              /* phys address of instruction */
+       lwz     r15,0(r14)               /* instruction, now insert top */
+       rlwimi  r15,r10,16,16,31         /* half of vp const in low half */
+       stw     r15,0(r14)               /* of instruction and restore. */
+       dcbst   r0,r14                   /* write it to memory */
+       sync
+       icbi    r0,r14                   /* flush the icache line */
+       cmpw    r12,r13
+       bne     1b
+       sync                            /* additional sync needed on g4 */
+       isync
+
+/*
+ * Map the memory where the exception handlers will
+ * be copied to when hash constants have been patched.
+ */
+#ifdef CONFIG_APUS_FAST_EXCEPT
+       lis     r8,0xfff0
+#else
+       lis     r8,0
+#endif
+       ori     r8,r8,0x2               /* 128KB, supervisor */
+       mtspr   SPRN_DBAT3U,r8
+       mtspr   SPRN_DBAT3L,r8
+
+       lis     r12,__ptov_table_begin@h
+       ori     r12,r12,__ptov_table_begin@l
+       add     r12,r12,r10              /* table begin phys address */
+       lis     r13,__ptov_table_end@h
+       ori     r13,r13,__ptov_table_end@l
+       add     r13,r13,r10              /* table end phys address */
+       subi    r12,r12,4
+       subi    r13,r13,4
+1:     lwzu    r14,4(r12)               /* virt address of instruction */
+       add     r14,r14,r10              /* phys address of instruction */
+       lwz     r15,0(r14)               /* instruction, now insert top */
+       rlwimi  r15,r11,16,16,31         /* half of pv const in low half*/
+       stw     r15,0(r14)               /* of instruction and restore. */
+       dcbst   r0,r14                   /* write it to memory */
+       sync
+       icbi    r0,r14                   /* flush the icache line */
+       cmpw    r12,r13
+       bne     1b
+
+       sync                            /* additional sync needed on g4 */
+       isync                           /* No speculative loading until now */
+       blr
+
+/***********************************************************************
+ *  Please note that on APUS the exception handlers are located at the
+ *  physical address 0xfff0000. For this reason, the exception handlers
+ *  cannot use relative branches to access the code below.
+ ***********************************************************************/
+#endif /* CONFIG_APUS */
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_GEMINI
+       .globl  __secondary_start_gemini
+__secondary_start_gemini:
+        mfspr   r4,SPRN_HID0
+        ori     r4,r4,HID0_ICFI
+        li      r3,0
+        ori     r3,r3,HID0_ICE
+        andc    r4,r4,r3
+        mtspr   SPRN_HID0,r4
+        sync
+        b       __secondary_start
+#endif /* CONFIG_GEMINI */
+
+       .globl  __secondary_start_pmac_0
+__secondary_start_pmac_0:
+       /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
+       li      r24,0
+       b       1f
+       li      r24,1
+       b       1f
+       li      r24,2
+       b       1f
+       li      r24,3
+1:
+       /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
+          set to map the 0xf0000000 - 0xffffffff region */
+       mfmsr   r0
+       rlwinm  r0,r0,0,28,26           /* clear DR (0x10) */
+       SYNC
+       mtmsr   r0
+       isync
+
+       .globl  __secondary_start
+__secondary_start:
+       /* Copy some CPU settings from CPU 0 */
+       bl      __restore_cpu_setup
+
+       lis     r3,-KERNELBASE@h
+       mr      r4,r24
+       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
+#ifdef CONFIG_6xx
+       lis     r3,-KERNELBASE@h
+       bl      init_idle_6xx
+#endif /* CONFIG_6xx */
+
+       /* get current_thread_info and current */
+       lis     r1,secondary_ti@ha
+       tophys(r1,r1)
+       lwz     r1,secondary_ti@l(r1)
+       tophys(r2,r1)
+       lwz     r2,TI_TASK(r2)
+
+       /* stack */
+       addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
+       li      r0,0
+       tophys(r3,r1)
+       stw     r0,0(r3)
+
+       /* load up the MMU */
+       bl      load_up_mmu
+
+       /* ptr to phys current thread */
+       tophys(r4,r2)
+       addi    r4,r4,THREAD    /* phys address of our thread_struct */
+       CLR_TOP32(r4)
+       mtspr   SPRN_SPRG3,r4
+       li      r3,0
+       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
+
+       /* enable MMU and jump to start_secondary */
+       li      r4,MSR_KERNEL
+       FIX_SRR1(r4,r5)
+       lis     r3,start_secondary@h
+       ori     r3,r3,start_secondary@l
+       mtspr   SPRN_SRR0,r3
+       mtspr   SPRN_SRR1,r4
+       SYNC
+       RFI
+#endif /* CONFIG_SMP */
+
+/*
+ * Those generic dummy functions are kept for CPUs not
+ * included in CONFIG_6xx
+ */
+#if !defined(CONFIG_6xx)
+_GLOBAL(__save_cpu_setup)
+       blr
+_GLOBAL(__restore_cpu_setup)
+       blr
+#endif /* !defined(CONFIG_6xx) */
+
+
+/*
+ * Load stuff into the MMU.  Intended to be called with
+ * IR=0 and DR=0.
+ */
+load_up_mmu:
+       sync                    /* Force all PTE updates to finish */
+       isync
+       tlbia                   /* Clear all TLB entries */
+       sync                    /* wait for tlbia/tlbie to finish */
+       TLBSYNC                 /* ... on all CPUs */
+       /* Load the SDR1 register (hash table base & size) */
+       lis     r6,_SDR1@ha
+       tophys(r6,r6)
+       lwz     r6,_SDR1@l(r6)
+       mtspr   SPRN_SDR1,r6
+       li      r0,16           /* load up segment register values */
+       mtctr   r0              /* for context 0 */
+       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
+       li      r4,0
+3:     mtsrin  r3,r4
+       addi    r3,r3,0x111     /* increment VSID */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+
+/* Load the BAT registers with the values set up by MMU_init.
+   MMU_init takes care of whether we're on a 601 or not. */
+       mfpvr   r3
+       srwi    r3,r3,16
+       cmpwi   r3,1
+       lis     r3,BATS@ha
+       addi    r3,r3,BATS@l
+       tophys(r3,r3)
+       LOAD_BAT(0,r3,r4,r5)
+       LOAD_BAT(1,r3,r4,r5)
+       LOAD_BAT(2,r3,r4,r5)
+       LOAD_BAT(3,r3,r4,r5)
+
+       blr
+
+/*
+ * This is where the main kernel code starts.
+ */
+start_here:
+       /* ptr to current */
+       lis     r2,init_task@h
+       ori     r2,r2,init_task@l
+       /* Set up for using our exception vectors */
+       /* ptr to phys current thread */
+       tophys(r4,r2)
+       addi    r4,r4,THREAD    /* init task's THREAD */
+       CLR_TOP32(r4)
+       mtspr   SPRN_SPRG3,r4
+       li      r3,0
+       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
+
+       /* stack */
+       lis     r1,init_thread_union@ha
+       addi    r1,r1,init_thread_union@l
+       li      r0,0
+       stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+/*
+ * Do early platform-specific initialization,
+ * and set up the MMU.
+ */
+       mr      r3,r31
+       mr      r4,r30
+       bl      machine_init
+       bl      MMU_init
+
+#ifdef CONFIG_APUS
+       /* Copy exception code to exception vector base on APUS. */
+       lis     r4,KERNELBASE@h
+#ifdef CONFIG_APUS_FAST_EXCEPT
+       lis     r3,0xfff0               /* Copy to 0xfff00000 */
+#else
+       lis     r3,0                    /* Copy to 0x00000000 */
+#endif
+       li      r5,0x4000               /* # bytes of memory to copy */
+       li      r6,0
+       bl      copy_and_flush          /* copy the first 0x4000 bytes */
+#endif  /* CONFIG_APUS */
+
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+       lis     r4,2f@h
+       ori     r4,r4,2f@l
+       tophys(r4,r4)
+       li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+       FIX_SRR1(r3,r5)
+       mtspr   SPRN_SRR0,r4
+       mtspr   SPRN_SRR1,r3
+       SYNC
+       RFI
+/* Load up the kernel context */
+2:     bl      load_up_mmu
+
+#ifdef CONFIG_BDI_SWITCH
+       /* Add helper information for the Abatron bdiGDB debugger.
+        * We do this here because we know the mmu is disabled, and
+        * will be enabled for real in just a few instructions.
+        */
+       lis     r5, abatron_pteptrs@h
+       ori     r5, r5, abatron_pteptrs@l
+       stw     r5, 0xf0(r0)    /* This much match your Abatron config */
+       lis     r6, swapper_pg_dir@h
+       ori     r6, r6, swapper_pg_dir@l
+       tophys(r5, r5)
+       stw     r6, 0(r5)
+#endif /* CONFIG_BDI_SWITCH */
+
+/* Now turn on the MMU for real! */
+       li      r4,MSR_KERNEL
+       FIX_SRR1(r4,r5)
+       lis     r3,start_kernel@h
+       ori     r3,r3,start_kernel@l
+       mtspr   SPRN_SRR0,r3
+       mtspr   SPRN_SRR1,r4
+       SYNC
+       RFI
+
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+       mulli   r3,r3,897       /* multiply context by skew factor */
+       rlwinm  r3,r3,4,8,27    /* VSID = (context & 0xfffff) << 4 */
+       addis   r3,r3,0x6000    /* Set Ks, Ku bits */
+       li      r0,NUM_USER_SEGMENTS
+       mtctr   r0
+
+#ifdef CONFIG_BDI_SWITCH
+       /* Context switch the PTE pointer for the Abatron BDI2000.
+        * The PGDIR is passed as second argument.
+        */
+       lis     r5, KERNELBASE@h
+       lwz     r5, 0xf0(r5)
+       stw     r4, 0x4(r5)
+#endif
+       li      r4,0
+       isync
+3:
+       mtsrin  r3,r4
+       addi    r3,r3,0x111     /* next VSID */
+       rlwinm  r3,r3,0,8,3     /* clear out any overflow from VSID field */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+       sync
+       isync
+       blr
+
+/*
+ * An undocumented "feature" of 604e requires that the v bit
+ * be cleared before changing BAT values.
+ *
+ * Also, newer IBM firmware does not clear bat3 and 4 so
+ * this makes sure it's done.
+ *  -- Cort
+ */
+clear_bats:
+       li      r10,0
+       mfspr   r9,SPRN_PVR
+       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
+       cmpwi   r9, 1
+       beq     1f
+
+       mtspr   SPRN_DBAT0U,r10
+       mtspr   SPRN_DBAT0L,r10
+       mtspr   SPRN_DBAT1U,r10
+       mtspr   SPRN_DBAT1L,r10
+       mtspr   SPRN_DBAT2U,r10
+       mtspr   SPRN_DBAT2L,r10
+       mtspr   SPRN_DBAT3U,r10
+       mtspr   SPRN_DBAT3L,r10
+1:
+       mtspr   SPRN_IBAT0U,r10
+       mtspr   SPRN_IBAT0L,r10
+       mtspr   SPRN_IBAT1U,r10
+       mtspr   SPRN_IBAT1L,r10
+       mtspr   SPRN_IBAT2U,r10
+       mtspr   SPRN_IBAT2L,r10
+       mtspr   SPRN_IBAT3U,r10
+       mtspr   SPRN_IBAT3L,r10
+BEGIN_FTR_SECTION
+       /* Here's a tweak: at this point, CPU setup have
+        * not been called yet, so HIGH_BAT_EN may not be
+        * set in HID0 for the 745x processors. However, it
+        * seems that doesn't affect our ability to actually
+        * write to these SPRs.
+        */
+       mtspr   SPRN_DBAT4U,r10
+       mtspr   SPRN_DBAT4L,r10
+       mtspr   SPRN_DBAT5U,r10
+       mtspr   SPRN_DBAT5L,r10
+       mtspr   SPRN_DBAT6U,r10
+       mtspr   SPRN_DBAT6L,r10
+       mtspr   SPRN_DBAT7U,r10
+       mtspr   SPRN_DBAT7L,r10
+       mtspr   SPRN_IBAT4U,r10
+       mtspr   SPRN_IBAT4L,r10
+       mtspr   SPRN_IBAT5U,r10
+       mtspr   SPRN_IBAT5L,r10
+       mtspr   SPRN_IBAT6U,r10
+       mtspr   SPRN_IBAT6L,r10
+       mtspr   SPRN_IBAT7U,r10
+       mtspr   SPRN_IBAT7L,r10
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+       blr
+
+flush_tlbs:
+       lis     r10, 0x40
+1:     addic.  r10, r10, -0x1000
+       tlbie   r10
+       blt     1b
+       sync
+       blr
+
+mmu_off:
+       addi    r4, r3, __after_mmu_off - _start
+       mfmsr   r3
+       andi.   r0,r3,MSR_DR|MSR_IR             /* MMU enabled? */
+       beqlr
+       andc    r3,r3,r0
+       mtspr   SPRN_SRR0,r4
+       mtspr   SPRN_SRR1,r3
+       sync
+       RFI
+
+/*
+ * Use the first pair of BAT registers to map the 1st 16MB
+ * of RAM to KERNELBASE.  From this point on we can't safely
+ * call OF any more.
+ */
+initial_bats:
+       lis     r11,KERNELBASE@h
+       mfspr   r9,SPRN_PVR
+       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
+       cmpwi   0,r9,1
+       bne     4f
+       ori     r11,r11,4               /* set up BAT registers for 601 */
+       li      r8,0x7f                 /* valid, block length = 8MB */
+       oris    r9,r11,0x800000@h       /* set up BAT reg for 2nd 8M */
+       oris    r10,r8,0x800000@h       /* set up BAT reg for 2nd 8M */
+       mtspr   SPRN_IBAT0U,r11         /* N.B. 601 has valid bit in */
+       mtspr   SPRN_IBAT0L,r8          /* lower BAT register */
+       mtspr   SPRN_IBAT1U,r9
+       mtspr   SPRN_IBAT1L,r10
+       isync
+       blr
+
+4:     tophys(r8,r11)
+#ifdef CONFIG_SMP
+       ori     r8,r8,0x12              /* R/W access, M=1 */
+#else
+       ori     r8,r8,2                 /* R/W access */
+#endif /* CONFIG_SMP */
+#ifdef CONFIG_APUS
+       ori     r11,r11,BL_8M<<2|0x2    /* set up 8MB BAT registers for 604 */
+#else
+       ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
+#endif /* CONFIG_APUS */
+
+       mtspr   SPRN_DBAT0L,r8          /* N.B. 6xx (not 601) have valid */
+       mtspr   SPRN_DBAT0U,r11         /* bit in upper BAT register */
+       mtspr   SPRN_IBAT0L,r8
+       mtspr   SPRN_IBAT0U,r11
+       isync
+       blr
+
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+setup_disp_bat:
+       /*
+        * setup the display bat prepared for us in prom.c
+        */
+       mflr    r8
+       bl      reloc_offset
+       mtlr    r8
+       addis   r8,r3,disp_BAT@ha
+       addi    r8,r8,disp_BAT@l
+       lwz     r11,0(r8)
+       lwz     r8,4(r8)
+       mfspr   r9,SPRN_PVR
+       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
+       cmpwi   0,r9,1
+       beq     1f
+       mtspr   SPRN_DBAT3L,r8
+       mtspr   SPRN_DBAT3U,r11
+       blr
+1:     mtspr   SPRN_IBAT3L,r8
+       mtspr   SPRN_IBAT3U,r11
+       blr
+
+#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+
+
+#ifdef CONFIG_8260
+/* Jump into the system reset for the rom.
+ * We first disable the MMU, and then jump to the ROM reset address.
+ *
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
+ */
+       .globl  m8260_gorom
+m8260_gorom:
+       mfmsr   r0
+       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
+       sync
+       mtmsr   r0
+       sync
+       mfspr   r11, SPRN_HID0
+       lis     r10, 0
+       ori     r10,r10,HID0_ICE|HID0_DCE
+       andc    r11, r11, r10
+       mtspr   SPRN_HID0, r11
+       isync
+       li      r5, MSR_ME|MSR_RI
+       lis     r6,2f@h
+       addis   r6,r6,-KERNELBASE@h
+       ori     r6,r6,2f@l
+       mtspr   SPRN_SRR0,r6
+       mtspr   SPRN_SRR1,r5
+       isync
+       sync
+       rfi
+2:
+       mtlr    r4
+       blr
+#endif
+
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+       .data
+       .globl  sdata
+sdata:
+       .globl  empty_zero_page
+empty_zero_page:
+       .space  4096
+
+       .globl  swapper_pg_dir
+swapper_pg_dir:
+       .space  4096
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * Used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+       .globl  cmd_line
+cmd_line:
+       .space  512
+
+       .globl intercept_table
+intercept_table:
+       .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700
+       .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0
+       .long 0, 0, 0, i0x1300, 0, 0, 0, 0
+       .long 0, 0, 0, 0, 0, 0, 0, 0
+       .long 0, 0, 0, 0, 0, 0, 0, 0
+       .long 0, 0, 0, 0, 0, 0, 0, 0
+
+/* Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+       .space  8
diff --git a/arch/powerpc/kernel/setup.c b/arch/powerpc/kernel/setup.c
deleted file mode 100644 (file)
index 27d7f82..0000000
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Common prep/pmac/chrp boot and setup code.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/reboot.h>
-#include <linux/delay.h>
-#include <linux/initrd.h>
-#include <linux/ide.h>
-#include <linux/tty.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/cpu.h>
-#include <linux/console.h>
-
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/processor.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-#include <asm/amigappc.h>
-#include <asm/smp.h>
-#include <asm/elf.h>
-#include <asm/cputable.h>
-#include <asm/bootx.h>
-#include <asm/btext.h>
-#include <asm/machdep.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/nvram.h>
-#include <asm/xmon.h>
-#include <asm/ocp.h>
-
-#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
-                     defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
-                     defined(CONFIG_PPC_MPC52xx))
-
-#if USES_PPC_SYS
-#include <asm/ppc_sys.h>
-#endif
-
-#if defined CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-
-extern void platform_init(void);
-extern void bootx_init(unsigned long r4, unsigned long phys);
-
-extern void ppc6xx_idle(void);
-extern void power4_idle(void);
-
-boot_infos_t *boot_infos;
-struct ide_machdep_calls ppc_ide_md;
-
-/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
-   size value reported by the boot loader. */
-unsigned long boot_mem_size;
-
-unsigned long ISA_DMA_THRESHOLD;
-unsigned int DMA_MODE_READ;
-unsigned int DMA_MODE_WRITE;
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-int _machine = 0;
-
-extern void prep_init(void);
-extern void pmac_init(void);
-extern void chrp_init(void);
-
-dev_t boot_dev;
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned long SYSRQ_KEY = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-#ifdef CONFIG_VGA_CONSOLE
-unsigned long vgacon_remap_base;
-#endif
-
-struct machdep_calls ppc_md;
-
-/*
- * These are used in binfmt_elf.c to put aux entries on the stack
- * for each elf executable being started.
- */
-int dcache_bsize;
-int icache_bsize;
-int ucache_bsize;
-
-#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \
-    defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA)
-struct screen_info screen_info = {
-       0, 25,                  /* orig-x, orig-y */
-       0,                      /* unused */
-       0,                      /* orig-video-page */
-       0,                      /* orig-video-mode */
-       80,                     /* orig-video-cols */
-       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
-       25,                     /* orig-video-lines */
-       1,                      /* orig-video-isVGA */
-       16                      /* orig-video-points */
-};
-#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */
-
-void machine_restart(char *cmd)
-{
-#ifdef CONFIG_NVRAM
-       nvram_sync();
-#endif
-       ppc_md.restart(cmd);
-}
-
-void machine_power_off(void)
-{
-#ifdef CONFIG_NVRAM
-       nvram_sync();
-#endif
-       ppc_md.power_off();
-}
-
-void machine_halt(void)
-{
-#ifdef CONFIG_NVRAM
-       nvram_sync();
-#endif
-       ppc_md.halt();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-
-#ifdef CONFIG_TAU
-extern u32 cpu_temp(unsigned long cpu);
-extern u32 cpu_temp_both(unsigned long cpu);
-#endif /* CONFIG_TAU */
-
-int show_cpuinfo(struct seq_file *m, void *v)
-{
-       int i = (int) v - 1;
-       int err = 0;
-       unsigned int pvr;
-       unsigned short maj, min;
-       unsigned long lpj;
-
-       if (i >= NR_CPUS) {
-               /* Show summary information */
-#ifdef CONFIG_SMP
-               unsigned long bogosum = 0;
-               for (i = 0; i < NR_CPUS; ++i)
-                       if (cpu_online(i))
-                               bogosum += cpu_data[i].loops_per_jiffy;
-               seq_printf(m, "total bogomips\t: %lu.%02lu\n",
-                          bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
-#endif /* CONFIG_SMP */
-
-               if (ppc_md.show_cpuinfo != NULL)
-                       err = ppc_md.show_cpuinfo(m);
-               return err;
-       }
-
-#ifdef CONFIG_SMP
-       if (!cpu_online(i))
-               return 0;
-       pvr = cpu_data[i].pvr;
-       lpj = cpu_data[i].loops_per_jiffy;
-#else
-       pvr = mfspr(SPRN_PVR);
-       lpj = loops_per_jiffy;
-#endif
-
-       seq_printf(m, "processor\t: %d\n", i);
-       seq_printf(m, "cpu\t\t: ");
-
-       if (cur_cpu_spec->pvr_mask)
-               seq_printf(m, "%s", cur_cpu_spec->cpu_name);
-       else
-               seq_printf(m, "unknown (%08x)", pvr);
-#ifdef CONFIG_ALTIVEC
-       if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
-               seq_printf(m, ", altivec supported");
-#endif
-       seq_printf(m, "\n");
-
-#ifdef CONFIG_TAU
-       if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) {
-#ifdef CONFIG_TAU_AVERAGE
-               /* more straightforward, but potentially misleading */
-               seq_printf(m,  "temperature \t: %u C (uncalibrated)\n",
-                          cpu_temp(i));
-#else
-               /* show the actual temp sensor range */
-               u32 temp;
-               temp = cpu_temp_both(i);
-               seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n",
-                          temp & 0xff, temp >> 16);
-#endif
-       }
-#endif /* CONFIG_TAU */
-
-       if (ppc_md.show_percpuinfo != NULL) {
-               err = ppc_md.show_percpuinfo(m, i);
-               if (err)
-                       return err;
-       }
-
-       /* If we are a Freescale core do a simple check so
-        * we dont have to keep adding cases in the future */
-       if ((PVR_VER(pvr) & 0x8000) == 0x8000) {
-               maj = PVR_MAJ(pvr);
-               min = PVR_MIN(pvr);
-       } else {
-               switch (PVR_VER(pvr)) {
-                       case 0x0020:    /* 403 family */
-                               maj = PVR_MAJ(pvr) + 1;
-                               min = PVR_MIN(pvr);
-                               break;
-                       case 0x1008:    /* 740P/750P ?? */
-                               maj = ((pvr >> 8) & 0xFF) - 1;
-                               min = pvr & 0xFF;
-                               break;
-                       default:
-                               maj = (pvr >> 8) & 0xFF;
-                               min = pvr & 0xFF;
-                               break;
-               }
-       }
-
-       seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n",
-                  maj, min, PVR_VER(pvr), PVR_REV(pvr));
-
-       seq_printf(m, "bogomips\t: %lu.%02lu\n",
-                  lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
-
-#if USES_PPC_SYS
-       if (cur_ppc_sys_spec->ppc_sys_name)
-               seq_printf(m, "chipset\t\t: %s\n",
-                       cur_ppc_sys_spec->ppc_sys_name);
-#endif
-
-#ifdef CONFIG_SMP
-       seq_printf(m, "\n");
-#endif
-
-       return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-       int i = *pos;
-
-       return i <= NR_CPUS? (void *) (i + 1): NULL;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return c_start(m, pos);
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-struct seq_operations cpuinfo_op = {
-       .start =c_start,
-       .next = c_next,
-       .stop = c_stop,
-       .show = show_cpuinfo,
-};
-
-/*
- * We're called here very early in the boot.  We determine the machine
- * type and call the appropriate low-level setup functions.
- *  -- Cort <cort@fsmlabs.com>
- *
- * Note that the kernel may be running at an address which is different
- * from the address that it was linked at, so we must use RELOC/PTRRELOC
- * to access static data (including strings).  -- paulus
- */
-unsigned long __init early_init(unsigned long dt_ptr)
-{
-       unsigned long offset = reloc_offset();
-
-       reloc_got2(offset);
-
-       /*
-        * Identify the CPU type and fix up code sections
-        * that depend on which cpu we have.
-        */
-       identify_cpu(offset, 0);
-       do_cpu_ftr_fixups(offset);
-
-#ifdef CONFIG_BOOTX_TEXT
-       btext_prepare_BAT();
-#endif
-
-       reloc_got2(-offset);
-
-       return KERNELBASE + offset;
-}
-
-#ifdef CONFIG_PPC_OF
-/*
- * Assume here that all clock rates are the same in a
- * smp system.  -- Cort
- */
-int
-of_show_percpuinfo(struct seq_file *m, int i)
-{
-       struct device_node *cpu_node;
-       u32 *fp;
-       int s;
-       
-       cpu_node = find_type_devices("cpu");
-       if (!cpu_node)
-               return 0;
-       for (s = 0; s < i && cpu_node->next; s++)
-               cpu_node = cpu_node->next;
-       fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
-       if (fp)
-               seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
-       return 0;
-}
-
-void __init
-intuit_machine_type(void)
-{
-       char *model;
-       struct device_node *root;
-       
-       /* ask the OF info if we're a chrp or pmac */
-       root = find_path_device("/");
-       if (root != 0) {
-               /* assume pmac unless proven to be chrp -- Cort */
-               _machine = _MACH_Pmac;
-               model = get_property(root, "device_type", NULL);
-               if (model && !strncmp("chrp", model, 4))
-                       _machine = _MACH_chrp;
-               else {
-                       model = get_property(root, "model", NULL);
-                       if (model && !strncmp(model, "IBM", 3))
-                               _machine = _MACH_chrp;
-               }
-       }
-}
-#endif
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-/*
- * The PPC_MULTIPLATFORM version of platform_init...
- */
-void __init platform_init(void)
-{
-       /* if we didn't get any bootinfo telling us what we are... */
-       if (_machine == 0) {
-               /* prep boot loader tells us if we're prep or not */
-               if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
-                       _machine = _MACH_prep;
-       }
-
-#ifdef CONFIG_PPC_PREP
-       /* not much more to do here, if prep */
-       if (_machine == _MACH_prep) {
-               prep_init();
-               return;
-       }
-#endif
-
-#ifdef CONFIG_ADB
-       if (strstr(cmd_line, "adb_sync")) {
-               extern int __adb_probe_sync;
-               __adb_probe_sync = 1;
-       }
-#endif /* CONFIG_ADB */
-
-       switch (_machine) {
-#ifdef CONFIG_PPC_PMAC
-       case _MACH_Pmac:
-               pmac_init();
-               break;
-#endif
-#ifdef CONFIG_PPC_CHRP
-       case _MACH_chrp:
-               chrp_init();
-               break;
-#endif
-       }
-}
-
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-extern char *of_stdout_device;
-
-static int __init set_preferred_console(void)
-{
-       struct device_node *prom_stdout;
-       char *name;
-       int offset = 0;
-
-       if (of_stdout_device == NULL)
-               return -ENODEV;
-
-       /* The user has requested a console so this is already set up. */
-       if (strstr(saved_command_line, "console="))
-               return -EBUSY;
-
-       prom_stdout = find_path_device(of_stdout_device);
-       if (!prom_stdout)
-               return -ENODEV;
-
-       name = (char *)get_property(prom_stdout, "name", NULL);
-       if (!name)
-               return -ENODEV;
-
-       if (strcmp(name, "serial") == 0) {
-               int i;
-               u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
-               if (i > 8) {
-                       switch (reg[1]) {
-                               case 0x3f8:
-                                       offset = 0;
-                                       break;
-                               case 0x2f8:
-                                       offset = 1;
-                                       break;
-                               case 0x898:
-                                       offset = 2;
-                                       break;
-                               case 0x890:
-                                       offset = 3;
-                                       break;
-                               default:
-                                       /* We dont recognise the serial port */
-                                       return -ENODEV;
-                       }
-               }
-       } else if (strcmp(name, "ch-a") == 0)
-               offset = 0;
-       else if (strcmp(name, "ch-b") == 0)
-               offset = 1;
-       else
-               return -ENODEV;
-       return add_preferred_console("ttyS", offset, NULL);
-}
-console_initcall(set_preferred_console);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
-struct bi_record *find_bootinfo(void)
-{
-       struct bi_record *rec;
-
-       rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20));
-       if ( rec->tag != BI_FIRST ) {
-               /*
-                * This 0x10000 offset is a terrible hack but it will go away when
-                * we have the bootloader handle all the relocation and
-                * prom calls -- Cort
-                */
-               rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
-               if ( rec->tag != BI_FIRST )
-                       return NULL;
-       }
-       return rec;
-}
-
-/*
- * Find out what kind of machine we're on and save any data we need
- * from the early boot process (devtree is copied on pmac by prom_init()).
- * This is called very early on the boot process, after a minimal
- * MMU environment has been set up but before MMU_init is called.
- */
-void __init machine_init(unsigned long dt_ptr, unsigned long phys)
-{
-       early_init_devtree(__va(dt_ptr));
-
-#ifdef CONFIG_CMDLINE
-       strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
-#endif /* CONFIG_CMDLINE */
-
-#ifdef CONFIG_6xx
-       ppc_md.power_save = ppc6xx_idle;
-#endif
-#ifdef CONFIG_POWER4
-       ppc_md.power_save = power4_idle;
-#endif
-
-       platform_init();
-
-       if (ppc_md.progress)
-               ppc_md.progress("id mach(): done", 0x200);
-}
-
-#ifdef CONFIG_BOOKE_WDT
-/* Checks wdt=x and wdt_period=xx command-line option */
-int __init early_parse_wdt(char *p)
-{
-       if (p && strncmp(p, "0", 1) != 0)
-              booke_wdt_enabled = 1;
-
-       return 0;
-}
-early_param("wdt", early_parse_wdt);
-
-int __init early_parse_wdt_period (char *p)
-{
-       if (p)
-               booke_wdt_period = simple_strtoul(p, NULL, 0);
-
-       return 0;
-}
-early_param("wdt_period", early_parse_wdt_period);
-#endif /* CONFIG_BOOKE_WDT */
-
-/* Checks "l2cr=xxxx" command-line option */
-int __init ppc_setup_l2cr(char *str)
-{
-       if (cpu_has_feature(CPU_FTR_L2CR)) {
-               unsigned long val = simple_strtoul(str, NULL, 0);
-               printk(KERN_INFO "l2cr set to %lx\n", val);
-               _set_L2CR(0);           /* force invalidate by disable cache */
-               _set_L2CR(val);         /* and enable it */
-       }
-       return 1;
-}
-__setup("l2cr=", ppc_setup_l2cr);
-
-#ifdef CONFIG_GENERIC_NVRAM
-
-/* Generic nvram hooks used by drivers/char/gen_nvram.c */
-unsigned char nvram_read_byte(int addr)
-{
-       if (ppc_md.nvram_read_val)
-               return ppc_md.nvram_read_val(addr);
-       return 0xff;
-}
-EXPORT_SYMBOL(nvram_read_byte);
-
-void nvram_write_byte(unsigned char val, int addr)
-{
-       if (ppc_md.nvram_write_val)
-               ppc_md.nvram_write_val(addr, val);
-}
-EXPORT_SYMBOL(nvram_write_byte);
-
-void nvram_sync(void)
-{
-       if (ppc_md.nvram_sync)
-               ppc_md.nvram_sync();
-}
-EXPORT_SYMBOL(nvram_sync);
-
-#endif /* CONFIG_NVRAM */
-
-static struct cpu cpu_devices[NR_CPUS];
-
-int __init ppc_init(void)
-{
-       int i;
-
-       /* clear the progress line */
-       if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
-
-       /* register CPU devices */
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_possible(i))
-                       register_cpu(&cpu_devices[i], i, NULL);
-
-       /* call platform init */
-       if (ppc_md.init != NULL) {
-               ppc_md.init();
-       }
-       return 0;
-}
-
-arch_initcall(ppc_init);
-
-/* Warning, IO base is not yet inited */
-void __init setup_arch(char **cmdline_p)
-{
-       extern char *klimit;
-       extern void do_init_bootmem(void);
-
-       /* so udelay does something sensible, assume <= 1000 bogomips */
-       loops_per_jiffy = 500000000 / HZ;
-
-#ifdef CONFIG_BOOTX_TEXT
-       map_boot_text();
-#endif
-
-       unflatten_device_tree();
-       finish_device_tree();
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-       /* This could be called "early setup arch", it must be done
-        * now because xmon need it
-        */
-       if (_machine == _MACH_Pmac)
-               pmac_feature_init();    /* New cool way */
-#endif
-
-#ifdef CONFIG_XMON
-       xmon_map_scc();
-       if (strstr(cmd_line, "xmon"))
-               xmon(NULL);
-#endif /* CONFIG_XMON */
-       if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
-
-#if defined(CONFIG_KGDB)
-       if (ppc_md.kgdb_map_scc)
-               ppc_md.kgdb_map_scc();
-       set_debug_traps();
-       if (strstr(cmd_line, "gdb")) {
-               if (ppc_md.progress)
-                       ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
-               printk("kgdb breakpoint activated\n");
-               breakpoint();
-       }
-#endif
-
-       /*
-        * Set cache line size based on type of cpu as a default.
-        * Systems with OF can look in the properties on the cpu node(s)
-        * for a possibly more accurate value.
-        */
-       if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
-               dcache_bsize = cur_cpu_spec->dcache_bsize;
-               icache_bsize = cur_cpu_spec->icache_bsize;
-               ucache_bsize = 0;
-       } else
-               ucache_bsize = dcache_bsize = icache_bsize
-                       = cur_cpu_spec->dcache_bsize;
-
-       /* reboot on panic */
-       panic_timeout = 180;
-
-       init_mm.start_code = PAGE_OFFSET;
-       init_mm.end_code = (unsigned long) _etext;
-       init_mm.end_data = (unsigned long) _edata;
-       init_mm.brk = (unsigned long) klimit;
-
-       /* Save unparsed command line copy for /proc/cmdline */
-       strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
-       *cmdline_p = cmd_line;
-
-       parse_early_param();
-
-       /* set up the bootmem stuff with available memory */
-       do_init_bootmem();
-       if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
-
-#ifdef CONFIG_PPC_OCP
-       /* Initialize OCP device list */
-       ocp_early_init();
-       if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
-#endif
-
-#ifdef CONFIG_DUMMY_CONSOLE
-       conswitchp = &dummy_con;
-#endif
-
-       ppc_md.setup_arch();
-       if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
-
-       paging_init();
-
-       /* this is for modules since _machine can be a define -- Cort */
-       ppc_md.ppc_machine = _machine;
-}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
new file mode 100644 (file)
index 0000000..27d7f82
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * Common prep/pmac/chrp boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/initrd.h>
+#include <linux/ide.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/cpu.h>
+#include <linux/console.h>
+
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigappc.h>
+#include <asm/smp.h>
+#include <asm/elf.h>
+#include <asm/cputable.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/nvram.h>
+#include <asm/xmon.h>
+#include <asm/ocp.h>
+
+#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
+                     defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
+                     defined(CONFIG_PPC_MPC52xx))
+
+#if USES_PPC_SYS
+#include <asm/ppc_sys.h>
+#endif
+
+#if defined CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+extern void platform_init(void);
+extern void bootx_init(unsigned long r4, unsigned long phys);
+
+extern void ppc6xx_idle(void);
+extern void power4_idle(void);
+
+boot_infos_t *boot_infos;
+struct ide_machdep_calls ppc_ide_md;
+
+/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
+   size value reported by the boot loader. */
+unsigned long boot_mem_size;
+
+unsigned long ISA_DMA_THRESHOLD;
+unsigned int DMA_MODE_READ;
+unsigned int DMA_MODE_WRITE;
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+int _machine = 0;
+
+extern void prep_init(void);
+extern void pmac_init(void);
+extern void chrp_init(void);
+
+dev_t boot_dev;
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
+
+struct machdep_calls ppc_md;
+
+/*
+ * These are used in binfmt_elf.c to put aux entries on the stack
+ * for each elf executable being started.
+ */
+int dcache_bsize;
+int icache_bsize;
+int ucache_bsize;
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \
+    defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA)
+struct screen_info screen_info = {
+       0, 25,                  /* orig-x, orig-y */
+       0,                      /* unused */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       80,                     /* orig-video-cols */
+       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+       25,                     /* orig-video-lines */
+       1,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */
+
+void machine_restart(char *cmd)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.restart(cmd);
+}
+
+void machine_power_off(void)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.power_off();
+}
+
+void machine_halt(void)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.halt();
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+
+#ifdef CONFIG_TAU
+extern u32 cpu_temp(unsigned long cpu);
+extern u32 cpu_temp_both(unsigned long cpu);
+#endif /* CONFIG_TAU */
+
+int show_cpuinfo(struct seq_file *m, void *v)
+{
+       int i = (int) v - 1;
+       int err = 0;
+       unsigned int pvr;
+       unsigned short maj, min;
+       unsigned long lpj;
+
+       if (i >= NR_CPUS) {
+               /* Show summary information */
+#ifdef CONFIG_SMP
+               unsigned long bogosum = 0;
+               for (i = 0; i < NR_CPUS; ++i)
+                       if (cpu_online(i))
+                               bogosum += cpu_data[i].loops_per_jiffy;
+               seq_printf(m, "total bogomips\t: %lu.%02lu\n",
+                          bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
+#endif /* CONFIG_SMP */
+
+               if (ppc_md.show_cpuinfo != NULL)
+                       err = ppc_md.show_cpuinfo(m);
+               return err;
+       }
+
+#ifdef CONFIG_SMP
+       if (!cpu_online(i))
+               return 0;
+       pvr = cpu_data[i].pvr;
+       lpj = cpu_data[i].loops_per_jiffy;
+#else
+       pvr = mfspr(SPRN_PVR);
+       lpj = loops_per_jiffy;
+#endif
+
+       seq_printf(m, "processor\t: %d\n", i);
+       seq_printf(m, "cpu\t\t: ");
+
+       if (cur_cpu_spec->pvr_mask)
+               seq_printf(m, "%s", cur_cpu_spec->cpu_name);
+       else
+               seq_printf(m, "unknown (%08x)", pvr);
+#ifdef CONFIG_ALTIVEC
+       if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
+               seq_printf(m, ", altivec supported");
+#endif
+       seq_printf(m, "\n");
+
+#ifdef CONFIG_TAU
+       if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) {
+#ifdef CONFIG_TAU_AVERAGE
+               /* more straightforward, but potentially misleading */
+               seq_printf(m,  "temperature \t: %u C (uncalibrated)\n",
+                          cpu_temp(i));
+#else
+               /* show the actual temp sensor range */
+               u32 temp;
+               temp = cpu_temp_both(i);
+               seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n",
+                          temp & 0xff, temp >> 16);
+#endif
+       }
+#endif /* CONFIG_TAU */
+
+       if (ppc_md.show_percpuinfo != NULL) {
+               err = ppc_md.show_percpuinfo(m, i);
+               if (err)
+                       return err;
+       }
+
+       /* If we are a Freescale core do a simple check so
+        * we dont have to keep adding cases in the future */
+       if ((PVR_VER(pvr) & 0x8000) == 0x8000) {
+               maj = PVR_MAJ(pvr);
+               min = PVR_MIN(pvr);
+       } else {
+               switch (PVR_VER(pvr)) {
+                       case 0x0020:    /* 403 family */
+                               maj = PVR_MAJ(pvr) + 1;
+                               min = PVR_MIN(pvr);
+                               break;
+                       case 0x1008:    /* 740P/750P ?? */
+                               maj = ((pvr >> 8) & 0xFF) - 1;
+                               min = pvr & 0xFF;
+                               break;
+                       default:
+                               maj = (pvr >> 8) & 0xFF;
+                               min = pvr & 0xFF;
+                               break;
+               }
+       }
+
+       seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n",
+                  maj, min, PVR_VER(pvr), PVR_REV(pvr));
+
+       seq_printf(m, "bogomips\t: %lu.%02lu\n",
+                  lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
+
+#if USES_PPC_SYS
+       if (cur_ppc_sys_spec->ppc_sys_name)
+               seq_printf(m, "chipset\t\t: %s\n",
+                       cur_ppc_sys_spec->ppc_sys_name);
+#endif
+
+#ifdef CONFIG_SMP
+       seq_printf(m, "\n");
+#endif
+
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       int i = *pos;
+
+       return i <= NR_CPUS? (void *) (i + 1): NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+       .start =c_start,
+       .next = c_next,
+       .stop = c_stop,
+       .show = show_cpuinfo,
+};
+
+/*
+ * We're called here very early in the boot.  We determine the machine
+ * type and call the appropriate low-level setup functions.
+ *  -- Cort <cort@fsmlabs.com>
+ *
+ * Note that the kernel may be running at an address which is different
+ * from the address that it was linked at, so we must use RELOC/PTRRELOC
+ * to access static data (including strings).  -- paulus
+ */
+unsigned long __init early_init(unsigned long dt_ptr)
+{
+       unsigned long offset = reloc_offset();
+
+       reloc_got2(offset);
+
+       /*
+        * Identify the CPU type and fix up code sections
+        * that depend on which cpu we have.
+        */
+       identify_cpu(offset, 0);
+       do_cpu_ftr_fixups(offset);
+
+#ifdef CONFIG_BOOTX_TEXT
+       btext_prepare_BAT();
+#endif
+
+       reloc_got2(-offset);
+
+       return KERNELBASE + offset;
+}
+
+#ifdef CONFIG_PPC_OF
+/*
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+       struct device_node *cpu_node;
+       u32 *fp;
+       int s;
+       
+       cpu_node = find_type_devices("cpu");
+       if (!cpu_node)
+               return 0;
+       for (s = 0; s < i && cpu_node->next; s++)
+               cpu_node = cpu_node->next;
+       fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
+       if (fp)
+               seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+       return 0;
+}
+
+void __init
+intuit_machine_type(void)
+{
+       char *model;
+       struct device_node *root;
+       
+       /* ask the OF info if we're a chrp or pmac */
+       root = find_path_device("/");
+       if (root != 0) {
+               /* assume pmac unless proven to be chrp -- Cort */
+               _machine = _MACH_Pmac;
+               model = get_property(root, "device_type", NULL);
+               if (model && !strncmp("chrp", model, 4))
+                       _machine = _MACH_chrp;
+               else {
+                       model = get_property(root, "model", NULL);
+                       if (model && !strncmp(model, "IBM", 3))
+                               _machine = _MACH_chrp;
+               }
+       }
+}
+#endif
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+/*
+ * The PPC_MULTIPLATFORM version of platform_init...
+ */
+void __init platform_init(void)
+{
+       /* if we didn't get any bootinfo telling us what we are... */
+       if (_machine == 0) {
+               /* prep boot loader tells us if we're prep or not */
+               if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+                       _machine = _MACH_prep;
+       }
+
+#ifdef CONFIG_PPC_PREP
+       /* not much more to do here, if prep */
+       if (_machine == _MACH_prep) {
+               prep_init();
+               return;
+       }
+#endif
+
+#ifdef CONFIG_ADB
+       if (strstr(cmd_line, "adb_sync")) {
+               extern int __adb_probe_sync;
+               __adb_probe_sync = 1;
+       }
+#endif /* CONFIG_ADB */
+
+       switch (_machine) {
+#ifdef CONFIG_PPC_PMAC
+       case _MACH_Pmac:
+               pmac_init();
+               break;
+#endif
+#ifdef CONFIG_PPC_CHRP
+       case _MACH_chrp:
+               chrp_init();
+               break;
+#endif
+       }
+}
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+extern char *of_stdout_device;
+
+static int __init set_preferred_console(void)
+{
+       struct device_node *prom_stdout;
+       char *name;
+       int offset = 0;
+
+       if (of_stdout_device == NULL)
+               return -ENODEV;
+
+       /* The user has requested a console so this is already set up. */
+       if (strstr(saved_command_line, "console="))
+               return -EBUSY;
+
+       prom_stdout = find_path_device(of_stdout_device);
+       if (!prom_stdout)
+               return -ENODEV;
+
+       name = (char *)get_property(prom_stdout, "name", NULL);
+       if (!name)
+               return -ENODEV;
+
+       if (strcmp(name, "serial") == 0) {
+               int i;
+               u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
+               if (i > 8) {
+                       switch (reg[1]) {
+                               case 0x3f8:
+                                       offset = 0;
+                                       break;
+                               case 0x2f8:
+                                       offset = 1;
+                                       break;
+                               case 0x898:
+                                       offset = 2;
+                                       break;
+                               case 0x890:
+                                       offset = 3;
+                                       break;
+                               default:
+                                       /* We dont recognise the serial port */
+                                       return -ENODEV;
+                       }
+               }
+       } else if (strcmp(name, "ch-a") == 0)
+               offset = 0;
+       else if (strcmp(name, "ch-b") == 0)
+               offset = 1;
+       else
+               return -ENODEV;
+       return add_preferred_console("ttyS", offset, NULL);
+}
+console_initcall(set_preferred_console);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+struct bi_record *find_bootinfo(void)
+{
+       struct bi_record *rec;
+
+       rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20));
+       if ( rec->tag != BI_FIRST ) {
+               /*
+                * This 0x10000 offset is a terrible hack but it will go away when
+                * we have the bootloader handle all the relocation and
+                * prom calls -- Cort
+                */
+               rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
+               if ( rec->tag != BI_FIRST )
+                       return NULL;
+       }
+       return rec;
+}
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init()).
+ * This is called very early on the boot process, after a minimal
+ * MMU environment has been set up but before MMU_init is called.
+ */
+void __init machine_init(unsigned long dt_ptr, unsigned long phys)
+{
+       early_init_devtree(__va(dt_ptr));
+
+#ifdef CONFIG_CMDLINE
+       strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
+#endif /* CONFIG_CMDLINE */
+
+#ifdef CONFIG_6xx
+       ppc_md.power_save = ppc6xx_idle;
+#endif
+#ifdef CONFIG_POWER4
+       ppc_md.power_save = power4_idle;
+#endif
+
+       platform_init();
+
+       if (ppc_md.progress)
+               ppc_md.progress("id mach(): done", 0x200);
+}
+
+#ifdef CONFIG_BOOKE_WDT
+/* Checks wdt=x and wdt_period=xx command-line option */
+int __init early_parse_wdt(char *p)
+{
+       if (p && strncmp(p, "0", 1) != 0)
+              booke_wdt_enabled = 1;
+
+       return 0;
+}
+early_param("wdt", early_parse_wdt);
+
+int __init early_parse_wdt_period (char *p)
+{
+       if (p)
+               booke_wdt_period = simple_strtoul(p, NULL, 0);
+
+       return 0;
+}
+early_param("wdt_period", early_parse_wdt_period);
+#endif /* CONFIG_BOOKE_WDT */
+
+/* Checks "l2cr=xxxx" command-line option */
+int __init ppc_setup_l2cr(char *str)
+{
+       if (cpu_has_feature(CPU_FTR_L2CR)) {
+               unsigned long val = simple_strtoul(str, NULL, 0);
+               printk(KERN_INFO "l2cr set to %lx\n", val);
+               _set_L2CR(0);           /* force invalidate by disable cache */
+               _set_L2CR(val);         /* and enable it */
+       }
+       return 1;
+}
+__setup("l2cr=", ppc_setup_l2cr);
+
+#ifdef CONFIG_GENERIC_NVRAM
+
+/* Generic nvram hooks used by drivers/char/gen_nvram.c */
+unsigned char nvram_read_byte(int addr)
+{
+       if (ppc_md.nvram_read_val)
+               return ppc_md.nvram_read_val(addr);
+       return 0xff;
+}
+EXPORT_SYMBOL(nvram_read_byte);
+
+void nvram_write_byte(unsigned char val, int addr)
+{
+       if (ppc_md.nvram_write_val)
+               ppc_md.nvram_write_val(addr, val);
+}
+EXPORT_SYMBOL(nvram_write_byte);
+
+void nvram_sync(void)
+{
+       if (ppc_md.nvram_sync)
+               ppc_md.nvram_sync();
+}
+EXPORT_SYMBOL(nvram_sync);
+
+#endif /* CONFIG_NVRAM */
+
+static struct cpu cpu_devices[NR_CPUS];
+
+int __init ppc_init(void)
+{
+       int i;
+
+       /* clear the progress line */
+       if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
+
+       /* register CPU devices */
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_possible(i))
+                       register_cpu(&cpu_devices[i], i, NULL);
+
+       /* call platform init */
+       if (ppc_md.init != NULL) {
+               ppc_md.init();
+       }
+       return 0;
+}
+
+arch_initcall(ppc_init);
+
+/* Warning, IO base is not yet inited */
+void __init setup_arch(char **cmdline_p)
+{
+       extern char *klimit;
+       extern void do_init_bootmem(void);
+
+       /* so udelay does something sensible, assume <= 1000 bogomips */
+       loops_per_jiffy = 500000000 / HZ;
+
+#ifdef CONFIG_BOOTX_TEXT
+       map_boot_text();
+#endif
+
+       unflatten_device_tree();
+       finish_device_tree();
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+       /* This could be called "early setup arch", it must be done
+        * now because xmon need it
+        */
+       if (_machine == _MACH_Pmac)
+               pmac_feature_init();    /* New cool way */
+#endif
+
+#ifdef CONFIG_XMON
+       xmon_map_scc();
+       if (strstr(cmd_line, "xmon"))
+               xmon(NULL);
+#endif /* CONFIG_XMON */
+       if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
+
+#if defined(CONFIG_KGDB)
+       if (ppc_md.kgdb_map_scc)
+               ppc_md.kgdb_map_scc();
+       set_debug_traps();
+       if (strstr(cmd_line, "gdb")) {
+               if (ppc_md.progress)
+                       ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
+               printk("kgdb breakpoint activated\n");
+               breakpoint();
+       }
+#endif
+
+       /*
+        * Set cache line size based on type of cpu as a default.
+        * Systems with OF can look in the properties on the cpu node(s)
+        * for a possibly more accurate value.
+        */
+       if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
+               dcache_bsize = cur_cpu_spec->dcache_bsize;
+               icache_bsize = cur_cpu_spec->icache_bsize;
+               ucache_bsize = 0;
+       } else
+               ucache_bsize = dcache_bsize = icache_bsize
+                       = cur_cpu_spec->dcache_bsize;
+
+       /* reboot on panic */
+       panic_timeout = 180;
+
+       init_mm.start_code = PAGE_OFFSET;
+       init_mm.end_code = (unsigned long) _etext;
+       init_mm.end_data = (unsigned long) _edata;
+       init_mm.brk = (unsigned long) klimit;
+
+       /* Save unparsed command line copy for /proc/cmdline */
+       strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
+       *cmdline_p = cmd_line;
+
+       parse_early_param();
+
+       /* set up the bootmem stuff with available memory */
+       do_init_bootmem();
+       if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
+
+#ifdef CONFIG_PPC_OCP
+       /* Initialize OCP device list */
+       ocp_early_init();
+       if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+
+       ppc_md.setup_arch();
+       if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+
+       paging_init();
+
+       /* this is for modules since _machine can be a define -- Cort */
+       ppc_md.ppc_machine = _machine;
+}
index 347f9798e433845fbfb9e205f5e495c1fadc0e9e..a8cedb96de5f66c3aa8de6a422aed33ad549c494 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y                  := strcase.o string.o
-obj-$(CONFIG_PPC32)    += div64.o copy32.o checksum.o
-obj-$(CONFIG_PPC64)    += copypage.o copyuser.o memcpy.o usercopy.o \
-                          sstep.o checksum64.o
+obj-$(CONFIG_PPC32)    += div64.o copy_32.o checksum_32.o
+obj-$(CONFIG_PPC64)    += copypage_64.o copyuser_64.o memcpy_64.o \
+                          usercopy_64.o sstep.o checksum_64.o mem_64.o
 obj-$(CONFIG_PPC_ISERIES) += e2a.o
diff --git a/arch/powerpc/lib/checksum.S b/arch/powerpc/lib/checksum.S
deleted file mode 100644 (file)
index 7874e8a..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * This file contains assembly-language implementations
- * of IP-style 1's complement checksum routines.
- *     
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
- */
-
-#include <linux/sys.h>
-#include <asm/processor.h>
-#include <asm/errno.h>
-#include <asm/ppc_asm.h>
-
-       .text
-
-/*
- * ip_fast_csum(buf, len) -- Optimized for IP header
- * len is in words and is always >= 5.
- */
-_GLOBAL(ip_fast_csum)
-       lwz     r0,0(r3)
-       lwzu    r5,4(r3)
-       addic.  r4,r4,-2
-       addc    r0,r0,r5
-       mtctr   r4
-       blelr-
-1:     lwzu    r4,4(r3)
-       adde    r0,r0,r4
-       bdnz    1b
-       addze   r0,r0           /* add in final carry */
-       rlwinm  r3,r0,16,0,31   /* fold two halves together */
-       add     r3,r0,r3
-       not     r3,r3
-       srwi    r3,r3,16
-       blr
-
-/*
- * Compute checksum of TCP or UDP pseudo-header:
- *   csum_tcpudp_magic(saddr, daddr, len, proto, sum)
- */    
-_GLOBAL(csum_tcpudp_magic)
-       rlwimi  r5,r6,16,0,15   /* put proto in upper half of len */
-       addc    r0,r3,r4        /* add 4 32-bit words together */
-       adde    r0,r0,r5
-       adde    r0,r0,r7
-       addze   r0,r0           /* add in final carry */
-       rlwinm  r3,r0,16,0,31   /* fold two halves together */
-       add     r3,r0,r3
-       not     r3,r3
-       srwi    r3,r3,16
-       blr
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * csum_partial(buff, len, sum)
- */
-_GLOBAL(csum_partial)
-       addic   r0,r5,0
-       subi    r3,r3,4
-       srwi.   r6,r4,2
-       beq     3f              /* if we're doing < 4 bytes */
-       andi.   r5,r3,2         /* Align buffer to longword boundary */
-       beq+    1f
-       lhz     r5,4(r3)        /* do 2 bytes to get aligned */
-       addi    r3,r3,2
-       subi    r4,r4,2
-       addc    r0,r0,r5
-       srwi.   r6,r4,2         /* # words to do */
-       beq     3f
-1:     mtctr   r6
-2:     lwzu    r5,4(r3)        /* the bdnz has zero overhead, so it should */
-       adde    r0,r0,r5        /* be unnecessary to unroll this loop */
-       bdnz    2b
-       andi.   r4,r4,3
-3:     cmpwi   0,r4,2
-       blt+    4f
-       lhz     r5,4(r3)
-       addi    r3,r3,2
-       subi    r4,r4,2
-       adde    r0,r0,r5
-4:     cmpwi   0,r4,1
-       bne+    5f
-       lbz     r5,4(r3)
-       slwi    r5,r5,8         /* Upper byte of word */
-       adde    r0,r0,r5
-5:     addze   r3,r0           /* add in final carry */
-       blr
-
-/*
- * Computes the checksum of a memory block at src, length len,
- * and adds in "sum" (32-bit), while copying the block to dst.
- * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively, and (for an error on
- * src) zeroes the rest of dst.
- *
- * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
- */
-_GLOBAL(csum_partial_copy_generic)
-       addic   r0,r6,0
-       subi    r3,r3,4
-       subi    r4,r4,4
-       srwi.   r6,r5,2
-       beq     3f              /* if we're doing < 4 bytes */
-       andi.   r9,r4,2         /* Align dst to longword boundary */
-       beq+    1f
-81:    lhz     r6,4(r3)        /* do 2 bytes to get aligned */
-       addi    r3,r3,2
-       subi    r5,r5,2
-91:    sth     r6,4(r4)
-       addi    r4,r4,2
-       addc    r0,r0,r6
-       srwi.   r6,r5,2         /* # words to do */
-       beq     3f
-1:     srwi.   r6,r5,4         /* # groups of 4 words to do */
-       beq     10f
-       mtctr   r6
-71:    lwz     r6,4(r3)
-72:    lwz     r9,8(r3)
-73:    lwz     r10,12(r3)
-74:    lwzu    r11,16(r3)
-       adde    r0,r0,r6
-75:    stw     r6,4(r4)
-       adde    r0,r0,r9
-76:    stw     r9,8(r4)
-       adde    r0,r0,r10
-77:    stw     r10,12(r4)
-       adde    r0,r0,r11
-78:    stwu    r11,16(r4)
-       bdnz    71b
-10:    rlwinm. r6,r5,30,30,31  /* # words left to do */
-       beq     13f
-       mtctr   r6
-82:    lwzu    r9,4(r3)
-92:    stwu    r9,4(r4)
-       adde    r0,r0,r9
-       bdnz    82b
-13:    andi.   r5,r5,3
-3:     cmpwi   0,r5,2
-       blt+    4f
-83:    lhz     r6,4(r3)
-       addi    r3,r3,2
-       subi    r5,r5,2
-93:    sth     r6,4(r4)
-       addi    r4,r4,2
-       adde    r0,r0,r6
-4:     cmpwi   0,r5,1
-       bne+    5f
-84:    lbz     r6,4(r3)
-94:    stb     r6,4(r4)
-       slwi    r6,r6,8         /* Upper byte of word */
-       adde    r0,r0,r6
-5:     addze   r3,r0           /* add in final carry */
-       blr
-
-/* These shouldn't go in the fixup section, since that would
-   cause the ex_table addresses to get out of order. */
-
-src_error_4:
-       mfctr   r6              /* update # bytes remaining from ctr */
-       rlwimi  r5,r6,4,0,27
-       b       79f
-src_error_1:
-       li      r6,0
-       subi    r5,r5,2
-95:    sth     r6,4(r4)
-       addi    r4,r4,2
-79:    srwi.   r6,r5,2
-       beq     3f
-       mtctr   r6
-src_error_2:
-       li      r6,0
-96:    stwu    r6,4(r4)
-       bdnz    96b
-3:     andi.   r5,r5,3
-       beq     src_error
-src_error_3:
-       li      r6,0
-       mtctr   r5
-       addi    r4,r4,3
-97:    stbu    r6,1(r4)
-       bdnz    97b
-src_error:
-       cmpwi   0,r7,0
-       beq     1f
-       li      r6,-EFAULT
-       stw     r6,0(r7)
-1:     addze   r3,r0
-       blr
-
-dst_error:
-       cmpwi   0,r8,0
-       beq     1f
-       li      r6,-EFAULT
-       stw     r6,0(r8)
-1:     addze   r3,r0
-       blr
-
-.section __ex_table,"a"
-       .long   81b,src_error_1
-       .long   91b,dst_error
-       .long   71b,src_error_4
-       .long   72b,src_error_4
-       .long   73b,src_error_4
-       .long   74b,src_error_4
-       .long   75b,dst_error
-       .long   76b,dst_error
-       .long   77b,dst_error
-       .long   78b,dst_error
-       .long   82b,src_error_2
-       .long   92b,dst_error
-       .long   83b,src_error_3
-       .long   93b,dst_error
-       .long   84b,src_error_3
-       .long   94b,dst_error
-       .long   95b,dst_error
-       .long   96b,dst_error
-       .long   97b,dst_error
diff --git a/arch/powerpc/lib/checksum64.S b/arch/powerpc/lib/checksum64.S
deleted file mode 100644 (file)
index ef96c6c..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * This file contains assembly-language implementations
- * of IP-style 1's complement checksum routines.
- *     
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
- */
-
-#include <linux/sys.h>
-#include <asm/processor.h>
-#include <asm/errno.h>
-#include <asm/ppc_asm.h>
-
-/*
- * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
- * len is in words and is always >= 5.
- *
- * In practice len == 5, but this is not guaranteed.  So this code does not
- * attempt to use doubleword instructions.
- */
-_GLOBAL(ip_fast_csum)
-       lwz     r0,0(r3)
-       lwzu    r5,4(r3)
-       addic.  r4,r4,-2
-       addc    r0,r0,r5
-       mtctr   r4
-       blelr-
-1:     lwzu    r4,4(r3)
-       adde    r0,r0,r4
-       bdnz    1b
-       addze   r0,r0           /* add in final carry */
-        rldicl  r4,r0,32,0      /* fold two 32-bit halves together */
-        add     r0,r0,r4
-        srdi    r0,r0,32
-       rlwinm  r3,r0,16,0,31   /* fold two halves together */
-       add     r3,r0,r3
-       not     r3,r3
-       srwi    r3,r3,16
-       blr
-
-/*
- * Compute checksum of TCP or UDP pseudo-header:
- *   csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum)
- * No real gain trying to do this specially for 64 bit, but
- * the 32 bit addition may spill into the upper bits of
- * the doubleword so we still must fold it down from 64.
- */    
-_GLOBAL(csum_tcpudp_magic)
-       rlwimi  r5,r6,16,0,15   /* put proto in upper half of len */
-       addc    r0,r3,r4        /* add 4 32-bit words together */
-       adde    r0,r0,r5
-       adde    r0,r0,r7
-        rldicl  r4,r0,32,0      /* fold 64 bit value */
-        add     r0,r4,r0
-        srdi    r0,r0,32
-       rlwinm  r3,r0,16,0,31   /* fold two halves together */
-       add     r3,r0,r3
-       not     r3,r3
-       srwi    r3,r3,16
-       blr
-
-/*
- * Computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit).
- *
- * This code assumes at least halfword alignment, though the length
- * can be any number of bytes.  The sum is accumulated in r5.
- *
- * csum_partial(r3=buff, r4=len, r5=sum)
- */
-_GLOBAL(csum_partial)
-        subi   r3,r3,8         /* we'll offset by 8 for the loads */
-        srdi.  r6,r4,3         /* divide by 8 for doubleword count */
-        addic   r5,r5,0         /* clear carry */
-        beq    3f              /* if we're doing < 8 bytes */
-        andi.  r0,r3,2         /* aligned on a word boundary already? */
-        beq+   1f
-        lhz     r6,8(r3)        /* do 2 bytes to get aligned */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        addc    r5,r5,r6
-        srdi.   r6,r4,3         /* recompute number of doublewords */
-        beq     3f              /* any left? */
-1:      mtctr   r6
-2:      ldu     r6,8(r3)        /* main sum loop */
-        adde    r5,r5,r6
-        bdnz    2b
-        andi.  r4,r4,7         /* compute bytes left to sum after doublewords */
-3:     cmpwi   0,r4,4          /* is at least a full word left? */
-       blt     4f
-       lwz     r6,8(r3)        /* sum this word */
-       addi    r3,r3,4
-       subi    r4,r4,4
-       adde    r5,r5,r6
-4:     cmpwi   0,r4,2          /* is at least a halfword left? */
-        blt+   5f
-        lhz     r6,8(r3)        /* sum this halfword */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        adde    r5,r5,r6
-5:     cmpwi   0,r4,1          /* is at least a byte left? */
-        bne+    6f
-        lbz     r6,8(r3)        /* sum this byte */
-        slwi    r6,r6,8         /* this byte is assumed to be the upper byte of a halfword */
-        adde    r5,r5,r6
-6:      addze  r5,r5           /* add in final carry */
-       rldicl  r4,r5,32,0      /* fold two 32-bit halves together */
-        add     r3,r4,r5
-        srdi    r3,r3,32
-        blr
-
-/*
- * Computes the checksum of a memory block at src, length len,
- * and adds in "sum" (32-bit), while copying the block to dst.
- * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively, and (for an error on
- * src) zeroes the rest of dst.
- *
- * This code needs to be reworked to take advantage of 64 bit sum+copy.
- * However, due to tokenring halfword alignment problems this will be very
- * tricky.  For now we'll leave it until we instrument it somehow.
- *
- * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
- */
-_GLOBAL(csum_partial_copy_generic)
-       addic   r0,r6,0
-       subi    r3,r3,4
-       subi    r4,r4,4
-       srwi.   r6,r5,2
-       beq     3f              /* if we're doing < 4 bytes */
-       andi.   r9,r4,2         /* Align dst to longword boundary */
-       beq+    1f
-81:    lhz     r6,4(r3)        /* do 2 bytes to get aligned */
-       addi    r3,r3,2
-       subi    r5,r5,2
-91:    sth     r6,4(r4)
-       addi    r4,r4,2
-       addc    r0,r0,r6
-       srwi.   r6,r5,2         /* # words to do */
-       beq     3f
-1:     mtctr   r6
-82:    lwzu    r6,4(r3)        /* the bdnz has zero overhead, so it should */
-92:    stwu    r6,4(r4)        /* be unnecessary to unroll this loop */
-       adde    r0,r0,r6
-       bdnz    82b
-       andi.   r5,r5,3
-3:     cmpwi   0,r5,2
-       blt+    4f
-83:    lhz     r6,4(r3)
-       addi    r3,r3,2
-       subi    r5,r5,2
-93:    sth     r6,4(r4)
-       addi    r4,r4,2
-       adde    r0,r0,r6
-4:     cmpwi   0,r5,1
-       bne+    5f
-84:    lbz     r6,4(r3)
-94:    stb     r6,4(r4)
-       slwi    r6,r6,8         /* Upper byte of word */
-       adde    r0,r0,r6
-5:     addze   r3,r0           /* add in final carry (unlikely with 64-bit regs) */
-        rldicl  r4,r3,32,0      /* fold 64 bit value */
-        add     r3,r4,r3
-        srdi    r3,r3,32
-       blr
-
-/* These shouldn't go in the fixup section, since that would
-   cause the ex_table addresses to get out of order. */
-
-       .globl src_error_1
-src_error_1:
-       li      r6,0
-       subi    r5,r5,2
-95:    sth     r6,4(r4)
-       addi    r4,r4,2
-       srwi.   r6,r5,2
-       beq     3f
-       mtctr   r6
-       .globl src_error_2
-src_error_2:
-       li      r6,0
-96:    stwu    r6,4(r4)
-       bdnz    96b
-3:     andi.   r5,r5,3
-       beq     src_error
-       .globl src_error_3
-src_error_3:
-       li      r6,0
-       mtctr   r5
-       addi    r4,r4,3
-97:    stbu    r6,1(r4)
-       bdnz    97b
-       .globl src_error
-src_error:
-       cmpdi   0,r7,0
-       beq     1f
-       li      r6,-EFAULT
-       stw     r6,0(r7)
-1:     addze   r3,r0
-       blr
-
-       .globl dst_error
-dst_error:
-       cmpdi   0,r8,0
-       beq     1f
-       li      r6,-EFAULT
-       stw     r6,0(r8)
-1:     addze   r3,r0
-       blr
-
-.section __ex_table,"a"
-       .align  3
-       .llong  81b,src_error_1
-       .llong  91b,dst_error
-       .llong  82b,src_error_2
-       .llong  92b,dst_error
-       .llong  83b,src_error_3
-       .llong  93b,dst_error
-       .llong  84b,src_error_3
-       .llong  94b,dst_error
-       .llong  95b,dst_error
-       .llong  96b,dst_error
-       .llong  97b,dst_error
diff --git a/arch/powerpc/lib/checksum_32.S b/arch/powerpc/lib/checksum_32.S
new file mode 100644 (file)
index 0000000..7874e8a
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *     
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/ppc_asm.h>
+
+       .text
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+       lwz     r0,0(r3)
+       lwzu    r5,4(r3)
+       addic.  r4,r4,-2
+       addc    r0,r0,r5
+       mtctr   r4
+       blelr-
+1:     lwzu    r4,4(r3)
+       adde    r0,r0,r4
+       bdnz    1b
+       addze   r0,r0           /* add in final carry */
+       rlwinm  r3,r0,16,0,31   /* fold two halves together */
+       add     r3,r0,r3
+       not     r3,r3
+       srwi    r3,r3,16
+       blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ *   csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */    
+_GLOBAL(csum_tcpudp_magic)
+       rlwimi  r5,r6,16,0,15   /* put proto in upper half of len */
+       addc    r0,r3,r4        /* add 4 32-bit words together */
+       adde    r0,r0,r5
+       adde    r0,r0,r7
+       addze   r0,r0           /* add in final carry */
+       rlwinm  r3,r0,16,0,31   /* fold two halves together */
+       add     r3,r0,r3
+       not     r3,r3
+       srwi    r3,r3,16
+       blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+       addic   r0,r5,0
+       subi    r3,r3,4
+       srwi.   r6,r4,2
+       beq     3f              /* if we're doing < 4 bytes */
+       andi.   r5,r3,2         /* Align buffer to longword boundary */
+       beq+    1f
+       lhz     r5,4(r3)        /* do 2 bytes to get aligned */
+       addi    r3,r3,2
+       subi    r4,r4,2
+       addc    r0,r0,r5
+       srwi.   r6,r4,2         /* # words to do */
+       beq     3f
+1:     mtctr   r6
+2:     lwzu    r5,4(r3)        /* the bdnz has zero overhead, so it should */
+       adde    r0,r0,r5        /* be unnecessary to unroll this loop */
+       bdnz    2b
+       andi.   r4,r4,3
+3:     cmpwi   0,r4,2
+       blt+    4f
+       lhz     r5,4(r3)
+       addi    r3,r3,2
+       subi    r4,r4,2
+       adde    r0,r0,r5
+4:     cmpwi   0,r4,1
+       bne+    5f
+       lbz     r5,4(r3)
+       slwi    r5,r5,8         /* Upper byte of word */
+       adde    r0,r0,r5
+5:     addze   r3,r0           /* add in final carry */
+       blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+       addic   r0,r6,0
+       subi    r3,r3,4
+       subi    r4,r4,4
+       srwi.   r6,r5,2
+       beq     3f              /* if we're doing < 4 bytes */
+       andi.   r9,r4,2         /* Align dst to longword boundary */
+       beq+    1f
+81:    lhz     r6,4(r3)        /* do 2 bytes to get aligned */
+       addi    r3,r3,2
+       subi    r5,r5,2
+91:    sth     r6,4(r4)
+       addi    r4,r4,2
+       addc    r0,r0,r6
+       srwi.   r6,r5,2         /* # words to do */
+       beq     3f
+1:     srwi.   r6,r5,4         /* # groups of 4 words to do */
+       beq     10f
+       mtctr   r6
+71:    lwz     r6,4(r3)
+72:    lwz     r9,8(r3)
+73:    lwz     r10,12(r3)
+74:    lwzu    r11,16(r3)
+       adde    r0,r0,r6
+75:    stw     r6,4(r4)
+       adde    r0,r0,r9
+76:    stw     r9,8(r4)
+       adde    r0,r0,r10
+77:    stw     r10,12(r4)
+       adde    r0,r0,r11
+78:    stwu    r11,16(r4)
+       bdnz    71b
+10:    rlwinm. r6,r5,30,30,31  /* # words left to do */
+       beq     13f
+       mtctr   r6
+82:    lwzu    r9,4(r3)
+92:    stwu    r9,4(r4)
+       adde    r0,r0,r9
+       bdnz    82b
+13:    andi.   r5,r5,3
+3:     cmpwi   0,r5,2
+       blt+    4f
+83:    lhz     r6,4(r3)
+       addi    r3,r3,2
+       subi    r5,r5,2
+93:    sth     r6,4(r4)
+       addi    r4,r4,2
+       adde    r0,r0,r6
+4:     cmpwi   0,r5,1
+       bne+    5f
+84:    lbz     r6,4(r3)
+94:    stb     r6,4(r4)
+       slwi    r6,r6,8         /* Upper byte of word */
+       adde    r0,r0,r6
+5:     addze   r3,r0           /* add in final carry */
+       blr
+
+/* These shouldn't go in the fixup section, since that would
+   cause the ex_table addresses to get out of order. */
+
+src_error_4:
+       mfctr   r6              /* update # bytes remaining from ctr */
+       rlwimi  r5,r6,4,0,27
+       b       79f
+src_error_1:
+       li      r6,0
+       subi    r5,r5,2
+95:    sth     r6,4(r4)
+       addi    r4,r4,2
+79:    srwi.   r6,r5,2
+       beq     3f
+       mtctr   r6
+src_error_2:
+       li      r6,0
+96:    stwu    r6,4(r4)
+       bdnz    96b
+3:     andi.   r5,r5,3
+       beq     src_error
+src_error_3:
+       li      r6,0
+       mtctr   r5
+       addi    r4,r4,3
+97:    stbu    r6,1(r4)
+       bdnz    97b
+src_error:
+       cmpwi   0,r7,0
+       beq     1f
+       li      r6,-EFAULT
+       stw     r6,0(r7)
+1:     addze   r3,r0
+       blr
+
+dst_error:
+       cmpwi   0,r8,0
+       beq     1f
+       li      r6,-EFAULT
+       stw     r6,0(r8)
+1:     addze   r3,r0
+       blr
+
+.section __ex_table,"a"
+       .long   81b,src_error_1
+       .long   91b,dst_error
+       .long   71b,src_error_4
+       .long   72b,src_error_4
+       .long   73b,src_error_4
+       .long   74b,src_error_4
+       .long   75b,dst_error
+       .long   76b,dst_error
+       .long   77b,dst_error
+       .long   78b,dst_error
+       .long   82b,src_error_2
+       .long   92b,dst_error
+       .long   83b,src_error_3
+       .long   93b,dst_error
+       .long   84b,src_error_3
+       .long   94b,dst_error
+       .long   95b,dst_error
+       .long   96b,dst_error
+       .long   97b,dst_error
diff --git a/arch/powerpc/lib/checksum_64.S b/arch/powerpc/lib/checksum_64.S
new file mode 100644 (file)
index 0000000..ef96c6c
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *     
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/ppc_asm.h>
+
+/*
+ * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ *
+ * In practice len == 5, but this is not guaranteed.  So this code does not
+ * attempt to use doubleword instructions.
+ */
+_GLOBAL(ip_fast_csum)
+       lwz     r0,0(r3)
+       lwzu    r5,4(r3)
+       addic.  r4,r4,-2
+       addc    r0,r0,r5
+       mtctr   r4
+       blelr-
+1:     lwzu    r4,4(r3)
+       adde    r0,r0,r4
+       bdnz    1b
+       addze   r0,r0           /* add in final carry */
+        rldicl  r4,r0,32,0      /* fold two 32-bit halves together */
+        add     r0,r0,r4
+        srdi    r0,r0,32
+       rlwinm  r3,r0,16,0,31   /* fold two halves together */
+       add     r3,r0,r3
+       not     r3,r3
+       srwi    r3,r3,16
+       blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ *   csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum)
+ * No real gain trying to do this specially for 64 bit, but
+ * the 32 bit addition may spill into the upper bits of
+ * the doubleword so we still must fold it down from 64.
+ */    
+_GLOBAL(csum_tcpudp_magic)
+       rlwimi  r5,r6,16,0,15   /* put proto in upper half of len */
+       addc    r0,r3,r4        /* add 4 32-bit words together */
+       adde    r0,r0,r5
+       adde    r0,r0,r7
+        rldicl  r4,r0,32,0      /* fold 64 bit value */
+        add     r0,r4,r0
+        srdi    r0,r0,32
+       rlwinm  r3,r0,16,0,31   /* fold two halves together */
+       add     r3,r0,r3
+       not     r3,r3
+       srwi    r3,r3,16
+       blr
+
+/*
+ * Computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit).
+ *
+ * This code assumes at least halfword alignment, though the length
+ * can be any number of bytes.  The sum is accumulated in r5.
+ *
+ * csum_partial(r3=buff, r4=len, r5=sum)
+ */
+_GLOBAL(csum_partial)
+        subi   r3,r3,8         /* we'll offset by 8 for the loads */
+        srdi.  r6,r4,3         /* divide by 8 for doubleword count */
+        addic   r5,r5,0         /* clear carry */
+        beq    3f              /* if we're doing < 8 bytes */
+        andi.  r0,r3,2         /* aligned on a word boundary already? */
+        beq+   1f
+        lhz     r6,8(r3)        /* do 2 bytes to get aligned */
+        addi    r3,r3,2
+        subi    r4,r4,2
+        addc    r5,r5,r6
+        srdi.   r6,r4,3         /* recompute number of doublewords */
+        beq     3f              /* any left? */
+1:      mtctr   r6
+2:      ldu     r6,8(r3)        /* main sum loop */
+        adde    r5,r5,r6
+        bdnz    2b
+        andi.  r4,r4,7         /* compute bytes left to sum after doublewords */
+3:     cmpwi   0,r4,4          /* is at least a full word left? */
+       blt     4f
+       lwz     r6,8(r3)        /* sum this word */
+       addi    r3,r3,4
+       subi    r4,r4,4
+       adde    r5,r5,r6
+4:     cmpwi   0,r4,2          /* is at least a halfword left? */
+        blt+   5f
+        lhz     r6,8(r3)        /* sum this halfword */
+        addi    r3,r3,2
+        subi    r4,r4,2
+        adde    r5,r5,r6
+5:     cmpwi   0,r4,1          /* is at least a byte left? */
+        bne+    6f
+        lbz     r6,8(r3)        /* sum this byte */
+        slwi    r6,r6,8         /* this byte is assumed to be the upper byte of a halfword */
+        adde    r5,r5,r6
+6:      addze  r5,r5           /* add in final carry */
+       rldicl  r4,r5,32,0      /* fold two 32-bit halves together */
+        add     r3,r4,r5
+        srdi    r3,r3,32
+        blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * This code needs to be reworked to take advantage of 64 bit sum+copy.
+ * However, due to tokenring halfword alignment problems this will be very
+ * tricky.  For now we'll leave it until we instrument it somehow.
+ *
+ * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+       addic   r0,r6,0
+       subi    r3,r3,4
+       subi    r4,r4,4
+       srwi.   r6,r5,2
+       beq     3f              /* if we're doing < 4 bytes */
+       andi.   r9,r4,2         /* Align dst to longword boundary */
+       beq+    1f
+81:    lhz     r6,4(r3)        /* do 2 bytes to get aligned */
+       addi    r3,r3,2
+       subi    r5,r5,2
+91:    sth     r6,4(r4)
+       addi    r4,r4,2
+       addc    r0,r0,r6
+       srwi.   r6,r5,2         /* # words to do */
+       beq     3f
+1:     mtctr   r6
+82:    lwzu    r6,4(r3)        /* the bdnz has zero overhead, so it should */
+92:    stwu    r6,4(r4)        /* be unnecessary to unroll this loop */
+       adde    r0,r0,r6
+       bdnz    82b
+       andi.   r5,r5,3
+3:     cmpwi   0,r5,2
+       blt+    4f
+83:    lhz     r6,4(r3)
+       addi    r3,r3,2
+       subi    r5,r5,2
+93:    sth     r6,4(r4)
+       addi    r4,r4,2
+       adde    r0,r0,r6
+4:     cmpwi   0,r5,1
+       bne+    5f
+84:    lbz     r6,4(r3)
+94:    stb     r6,4(r4)
+       slwi    r6,r6,8         /* Upper byte of word */
+       adde    r0,r0,r6
+5:     addze   r3,r0           /* add in final carry (unlikely with 64-bit regs) */
+        rldicl  r4,r3,32,0      /* fold 64 bit value */
+        add     r3,r4,r3
+        srdi    r3,r3,32
+       blr
+
+/* These shouldn't go in the fixup section, since that would
+   cause the ex_table addresses to get out of order. */
+
+       .globl src_error_1
+src_error_1:
+       li      r6,0
+       subi    r5,r5,2
+95:    sth     r6,4(r4)
+       addi    r4,r4,2
+       srwi.   r6,r5,2
+       beq     3f
+       mtctr   r6
+       .globl src_error_2
+src_error_2:
+       li      r6,0
+96:    stwu    r6,4(r4)
+       bdnz    96b
+3:     andi.   r5,r5,3
+       beq     src_error
+       .globl src_error_3
+src_error_3:
+       li      r6,0
+       mtctr   r5
+       addi    r4,r4,3
+97:    stbu    r6,1(r4)
+       bdnz    97b
+       .globl src_error
+src_error:
+       cmpdi   0,r7,0
+       beq     1f
+       li      r6,-EFAULT
+       stw     r6,0(r7)
+1:     addze   r3,r0
+       blr
+
+       .globl dst_error
+dst_error:
+       cmpdi   0,r8,0
+       beq     1f
+       li      r6,-EFAULT
+       stw     r6,0(r8)
+1:     addze   r3,r0
+       blr
+
+.section __ex_table,"a"
+       .align  3
+       .llong  81b,src_error_1
+       .llong  91b,dst_error
+       .llong  82b,src_error_2
+       .llong  92b,dst_error
+       .llong  83b,src_error_3
+       .llong  93b,dst_error
+       .llong  84b,src_error_3
+       .llong  94b,dst_error
+       .llong  95b,dst_error
+       .llong  96b,dst_error
+       .llong  97b,dst_error
diff --git a/arch/powerpc/lib/copy32.S b/arch/powerpc/lib/copy32.S
deleted file mode 100644 (file)
index 420a912..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Memory copy functions for 32-bit PowerPC.
- *
- * Copyright (C) 1996-2005 Paul Mackerras.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/cache.h>
-#include <asm/errno.h>
-#include <asm/ppc_asm.h>
-
-#define COPY_16_BYTES          \
-       lwz     r7,4(r4);       \
-       lwz     r8,8(r4);       \
-       lwz     r9,12(r4);      \
-       lwzu    r10,16(r4);     \
-       stw     r7,4(r6);       \
-       stw     r8,8(r6);       \
-       stw     r9,12(r6);      \
-       stwu    r10,16(r6)
-
-#define COPY_16_BYTES_WITHEX(n)        \
-8 ## n ## 0:                   \
-       lwz     r7,4(r4);       \
-8 ## n ## 1:                   \
-       lwz     r8,8(r4);       \
-8 ## n ## 2:                   \
-       lwz     r9,12(r4);      \
-8 ## n ## 3:                   \
-       lwzu    r10,16(r4);     \
-8 ## n ## 4:                   \
-       stw     r7,4(r6);       \
-8 ## n ## 5:                   \
-       stw     r8,8(r6);       \
-8 ## n ## 6:                   \
-       stw     r9,12(r6);      \
-8 ## n ## 7:                   \
-       stwu    r10,16(r6)
-
-#define COPY_16_BYTES_EXCODE(n)                        \
-9 ## n ## 0:                                   \
-       addi    r5,r5,-(16 * n);                \
-       b       104f;                           \
-9 ## n ## 1:                                   \
-       addi    r5,r5,-(16 * n);                \
-       b       105f;                           \
-.section __ex_table,"a";                       \
-       .align  2;                              \
-       .long   8 ## n ## 0b,9 ## n ## 0b;      \
-       .long   8 ## n ## 1b,9 ## n ## 0b;      \
-       .long   8 ## n ## 2b,9 ## n ## 0b;      \
-       .long   8 ## n ## 3b,9 ## n ## 0b;      \
-       .long   8 ## n ## 4b,9 ## n ## 1b;      \
-       .long   8 ## n ## 5b,9 ## n ## 1b;      \
-       .long   8 ## n ## 6b,9 ## n ## 1b;      \
-       .long   8 ## n ## 7b,9 ## n ## 1b;      \
-       .text
-
-       .text
-       .stabs  "arch/powerpc/lib/",N_SO,0,0,0f
-       .stabs  "copy32.S",N_SO,0,0,0f
-0:
-
-CACHELINE_BYTES = L1_CACHE_LINE_SIZE
-LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE
-CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1)
-
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-       mr      r5,r4
-       li      r4,0
-       addi    r6,r3,-4
-       cmplwi  0,r5,4
-       blt     7f
-       stwu    r4,4(r6)
-       beqlr
-       andi.   r0,r6,3
-       add     r5,r0,r5
-       subf    r6,r0,r6
-       clrlwi  r7,r6,32-LG_CACHELINE_BYTES
-       add     r8,r7,r5
-       srwi    r9,r8,LG_CACHELINE_BYTES
-       addic.  r9,r9,-1        /* total number of complete cachelines */
-       ble     2f
-       xori    r0,r7,CACHELINE_MASK & ~3
-       srwi.   r0,r0,2
-       beq     3f
-       mtctr   r0
-4:     stwu    r4,4(r6)
-       bdnz    4b
-3:     mtctr   r9
-       li      r7,4
-#if !defined(CONFIG_8xx)
-10:    dcbz    r7,r6
-#else
-10:    stw     r4, 4(r6)
-       stw     r4, 8(r6)
-       stw     r4, 12(r6)
-       stw     r4, 16(r6)
-#if CACHE_LINE_SIZE >= 32
-       stw     r4, 20(r6)
-       stw     r4, 24(r6)
-       stw     r4, 28(r6)
-       stw     r4, 32(r6)
-#endif /* CACHE_LINE_SIZE */
-#endif
-       addi    r6,r6,CACHELINE_BYTES
-       bdnz    10b
-       clrlwi  r5,r8,32-LG_CACHELINE_BYTES
-       addi    r5,r5,4
-2:     srwi    r0,r5,2
-       mtctr   r0
-       bdz     6f
-1:     stwu    r4,4(r6)
-       bdnz    1b
-6:     andi.   r5,r5,3
-7:     cmpwi   0,r5,0
-       beqlr
-       mtctr   r5
-       addi    r6,r6,3
-8:     stbu    r4,1(r6)
-       bdnz    8b
-       blr
-
-_GLOBAL(memset)
-       rlwimi  r4,r4,8,16,23
-       rlwimi  r4,r4,16,0,15
-       addi    r6,r3,-4
-       cmplwi  0,r5,4
-       blt     7f
-       stwu    r4,4(r6)
-       beqlr
-       andi.   r0,r6,3
-       add     r5,r0,r5
-       subf    r6,r0,r6
-       srwi    r0,r5,2
-       mtctr   r0
-       bdz     6f
-1:     stwu    r4,4(r6)
-       bdnz    1b
-6:     andi.   r5,r5,3
-7:     cmpwi   0,r5,0
-       beqlr
-       mtctr   r5
-       addi    r6,r6,3
-8:     stbu    r4,1(r6)
-       bdnz    8b
-       blr
-
-/*
- * This version uses dcbz on the complete cache lines in the
- * destination area to reduce memory traffic.  This requires that
- * the destination area is cacheable.
- * We only use this version if the source and dest don't overlap.
- * -- paulus.
- */
-_GLOBAL(cacheable_memcpy)
-       add     r7,r3,r5                /* test if the src & dst overlap */
-       add     r8,r4,r5
-       cmplw   0,r4,r7
-       cmplw   1,r3,r8
-       crand   0,0,4                   /* cr0.lt &= cr1.lt */
-       blt     memcpy                  /* if regions overlap */
-
-       addi    r4,r4,-4
-       addi    r6,r3,-4
-       neg     r0,r3
-       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
-       beq     58f
-
-       cmplw   0,r5,r0                 /* is this more than total to do? */
-       blt     63f                     /* if not much to do */
-       andi.   r8,r0,3                 /* get it word-aligned first */
-       subf    r5,r0,r5
-       mtctr   r8
-       beq+    61f
-70:    lbz     r9,4(r4)                /* do some bytes */
-       stb     r9,4(r6)
-       addi    r4,r4,1
-       addi    r6,r6,1
-       bdnz    70b
-61:    srwi.   r0,r0,2
-       mtctr   r0
-       beq     58f
-72:    lwzu    r9,4(r4)                /* do some words */
-       stwu    r9,4(r6)
-       bdnz    72b
-
-58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
-       li      r11,4
-       mtctr   r0
-       beq     63f
-53:
-#if !defined(CONFIG_8xx)
-       dcbz    r11,r6
-#endif
-       COPY_16_BYTES
-#if L1_CACHE_LINE_SIZE >= 32
-       COPY_16_BYTES
-#if L1_CACHE_LINE_SIZE >= 64
-       COPY_16_BYTES
-       COPY_16_BYTES
-#if L1_CACHE_LINE_SIZE >= 128
-       COPY_16_BYTES
-       COPY_16_BYTES
-       COPY_16_BYTES
-       COPY_16_BYTES
-#endif
-#endif
-#endif
-       bdnz    53b
-
-63:    srwi.   r0,r5,2
-       mtctr   r0
-       beq     64f
-30:    lwzu    r0,4(r4)
-       stwu    r0,4(r6)
-       bdnz    30b
-
-64:    andi.   r0,r5,3
-       mtctr   r0
-       beq+    65f
-40:    lbz     r0,4(r4)
-       stb     r0,4(r6)
-       addi    r4,r4,1
-       addi    r6,r6,1
-       bdnz    40b
-65:    blr
-
-_GLOBAL(memmove)
-       cmplw   0,r3,r4
-       bgt     backwards_memcpy
-       /* fall through */
-
-_GLOBAL(memcpy)
-       srwi.   r7,r5,3
-       addi    r6,r3,-4
-       addi    r4,r4,-4
-       beq     2f                      /* if less than 8 bytes to do */
-       andi.   r0,r6,3                 /* get dest word aligned */
-       mtctr   r7
-       bne     5f
-1:     lwz     r7,4(r4)
-       lwzu    r8,8(r4)
-       stw     r7,4(r6)
-       stwu    r8,8(r6)
-       bdnz    1b
-       andi.   r5,r5,7
-2:     cmplwi  0,r5,4
-       blt     3f
-       lwzu    r0,4(r4)
-       addi    r5,r5,-4
-       stwu    r0,4(r6)
-3:     cmpwi   0,r5,0
-       beqlr
-       mtctr   r5
-       addi    r4,r4,3
-       addi    r6,r6,3
-4:     lbzu    r0,1(r4)
-       stbu    r0,1(r6)
-       bdnz    4b
-       blr
-5:     subfic  r0,r0,4
-       mtctr   r0
-6:     lbz     r7,4(r4)
-       addi    r4,r4,1
-       stb     r7,4(r6)
-       addi    r6,r6,1
-       bdnz    6b
-       subf    r5,r0,r5
-       rlwinm. r7,r5,32-3,3,31
-       beq     2b
-       mtctr   r7
-       b       1b
-
-_GLOBAL(backwards_memcpy)
-       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
-       add     r6,r3,r5
-       add     r4,r4,r5
-       beq     2f
-       andi.   r0,r6,3
-       mtctr   r7
-       bne     5f
-1:     lwz     r7,-4(r4)
-       lwzu    r8,-8(r4)
-       stw     r7,-4(r6)
-       stwu    r8,-8(r6)
-       bdnz    1b
-       andi.   r5,r5,7
-2:     cmplwi  0,r5,4
-       blt     3f
-       lwzu    r0,-4(r4)
-       subi    r5,r5,4
-       stwu    r0,-4(r6)
-3:     cmpwi   0,r5,0
-       beqlr
-       mtctr   r5
-4:     lbzu    r0,-1(r4)
-       stbu    r0,-1(r6)
-       bdnz    4b
-       blr
-5:     mtctr   r0
-6:     lbzu    r7,-1(r4)
-       stbu    r7,-1(r6)
-       bdnz    6b
-       subf    r5,r0,r5
-       rlwinm. r7,r5,32-3,3,31
-       beq     2b
-       mtctr   r7
-       b       1b
-
-_GLOBAL(__copy_tofrom_user)
-       addi    r4,r4,-4
-       addi    r6,r3,-4
-       neg     r0,r3
-       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
-       beq     58f
-
-       cmplw   0,r5,r0                 /* is this more than total to do? */
-       blt     63f                     /* if not much to do */
-       andi.   r8,r0,3                 /* get it word-aligned first */
-       mtctr   r8
-       beq+    61f
-70:    lbz     r9,4(r4)                /* do some bytes */
-71:    stb     r9,4(r6)
-       addi    r4,r4,1
-       addi    r6,r6,1
-       bdnz    70b
-61:    subf    r5,r0,r5
-       srwi.   r0,r0,2
-       mtctr   r0
-       beq     58f
-72:    lwzu    r9,4(r4)                /* do some words */
-73:    stwu    r9,4(r6)
-       bdnz    72b
-
-       .section __ex_table,"a"
-       .align  2
-       .long   70b,100f
-       .long   71b,101f
-       .long   72b,102f
-       .long   73b,103f
-       .text
-
-58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
-       li      r11,4
-       beq     63f
-
-#ifdef CONFIG_8xx
-       /* Don't use prefetch on 8xx */
-       mtctr   r0
-       li      r0,0
-53:    COPY_16_BYTES_WITHEX(0)
-       bdnz    53b
-
-#else /* not CONFIG_8xx */
-       /* Here we decide how far ahead to prefetch the source */
-       li      r3,4
-       cmpwi   r0,1
-       li      r7,0
-       ble     114f
-       li      r7,1
-#if MAX_COPY_PREFETCH > 1
-       /* Heuristically, for large transfers we prefetch
-          MAX_COPY_PREFETCH cachelines ahead.  For small transfers
-          we prefetch 1 cacheline ahead. */
-       cmpwi   r0,MAX_COPY_PREFETCH
-       ble     112f
-       li      r7,MAX_COPY_PREFETCH
-112:   mtctr   r7
-111:   dcbt    r3,r4
-       addi    r3,r3,CACHELINE_BYTES
-       bdnz    111b
-#else
-       dcbt    r3,r4
-       addi    r3,r3,CACHELINE_BYTES
-#endif /* MAX_COPY_PREFETCH > 1 */
-
-114:   subf    r8,r7,r0
-       mr      r0,r7
-       mtctr   r8
-
-53:    dcbt    r3,r4
-54:    dcbz    r11,r6
-       .section __ex_table,"a"
-       .align  2
-       .long   54b,105f
-       .text
-/* the main body of the cacheline loop */
-       COPY_16_BYTES_WITHEX(0)
-#if L1_CACHE_LINE_SIZE >= 32
-       COPY_16_BYTES_WITHEX(1)
-#if L1_CACHE_LINE_SIZE >= 64
-       COPY_16_BYTES_WITHEX(2)
-       COPY_16_BYTES_WITHEX(3)
-#if L1_CACHE_LINE_SIZE >= 128
-       COPY_16_BYTES_WITHEX(4)
-       COPY_16_BYTES_WITHEX(5)
-       COPY_16_BYTES_WITHEX(6)
-       COPY_16_BYTES_WITHEX(7)
-#endif
-#endif
-#endif
-       bdnz    53b
-       cmpwi   r0,0
-       li      r3,4
-       li      r7,0
-       bne     114b
-#endif /* CONFIG_8xx */
-
-63:    srwi.   r0,r5,2
-       mtctr   r0
-       beq     64f
-30:    lwzu    r0,4(r4)
-31:    stwu    r0,4(r6)
-       bdnz    30b
-
-64:    andi.   r0,r5,3
-       mtctr   r0
-       beq+    65f
-40:    lbz     r0,4(r4)
-41:    stb     r0,4(r6)
-       addi    r4,r4,1
-       addi    r6,r6,1
-       bdnz    40b
-65:    li      r3,0
-       blr
-
-/* read fault, initial single-byte copy */
-100:   li      r9,0
-       b       90f
-/* write fault, initial single-byte copy */
-101:   li      r9,1
-90:    subf    r5,r8,r5
-       li      r3,0
-       b       99f
-/* read fault, initial word copy */
-102:   li      r9,0
-       b       91f
-/* write fault, initial word copy */
-103:   li      r9,1
-91:    li      r3,2
-       b       99f
-
-/*
- * this stuff handles faults in the cacheline loop and branches to either
- * 104f (if in read part) or 105f (if in write part), after updating r5
- */
-       COPY_16_BYTES_EXCODE(0)
-#if L1_CACHE_LINE_SIZE >= 32
-       COPY_16_BYTES_EXCODE(1)
-#if L1_CACHE_LINE_SIZE >= 64
-       COPY_16_BYTES_EXCODE(2)
-       COPY_16_BYTES_EXCODE(3)
-#if L1_CACHE_LINE_SIZE >= 128
-       COPY_16_BYTES_EXCODE(4)
-       COPY_16_BYTES_EXCODE(5)
-       COPY_16_BYTES_EXCODE(6)
-       COPY_16_BYTES_EXCODE(7)
-#endif
-#endif
-#endif
-
-/* read fault in cacheline loop */
-104:   li      r9,0
-       b       92f
-/* fault on dcbz (effectively a write fault) */
-/* or write fault in cacheline loop */
-105:   li      r9,1
-92:    li      r3,LG_CACHELINE_BYTES
-       mfctr   r8
-       add     r0,r0,r8
-       b       106f
-/* read fault in final word loop */
-108:   li      r9,0
-       b       93f
-/* write fault in final word loop */
-109:   li      r9,1
-93:    andi.   r5,r5,3
-       li      r3,2
-       b       99f
-/* read fault in final byte loop */
-110:   li      r9,0
-       b       94f
-/* write fault in final byte loop */
-111:   li      r9,1
-94:    li      r5,0
-       li      r3,0
-/*
- * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
- */
-99:    mfctr   r0
-106:   slw     r3,r0,r3
-       add.    r3,r3,r5
-       beq     120f                    /* shouldn't happen */
-       cmpwi   0,r9,0
-       bne     120f
-/* for a read fault, first try to continue the copy one byte at a time */
-       mtctr   r3
-130:   lbz     r0,4(r4)
-131:   stb     r0,4(r6)
-       addi    r4,r4,1
-       addi    r6,r6,1
-       bdnz    130b
-/* then clear out the destination: r3 bytes starting at 4(r6) */
-132:   mfctr   r3
-       srwi.   r0,r3,2
-       li      r9,0
-       mtctr   r0
-       beq     113f
-112:   stwu    r9,4(r6)
-       bdnz    112b
-113:   andi.   r0,r3,3
-       mtctr   r0
-       beq     120f
-114:   stb     r9,4(r6)
-       addi    r6,r6,1
-       bdnz    114b
-120:   blr
-
-       .section __ex_table,"a"
-       .align  2
-       .long   30b,108b
-       .long   31b,109b
-       .long   40b,110b
-       .long   41b,111b
-       .long   130b,132b
-       .long   131b,120b
-       .long   112b,120b
-       .long   114b,120b
-       .text
diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S
new file mode 100644 (file)
index 0000000..420a912
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Memory copy functions for 32-bit PowerPC.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/errno.h>
+#include <asm/ppc_asm.h>
+
+#define COPY_16_BYTES          \
+       lwz     r7,4(r4);       \
+       lwz     r8,8(r4);       \
+       lwz     r9,12(r4);      \
+       lwzu    r10,16(r4);     \
+       stw     r7,4(r6);       \
+       stw     r8,8(r6);       \
+       stw     r9,12(r6);      \
+       stwu    r10,16(r6)
+
+#define COPY_16_BYTES_WITHEX(n)        \
+8 ## n ## 0:                   \
+       lwz     r7,4(r4);       \
+8 ## n ## 1:                   \
+       lwz     r8,8(r4);       \
+8 ## n ## 2:                   \
+       lwz     r9,12(r4);      \
+8 ## n ## 3:                   \
+       lwzu    r10,16(r4);     \
+8 ## n ## 4:                   \
+       stw     r7,4(r6);       \
+8 ## n ## 5:                   \
+       stw     r8,8(r6);       \
+8 ## n ## 6:                   \
+       stw     r9,12(r6);      \
+8 ## n ## 7:                   \
+       stwu    r10,16(r6)
+
+#define COPY_16_BYTES_EXCODE(n)                        \
+9 ## n ## 0:                                   \
+       addi    r5,r5,-(16 * n);                \
+       b       104f;                           \
+9 ## n ## 1:                                   \
+       addi    r5,r5,-(16 * n);                \
+       b       105f;                           \
+.section __ex_table,"a";                       \
+       .align  2;                              \
+       .long   8 ## n ## 0b,9 ## n ## 0b;      \
+       .long   8 ## n ## 1b,9 ## n ## 0b;      \
+       .long   8 ## n ## 2b,9 ## n ## 0b;      \
+       .long   8 ## n ## 3b,9 ## n ## 0b;      \
+       .long   8 ## n ## 4b,9 ## n ## 1b;      \
+       .long   8 ## n ## 5b,9 ## n ## 1b;      \
+       .long   8 ## n ## 6b,9 ## n ## 1b;      \
+       .long   8 ## n ## 7b,9 ## n ## 1b;      \
+       .text
+
+       .text
+       .stabs  "arch/powerpc/lib/",N_SO,0,0,0f
+       .stabs  "copy32.S",N_SO,0,0,0f
+0:
+
+CACHELINE_BYTES = L1_CACHE_LINE_SIZE
+LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE
+CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1)
+
+/*
+ * Use dcbz on the complete cache lines in the destination
+ * to set them to zero.  This requires that the destination
+ * area is cacheable.  -- paulus
+ */
+_GLOBAL(cacheable_memzero)
+       mr      r5,r4
+       li      r4,0
+       addi    r6,r3,-4
+       cmplwi  0,r5,4
+       blt     7f
+       stwu    r4,4(r6)
+       beqlr
+       andi.   r0,r6,3
+       add     r5,r0,r5
+       subf    r6,r0,r6
+       clrlwi  r7,r6,32-LG_CACHELINE_BYTES
+       add     r8,r7,r5
+       srwi    r9,r8,LG_CACHELINE_BYTES
+       addic.  r9,r9,-1        /* total number of complete cachelines */
+       ble     2f
+       xori    r0,r7,CACHELINE_MASK & ~3
+       srwi.   r0,r0,2
+       beq     3f
+       mtctr   r0
+4:     stwu    r4,4(r6)
+       bdnz    4b
+3:     mtctr   r9
+       li      r7,4
+#if !defined(CONFIG_8xx)
+10:    dcbz    r7,r6
+#else
+10:    stw     r4, 4(r6)
+       stw     r4, 8(r6)
+       stw     r4, 12(r6)
+       stw     r4, 16(r6)
+#if CACHE_LINE_SIZE >= 32
+       stw     r4, 20(r6)
+       stw     r4, 24(r6)
+       stw     r4, 28(r6)
+       stw     r4, 32(r6)
+#endif /* CACHE_LINE_SIZE */
+#endif
+       addi    r6,r6,CACHELINE_BYTES
+       bdnz    10b
+       clrlwi  r5,r8,32-LG_CACHELINE_BYTES
+       addi    r5,r5,4
+2:     srwi    r0,r5,2
+       mtctr   r0
+       bdz     6f
+1:     stwu    r4,4(r6)
+       bdnz    1b
+6:     andi.   r5,r5,3
+7:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r6,3
+8:     stbu    r4,1(r6)
+       bdnz    8b
+       blr
+
+_GLOBAL(memset)
+       rlwimi  r4,r4,8,16,23
+       rlwimi  r4,r4,16,0,15
+       addi    r6,r3,-4
+       cmplwi  0,r5,4
+       blt     7f
+       stwu    r4,4(r6)
+       beqlr
+       andi.   r0,r6,3
+       add     r5,r0,r5
+       subf    r6,r0,r6
+       srwi    r0,r5,2
+       mtctr   r0
+       bdz     6f
+1:     stwu    r4,4(r6)
+       bdnz    1b
+6:     andi.   r5,r5,3
+7:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r6,3
+8:     stbu    r4,1(r6)
+       bdnz    8b
+       blr
+
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic.  This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+_GLOBAL(cacheable_memcpy)
+       add     r7,r3,r5                /* test if the src & dst overlap */
+       add     r8,r4,r5
+       cmplw   0,r4,r7
+       cmplw   1,r3,r8
+       crand   0,0,4                   /* cr0.lt &= cr1.lt */
+       blt     memcpy                  /* if regions overlap */
+
+       addi    r4,r4,-4
+       addi    r6,r3,-4
+       neg     r0,r3
+       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
+       beq     58f
+
+       cmplw   0,r5,r0                 /* is this more than total to do? */
+       blt     63f                     /* if not much to do */
+       andi.   r8,r0,3                 /* get it word-aligned first */
+       subf    r5,r0,r5
+       mtctr   r8
+       beq+    61f
+70:    lbz     r9,4(r4)                /* do some bytes */
+       stb     r9,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    70b
+61:    srwi.   r0,r0,2
+       mtctr   r0
+       beq     58f
+72:    lwzu    r9,4(r4)                /* do some words */
+       stwu    r9,4(r6)
+       bdnz    72b
+
+58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
+       li      r11,4
+       mtctr   r0
+       beq     63f
+53:
+#if !defined(CONFIG_8xx)
+       dcbz    r11,r6
+#endif
+       COPY_16_BYTES
+#if L1_CACHE_LINE_SIZE >= 32
+       COPY_16_BYTES
+#if L1_CACHE_LINE_SIZE >= 64
+       COPY_16_BYTES
+       COPY_16_BYTES
+#if L1_CACHE_LINE_SIZE >= 128
+       COPY_16_BYTES
+       COPY_16_BYTES
+       COPY_16_BYTES
+       COPY_16_BYTES
+#endif
+#endif
+#endif
+       bdnz    53b
+
+63:    srwi.   r0,r5,2
+       mtctr   r0
+       beq     64f
+30:    lwzu    r0,4(r4)
+       stwu    r0,4(r6)
+       bdnz    30b
+
+64:    andi.   r0,r5,3
+       mtctr   r0
+       beq+    65f
+40:    lbz     r0,4(r4)
+       stb     r0,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    40b
+65:    blr
+
+_GLOBAL(memmove)
+       cmplw   0,r3,r4
+       bgt     backwards_memcpy
+       /* fall through */
+
+_GLOBAL(memcpy)
+       srwi.   r7,r5,3
+       addi    r6,r3,-4
+       addi    r4,r4,-4
+       beq     2f                      /* if less than 8 bytes to do */
+       andi.   r0,r6,3                 /* get dest word aligned */
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,4(r4)
+       lwzu    r8,8(r4)
+       stw     r7,4(r6)
+       stwu    r8,8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,4(r4)
+       addi    r5,r5,-4
+       stwu    r0,4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r4,r4,3
+       addi    r6,r6,3
+4:     lbzu    r0,1(r4)
+       stbu    r0,1(r6)
+       bdnz    4b
+       blr
+5:     subfic  r0,r0,4
+       mtctr   r0
+6:     lbz     r7,4(r4)
+       addi    r4,r4,1
+       stb     r7,4(r6)
+       addi    r6,r6,1
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+
+_GLOBAL(backwards_memcpy)
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       add     r6,r3,r5
+       add     r4,r4,r5
+       beq     2f
+       andi.   r0,r6,3
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,-4(r4)
+       lwzu    r8,-8(r4)
+       stw     r7,-4(r6)
+       stwu    r8,-8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,-4(r4)
+       subi    r5,r5,4
+       stwu    r0,-4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+4:     lbzu    r0,-1(r4)
+       stbu    r0,-1(r6)
+       bdnz    4b
+       blr
+5:     mtctr   r0
+6:     lbzu    r7,-1(r4)
+       stbu    r7,-1(r6)
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+
+_GLOBAL(__copy_tofrom_user)
+       addi    r4,r4,-4
+       addi    r6,r3,-4
+       neg     r0,r3
+       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
+       beq     58f
+
+       cmplw   0,r5,r0                 /* is this more than total to do? */
+       blt     63f                     /* if not much to do */
+       andi.   r8,r0,3                 /* get it word-aligned first */
+       mtctr   r8
+       beq+    61f
+70:    lbz     r9,4(r4)                /* do some bytes */
+71:    stb     r9,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    70b
+61:    subf    r5,r0,r5
+       srwi.   r0,r0,2
+       mtctr   r0
+       beq     58f
+72:    lwzu    r9,4(r4)                /* do some words */
+73:    stwu    r9,4(r6)
+       bdnz    72b
+
+       .section __ex_table,"a"
+       .align  2
+       .long   70b,100f
+       .long   71b,101f
+       .long   72b,102f
+       .long   73b,103f
+       .text
+
+58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
+       li      r11,4
+       beq     63f
+
+#ifdef CONFIG_8xx
+       /* Don't use prefetch on 8xx */
+       mtctr   r0
+       li      r0,0
+53:    COPY_16_BYTES_WITHEX(0)
+       bdnz    53b
+
+#else /* not CONFIG_8xx */
+       /* Here we decide how far ahead to prefetch the source */
+       li      r3,4
+       cmpwi   r0,1
+       li      r7,0
+       ble     114f
+       li      r7,1
+#if MAX_COPY_PREFETCH > 1
+       /* Heuristically, for large transfers we prefetch
+          MAX_COPY_PREFETCH cachelines ahead.  For small transfers
+          we prefetch 1 cacheline ahead. */
+       cmpwi   r0,MAX_COPY_PREFETCH
+       ble     112f
+       li      r7,MAX_COPY_PREFETCH
+112:   mtctr   r7
+111:   dcbt    r3,r4
+       addi    r3,r3,CACHELINE_BYTES
+       bdnz    111b
+#else
+       dcbt    r3,r4
+       addi    r3,r3,CACHELINE_BYTES
+#endif /* MAX_COPY_PREFETCH > 1 */
+
+114:   subf    r8,r7,r0
+       mr      r0,r7
+       mtctr   r8
+
+53:    dcbt    r3,r4
+54:    dcbz    r11,r6
+       .section __ex_table,"a"
+       .align  2
+       .long   54b,105f
+       .text
+/* the main body of the cacheline loop */
+       COPY_16_BYTES_WITHEX(0)
+#if L1_CACHE_LINE_SIZE >= 32
+       COPY_16_BYTES_WITHEX(1)
+#if L1_CACHE_LINE_SIZE >= 64
+       COPY_16_BYTES_WITHEX(2)
+       COPY_16_BYTES_WITHEX(3)
+#if L1_CACHE_LINE_SIZE >= 128
+       COPY_16_BYTES_WITHEX(4)
+       COPY_16_BYTES_WITHEX(5)
+       COPY_16_BYTES_WITHEX(6)
+       COPY_16_BYTES_WITHEX(7)
+#endif
+#endif
+#endif
+       bdnz    53b
+       cmpwi   r0,0
+       li      r3,4
+       li      r7,0
+       bne     114b
+#endif /* CONFIG_8xx */
+
+63:    srwi.   r0,r5,2
+       mtctr   r0
+       beq     64f
+30:    lwzu    r0,4(r4)
+31:    stwu    r0,4(r6)
+       bdnz    30b
+
+64:    andi.   r0,r5,3
+       mtctr   r0
+       beq+    65f
+40:    lbz     r0,4(r4)
+41:    stb     r0,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    40b
+65:    li      r3,0
+       blr
+
+/* read fault, initial single-byte copy */
+100:   li      r9,0
+       b       90f
+/* write fault, initial single-byte copy */
+101:   li      r9,1
+90:    subf    r5,r8,r5
+       li      r3,0
+       b       99f
+/* read fault, initial word copy */
+102:   li      r9,0
+       b       91f
+/* write fault, initial word copy */
+103:   li      r9,1
+91:    li      r3,2
+       b       99f
+
+/*
+ * this stuff handles faults in the cacheline loop and branches to either
+ * 104f (if in read part) or 105f (if in write part), after updating r5
+ */
+       COPY_16_BYTES_EXCODE(0)
+#if L1_CACHE_LINE_SIZE >= 32
+       COPY_16_BYTES_EXCODE(1)
+#if L1_CACHE_LINE_SIZE >= 64
+       COPY_16_BYTES_EXCODE(2)
+       COPY_16_BYTES_EXCODE(3)
+#if L1_CACHE_LINE_SIZE >= 128
+       COPY_16_BYTES_EXCODE(4)
+       COPY_16_BYTES_EXCODE(5)
+       COPY_16_BYTES_EXCODE(6)
+       COPY_16_BYTES_EXCODE(7)
+#endif
+#endif
+#endif
+
+/* read fault in cacheline loop */
+104:   li      r9,0
+       b       92f
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in cacheline loop */
+105:   li      r9,1
+92:    li      r3,LG_CACHELINE_BYTES
+       mfctr   r8
+       add     r0,r0,r8
+       b       106f
+/* read fault in final word loop */
+108:   li      r9,0
+       b       93f
+/* write fault in final word loop */
+109:   li      r9,1
+93:    andi.   r5,r5,3
+       li      r3,2
+       b       99f
+/* read fault in final byte loop */
+110:   li      r9,0
+       b       94f
+/* write fault in final byte loop */
+111:   li      r9,1
+94:    li      r5,0
+       li      r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
+ */
+99:    mfctr   r0
+106:   slw     r3,r0,r3
+       add.    r3,r3,r5
+       beq     120f                    /* shouldn't happen */
+       cmpwi   0,r9,0
+       bne     120f
+/* for a read fault, first try to continue the copy one byte at a time */
+       mtctr   r3
+130:   lbz     r0,4(r4)
+131:   stb     r0,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    130b
+/* then clear out the destination: r3 bytes starting at 4(r6) */
+132:   mfctr   r3
+       srwi.   r0,r3,2
+       li      r9,0
+       mtctr   r0
+       beq     113f
+112:   stwu    r9,4(r6)
+       bdnz    112b
+113:   andi.   r0,r3,3
+       mtctr   r0
+       beq     120f
+114:   stb     r9,4(r6)
+       addi    r6,r6,1
+       bdnz    114b
+120:   blr
+
+       .section __ex_table,"a"
+       .align  2
+       .long   30b,108b
+       .long   31b,109b
+       .long   40b,110b
+       .long   41b,111b
+       .long   130b,132b
+       .long   131b,120b
+       .long   112b,120b
+       .long   114b,120b
+       .text
diff --git a/arch/powerpc/lib/copypage.S b/arch/powerpc/lib/copypage.S
deleted file mode 100644 (file)
index 733d616..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/ppc64/lib/copypage.S
- *
- * Copyright (C) 2002 Paul Mackerras, IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-
-_GLOBAL(copy_page)
-       std     r31,-8(1)
-       std     r30,-16(1)
-       std     r29,-24(1)
-       std     r28,-32(1)
-       std     r27,-40(1)
-       std     r26,-48(1)
-       std     r25,-56(1)
-       std     r24,-64(1)
-       std     r23,-72(1)
-       std     r22,-80(1)
-       std     r21,-88(1)
-       std     r20,-96(1)
-       li      r5,4096/32 - 1
-       addi    r3,r3,-8
-       li      r12,5
-0:     addi    r5,r5,-24
-       mtctr   r12
-       ld      r22,640(4)
-       ld      r21,512(4)
-       ld      r20,384(4)
-       ld      r11,256(4)
-       ld      r9,128(4)
-       ld      r7,0(4)
-       ld      r25,648(4)
-       ld      r24,520(4)
-       ld      r23,392(4)
-       ld      r10,264(4)
-       ld      r8,136(4)
-       ldu     r6,8(4)
-       cmpwi   r5,24
-1:     std     r22,648(3)
-       std     r21,520(3)
-       std     r20,392(3)
-       std     r11,264(3)
-       std     r9,136(3)
-       std     r7,8(3)
-       ld      r28,648(4)
-       ld      r27,520(4)
-       ld      r26,392(4)
-       ld      r31,264(4)
-       ld      r30,136(4)
-       ld      r29,8(4)
-       std     r25,656(3)
-       std     r24,528(3)
-       std     r23,400(3)
-       std     r10,272(3)
-       std     r8,144(3)
-       std     r6,16(3)
-       ld      r22,656(4)
-       ld      r21,528(4)
-       ld      r20,400(4)
-       ld      r11,272(4)
-       ld      r9,144(4)
-       ld      r7,16(4)
-       std     r28,664(3)
-       std     r27,536(3)
-       std     r26,408(3)
-       std     r31,280(3)
-       std     r30,152(3)
-       stdu    r29,24(3)
-       ld      r25,664(4)
-       ld      r24,536(4)
-       ld      r23,408(4)
-       ld      r10,280(4)
-       ld      r8,152(4)
-       ldu     r6,24(4)
-       bdnz    1b
-       std     r22,648(3)
-       std     r21,520(3)
-       std     r20,392(3)
-       std     r11,264(3)
-       std     r9,136(3)
-       std     r7,8(3)
-       addi    r4,r4,640
-       addi    r3,r3,648
-       bge     0b
-       mtctr   r5
-       ld      r7,0(4)
-       ld      r8,8(4)
-       ldu     r9,16(4)
-3:     ld      r10,8(4)
-       std     r7,8(3)
-       ld      r7,16(4)
-       std     r8,16(3)
-       ld      r8,24(4)
-       std     r9,24(3)
-       ldu     r9,32(4)
-       stdu    r10,32(3)
-       bdnz    3b
-4:     ld      r10,8(4)
-       std     r7,8(3)
-       std     r8,16(3)
-       std     r9,24(3)
-       std     r10,32(3)
-9:     ld      r20,-96(1)
-       ld      r21,-88(1)
-       ld      r22,-80(1)
-       ld      r23,-72(1)
-       ld      r24,-64(1)
-       ld      r25,-56(1)
-       ld      r26,-48(1)
-       ld      r27,-40(1)
-       ld      r28,-32(1)
-       ld      r29,-24(1)
-       ld      r30,-16(1)
-       ld      r31,-8(1)
-       blr
diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S
new file mode 100644 (file)
index 0000000..733d616
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * arch/ppc64/lib/copypage.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+
+_GLOBAL(copy_page)
+       std     r31,-8(1)
+       std     r30,-16(1)
+       std     r29,-24(1)
+       std     r28,-32(1)
+       std     r27,-40(1)
+       std     r26,-48(1)
+       std     r25,-56(1)
+       std     r24,-64(1)
+       std     r23,-72(1)
+       std     r22,-80(1)
+       std     r21,-88(1)
+       std     r20,-96(1)
+       li      r5,4096/32 - 1
+       addi    r3,r3,-8
+       li      r12,5
+0:     addi    r5,r5,-24
+       mtctr   r12
+       ld      r22,640(4)
+       ld      r21,512(4)
+       ld      r20,384(4)
+       ld      r11,256(4)
+       ld      r9,128(4)
+       ld      r7,0(4)
+       ld      r25,648(4)
+       ld      r24,520(4)
+       ld      r23,392(4)
+       ld      r10,264(4)
+       ld      r8,136(4)
+       ldu     r6,8(4)
+       cmpwi   r5,24
+1:     std     r22,648(3)
+       std     r21,520(3)
+       std     r20,392(3)
+       std     r11,264(3)
+       std     r9,136(3)
+       std     r7,8(3)
+       ld      r28,648(4)
+       ld      r27,520(4)
+       ld      r26,392(4)
+       ld      r31,264(4)
+       ld      r30,136(4)
+       ld      r29,8(4)
+       std     r25,656(3)
+       std     r24,528(3)
+       std     r23,400(3)
+       std     r10,272(3)
+       std     r8,144(3)
+       std     r6,16(3)
+       ld      r22,656(4)
+       ld      r21,528(4)
+       ld      r20,400(4)
+       ld      r11,272(4)
+       ld      r9,144(4)
+       ld      r7,16(4)
+       std     r28,664(3)
+       std     r27,536(3)
+       std     r26,408(3)
+       std     r31,280(3)
+       std     r30,152(3)
+       stdu    r29,24(3)
+       ld      r25,664(4)
+       ld      r24,536(4)
+       ld      r23,408(4)
+       ld      r10,280(4)
+       ld      r8,152(4)
+       ldu     r6,24(4)
+       bdnz    1b
+       std     r22,648(3)
+       std     r21,520(3)
+       std     r20,392(3)
+       std     r11,264(3)
+       std     r9,136(3)
+       std     r7,8(3)
+       addi    r4,r4,640
+       addi    r3,r3,648
+       bge     0b
+       mtctr   r5
+       ld      r7,0(4)
+       ld      r8,8(4)
+       ldu     r9,16(4)
+3:     ld      r10,8(4)
+       std     r7,8(3)
+       ld      r7,16(4)
+       std     r8,16(3)
+       ld      r8,24(4)
+       std     r9,24(3)
+       ldu     r9,32(4)
+       stdu    r10,32(3)
+       bdnz    3b
+4:     ld      r10,8(4)
+       std     r7,8(3)
+       std     r8,16(3)
+       std     r9,24(3)
+       std     r10,32(3)
+9:     ld      r20,-96(1)
+       ld      r21,-88(1)
+       ld      r22,-80(1)
+       ld      r23,-72(1)
+       ld      r24,-64(1)
+       ld      r25,-56(1)
+       ld      r26,-48(1)
+       ld      r27,-40(1)
+       ld      r28,-32(1)
+       ld      r29,-24(1)
+       ld      r30,-16(1)
+       ld      r31,-8(1)
+       blr
diff --git a/arch/powerpc/lib/copyuser.S b/arch/powerpc/lib/copyuser.S
deleted file mode 100644 (file)
index a0b3fbb..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * arch/ppc64/lib/copyuser.S
- *
- * Copyright (C) 2002 Paul Mackerras, IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-
-       .align  7
-_GLOBAL(__copy_tofrom_user)
-       /* first check for a whole page copy on a page boundary */
-       cmpldi  cr1,r5,16
-       cmpdi   cr6,r5,4096
-       or      r0,r3,r4
-       neg     r6,r3           /* LS 3 bits = # bytes to 8-byte dest bdry */
-       andi.   r0,r0,4095
-       std     r3,-24(r1)
-       crand   cr0*4+2,cr0*4+2,cr6*4+2
-       std     r4,-16(r1)
-       std     r5,-8(r1)
-       dcbt    0,r4
-       beq     .Lcopy_page
-       andi.   r6,r6,7
-       mtcrf   0x01,r5
-       blt     cr1,.Lshort_copy
-       bne     .Ldst_unaligned
-.Ldst_aligned:
-       andi.   r0,r4,7
-       addi    r3,r3,-16
-       bne     .Lsrc_unaligned
-       srdi    r7,r5,4
-20:    ld      r9,0(r4)
-       addi    r4,r4,-8
-       mtctr   r7
-       andi.   r5,r5,7
-       bf      cr7*4+0,22f
-       addi    r3,r3,8
-       addi    r4,r4,8
-       mr      r8,r9
-       blt     cr1,72f
-21:    ld      r9,8(r4)
-70:    std     r8,8(r3)
-22:    ldu     r8,16(r4)
-71:    stdu    r9,16(r3)
-       bdnz    21b
-72:    std     r8,8(r3)
-       beq+    3f
-       addi    r3,r3,16
-23:    ld      r9,8(r4)
-.Ldo_tail:
-       bf      cr7*4+1,1f
-       rotldi  r9,r9,32
-73:    stw     r9,0(r3)
-       addi    r3,r3,4
-1:     bf      cr7*4+2,2f
-       rotldi  r9,r9,16
-74:    sth     r9,0(r3)
-       addi    r3,r3,2
-2:     bf      cr7*4+3,3f
-       rotldi  r9,r9,8
-75:    stb     r9,0(r3)
-3:     li      r3,0
-       blr
-
-.Lsrc_unaligned:
-       srdi    r6,r5,3
-       addi    r5,r5,-16
-       subf    r4,r0,r4
-       srdi    r7,r5,4
-       sldi    r10,r0,3
-       cmpldi  cr6,r6,3
-       andi.   r5,r5,7
-       mtctr   r7
-       subfic  r11,r10,64
-       add     r5,r5,r0
-       bt      cr7*4+0,28f
-
-24:    ld      r9,0(r4)        /* 3+2n loads, 2+2n stores */
-25:    ld      r0,8(r4)
-       sld     r6,r9,r10
-26:    ldu     r9,16(r4)
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       or      r7,r7,r6
-       blt     cr6,79f
-27:    ld      r0,8(r4)
-       b       2f
-
-28:    ld      r0,0(r4)        /* 4+2n loads, 3+2n stores */
-29:    ldu     r9,8(r4)
-       sld     r8,r0,r10
-       addi    r3,r3,-8
-       blt     cr6,5f
-30:    ld      r0,8(r4)
-       srd     r12,r9,r11
-       sld     r6,r9,r10
-31:    ldu     r9,16(r4)
-       or      r12,r8,r12
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       addi    r3,r3,16
-       beq     cr6,78f
-
-1:     or      r7,r7,r6
-32:    ld      r0,8(r4)
-76:    std     r12,8(r3)
-2:     srd     r12,r9,r11
-       sld     r6,r9,r10
-33:    ldu     r9,16(r4)
-       or      r12,r8,r12
-77:    stdu    r7,16(r3)
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       bdnz    1b
-
-78:    std     r12,8(r3)
-       or      r7,r7,r6
-79:    std     r7,16(r3)
-5:     srd     r12,r9,r11
-       or      r12,r8,r12
-80:    std     r12,24(r3)
-       bne     6f
-       li      r3,0
-       blr
-6:     cmpwi   cr1,r5,8
-       addi    r3,r3,32
-       sld     r9,r9,r10
-       ble     cr1,.Ldo_tail
-34:    ld      r0,8(r4)
-       srd     r7,r0,r11
-       or      r9,r7,r9
-       b       .Ldo_tail
-
-.Ldst_unaligned:
-       mtcrf   0x01,r6         /* put #bytes to 8B bdry into cr7 */
-       subf    r5,r6,r5
-       li      r7,0
-       cmpldi  r1,r5,16
-       bf      cr7*4+3,1f
-35:    lbz     r0,0(r4)
-81:    stb     r0,0(r3)
-       addi    r7,r7,1
-1:     bf      cr7*4+2,2f
-36:    lhzx    r0,r7,r4
-82:    sthx    r0,r7,r3
-       addi    r7,r7,2
-2:     bf      cr7*4+1,3f
-37:    lwzx    r0,r7,r4
-83:    stwx    r0,r7,r3
-3:     mtcrf   0x01,r5
-       add     r4,r6,r4
-       add     r3,r6,r3
-       b       .Ldst_aligned
-
-.Lshort_copy:
-       bf      cr7*4+0,1f
-38:    lwz     r0,0(r4)
-39:    lwz     r9,4(r4)
-       addi    r4,r4,8
-84:    stw     r0,0(r3)
-85:    stw     r9,4(r3)
-       addi    r3,r3,8
-1:     bf      cr7*4+1,2f
-40:    lwz     r0,0(r4)
-       addi    r4,r4,4
-86:    stw     r0,0(r3)
-       addi    r3,r3,4
-2:     bf      cr7*4+2,3f
-41:    lhz     r0,0(r4)
-       addi    r4,r4,2
-87:    sth     r0,0(r3)
-       addi    r3,r3,2
-3:     bf      cr7*4+3,4f
-42:    lbz     r0,0(r4)
-88:    stb     r0,0(r3)
-4:     li      r3,0
-       blr
-
-/*
- * exception handlers follow
- * we have to return the number of bytes not copied
- * for an exception on a load, we set the rest of the destination to 0
- */
-
-136:
-137:
-       add     r3,r3,r7
-       b       1f
-130:
-131:
-       addi    r3,r3,8
-120:
-122:
-124:
-125:
-126:
-127:
-128:
-129:
-133:
-       addi    r3,r3,8
-121:
-132:
-       addi    r3,r3,8
-123:
-134:
-135:
-138:
-139:
-140:
-141:
-142:
-
-/*
- * here we have had a fault on a load and r3 points to the first
- * unmodified byte of the destination
- */
-1:     ld      r6,-24(r1)
-       ld      r4,-16(r1)
-       ld      r5,-8(r1)
-       subf    r6,r6,r3
-       add     r4,r4,r6
-       subf    r5,r6,r5        /* #bytes left to go */
-
-/*
- * first see if we can copy any more bytes before hitting another exception
- */
-       mtctr   r5
-43:    lbz     r0,0(r4)
-       addi    r4,r4,1
-89:    stb     r0,0(r3)
-       addi    r3,r3,1
-       bdnz    43b
-       li      r3,0            /* huh? all copied successfully this time? */
-       blr
-
-/*
- * here we have trapped again, need to clear ctr bytes starting at r3
- */
-143:   mfctr   r5
-       li      r0,0
-       mr      r4,r3
-       mr      r3,r5           /* return the number of bytes not copied */
-1:     andi.   r9,r4,7
-       beq     3f
-90:    stb     r0,0(r4)
-       addic.  r5,r5,-1
-       addi    r4,r4,1
-       bne     1b
-       blr
-3:     cmpldi  cr1,r5,8
-       srdi    r9,r5,3
-       andi.   r5,r5,7
-       blt     cr1,93f
-       mtctr   r9
-91:    std     r0,0(r4)
-       addi    r4,r4,8
-       bdnz    91b
-93:    beqlr
-       mtctr   r5      
-92:    stb     r0,0(r4)
-       addi    r4,r4,1
-       bdnz    92b
-       blr
-
-/*
- * exception handlers for stores: we just need to work
- * out how many bytes weren't copied
- */
-182:
-183:
-       add     r3,r3,r7
-       b       1f
-180:
-       addi    r3,r3,8
-171:
-177:
-       addi    r3,r3,8
-170:
-172:
-176:
-178:
-       addi    r3,r3,4
-185:
-       addi    r3,r3,4
-173:
-174:
-175:
-179:
-181:
-184:
-186:
-187:
-188:
-189:   
-1:
-       ld      r6,-24(r1)
-       ld      r5,-8(r1)
-       add     r6,r6,r5
-       subf    r3,r3,r6        /* #bytes not copied */
-190:
-191:
-192:
-       blr                     /* #bytes not copied in r3 */
-
-       .section __ex_table,"a"
-       .align  3
-       .llong  20b,120b
-       .llong  21b,121b
-       .llong  70b,170b
-       .llong  22b,122b
-       .llong  71b,171b
-       .llong  72b,172b
-       .llong  23b,123b
-       .llong  73b,173b
-       .llong  74b,174b
-       .llong  75b,175b
-       .llong  24b,124b
-       .llong  25b,125b
-       .llong  26b,126b
-       .llong  27b,127b
-       .llong  28b,128b
-       .llong  29b,129b
-       .llong  30b,130b
-       .llong  31b,131b
-       .llong  32b,132b
-       .llong  76b,176b
-       .llong  33b,133b
-       .llong  77b,177b
-       .llong  78b,178b
-       .llong  79b,179b
-       .llong  80b,180b
-       .llong  34b,134b
-       .llong  35b,135b
-       .llong  81b,181b
-       .llong  36b,136b
-       .llong  82b,182b
-       .llong  37b,137b
-       .llong  83b,183b
-       .llong  38b,138b
-       .llong  39b,139b
-       .llong  84b,184b
-       .llong  85b,185b
-       .llong  40b,140b
-       .llong  86b,186b
-       .llong  41b,141b
-       .llong  87b,187b
-       .llong  42b,142b
-       .llong  88b,188b
-       .llong  43b,143b
-       .llong  89b,189b
-       .llong  90b,190b
-       .llong  91b,191b
-       .llong  92b,192b
-       
-       .text
-
-/*
- * Routine to copy a whole page of data, optimized for POWER4.
- * On POWER4 it is more than 50% faster than the simple loop
- * above (following the .Ldst_aligned label) but it runs slightly
- * slower on POWER3.
- */
-.Lcopy_page:
-       std     r31,-32(1)
-       std     r30,-40(1)
-       std     r29,-48(1)
-       std     r28,-56(1)
-       std     r27,-64(1)
-       std     r26,-72(1)
-       std     r25,-80(1)
-       std     r24,-88(1)
-       std     r23,-96(1)
-       std     r22,-104(1)
-       std     r21,-112(1)
-       std     r20,-120(1)
-       li      r5,4096/32 - 1
-       addi    r3,r3,-8
-       li      r0,5
-0:     addi    r5,r5,-24
-       mtctr   r0
-20:    ld      r22,640(4)
-21:    ld      r21,512(4)
-22:    ld      r20,384(4)
-23:    ld      r11,256(4)
-24:    ld      r9,128(4)
-25:    ld      r7,0(4)
-26:    ld      r25,648(4)
-27:    ld      r24,520(4)
-28:    ld      r23,392(4)
-29:    ld      r10,264(4)
-30:    ld      r8,136(4)
-31:    ldu     r6,8(4)
-       cmpwi   r5,24
-1:
-32:    std     r22,648(3)
-33:    std     r21,520(3)
-34:    std     r20,392(3)
-35:    std     r11,264(3)
-36:    std     r9,136(3)
-37:    std     r7,8(3)
-38:    ld      r28,648(4)
-39:    ld      r27,520(4)
-40:    ld      r26,392(4)
-41:    ld      r31,264(4)
-42:    ld      r30,136(4)
-43:    ld      r29,8(4)
-44:    std     r25,656(3)
-45:    std     r24,528(3)
-46:    std     r23,400(3)
-47:    std     r10,272(3)
-48:    std     r8,144(3)
-49:    std     r6,16(3)
-50:    ld      r22,656(4)
-51:    ld      r21,528(4)
-52:    ld      r20,400(4)
-53:    ld      r11,272(4)
-54:    ld      r9,144(4)
-55:    ld      r7,16(4)
-56:    std     r28,664(3)
-57:    std     r27,536(3)
-58:    std     r26,408(3)
-59:    std     r31,280(3)
-60:    std     r30,152(3)
-61:    stdu    r29,24(3)
-62:    ld      r25,664(4)
-63:    ld      r24,536(4)
-64:    ld      r23,408(4)
-65:    ld      r10,280(4)
-66:    ld      r8,152(4)
-67:    ldu     r6,24(4)
-       bdnz    1b
-68:    std     r22,648(3)
-69:    std     r21,520(3)
-70:    std     r20,392(3)
-71:    std     r11,264(3)
-72:    std     r9,136(3)
-73:    std     r7,8(3)
-74:    addi    r4,r4,640
-75:    addi    r3,r3,648
-       bge     0b
-       mtctr   r5
-76:    ld      r7,0(4)
-77:    ld      r8,8(4)
-78:    ldu     r9,16(4)
-3:
-79:    ld      r10,8(4)
-80:    std     r7,8(3)
-81:    ld      r7,16(4)
-82:    std     r8,16(3)
-83:    ld      r8,24(4)
-84:    std     r9,24(3)
-85:    ldu     r9,32(4)
-86:    stdu    r10,32(3)
-       bdnz    3b
-4:
-87:    ld      r10,8(4)
-88:    std     r7,8(3)
-89:    std     r8,16(3)
-90:    std     r9,24(3)
-91:    std     r10,32(3)
-9:     ld      r20,-120(1)
-       ld      r21,-112(1)
-       ld      r22,-104(1)
-       ld      r23,-96(1)
-       ld      r24,-88(1)
-       ld      r25,-80(1)
-       ld      r26,-72(1)
-       ld      r27,-64(1)
-       ld      r28,-56(1)
-       ld      r29,-48(1)
-       ld      r30,-40(1)
-       ld      r31,-32(1)
-       li      r3,0
-       blr
-
-/*
- * on an exception, reset to the beginning and jump back into the
- * standard __copy_tofrom_user
- */
-100:   ld      r20,-120(1)
-       ld      r21,-112(1)
-       ld      r22,-104(1)
-       ld      r23,-96(1)
-       ld      r24,-88(1)
-       ld      r25,-80(1)
-       ld      r26,-72(1)
-       ld      r27,-64(1)
-       ld      r28,-56(1)
-       ld      r29,-48(1)
-       ld      r30,-40(1)
-       ld      r31,-32(1)
-       ld      r3,-24(r1)
-       ld      r4,-16(r1)
-       li      r5,4096
-       b       .Ldst_aligned
-
-       .section __ex_table,"a"
-       .align  3
-       .llong  20b,100b
-       .llong  21b,100b
-       .llong  22b,100b
-       .llong  23b,100b
-       .llong  24b,100b
-       .llong  25b,100b
-       .llong  26b,100b
-       .llong  27b,100b
-       .llong  28b,100b
-       .llong  29b,100b
-       .llong  30b,100b
-       .llong  31b,100b
-       .llong  32b,100b
-       .llong  33b,100b
-       .llong  34b,100b
-       .llong  35b,100b
-       .llong  36b,100b
-       .llong  37b,100b
-       .llong  38b,100b
-       .llong  39b,100b
-       .llong  40b,100b
-       .llong  41b,100b
-       .llong  42b,100b
-       .llong  43b,100b
-       .llong  44b,100b
-       .llong  45b,100b
-       .llong  46b,100b
-       .llong  47b,100b
-       .llong  48b,100b
-       .llong  49b,100b
-       .llong  50b,100b
-       .llong  51b,100b
-       .llong  52b,100b
-       .llong  53b,100b
-       .llong  54b,100b
-       .llong  55b,100b
-       .llong  56b,100b
-       .llong  57b,100b
-       .llong  58b,100b
-       .llong  59b,100b
-       .llong  60b,100b
-       .llong  61b,100b
-       .llong  62b,100b
-       .llong  63b,100b
-       .llong  64b,100b
-       .llong  65b,100b
-       .llong  66b,100b
-       .llong  67b,100b
-       .llong  68b,100b
-       .llong  69b,100b
-       .llong  70b,100b
-       .llong  71b,100b
-       .llong  72b,100b
-       .llong  73b,100b
-       .llong  74b,100b
-       .llong  75b,100b
-       .llong  76b,100b
-       .llong  77b,100b
-       .llong  78b,100b
-       .llong  79b,100b
-       .llong  80b,100b
-       .llong  81b,100b
-       .llong  82b,100b
-       .llong  83b,100b
-       .llong  84b,100b
-       .llong  85b,100b
-       .llong  86b,100b
-       .llong  87b,100b
-       .llong  88b,100b
-       .llong  89b,100b
-       .llong  90b,100b
-       .llong  91b,100b
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
new file mode 100644 (file)
index 0000000..a0b3fbb
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * arch/ppc64/lib/copyuser.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+
+       .align  7
+_GLOBAL(__copy_tofrom_user)
+       /* first check for a whole page copy on a page boundary */
+       cmpldi  cr1,r5,16
+       cmpdi   cr6,r5,4096
+       or      r0,r3,r4
+       neg     r6,r3           /* LS 3 bits = # bytes to 8-byte dest bdry */
+       andi.   r0,r0,4095
+       std     r3,-24(r1)
+       crand   cr0*4+2,cr0*4+2,cr6*4+2
+       std     r4,-16(r1)
+       std     r5,-8(r1)
+       dcbt    0,r4
+       beq     .Lcopy_page
+       andi.   r6,r6,7
+       mtcrf   0x01,r5
+       blt     cr1,.Lshort_copy
+       bne     .Ldst_unaligned
+.Ldst_aligned:
+       andi.   r0,r4,7
+       addi    r3,r3,-16
+       bne     .Lsrc_unaligned
+       srdi    r7,r5,4
+20:    ld      r9,0(r4)
+       addi    r4,r4,-8
+       mtctr   r7
+       andi.   r5,r5,7
+       bf      cr7*4+0,22f
+       addi    r3,r3,8
+       addi    r4,r4,8
+       mr      r8,r9
+       blt     cr1,72f
+21:    ld      r9,8(r4)
+70:    std     r8,8(r3)
+22:    ldu     r8,16(r4)
+71:    stdu    r9,16(r3)
+       bdnz    21b
+72:    std     r8,8(r3)
+       beq+    3f
+       addi    r3,r3,16
+23:    ld      r9,8(r4)
+.Ldo_tail:
+       bf      cr7*4+1,1f
+       rotldi  r9,r9,32
+73:    stw     r9,0(r3)
+       addi    r3,r3,4
+1:     bf      cr7*4+2,2f
+       rotldi  r9,r9,16
+74:    sth     r9,0(r3)
+       addi    r3,r3,2
+2:     bf      cr7*4+3,3f
+       rotldi  r9,r9,8
+75:    stb     r9,0(r3)
+3:     li      r3,0
+       blr
+
+.Lsrc_unaligned:
+       srdi    r6,r5,3
+       addi    r5,r5,-16
+       subf    r4,r0,r4
+       srdi    r7,r5,4
+       sldi    r10,r0,3
+       cmpldi  cr6,r6,3
+       andi.   r5,r5,7
+       mtctr   r7
+       subfic  r11,r10,64
+       add     r5,r5,r0
+       bt      cr7*4+0,28f
+
+24:    ld      r9,0(r4)        /* 3+2n loads, 2+2n stores */
+25:    ld      r0,8(r4)
+       sld     r6,r9,r10
+26:    ldu     r9,16(r4)
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       or      r7,r7,r6
+       blt     cr6,79f
+27:    ld      r0,8(r4)
+       b       2f
+
+28:    ld      r0,0(r4)        /* 4+2n loads, 3+2n stores */
+29:    ldu     r9,8(r4)
+       sld     r8,r0,r10
+       addi    r3,r3,-8
+       blt     cr6,5f
+30:    ld      r0,8(r4)
+       srd     r12,r9,r11
+       sld     r6,r9,r10
+31:    ldu     r9,16(r4)
+       or      r12,r8,r12
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       addi    r3,r3,16
+       beq     cr6,78f
+
+1:     or      r7,r7,r6
+32:    ld      r0,8(r4)
+76:    std     r12,8(r3)
+2:     srd     r12,r9,r11
+       sld     r6,r9,r10
+33:    ldu     r9,16(r4)
+       or      r12,r8,r12
+77:    stdu    r7,16(r3)
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       bdnz    1b
+
+78:    std     r12,8(r3)
+       or      r7,r7,r6
+79:    std     r7,16(r3)
+5:     srd     r12,r9,r11
+       or      r12,r8,r12
+80:    std     r12,24(r3)
+       bne     6f
+       li      r3,0
+       blr
+6:     cmpwi   cr1,r5,8
+       addi    r3,r3,32
+       sld     r9,r9,r10
+       ble     cr1,.Ldo_tail
+34:    ld      r0,8(r4)
+       srd     r7,r0,r11
+       or      r9,r7,r9
+       b       .Ldo_tail
+
+.Ldst_unaligned:
+       mtcrf   0x01,r6         /* put #bytes to 8B bdry into cr7 */
+       subf    r5,r6,r5
+       li      r7,0
+       cmpldi  r1,r5,16
+       bf      cr7*4+3,1f
+35:    lbz     r0,0(r4)
+81:    stb     r0,0(r3)
+       addi    r7,r7,1
+1:     bf      cr7*4+2,2f
+36:    lhzx    r0,r7,r4
+82:    sthx    r0,r7,r3
+       addi    r7,r7,2
+2:     bf      cr7*4+1,3f
+37:    lwzx    r0,r7,r4
+83:    stwx    r0,r7,r3
+3:     mtcrf   0x01,r5
+       add     r4,r6,r4
+       add     r3,r6,r3
+       b       .Ldst_aligned
+
+.Lshort_copy:
+       bf      cr7*4+0,1f
+38:    lwz     r0,0(r4)
+39:    lwz     r9,4(r4)
+       addi    r4,r4,8
+84:    stw     r0,0(r3)
+85:    stw     r9,4(r3)
+       addi    r3,r3,8
+1:     bf      cr7*4+1,2f
+40:    lwz     r0,0(r4)
+       addi    r4,r4,4
+86:    stw     r0,0(r3)
+       addi    r3,r3,4
+2:     bf      cr7*4+2,3f
+41:    lhz     r0,0(r4)
+       addi    r4,r4,2
+87:    sth     r0,0(r3)
+       addi    r3,r3,2
+3:     bf      cr7*4+3,4f
+42:    lbz     r0,0(r4)
+88:    stb     r0,0(r3)
+4:     li      r3,0
+       blr
+
+/*
+ * exception handlers follow
+ * we have to return the number of bytes not copied
+ * for an exception on a load, we set the rest of the destination to 0
+ */
+
+136:
+137:
+       add     r3,r3,r7
+       b       1f
+130:
+131:
+       addi    r3,r3,8
+120:
+122:
+124:
+125:
+126:
+127:
+128:
+129:
+133:
+       addi    r3,r3,8
+121:
+132:
+       addi    r3,r3,8
+123:
+134:
+135:
+138:
+139:
+140:
+141:
+142:
+
+/*
+ * here we have had a fault on a load and r3 points to the first
+ * unmodified byte of the destination
+ */
+1:     ld      r6,-24(r1)
+       ld      r4,-16(r1)
+       ld      r5,-8(r1)
+       subf    r6,r6,r3
+       add     r4,r4,r6
+       subf    r5,r6,r5        /* #bytes left to go */
+
+/*
+ * first see if we can copy any more bytes before hitting another exception
+ */
+       mtctr   r5
+43:    lbz     r0,0(r4)
+       addi    r4,r4,1
+89:    stb     r0,0(r3)
+       addi    r3,r3,1
+       bdnz    43b
+       li      r3,0            /* huh? all copied successfully this time? */
+       blr
+
+/*
+ * here we have trapped again, need to clear ctr bytes starting at r3
+ */
+143:   mfctr   r5
+       li      r0,0
+       mr      r4,r3
+       mr      r3,r5           /* return the number of bytes not copied */
+1:     andi.   r9,r4,7
+       beq     3f
+90:    stb     r0,0(r4)
+       addic.  r5,r5,-1
+       addi    r4,r4,1
+       bne     1b
+       blr
+3:     cmpldi  cr1,r5,8
+       srdi    r9,r5,3
+       andi.   r5,r5,7
+       blt     cr1,93f
+       mtctr   r9
+91:    std     r0,0(r4)
+       addi    r4,r4,8
+       bdnz    91b
+93:    beqlr
+       mtctr   r5      
+92:    stb     r0,0(r4)
+       addi    r4,r4,1
+       bdnz    92b
+       blr
+
+/*
+ * exception handlers for stores: we just need to work
+ * out how many bytes weren't copied
+ */
+182:
+183:
+       add     r3,r3,r7
+       b       1f
+180:
+       addi    r3,r3,8
+171:
+177:
+       addi    r3,r3,8
+170:
+172:
+176:
+178:
+       addi    r3,r3,4
+185:
+       addi    r3,r3,4
+173:
+174:
+175:
+179:
+181:
+184:
+186:
+187:
+188:
+189:   
+1:
+       ld      r6,-24(r1)
+       ld      r5,-8(r1)
+       add     r6,r6,r5
+       subf    r3,r3,r6        /* #bytes not copied */
+190:
+191:
+192:
+       blr                     /* #bytes not copied in r3 */
+
+       .section __ex_table,"a"
+       .align  3
+       .llong  20b,120b
+       .llong  21b,121b
+       .llong  70b,170b
+       .llong  22b,122b
+       .llong  71b,171b
+       .llong  72b,172b
+       .llong  23b,123b
+       .llong  73b,173b
+       .llong  74b,174b
+       .llong  75b,175b
+       .llong  24b,124b
+       .llong  25b,125b
+       .llong  26b,126b
+       .llong  27b,127b
+       .llong  28b,128b
+       .llong  29b,129b
+       .llong  30b,130b
+       .llong  31b,131b
+       .llong  32b,132b
+       .llong  76b,176b
+       .llong  33b,133b
+       .llong  77b,177b
+       .llong  78b,178b
+       .llong  79b,179b
+       .llong  80b,180b
+       .llong  34b,134b
+       .llong  35b,135b
+       .llong  81b,181b
+       .llong  36b,136b
+       .llong  82b,182b
+       .llong  37b,137b
+       .llong  83b,183b
+       .llong  38b,138b
+       .llong  39b,139b
+       .llong  84b,184b
+       .llong  85b,185b
+       .llong  40b,140b
+       .llong  86b,186b
+       .llong  41b,141b
+       .llong  87b,187b
+       .llong  42b,142b
+       .llong  88b,188b
+       .llong  43b,143b
+       .llong  89b,189b
+       .llong  90b,190b
+       .llong  91b,191b
+       .llong  92b,192b
+       
+       .text
+
+/*
+ * Routine to copy a whole page of data, optimized for POWER4.
+ * On POWER4 it is more than 50% faster than the simple loop
+ * above (following the .Ldst_aligned label) but it runs slightly
+ * slower on POWER3.
+ */
+.Lcopy_page:
+       std     r31,-32(1)
+       std     r30,-40(1)
+       std     r29,-48(1)
+       std     r28,-56(1)
+       std     r27,-64(1)
+       std     r26,-72(1)
+       std     r25,-80(1)
+       std     r24,-88(1)
+       std     r23,-96(1)
+       std     r22,-104(1)
+       std     r21,-112(1)
+       std     r20,-120(1)
+       li      r5,4096/32 - 1
+       addi    r3,r3,-8
+       li      r0,5
+0:     addi    r5,r5,-24
+       mtctr   r0
+20:    ld      r22,640(4)
+21:    ld      r21,512(4)
+22:    ld      r20,384(4)
+23:    ld      r11,256(4)
+24:    ld      r9,128(4)
+25:    ld      r7,0(4)
+26:    ld      r25,648(4)
+27:    ld      r24,520(4)
+28:    ld      r23,392(4)
+29:    ld      r10,264(4)
+30:    ld      r8,136(4)
+31:    ldu     r6,8(4)
+       cmpwi   r5,24
+1:
+32:    std     r22,648(3)
+33:    std     r21,520(3)
+34:    std     r20,392(3)
+35:    std     r11,264(3)
+36:    std     r9,136(3)
+37:    std     r7,8(3)
+38:    ld      r28,648(4)
+39:    ld      r27,520(4)
+40:    ld      r26,392(4)
+41:    ld      r31,264(4)
+42:    ld      r30,136(4)
+43:    ld      r29,8(4)
+44:    std     r25,656(3)
+45:    std     r24,528(3)
+46:    std     r23,400(3)
+47:    std     r10,272(3)
+48:    std     r8,144(3)
+49:    std     r6,16(3)
+50:    ld      r22,656(4)
+51:    ld      r21,528(4)
+52:    ld      r20,400(4)
+53:    ld      r11,272(4)
+54:    ld      r9,144(4)
+55:    ld      r7,16(4)
+56:    std     r28,664(3)
+57:    std     r27,536(3)
+58:    std     r26,408(3)
+59:    std     r31,280(3)
+60:    std     r30,152(3)
+61:    stdu    r29,24(3)
+62:    ld      r25,664(4)
+63:    ld      r24,536(4)
+64:    ld      r23,408(4)
+65:    ld      r10,280(4)
+66:    ld      r8,152(4)
+67:    ldu     r6,24(4)
+       bdnz    1b
+68:    std     r22,648(3)
+69:    std     r21,520(3)
+70:    std     r20,392(3)
+71:    std     r11,264(3)
+72:    std     r9,136(3)
+73:    std     r7,8(3)
+74:    addi    r4,r4,640
+75:    addi    r3,r3,648
+       bge     0b
+       mtctr   r5
+76:    ld      r7,0(4)
+77:    ld      r8,8(4)
+78:    ldu     r9,16(4)
+3:
+79:    ld      r10,8(4)
+80:    std     r7,8(3)
+81:    ld      r7,16(4)
+82:    std     r8,16(3)
+83:    ld      r8,24(4)
+84:    std     r9,24(3)
+85:    ldu     r9,32(4)
+86:    stdu    r10,32(3)
+       bdnz    3b
+4:
+87:    ld      r10,8(4)
+88:    std     r7,8(3)
+89:    std     r8,16(3)
+90:    std     r9,24(3)
+91:    std     r10,32(3)
+9:     ld      r20,-120(1)
+       ld      r21,-112(1)
+       ld      r22,-104(1)
+       ld      r23,-96(1)
+       ld      r24,-88(1)
+       ld      r25,-80(1)
+       ld      r26,-72(1)
+       ld      r27,-64(1)
+       ld      r28,-56(1)
+       ld      r29,-48(1)
+       ld      r30,-40(1)
+       ld      r31,-32(1)
+       li      r3,0
+       blr
+
+/*
+ * on an exception, reset to the beginning and jump back into the
+ * standard __copy_tofrom_user
+ */
+100:   ld      r20,-120(1)
+       ld      r21,-112(1)
+       ld      r22,-104(1)
+       ld      r23,-96(1)
+       ld      r24,-88(1)
+       ld      r25,-80(1)
+       ld      r26,-72(1)
+       ld      r27,-64(1)
+       ld      r28,-56(1)
+       ld      r29,-48(1)
+       ld      r30,-40(1)
+       ld      r31,-32(1)
+       ld      r3,-24(r1)
+       ld      r4,-16(r1)
+       li      r5,4096
+       b       .Ldst_aligned
+
+       .section __ex_table,"a"
+       .align  3
+       .llong  20b,100b
+       .llong  21b,100b
+       .llong  22b,100b
+       .llong  23b,100b
+       .llong  24b,100b
+       .llong  25b,100b
+       .llong  26b,100b
+       .llong  27b,100b
+       .llong  28b,100b
+       .llong  29b,100b
+       .llong  30b,100b
+       .llong  31b,100b
+       .llong  32b,100b
+       .llong  33b,100b
+       .llong  34b,100b
+       .llong  35b,100b
+       .llong  36b,100b
+       .llong  37b,100b
+       .llong  38b,100b
+       .llong  39b,100b
+       .llong  40b,100b
+       .llong  41b,100b
+       .llong  42b,100b
+       .llong  43b,100b
+       .llong  44b,100b
+       .llong  45b,100b
+       .llong  46b,100b
+       .llong  47b,100b
+       .llong  48b,100b
+       .llong  49b,100b
+       .llong  50b,100b
+       .llong  51b,100b
+       .llong  52b,100b
+       .llong  53b,100b
+       .llong  54b,100b
+       .llong  55b,100b
+       .llong  56b,100b
+       .llong  57b,100b
+       .llong  58b,100b
+       .llong  59b,100b
+       .llong  60b,100b
+       .llong  61b,100b
+       .llong  62b,100b
+       .llong  63b,100b
+       .llong  64b,100b
+       .llong  65b,100b
+       .llong  66b,100b
+       .llong  67b,100b
+       .llong  68b,100b
+       .llong  69b,100b
+       .llong  70b,100b
+       .llong  71b,100b
+       .llong  72b,100b
+       .llong  73b,100b
+       .llong  74b,100b
+       .llong  75b,100b
+       .llong  76b,100b
+       .llong  77b,100b
+       .llong  78b,100b
+       .llong  79b,100b
+       .llong  80b,100b
+       .llong  81b,100b
+       .llong  82b,100b
+       .llong  83b,100b
+       .llong  84b,100b
+       .llong  85b,100b
+       .llong  86b,100b
+       .llong  87b,100b
+       .llong  88b,100b
+       .llong  89b,100b
+       .llong  90b,100b
+       .llong  91b,100b
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
new file mode 100644 (file)
index 0000000..68df202
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/ppc_asm.h>
+
+_GLOBAL(memset)
+       neg     r0,r3
+       rlwimi  r4,r4,8,16,23
+       andi.   r0,r0,7                 /* # bytes to be 8-byte aligned */
+       rlwimi  r4,r4,16,0,15
+       cmplw   cr1,r5,r0               /* do we get that far? */
+       rldimi  r4,r4,32,0
+       mtcrf   1,r0
+       mr      r6,r3
+       blt     cr1,8f
+       beq+    3f                      /* if already 8-byte aligned */
+       subf    r5,r0,r5
+       bf      31,1f
+       stb     r4,0(r6)
+       addi    r6,r6,1
+1:     bf      30,2f
+       sth     r4,0(r6)
+       addi    r6,r6,2
+2:     bf      29,3f
+       stw     r4,0(r6)
+       addi    r6,r6,4
+3:     srdi.   r0,r5,6
+       clrldi  r5,r5,58
+       mtctr   r0
+       beq     5f
+4:     std     r4,0(r6)
+       std     r4,8(r6)
+       std     r4,16(r6)
+       std     r4,24(r6)
+       std     r4,32(r6)
+       std     r4,40(r6)
+       std     r4,48(r6)
+       std     r4,56(r6)
+       addi    r6,r6,64
+       bdnz    4b
+5:     srwi.   r0,r5,3
+       clrlwi  r5,r5,29
+       mtcrf   1,r0
+       beq     8f
+       bf      29,6f
+       std     r4,0(r6)
+       std     r4,8(r6)
+       std     r4,16(r6)
+       std     r4,24(r6)
+       addi    r6,r6,32
+6:     bf      30,7f
+       std     r4,0(r6)
+       std     r4,8(r6)
+       addi    r6,r6,16
+7:     bf      31,8f
+       std     r4,0(r6)
+       addi    r6,r6,8
+8:     cmpwi   r5,0
+       mtcrf   1,r5
+       beqlr+
+       bf      29,9f
+       stw     r4,0(r6)
+       addi    r6,r6,4
+9:     bf      30,10f
+       sth     r4,0(r6)
+       addi    r6,r6,2
+10:    bflr    31
+       stb     r4,0(r6)
+       blr
+
+_GLOBAL(memmove)
+       cmplw   0,r3,r4
+       bgt     .backwards_memcpy
+       b       .memcpy
+
+_GLOBAL(backwards_memcpy)
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       add     r6,r3,r5
+       add     r4,r4,r5
+       beq     2f
+       andi.   r0,r6,3
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,-4(r4)
+       lwzu    r8,-8(r4)
+       stw     r7,-4(r6)
+       stwu    r8,-8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,-4(r4)
+       subi    r5,r5,4
+       stwu    r0,-4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+4:     lbzu    r0,-1(r4)
+       stbu    r0,-1(r6)
+       bdnz    4b
+       blr
+5:     mtctr   r0
+6:     lbzu    r7,-1(r4)
+       stbu    r7,-1(r6)
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
diff --git a/arch/powerpc/lib/memcpy.S b/arch/powerpc/lib/memcpy.S
deleted file mode 100644 (file)
index 9ccacdf..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * arch/ppc64/lib/memcpy.S
- *
- * Copyright (C) 2002 Paul Mackerras, IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-
-       .align  7
-_GLOBAL(memcpy)
-       mtcrf   0x01,r5
-       cmpldi  cr1,r5,16
-       neg     r6,r3           # LS 3 bits = # bytes to 8-byte dest bdry
-       andi.   r6,r6,7
-       dcbt    0,r4
-       blt     cr1,.Lshort_copy
-       bne     .Ldst_unaligned
-.Ldst_aligned:
-       andi.   r0,r4,7
-       addi    r3,r3,-16
-       bne     .Lsrc_unaligned
-       srdi    r7,r5,4
-       ld      r9,0(r4)
-       addi    r4,r4,-8
-       mtctr   r7
-       andi.   r5,r5,7
-       bf      cr7*4+0,2f
-       addi    r3,r3,8
-       addi    r4,r4,8
-       mr      r8,r9
-       blt     cr1,3f
-1:     ld      r9,8(r4)
-       std     r8,8(r3)
-2:     ldu     r8,16(r4)
-       stdu    r9,16(r3)
-       bdnz    1b
-3:     std     r8,8(r3)
-       beqlr
-       addi    r3,r3,16
-       ld      r9,8(r4)
-.Ldo_tail:
-       bf      cr7*4+1,1f
-       rotldi  r9,r9,32
-       stw     r9,0(r3)
-       addi    r3,r3,4
-1:     bf      cr7*4+2,2f
-       rotldi  r9,r9,16
-       sth     r9,0(r3)
-       addi    r3,r3,2
-2:     bf      cr7*4+3,3f
-       rotldi  r9,r9,8
-       stb     r9,0(r3)
-3:     blr
-
-.Lsrc_unaligned:
-       srdi    r6,r5,3
-       addi    r5,r5,-16
-       subf    r4,r0,r4
-       srdi    r7,r5,4
-       sldi    r10,r0,3
-       cmpdi   cr6,r6,3
-       andi.   r5,r5,7
-       mtctr   r7
-       subfic  r11,r10,64
-       add     r5,r5,r0
-
-       bt      cr7*4+0,0f
-
-       ld      r9,0(r4)        # 3+2n loads, 2+2n stores
-       ld      r0,8(r4)
-       sld     r6,r9,r10
-       ldu     r9,16(r4)
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       or      r7,r7,r6
-       blt     cr6,4f
-       ld      r0,8(r4)
-       # s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12
-       b       2f
-
-0:     ld      r0,0(r4)        # 4+2n loads, 3+2n stores
-       ldu     r9,8(r4)
-       sld     r8,r0,r10
-       addi    r3,r3,-8
-       blt     cr6,5f
-       ld      r0,8(r4)
-       srd     r12,r9,r11
-       sld     r6,r9,r10
-       ldu     r9,16(r4)
-       or      r12,r8,r12
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       addi    r3,r3,16
-       beq     cr6,3f
-
-       # d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9
-1:     or      r7,r7,r6
-       ld      r0,8(r4)
-       std     r12,8(r3)
-2:     srd     r12,r9,r11
-       sld     r6,r9,r10
-       ldu     r9,16(r4)
-       or      r12,r8,r12
-       stdu    r7,16(r3)
-       srd     r7,r0,r11
-       sld     r8,r0,r10
-       bdnz    1b
-
-3:     std     r12,8(r3)
-       or      r7,r7,r6
-4:     std     r7,16(r3)
-5:     srd     r12,r9,r11
-       or      r12,r8,r12
-       std     r12,24(r3)
-       beqlr
-       cmpwi   cr1,r5,8
-       addi    r3,r3,32
-       sld     r9,r9,r10
-       ble     cr1,.Ldo_tail
-       ld      r0,8(r4)
-       srd     r7,r0,r11
-       or      r9,r7,r9
-       b       .Ldo_tail
-
-.Ldst_unaligned:
-       mtcrf   0x01,r6         # put #bytes to 8B bdry into cr7
-       subf    r5,r6,r5
-       li      r7,0
-       cmpldi  r1,r5,16
-       bf      cr7*4+3,1f
-       lbz     r0,0(r4)
-       stb     r0,0(r3)
-       addi    r7,r7,1
-1:     bf      cr7*4+2,2f
-       lhzx    r0,r7,r4
-       sthx    r0,r7,r3
-       addi    r7,r7,2
-2:     bf      cr7*4+1,3f
-       lwzx    r0,r7,r4
-       stwx    r0,r7,r3
-3:     mtcrf   0x01,r5
-       add     r4,r6,r4
-       add     r3,r6,r3
-       b       .Ldst_aligned
-
-.Lshort_copy:
-       bf      cr7*4+0,1f
-       lwz     r0,0(r4)
-       lwz     r9,4(r4)
-       addi    r4,r4,8
-       stw     r0,0(r3)
-       stw     r9,4(r3)
-       addi    r3,r3,8
-1:     bf      cr7*4+1,2f
-       lwz     r0,0(r4)
-       addi    r4,r4,4
-       stw     r0,0(r3)
-       addi    r3,r3,4
-2:     bf      cr7*4+2,3f
-       lhz     r0,0(r4)
-       addi    r4,r4,2
-       sth     r0,0(r3)
-       addi    r3,r3,2
-3:     bf      cr7*4+3,4f
-       lbz     r0,0(r4)
-       stb     r0,0(r3)
-4:     blr
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
new file mode 100644 (file)
index 0000000..9ccacdf
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * arch/ppc64/lib/memcpy.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+
+       .align  7
+_GLOBAL(memcpy)
+       mtcrf   0x01,r5
+       cmpldi  cr1,r5,16
+       neg     r6,r3           # LS 3 bits = # bytes to 8-byte dest bdry
+       andi.   r6,r6,7
+       dcbt    0,r4
+       blt     cr1,.Lshort_copy
+       bne     .Ldst_unaligned
+.Ldst_aligned:
+       andi.   r0,r4,7
+       addi    r3,r3,-16
+       bne     .Lsrc_unaligned
+       srdi    r7,r5,4
+       ld      r9,0(r4)
+       addi    r4,r4,-8
+       mtctr   r7
+       andi.   r5,r5,7
+       bf      cr7*4+0,2f
+       addi    r3,r3,8
+       addi    r4,r4,8
+       mr      r8,r9
+       blt     cr1,3f
+1:     ld      r9,8(r4)
+       std     r8,8(r3)
+2:     ldu     r8,16(r4)
+       stdu    r9,16(r3)
+       bdnz    1b
+3:     std     r8,8(r3)
+       beqlr
+       addi    r3,r3,16
+       ld      r9,8(r4)
+.Ldo_tail:
+       bf      cr7*4+1,1f
+       rotldi  r9,r9,32
+       stw     r9,0(r3)
+       addi    r3,r3,4
+1:     bf      cr7*4+2,2f
+       rotldi  r9,r9,16
+       sth     r9,0(r3)
+       addi    r3,r3,2
+2:     bf      cr7*4+3,3f
+       rotldi  r9,r9,8
+       stb     r9,0(r3)
+3:     blr
+
+.Lsrc_unaligned:
+       srdi    r6,r5,3
+       addi    r5,r5,-16
+       subf    r4,r0,r4
+       srdi    r7,r5,4
+       sldi    r10,r0,3
+       cmpdi   cr6,r6,3
+       andi.   r5,r5,7
+       mtctr   r7
+       subfic  r11,r10,64
+       add     r5,r5,r0
+
+       bt      cr7*4+0,0f
+
+       ld      r9,0(r4)        # 3+2n loads, 2+2n stores
+       ld      r0,8(r4)
+       sld     r6,r9,r10
+       ldu     r9,16(r4)
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       or      r7,r7,r6
+       blt     cr6,4f
+       ld      r0,8(r4)
+       # s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12
+       b       2f
+
+0:     ld      r0,0(r4)        # 4+2n loads, 3+2n stores
+       ldu     r9,8(r4)
+       sld     r8,r0,r10
+       addi    r3,r3,-8
+       blt     cr6,5f
+       ld      r0,8(r4)
+       srd     r12,r9,r11
+       sld     r6,r9,r10
+       ldu     r9,16(r4)
+       or      r12,r8,r12
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       addi    r3,r3,16
+       beq     cr6,3f
+
+       # d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9
+1:     or      r7,r7,r6
+       ld      r0,8(r4)
+       std     r12,8(r3)
+2:     srd     r12,r9,r11
+       sld     r6,r9,r10
+       ldu     r9,16(r4)
+       or      r12,r8,r12
+       stdu    r7,16(r3)
+       srd     r7,r0,r11
+       sld     r8,r0,r10
+       bdnz    1b
+
+3:     std     r12,8(r3)
+       or      r7,r7,r6
+4:     std     r7,16(r3)
+5:     srd     r12,r9,r11
+       or      r12,r8,r12
+       std     r12,24(r3)
+       beqlr
+       cmpwi   cr1,r5,8
+       addi    r3,r3,32
+       sld     r9,r9,r10
+       ble     cr1,.Ldo_tail
+       ld      r0,8(r4)
+       srd     r7,r0,r11
+       or      r9,r7,r9
+       b       .Ldo_tail
+
+.Ldst_unaligned:
+       mtcrf   0x01,r6         # put #bytes to 8B bdry into cr7
+       subf    r5,r6,r5
+       li      r7,0
+       cmpldi  r1,r5,16
+       bf      cr7*4+3,1f
+       lbz     r0,0(r4)
+       stb     r0,0(r3)
+       addi    r7,r7,1
+1:     bf      cr7*4+2,2f
+       lhzx    r0,r7,r4
+       sthx    r0,r7,r3
+       addi    r7,r7,2
+2:     bf      cr7*4+1,3f
+       lwzx    r0,r7,r4
+       stwx    r0,r7,r3
+3:     mtcrf   0x01,r5
+       add     r4,r6,r4
+       add     r3,r6,r3
+       b       .Ldst_aligned
+
+.Lshort_copy:
+       bf      cr7*4+0,1f
+       lwz     r0,0(r4)
+       lwz     r9,4(r4)
+       addi    r4,r4,8
+       stw     r0,0(r3)
+       stw     r9,4(r3)
+       addi    r3,r3,8
+1:     bf      cr7*4+1,2f
+       lwz     r0,0(r4)
+       addi    r4,r4,4
+       stw     r0,0(r3)
+       addi    r3,r3,4
+2:     bf      cr7*4+2,3f
+       lhz     r0,0(r4)
+       addi    r4,r4,2
+       sth     r0,0(r3)
+       addi    r3,r3,2
+3:     bf      cr7*4+3,4f
+       lbz     r0,0(r4)
+       stb     r0,0(r3)
+4:     blr
diff --git a/arch/powerpc/lib/usercopy.c b/arch/powerpc/lib/usercopy.c
deleted file mode 100644 (file)
index 5eea6f3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Functions which are too large to be inlined.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       if (likely(access_ok(VERIFY_READ, from, n)))
-               n = __copy_from_user(to, from, n);
-       else
-               memset(to, 0, n);
-       return n;
-}
-
-unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       if (likely(access_ok(VERIFY_WRITE, to, n)))
-               n = __copy_to_user(to, from, n);
-       return n;
-}
-
-unsigned long copy_in_user(void __user *to, const void __user *from,
-                          unsigned long n)
-{
-       might_sleep();
-       if (likely(access_ok(VERIFY_READ, from, n) &&
-           access_ok(VERIFY_WRITE, to, n)))
-               n =__copy_tofrom_user(to, from, n);
-       return n;
-}
-
-EXPORT_SYMBOL(copy_from_user);
-EXPORT_SYMBOL(copy_to_user);
-EXPORT_SYMBOL(copy_in_user);
-
diff --git a/arch/powerpc/lib/usercopy_64.c b/arch/powerpc/lib/usercopy_64.c
new file mode 100644 (file)
index 0000000..5eea6f3
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Functions which are too large to be inlined.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       if (likely(access_ok(VERIFY_READ, from, n)))
+               n = __copy_from_user(to, from, n);
+       else
+               memset(to, 0, n);
+       return n;
+}
+
+unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (likely(access_ok(VERIFY_WRITE, to, n)))
+               n = __copy_to_user(to, from, n);
+       return n;
+}
+
+unsigned long copy_in_user(void __user *to, const void __user *from,
+                          unsigned long n)
+{
+       might_sleep();
+       if (likely(access_ok(VERIFY_READ, from, n) &&
+           access_ok(VERIFY_WRITE, to, n)))
+               n =__copy_tofrom_user(to, from, n);
+       return n;
+}
+
+EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(copy_to_user);
+EXPORT_SYMBOL(copy_in_user);
+
index afd3be112b79218d376767c11ceafdafa4719439..35497deeb4b21522e0bfcd0e015b8dca2242f3a4 100644 (file)
@@ -3,10 +3,10 @@
 #
 
 obj-y                          := fault.o mem.o lmb.o
-obj-$(CONFIG_PPC32)            += init.o pgtable.o mmu_context.o \
-                                  tlb.o
-obj-$(CONFIG_PPC64)            += init64.o pgtable64.o mmu_context64.o
-obj-$(CONFIG_PPC_STD_MMU_32)   += ppc_mmu.o hash_32.o
+obj-$(CONFIG_PPC32)            += init_32.o pgtable_32.o mmu_context_32.o \
+                                  tlb_32.o
+obj-$(CONFIG_PPC64)            += init_64.o pgtable_64.o mmu_context_64.o
+obj-$(CONFIG_PPC_STD_MMU_32)   += ppc_mmu_32.o hash_low_32.o
 obj-$(CONFIG_40x)              += 4xx_mmu.o
 obj-$(CONFIG_44x)              += 44x_mmu.o
 obj-$(CONFIG_FSL_BOOKE)                += fsl_booke_mmu.o
diff --git a/arch/powerpc/mm/hash_32.S b/arch/powerpc/mm/hash_32.S
deleted file mode 100644 (file)
index 57278a8..0000000
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- *  arch/ppc/kernel/hashtable.S
- *
- *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  This file contains low-level assembler routines for managing
- *  the PowerPC MMU hash table.  (PPC 8xx processors don't use a
- *  hash table, so this file is not used on them.)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/cputable.h>
-#include <asm/ppc_asm.h>
-#include <asm/thread_info.h>
-#include <asm/asm-offsets.h>
-
-#ifdef CONFIG_SMP
-       .comm   mmu_hash_lock,4
-#endif /* CONFIG_SMP */
-
-/*
- * Sync CPUs with hash_page taking & releasing the hash
- * table lock
- */
-#ifdef CONFIG_SMP
-       .text
-_GLOBAL(hash_page_sync)
-       lis     r8,mmu_hash_lock@h
-       ori     r8,r8,mmu_hash_lock@l
-       lis     r0,0x0fff
-       b       10f
-11:    lwz     r6,0(r8)
-       cmpwi   0,r6,0
-       bne     11b
-10:    lwarx   r6,0,r8
-       cmpwi   0,r6,0
-       bne-    11b
-       stwcx.  r0,0,r8
-       bne-    10b
-       isync
-       eieio
-       li      r0,0
-       stw     r0,0(r8)
-       blr     
-#endif
-
-/*
- * Load a PTE into the hash table, if possible.
- * The address is in r4, and r3 contains an access flag:
- * _PAGE_RW (0x400) if a write.
- * r9 contains the SRR1 value, from which we use the MSR_PR bit.
- * SPRG3 contains the physical address of the current task's thread.
- *
- * Returns to the caller if the access is illegal or there is no
- * mapping for the address.  Otherwise it places an appropriate PTE
- * in the hash table and returns from the exception.
- * Uses r0, r3 - r8, ctr, lr.
- */
-       .text
-_GLOBAL(hash_page)
-#ifdef CONFIG_PPC64BRIDGE
-       mfmsr   r0
-       clrldi  r0,r0,1         /* make sure it's in 32-bit mode */
-       MTMSRD(r0)
-       isync
-#endif
-       tophys(r7,0)                    /* gets -KERNELBASE into r7 */
-#ifdef CONFIG_SMP
-       addis   r8,r7,mmu_hash_lock@h
-       ori     r8,r8,mmu_hash_lock@l
-       lis     r0,0x0fff
-       b       10f
-11:    lwz     r6,0(r8)
-       cmpwi   0,r6,0
-       bne     11b
-10:    lwarx   r6,0,r8
-       cmpwi   0,r6,0
-       bne-    11b
-       stwcx.  r0,0,r8
-       bne-    10b
-       isync
-#endif
-       /* Get PTE (linux-style) and check access */
-       lis     r0,KERNELBASE@h         /* check if kernel address */
-       cmplw   0,r4,r0
-       mfspr   r8,SPRN_SPRG3           /* current task's THREAD (phys) */
-       ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
-       lwz     r5,PGDIR(r8)            /* virt page-table root */
-       blt+    112f                    /* assume user more likely */
-       lis     r5,swapper_pg_dir@ha    /* if kernel address, use */
-       addi    r5,r5,swapper_pg_dir@l  /* kernel page table */
-       rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
-112:   add     r5,r5,r7                /* convert to phys addr */
-       rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
-       lwz     r8,0(r5)                /* get pmd entry */
-       rlwinm. r8,r8,0,0,19            /* extract address of pte page */
-#ifdef CONFIG_SMP
-       beq-    hash_page_out           /* return if no mapping */
-#else
-       /* XXX it seems like the 601 will give a machine fault on the
-          rfi if its alignment is wrong (bottom 4 bits of address are
-          8 or 0xc) and we have had a not-taken conditional branch
-          to the address following the rfi. */
-       beqlr-
-#endif
-       rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
-       rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
-       ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
-
-       /*
-        * Update the linux PTE atomically.  We do the lwarx up-front
-        * because almost always, there won't be a permission violation
-        * and there won't already be an HPTE, and thus we will have
-        * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
-        */
-retry:
-       lwarx   r6,0,r8                 /* get linux-style pte */
-       andc.   r5,r3,r6                /* check access & ~permission */
-#ifdef CONFIG_SMP
-       bne-    hash_page_out           /* return if access not permitted */
-#else
-       bnelr-
-#endif
-       or      r5,r0,r6                /* set accessed/dirty bits */
-       stwcx.  r5,0,r8                 /* attempt to update PTE */
-       bne-    retry                   /* retry if someone got there first */
-
-       mfsrin  r3,r4                   /* get segment reg for segment */
-       mfctr   r0
-       stw     r0,_CTR(r11)
-       bl      create_hpte             /* add the hash table entry */
-
-#ifdef CONFIG_SMP
-       eieio
-       addis   r8,r7,mmu_hash_lock@ha
-       li      r0,0
-       stw     r0,mmu_hash_lock@l(r8)
-#endif
-
-       /* Return from the exception */
-       lwz     r5,_CTR(r11)
-       mtctr   r5
-       lwz     r0,GPR0(r11)
-       lwz     r7,GPR7(r11)
-       lwz     r8,GPR8(r11)
-       b       fast_exception_return
-
-#ifdef CONFIG_SMP
-hash_page_out:
-       eieio
-       addis   r8,r7,mmu_hash_lock@ha
-       li      r0,0
-       stw     r0,mmu_hash_lock@l(r8)
-       blr
-#endif /* CONFIG_SMP */
-
-/*
- * Add an entry for a particular page to the hash table.
- *
- * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
- *
- * We assume any necessary modifications to the pte (e.g. setting
- * the accessed bit) have already been done and that there is actually
- * a hash table in use (i.e. we're not on a 603).
- */
-_GLOBAL(add_hash_page)
-       mflr    r0
-       stw     r0,4(r1)
-
-       /* Convert context and va to VSID */
-       mulli   r3,r3,897*16            /* multiply context by context skew */
-       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
-       mulli   r0,r0,0x111             /* multiply by ESID skew */
-       add     r3,r3,r0                /* note create_hpte trims to 24 bits */
-
-#ifdef CONFIG_SMP
-       rlwinm  r8,r1,0,0,18            /* use cpu number to make tag */
-       lwz     r8,TI_CPU(r8)           /* to go in mmu_hash_lock */
-       oris    r8,r8,12
-#endif /* CONFIG_SMP */
-
-       /*
-        * We disable interrupts here, even on UP, because we don't
-        * want to race with hash_page, and because we want the
-        * _PAGE_HASHPTE bit to be a reliable indication of whether
-        * the HPTE exists (or at least whether one did once).
-        * We also turn off the MMU for data accesses so that we
-        * we can't take a hash table miss (assuming the code is
-        * covered by a BAT).  -- paulus
-        */
-       mfmsr   r10
-       SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-
-       tophys(r7,0)
-
-#ifdef CONFIG_SMP
-       addis   r9,r7,mmu_hash_lock@ha
-       addi    r9,r9,mmu_hash_lock@l
-10:    lwarx   r0,0,r9                 /* take the mmu_hash_lock */
-       cmpi    0,r0,0
-       bne-    11f
-       stwcx.  r8,0,r9
-       beq+    12f
-11:    lwz     r0,0(r9)
-       cmpi    0,r0,0
-       beq     10b
-       b       11b
-12:    isync
-#endif
-
-       /*
-        * Fetch the linux pte and test and set _PAGE_HASHPTE atomically.
-        * If _PAGE_HASHPTE was already set, we don't replace the existing
-        * HPTE, so we just unlock and return.
-        */
-       mr      r8,r5
-       rlwimi  r8,r4,22,20,29
-1:     lwarx   r6,0,r8
-       andi.   r0,r6,_PAGE_HASHPTE
-       bne     9f                      /* if HASHPTE already set, done */
-       ori     r5,r6,_PAGE_HASHPTE
-       stwcx.  r5,0,r8
-       bne-    1b
-
-       bl      create_hpte
-
-9:
-#ifdef CONFIG_SMP
-       eieio
-       li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
-#endif
-
-       /* reenable interrupts and DR */
-       mtmsr   r10
-       SYNC_601
-       isync
-
-       lwz     r0,4(r1)
-       mtlr    r0
-       blr
-
-/*
- * This routine adds a hardware PTE to the hash table.
- * It is designed to be called with the MMU either on or off.
- * r3 contains the VSID, r4 contains the virtual address,
- * r5 contains the linux PTE, r6 contains the old value of the
- * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
- * offset to be added to addresses (0 if the MMU is on,
- * -KERNELBASE if it is off).
- * On SMP, the caller should have the mmu_hash_lock held.
- * We assume that the caller has (or will) set the _PAGE_HASHPTE
- * bit in the linux PTE in memory.  The value passed in r6 should
- * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
- * this routine will skip the search for an existing HPTE.
- * This procedure modifies r0, r3 - r6, r8, cr0.
- *  -- paulus.
- *
- * For speed, 4 of the instructions get patched once the size and
- * physical address of the hash table are known.  These definitions
- * of Hash_base and Hash_bits below are just an example.
- */
-Hash_base = 0xc0180000
-Hash_bits = 12                         /* e.g. 256kB hash table */
-Hash_msk = (((1 << Hash_bits) - 1) * 64)
-
-#ifndef CONFIG_PPC64BRIDGE
-/* defines for the PTE format for 32-bit PPCs */
-#define PTE_SIZE       8
-#define PTEG_SIZE      64
-#define LG_PTEG_SIZE   6
-#define LDPTEu         lwzu
-#define STPTE          stw
-#define CMPPTE         cmpw
-#define PTE_H          0x40
-#define PTE_V          0x80000000
-#define TST_V(r)       rlwinm. r,r,0,0,0
-#define SET_V(r)       oris r,r,PTE_V@h
-#define CLR_V(r,t)     rlwinm r,r,0,1,31
-
-#else
-/* defines for the PTE format for 64-bit PPCs */
-#define PTE_SIZE       16
-#define PTEG_SIZE      128
-#define LG_PTEG_SIZE   7
-#define LDPTEu         ldu
-#define STPTE          std
-#define CMPPTE         cmpd
-#define PTE_H          2
-#define PTE_V          1
-#define TST_V(r)       andi. r,r,PTE_V
-#define SET_V(r)       ori r,r,PTE_V
-#define CLR_V(r,t)     li t,PTE_V; andc r,r,t
-#endif /* CONFIG_PPC64BRIDGE */
-
-#define HASH_LEFT      31-(LG_PTEG_SIZE+Hash_bits-1)
-#define HASH_RIGHT     31-LG_PTEG_SIZE
-
-_GLOBAL(create_hpte)
-       /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
-       rlwinm  r8,r5,32-10,31,31       /* _PAGE_RW -> PP lsb */
-       rlwinm  r0,r5,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
-       and     r8,r8,r0                /* writable if _RW & _DIRTY */
-       rlwimi  r5,r5,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r5,r5,32-2,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r8,r8,0xe14             /* clear out reserved bits and M */
-       andc    r8,r5,r8                /* PP = user? (rw&dirty? 2: 3): 0 */
-BEGIN_FTR_SECTION
-       ori     r8,r8,_PAGE_COHERENT    /* set M (coherence required) */
-END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
-
-       /* Construct the high word of the PPC-style PTE (r5) */
-#ifndef CONFIG_PPC64BRIDGE
-       rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
-       rlwimi  r5,r4,10,26,31          /* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
-       clrlwi  r3,r3,8                 /* reduce vsid to 24 bits */
-       sldi    r5,r3,12                /* shift vsid into position */
-       rlwimi  r5,r4,16,20,24          /* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
-       SET_V(r5)                       /* set V (valid) bit */
-
-       /* Get the address of the primary PTE group in the hash table (r3) */
-_GLOBAL(hash_page_patch_A)
-       addis   r0,r7,Hash_base@h       /* base address of hash table */
-       rlwimi  r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
-       rlwinm  r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
-       xor     r3,r3,r0                /* make primary hash */
-       li      r0,8                    /* PTEs/group */
-
-       /*
-        * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search
-        * if it is clear, meaning that the HPTE isn't there already...
-        */
-       andi.   r6,r6,_PAGE_HASHPTE
-       beq+    10f                     /* no PTE: go look for an empty slot */
-       tlbie   r4
-
-       addis   r4,r7,htab_hash_searches@ha
-       lwz     r6,htab_hash_searches@l(r4)
-       addi    r6,r6,1                 /* count how many searches we do */
-       stw     r6,htab_hash_searches@l(r4)
-
-       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
-       mtctr   r0
-       addi    r4,r3,-PTE_SIZE
-1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
-       CMPPTE  0,r6,r5
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    found_slot
-
-       /* Search the secondary PTEG for a matching PTE */
-       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
-_GLOBAL(hash_page_patch_B)
-       xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
-       xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-PTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r6,PTE_SIZE(r4)
-       CMPPTE  0,r6,r5
-       bdnzf   2,2b
-       beq+    found_slot
-       xori    r5,r5,PTE_H             /* clear H bit again */
-
-       /* Search the primary PTEG for an empty slot */
-10:    mtctr   r0
-       addi    r4,r3,-PTE_SIZE         /* search primary PTEG */
-1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
-       TST_V(r6)                       /* test valid bit */
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    found_empty
-
-       /* update counter of times that the primary PTEG is full */
-       addis   r4,r7,primary_pteg_full@ha
-       lwz     r6,primary_pteg_full@l(r4)
-       addi    r6,r6,1
-       stw     r6,primary_pteg_full@l(r4)
-
-       /* Search the secondary PTEG for an empty slot */
-       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
-_GLOBAL(hash_page_patch_C)
-       xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
-       xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-PTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r6,PTE_SIZE(r4)
-       TST_V(r6)
-       bdnzf   2,2b
-       beq+    found_empty
-       xori    r5,r5,PTE_H             /* clear H bit again */
-
-       /*
-        * Choose an arbitrary slot in the primary PTEG to overwrite.
-        * Since both the primary and secondary PTEGs are full, and we
-        * have no information that the PTEs in the primary PTEG are
-        * more important or useful than those in the secondary PTEG,
-        * and we know there is a definite (although small) speed
-        * advantage to putting the PTE in the primary PTEG, we always
-        * put the PTE in the primary PTEG.
-        */
-       addis   r4,r7,next_slot@ha
-       lwz     r6,next_slot@l(r4)
-       addi    r6,r6,PTE_SIZE
-       andi.   r6,r6,7*PTE_SIZE
-       stw     r6,next_slot@l(r4)
-       add     r4,r3,r6
-
-#ifndef CONFIG_SMP
-       /* Store PTE in PTEG */
-found_empty:
-       STPTE   r5,0(r4)
-found_slot:
-       STPTE   r8,PTE_SIZE/2(r4)
-
-#else /* CONFIG_SMP */
-/*
- * Between the tlbie above and updating the hash table entry below,
- * another CPU could read the hash table entry and put it in its TLB.
- * There are 3 cases:
- * 1. using an empty slot
- * 2. updating an earlier entry to change permissions (i.e. enable write)
- * 3. taking over the PTE for an unrelated address
- *
- * In each case it doesn't really matter if the other CPUs have the old
- * PTE in their TLB.  So we don't need to bother with another tlbie here,
- * which is convenient as we've overwritten the register that had the
- * address. :-)  The tlbie above is mainly to make sure that this CPU comes
- * and gets the new PTE from the hash table.
- *
- * We do however have to make sure that the PTE is never in an invalid
- * state with the V bit set.
- */
-found_empty:
-found_slot:
-       CLR_V(r5,r0)            /* clear V (valid) bit in PTE */
-       STPTE   r5,0(r4)
-       sync
-       TLBSYNC
-       STPTE   r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
-       sync
-       SET_V(r5)
-       STPTE   r5,0(r4)        /* finally set V bit in PTE */
-#endif /* CONFIG_SMP */
-
-       sync            /* make sure pte updates get to memory */
-       blr
-
-       .comm   next_slot,4
-       .comm   primary_pteg_full,4
-       .comm   htab_hash_searches,4
-
-/*
- * Flush the entry for a particular page from the hash table.
- *
- * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
- *                 int count)
- *
- * We assume that there is a hash table in use (Hash != 0).
- */
-_GLOBAL(flush_hash_pages)
-       tophys(r7,0)
-
-       /*
-        * We disable interrupts here, even on UP, because we want
-        * the _PAGE_HASHPTE bit to be a reliable indication of
-        * whether the HPTE exists (or at least whether one did once).
-        * We also turn off the MMU for data accesses so that we
-        * we can't take a hash table miss (assuming the code is
-        * covered by a BAT).  -- paulus
-        */
-       mfmsr   r10
-       SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
-       mtmsr   r0
-       SYNC_601
-       isync
-
-       /* First find a PTE in the range that has _PAGE_HASHPTE set */
-       rlwimi  r5,r4,22,20,29
-1:     lwz     r0,0(r5)
-       cmpwi   cr1,r6,1
-       andi.   r0,r0,_PAGE_HASHPTE
-       bne     2f
-       ble     cr1,19f
-       addi    r4,r4,0x1000
-       addi    r5,r5,4
-       addi    r6,r6,-1
-       b       1b
-
-       /* Convert context and va to VSID */
-2:     mulli   r3,r3,897*16            /* multiply context by context skew */
-       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
-       mulli   r0,r0,0x111             /* multiply by ESID skew */
-       add     r3,r3,r0                /* note code below trims to 24 bits */
-
-       /* Construct the high word of the PPC-style PTE (r11) */
-#ifndef CONFIG_PPC64BRIDGE
-       rlwinm  r11,r3,7,1,24           /* put VSID in 0x7fffff80 bits */
-       rlwimi  r11,r4,10,26,31         /* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
-       clrlwi  r3,r3,8                 /* reduce vsid to 24 bits */
-       sldi    r11,r3,12               /* shift vsid into position */
-       rlwimi  r11,r4,16,20,24         /* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
-       SET_V(r11)                      /* set V (valid) bit */
-
-#ifdef CONFIG_SMP
-       addis   r9,r7,mmu_hash_lock@ha
-       addi    r9,r9,mmu_hash_lock@l
-       rlwinm  r8,r1,0,0,18
-       add     r8,r8,r7
-       lwz     r8,TI_CPU(r8)
-       oris    r8,r8,9
-10:    lwarx   r0,0,r9
-       cmpi    0,r0,0
-       bne-    11f
-       stwcx.  r8,0,r9
-       beq+    12f
-11:    lwz     r0,0(r9)
-       cmpi    0,r0,0
-       beq     10b
-       b       11b
-12:    isync
-#endif
-
-       /*
-        * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
-        * already clear, we're done (for this pte).  If not,
-        * clear it (atomically) and proceed.  -- paulus.
-        */
-33:    lwarx   r8,0,r5                 /* fetch the pte */
-       andi.   r0,r8,_PAGE_HASHPTE
-       beq     8f                      /* done if HASHPTE is already clear */
-       rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
-       stwcx.  r8,0,r5                 /* update the pte */
-       bne-    33b
-
-       /* Get the address of the primary PTE group in the hash table (r3) */
-_GLOBAL(flush_hash_patch_A)
-       addis   r8,r7,Hash_base@h       /* base address of hash table */
-       rlwimi  r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
-       rlwinm  r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
-       xor     r8,r0,r8                /* make primary hash */
-
-       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
-       li      r0,8                    /* PTEs/group */
-       mtctr   r0
-       addi    r12,r8,-PTE_SIZE
-1:     LDPTEu  r0,PTE_SIZE(r12)        /* get next PTE */
-       CMPPTE  0,r0,r11
-       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
-       beq+    3f
-
-       /* Search the secondary PTEG for a matching PTE */
-       ori     r11,r11,PTE_H           /* set H (secondary hash) bit */
-       li      r0,8                    /* PTEs/group */
-_GLOBAL(flush_hash_patch_B)
-       xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
-       xori    r12,r12,(-PTEG_SIZE & 0xffff)
-       addi    r12,r12,-PTE_SIZE
-       mtctr   r0
-2:     LDPTEu  r0,PTE_SIZE(r12)
-       CMPPTE  0,r0,r11
-       bdnzf   2,2b
-       xori    r11,r11,PTE_H           /* clear H again */
-       bne-    4f                      /* should rarely fail to find it */
-
-3:     li      r0,0
-       STPTE   r0,0(r12)               /* invalidate entry */
-4:     sync
-       tlbie   r4                      /* in hw tlb too */
-       sync
-
-8:     ble     cr1,9f                  /* if all ptes checked */
-81:    addi    r6,r6,-1
-       addi    r5,r5,4                 /* advance to next pte */
-       addi    r4,r4,0x1000
-       lwz     r0,0(r5)                /* check next pte */
-       cmpwi   cr1,r6,1
-       andi.   r0,r0,_PAGE_HASHPTE
-       bne     33b
-       bgt     cr1,81b
-
-9:
-#ifdef CONFIG_SMP
-       TLBSYNC
-       li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
-#endif
-
-19:    mtmsr   r10
-       SYNC_601
-       isync
-       blr
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
new file mode 100644 (file)
index 0000000..57278a8
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ *  arch/ppc/kernel/hashtable.S
+ *
+ *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  This file contains low-level assembler routines for managing
+ *  the PowerPC MMU hash table.  (PPC 8xx processors don't use a
+ *  hash table, so this file is not used on them.)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+#ifdef CONFIG_SMP
+       .comm   mmu_hash_lock,4
+#endif /* CONFIG_SMP */
+
+/*
+ * Sync CPUs with hash_page taking & releasing the hash
+ * table lock
+ */
+#ifdef CONFIG_SMP
+       .text
+_GLOBAL(hash_page_sync)
+       lis     r8,mmu_hash_lock@h
+       ori     r8,r8,mmu_hash_lock@l
+       lis     r0,0x0fff
+       b       10f
+11:    lwz     r6,0(r8)
+       cmpwi   0,r6,0
+       bne     11b
+10:    lwarx   r6,0,r8
+       cmpwi   0,r6,0
+       bne-    11b
+       stwcx.  r0,0,r8
+       bne-    10b
+       isync
+       eieio
+       li      r0,0
+       stw     r0,0(r8)
+       blr     
+#endif
+
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r4, and r3 contains an access flag:
+ * _PAGE_RW (0x400) if a write.
+ * r9 contains the SRR1 value, from which we use the MSR_PR bit.
+ * SPRG3 contains the physical address of the current task's thread.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address.  Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r3 - r8, ctr, lr.
+ */
+       .text
+_GLOBAL(hash_page)
+#ifdef CONFIG_PPC64BRIDGE
+       mfmsr   r0
+       clrldi  r0,r0,1         /* make sure it's in 32-bit mode */
+       MTMSRD(r0)
+       isync
+#endif
+       tophys(r7,0)                    /* gets -KERNELBASE into r7 */
+#ifdef CONFIG_SMP
+       addis   r8,r7,mmu_hash_lock@h
+       ori     r8,r8,mmu_hash_lock@l
+       lis     r0,0x0fff
+       b       10f
+11:    lwz     r6,0(r8)
+       cmpwi   0,r6,0
+       bne     11b
+10:    lwarx   r6,0,r8
+       cmpwi   0,r6,0
+       bne-    11b
+       stwcx.  r0,0,r8
+       bne-    10b
+       isync
+#endif
+       /* Get PTE (linux-style) and check access */
+       lis     r0,KERNELBASE@h         /* check if kernel address */
+       cmplw   0,r4,r0
+       mfspr   r8,SPRN_SPRG3           /* current task's THREAD (phys) */
+       ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
+       lwz     r5,PGDIR(r8)            /* virt page-table root */
+       blt+    112f                    /* assume user more likely */
+       lis     r5,swapper_pg_dir@ha    /* if kernel address, use */
+       addi    r5,r5,swapper_pg_dir@l  /* kernel page table */
+       rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
+112:   add     r5,r5,r7                /* convert to phys addr */
+       rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
+       lwz     r8,0(r5)                /* get pmd entry */
+       rlwinm. r8,r8,0,0,19            /* extract address of pte page */
+#ifdef CONFIG_SMP
+       beq-    hash_page_out           /* return if no mapping */
+#else
+       /* XXX it seems like the 601 will give a machine fault on the
+          rfi if its alignment is wrong (bottom 4 bits of address are
+          8 or 0xc) and we have had a not-taken conditional branch
+          to the address following the rfi. */
+       beqlr-
+#endif
+       rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
+       rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
+       ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
+
+       /*
+        * Update the linux PTE atomically.  We do the lwarx up-front
+        * because almost always, there won't be a permission violation
+        * and there won't already be an HPTE, and thus we will have
+        * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
+        */
+retry:
+       lwarx   r6,0,r8                 /* get linux-style pte */
+       andc.   r5,r3,r6                /* check access & ~permission */
+#ifdef CONFIG_SMP
+       bne-    hash_page_out           /* return if access not permitted */
+#else
+       bnelr-
+#endif
+       or      r5,r0,r6                /* set accessed/dirty bits */
+       stwcx.  r5,0,r8                 /* attempt to update PTE */
+       bne-    retry                   /* retry if someone got there first */
+
+       mfsrin  r3,r4                   /* get segment reg for segment */
+       mfctr   r0
+       stw     r0,_CTR(r11)
+       bl      create_hpte             /* add the hash table entry */
+
+#ifdef CONFIG_SMP
+       eieio
+       addis   r8,r7,mmu_hash_lock@ha
+       li      r0,0
+       stw     r0,mmu_hash_lock@l(r8)
+#endif
+
+       /* Return from the exception */
+       lwz     r5,_CTR(r11)
+       mtctr   r5
+       lwz     r0,GPR0(r11)
+       lwz     r7,GPR7(r11)
+       lwz     r8,GPR8(r11)
+       b       fast_exception_return
+
+#ifdef CONFIG_SMP
+hash_page_out:
+       eieio
+       addis   r8,r7,mmu_hash_lock@ha
+       li      r0,0
+       stw     r0,mmu_hash_lock@l(r8)
+       blr
+#endif /* CONFIG_SMP */
+
+/*
+ * Add an entry for a particular page to the hash table.
+ *
+ * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
+ *
+ * We assume any necessary modifications to the pte (e.g. setting
+ * the accessed bit) have already been done and that there is actually
+ * a hash table in use (i.e. we're not on a 603).
+ */
+_GLOBAL(add_hash_page)
+       mflr    r0
+       stw     r0,4(r1)
+
+       /* Convert context and va to VSID */
+       mulli   r3,r3,897*16            /* multiply context by context skew */
+       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
+       mulli   r0,r0,0x111             /* multiply by ESID skew */
+       add     r3,r3,r0                /* note create_hpte trims to 24 bits */
+
+#ifdef CONFIG_SMP
+       rlwinm  r8,r1,0,0,18            /* use cpu number to make tag */
+       lwz     r8,TI_CPU(r8)           /* to go in mmu_hash_lock */
+       oris    r8,r8,12
+#endif /* CONFIG_SMP */
+
+       /*
+        * We disable interrupts here, even on UP, because we don't
+        * want to race with hash_page, and because we want the
+        * _PAGE_HASHPTE bit to be a reliable indication of whether
+        * the HPTE exists (or at least whether one did once).
+        * We also turn off the MMU for data accesses so that we
+        * we can't take a hash table miss (assuming the code is
+        * covered by a BAT).  -- paulus
+        */
+       mfmsr   r10
+       SYNC
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+
+       tophys(r7,0)
+
+#ifdef CONFIG_SMP
+       addis   r9,r7,mmu_hash_lock@ha
+       addi    r9,r9,mmu_hash_lock@l
+10:    lwarx   r0,0,r9                 /* take the mmu_hash_lock */
+       cmpi    0,r0,0
+       bne-    11f
+       stwcx.  r8,0,r9
+       beq+    12f
+11:    lwz     r0,0(r9)
+       cmpi    0,r0,0
+       beq     10b
+       b       11b
+12:    isync
+#endif
+
+       /*
+        * Fetch the linux pte and test and set _PAGE_HASHPTE atomically.
+        * If _PAGE_HASHPTE was already set, we don't replace the existing
+        * HPTE, so we just unlock and return.
+        */
+       mr      r8,r5
+       rlwimi  r8,r4,22,20,29
+1:     lwarx   r6,0,r8
+       andi.   r0,r6,_PAGE_HASHPTE
+       bne     9f                      /* if HASHPTE already set, done */
+       ori     r5,r6,_PAGE_HASHPTE
+       stwcx.  r5,0,r8
+       bne-    1b
+
+       bl      create_hpte
+
+9:
+#ifdef CONFIG_SMP
+       eieio
+       li      r0,0
+       stw     r0,0(r9)                /* clear mmu_hash_lock */
+#endif
+
+       /* reenable interrupts and DR */
+       mtmsr   r10
+       SYNC_601
+       isync
+
+       lwz     r0,4(r1)
+       mtlr    r0
+       blr
+
+/*
+ * This routine adds a hardware PTE to the hash table.
+ * It is designed to be called with the MMU either on or off.
+ * r3 contains the VSID, r4 contains the virtual address,
+ * r5 contains the linux PTE, r6 contains the old value of the
+ * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
+ * offset to be added to addresses (0 if the MMU is on,
+ * -KERNELBASE if it is off).
+ * On SMP, the caller should have the mmu_hash_lock held.
+ * We assume that the caller has (or will) set the _PAGE_HASHPTE
+ * bit in the linux PTE in memory.  The value passed in r6 should
+ * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
+ * this routine will skip the search for an existing HPTE.
+ * This procedure modifies r0, r3 - r6, r8, cr0.
+ *  -- paulus.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known.  These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0xc0180000
+Hash_bits = 12                         /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+#ifndef CONFIG_PPC64BRIDGE
+/* defines for the PTE format for 32-bit PPCs */
+#define PTE_SIZE       8
+#define PTEG_SIZE      64
+#define LG_PTEG_SIZE   6
+#define LDPTEu         lwzu
+#define STPTE          stw
+#define CMPPTE         cmpw
+#define PTE_H          0x40
+#define PTE_V          0x80000000
+#define TST_V(r)       rlwinm. r,r,0,0,0
+#define SET_V(r)       oris r,r,PTE_V@h
+#define CLR_V(r,t)     rlwinm r,r,0,1,31
+
+#else
+/* defines for the PTE format for 64-bit PPCs */
+#define PTE_SIZE       16
+#define PTEG_SIZE      128
+#define LG_PTEG_SIZE   7
+#define LDPTEu         ldu
+#define STPTE          std
+#define CMPPTE         cmpd
+#define PTE_H          2
+#define PTE_V          1
+#define TST_V(r)       andi. r,r,PTE_V
+#define SET_V(r)       ori r,r,PTE_V
+#define CLR_V(r,t)     li t,PTE_V; andc r,r,t
+#endif /* CONFIG_PPC64BRIDGE */
+
+#define HASH_LEFT      31-(LG_PTEG_SIZE+Hash_bits-1)
+#define HASH_RIGHT     31-LG_PTEG_SIZE
+
+_GLOBAL(create_hpte)
+       /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
+       rlwinm  r8,r5,32-10,31,31       /* _PAGE_RW -> PP lsb */
+       rlwinm  r0,r5,32-7,31,31        /* _PAGE_DIRTY -> PP lsb */
+       and     r8,r8,r0                /* writable if _RW & _DIRTY */
+       rlwimi  r5,r5,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r5,r5,32-2,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r8,r8,0xe14             /* clear out reserved bits and M */
+       andc    r8,r5,r8                /* PP = user? (rw&dirty? 2: 3): 0 */
+BEGIN_FTR_SECTION
+       ori     r8,r8,_PAGE_COHERENT    /* set M (coherence required) */
+END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
+
+       /* Construct the high word of the PPC-style PTE (r5) */
+#ifndef CONFIG_PPC64BRIDGE
+       rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
+       rlwimi  r5,r4,10,26,31          /* put in API (abbrev page index) */
+#else /* CONFIG_PPC64BRIDGE */
+       clrlwi  r3,r3,8                 /* reduce vsid to 24 bits */
+       sldi    r5,r3,12                /* shift vsid into position */
+       rlwimi  r5,r4,16,20,24          /* put in API (abbrev page index) */
+#endif /* CONFIG_PPC64BRIDGE */
+       SET_V(r5)                       /* set V (valid) bit */
+
+       /* Get the address of the primary PTE group in the hash table (r3) */
+_GLOBAL(hash_page_patch_A)
+       addis   r0,r7,Hash_base@h       /* base address of hash table */
+       rlwimi  r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
+       rlwinm  r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
+       xor     r3,r3,r0                /* make primary hash */
+       li      r0,8                    /* PTEs/group */
+
+       /*
+        * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search
+        * if it is clear, meaning that the HPTE isn't there already...
+        */
+       andi.   r6,r6,_PAGE_HASHPTE
+       beq+    10f                     /* no PTE: go look for an empty slot */
+       tlbie   r4
+
+       addis   r4,r7,htab_hash_searches@ha
+       lwz     r6,htab_hash_searches@l(r4)
+       addi    r6,r6,1                 /* count how many searches we do */
+       stw     r6,htab_hash_searches@l(r4)
+
+       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
+       mtctr   r0
+       addi    r4,r3,-PTE_SIZE
+1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
+       CMPPTE  0,r6,r5
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_slot
+
+       /* Search the secondary PTEG for a matching PTE */
+       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
+_GLOBAL(hash_page_patch_B)
+       xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
+       xori    r4,r4,(-PTEG_SIZE & 0xffff)
+       addi    r4,r4,-PTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r6,PTE_SIZE(r4)
+       CMPPTE  0,r6,r5
+       bdnzf   2,2b
+       beq+    found_slot
+       xori    r5,r5,PTE_H             /* clear H bit again */
+
+       /* Search the primary PTEG for an empty slot */
+10:    mtctr   r0
+       addi    r4,r3,-PTE_SIZE         /* search primary PTEG */
+1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
+       TST_V(r6)                       /* test valid bit */
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_empty
+
+       /* update counter of times that the primary PTEG is full */
+       addis   r4,r7,primary_pteg_full@ha
+       lwz     r6,primary_pteg_full@l(r4)
+       addi    r6,r6,1
+       stw     r6,primary_pteg_full@l(r4)
+
+       /* Search the secondary PTEG for an empty slot */
+       ori     r5,r5,PTE_H             /* set H (secondary hash) bit */
+_GLOBAL(hash_page_patch_C)
+       xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
+       xori    r4,r4,(-PTEG_SIZE & 0xffff)
+       addi    r4,r4,-PTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r6,PTE_SIZE(r4)
+       TST_V(r6)
+       bdnzf   2,2b
+       beq+    found_empty
+       xori    r5,r5,PTE_H             /* clear H bit again */
+
+       /*
+        * Choose an arbitrary slot in the primary PTEG to overwrite.
+        * Since both the primary and secondary PTEGs are full, and we
+        * have no information that the PTEs in the primary PTEG are
+        * more important or useful than those in the secondary PTEG,
+        * and we know there is a definite (although small) speed
+        * advantage to putting the PTE in the primary PTEG, we always
+        * put the PTE in the primary PTEG.
+        */
+       addis   r4,r7,next_slot@ha
+       lwz     r6,next_slot@l(r4)
+       addi    r6,r6,PTE_SIZE
+       andi.   r6,r6,7*PTE_SIZE
+       stw     r6,next_slot@l(r4)
+       add     r4,r3,r6
+
+#ifndef CONFIG_SMP
+       /* Store PTE in PTEG */
+found_empty:
+       STPTE   r5,0(r4)
+found_slot:
+       STPTE   r8,PTE_SIZE/2(r4)
+
+#else /* CONFIG_SMP */
+/*
+ * Between the tlbie above and updating the hash table entry below,
+ * another CPU could read the hash table entry and put it in its TLB.
+ * There are 3 cases:
+ * 1. using an empty slot
+ * 2. updating an earlier entry to change permissions (i.e. enable write)
+ * 3. taking over the PTE for an unrelated address
+ *
+ * In each case it doesn't really matter if the other CPUs have the old
+ * PTE in their TLB.  So we don't need to bother with another tlbie here,
+ * which is convenient as we've overwritten the register that had the
+ * address. :-)  The tlbie above is mainly to make sure that this CPU comes
+ * and gets the new PTE from the hash table.
+ *
+ * We do however have to make sure that the PTE is never in an invalid
+ * state with the V bit set.
+ */
+found_empty:
+found_slot:
+       CLR_V(r5,r0)            /* clear V (valid) bit in PTE */
+       STPTE   r5,0(r4)
+       sync
+       TLBSYNC
+       STPTE   r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
+       sync
+       SET_V(r5)
+       STPTE   r5,0(r4)        /* finally set V bit in PTE */
+#endif /* CONFIG_SMP */
+
+       sync            /* make sure pte updates get to memory */
+       blr
+
+       .comm   next_slot,4
+       .comm   primary_pteg_full,4
+       .comm   htab_hash_searches,4
+
+/*
+ * Flush the entry for a particular page from the hash table.
+ *
+ * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
+ *                 int count)
+ *
+ * We assume that there is a hash table in use (Hash != 0).
+ */
+_GLOBAL(flush_hash_pages)
+       tophys(r7,0)
+
+       /*
+        * We disable interrupts here, even on UP, because we want
+        * the _PAGE_HASHPTE bit to be a reliable indication of
+        * whether the HPTE exists (or at least whether one did once).
+        * We also turn off the MMU for data accesses so that we
+        * we can't take a hash table miss (assuming the code is
+        * covered by a BAT).  -- paulus
+        */
+       mfmsr   r10
+       SYNC
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
+       mtmsr   r0
+       SYNC_601
+       isync
+
+       /* First find a PTE in the range that has _PAGE_HASHPTE set */
+       rlwimi  r5,r4,22,20,29
+1:     lwz     r0,0(r5)
+       cmpwi   cr1,r6,1
+       andi.   r0,r0,_PAGE_HASHPTE
+       bne     2f
+       ble     cr1,19f
+       addi    r4,r4,0x1000
+       addi    r5,r5,4
+       addi    r6,r6,-1
+       b       1b
+
+       /* Convert context and va to VSID */
+2:     mulli   r3,r3,897*16            /* multiply context by context skew */
+       rlwinm  r0,r4,4,28,31           /* get ESID (top 4 bits of va) */
+       mulli   r0,r0,0x111             /* multiply by ESID skew */
+       add     r3,r3,r0                /* note code below trims to 24 bits */
+
+       /* Construct the high word of the PPC-style PTE (r11) */
+#ifndef CONFIG_PPC64BRIDGE
+       rlwinm  r11,r3,7,1,24           /* put VSID in 0x7fffff80 bits */
+       rlwimi  r11,r4,10,26,31         /* put in API (abbrev page index) */
+#else /* CONFIG_PPC64BRIDGE */
+       clrlwi  r3,r3,8                 /* reduce vsid to 24 bits */
+       sldi    r11,r3,12               /* shift vsid into position */
+       rlwimi  r11,r4,16,20,24         /* put in API (abbrev page index) */
+#endif /* CONFIG_PPC64BRIDGE */
+       SET_V(r11)                      /* set V (valid) bit */
+
+#ifdef CONFIG_SMP
+       addis   r9,r7,mmu_hash_lock@ha
+       addi    r9,r9,mmu_hash_lock@l
+       rlwinm  r8,r1,0,0,18
+       add     r8,r8,r7
+       lwz     r8,TI_CPU(r8)
+       oris    r8,r8,9
+10:    lwarx   r0,0,r9
+       cmpi    0,r0,0
+       bne-    11f
+       stwcx.  r8,0,r9
+       beq+    12f
+11:    lwz     r0,0(r9)
+       cmpi    0,r0,0
+       beq     10b
+       b       11b
+12:    isync
+#endif
+
+       /*
+        * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
+        * already clear, we're done (for this pte).  If not,
+        * clear it (atomically) and proceed.  -- paulus.
+        */
+33:    lwarx   r8,0,r5                 /* fetch the pte */
+       andi.   r0,r8,_PAGE_HASHPTE
+       beq     8f                      /* done if HASHPTE is already clear */
+       rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
+       stwcx.  r8,0,r5                 /* update the pte */
+       bne-    33b
+
+       /* Get the address of the primary PTE group in the hash table (r3) */
+_GLOBAL(flush_hash_patch_A)
+       addis   r8,r7,Hash_base@h       /* base address of hash table */
+       rlwimi  r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
+       rlwinm  r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
+       xor     r8,r0,r8                /* make primary hash */
+
+       /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
+       li      r0,8                    /* PTEs/group */
+       mtctr   r0
+       addi    r12,r8,-PTE_SIZE
+1:     LDPTEu  r0,PTE_SIZE(r12)        /* get next PTE */
+       CMPPTE  0,r0,r11
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    3f
+
+       /* Search the secondary PTEG for a matching PTE */
+       ori     r11,r11,PTE_H           /* set H (secondary hash) bit */
+       li      r0,8                    /* PTEs/group */
+_GLOBAL(flush_hash_patch_B)
+       xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
+       xori    r12,r12,(-PTEG_SIZE & 0xffff)
+       addi    r12,r12,-PTE_SIZE
+       mtctr   r0
+2:     LDPTEu  r0,PTE_SIZE(r12)
+       CMPPTE  0,r0,r11
+       bdnzf   2,2b
+       xori    r11,r11,PTE_H           /* clear H again */
+       bne-    4f                      /* should rarely fail to find it */
+
+3:     li      r0,0
+       STPTE   r0,0(r12)               /* invalidate entry */
+4:     sync
+       tlbie   r4                      /* in hw tlb too */
+       sync
+
+8:     ble     cr1,9f                  /* if all ptes checked */
+81:    addi    r6,r6,-1
+       addi    r5,r5,4                 /* advance to next pte */
+       addi    r4,r4,0x1000
+       lwz     r0,0(r5)                /* check next pte */
+       cmpwi   cr1,r6,1
+       andi.   r0,r0,_PAGE_HASHPTE
+       bne     33b
+       bgt     cr1,81b
+
+9:
+#ifdef CONFIG_SMP
+       TLBSYNC
+       li      r0,0
+       stw     r0,0(r9)                /* clear mmu_hash_lock */
+#endif
+
+19:    mtmsr   r10
+       SYNC_601
+       isync
+       blr
diff --git a/arch/powerpc/mm/init.c b/arch/powerpc/mm/init.c
deleted file mode 100644 (file)
index bf13c14..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *  PPC44x/36-bit changes by Matt Porter (mporter@mvista.com)
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/initrd.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/btext.h>
-#include <asm/tlb.h>
-#include <asm/bootinfo.h>
-#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/sections.h>
-
-#include "mmu_decl.h"
-
-#if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL)
-/* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */
-#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE))
-#error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL"
-#endif
-#endif
-#define MAX_LOW_MEM    CONFIG_LOWMEM_SIZE
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-unsigned long total_memory;
-unsigned long total_lowmem;
-
-unsigned long ppc_memstart;
-unsigned long ppc_memoffset = PAGE_OFFSET;
-
-int boot_mapsize;
-#ifdef CONFIG_PPC_PMAC
-unsigned long agp_special_page;
-#endif
-
-#ifdef CONFIG_HIGHMEM
-pte_t *kmap_pte;
-pgprot_t kmap_prot;
-
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-#endif
-
-void MMU_init(void);
-
-/* XXX should be in current.h  -- paulus */
-extern struct task_struct *current_set[NR_CPUS];
-
-char *klimit = _end;
-struct device_node *memory_node;
-
-extern int init_bootmem_done;
-
-/*
- * this tells the system to map all of ram with the segregs
- * (i.e. page tables) instead of the bats.
- * -- Cort
- */
-int __map_without_bats;
-int __map_without_ltlbs;
-
-/* max amount of low RAM to map in */
-unsigned long __max_low_memory = MAX_LOW_MEM;
-
-/*
- * limit of what is accessible with initial MMU setup -
- * 256MB usually, but only 16MB on 601.
- */
-unsigned long __initial_memory_limit = 0x10000000;
-
-/*
- * Check for command-line options that affect what MMU_init will do.
- */
-void MMU_setup(void)
-{
-       /* Check for nobats option (used in mapin_ram). */
-       if (strstr(cmd_line, "nobats")) {
-               __map_without_bats = 1;
-       }
-
-       if (strstr(cmd_line, "noltlbs")) {
-               __map_without_ltlbs = 1;
-       }
-}
-
-/*
- * MMU_init sets up the basic memory mappings for the kernel,
- * including both RAM and possibly some I/O regions,
- * and sets up the page tables and the MMU hardware ready to go.
- */
-void __init MMU_init(void)
-{
-       if (ppc_md.progress)
-               ppc_md.progress("MMU:enter", 0x111);
-
-       /* 601 can only access 16MB at the moment */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               __initial_memory_limit = 0x01000000;
-
-       /* parse args from command line */
-       MMU_setup();
-
-       if (lmb.memory.cnt > 1) {
-               lmb.memory.cnt = 1;
-               lmb_analyze();
-               printk(KERN_WARNING "Only using first contiguous memory region");
-       }
-
-       total_memory = lmb_end_of_DRAM();
-       total_lowmem = total_memory;
-
-#ifdef CONFIG_FSL_BOOKE
-       /* Freescale Book-E parts expect lowmem to be mapped by fixed TLB
-        * entries, so we need to adjust lowmem to match the amount we can map
-        * in the fixed entries */
-       adjust_total_lowmem();
-#endif /* CONFIG_FSL_BOOKE */
-       if (total_lowmem > __max_low_memory) {
-               total_lowmem = __max_low_memory;
-#ifndef CONFIG_HIGHMEM
-               total_memory = total_lowmem;
-#endif /* CONFIG_HIGHMEM */
-       }
-
-       /* Initialize the MMU hardware */
-       if (ppc_md.progress)
-               ppc_md.progress("MMU:hw init", 0x300);
-       MMU_init_hw();
-
-       /* Map in all of RAM starting at KERNELBASE */
-       if (ppc_md.progress)
-               ppc_md.progress("MMU:mapin", 0x301);
-       mapin_ram();
-
-#ifdef CONFIG_HIGHMEM
-       ioremap_base = PKMAP_BASE;
-#else
-       ioremap_base = 0xfe000000UL;    /* for now, could be 0xfffff000 */
-#endif /* CONFIG_HIGHMEM */
-       ioremap_bot = ioremap_base;
-
-       /* Map in I/O resources */
-       if (ppc_md.progress)
-               ppc_md.progress("MMU:setio", 0x302);
-       if (ppc_md.setup_io_mappings)
-               ppc_md.setup_io_mappings();
-
-       /* Initialize the context management stuff */
-       mmu_context_init();
-
-       if (ppc_md.progress)
-               ppc_md.progress("MMU:exit", 0x211);
-
-#ifdef CONFIG_BOOTX_TEXT
-       /* By default, we are no longer mapped */
-               boot_text_mapped = 0;
-       /* Must be done last, or ppc_md.progress will die. */
-       map_boot_text();
-#endif
-}
-
-/* This is only called until mem_init is done. */
-void __init *early_get_page(void)
-{
-       void *p;
-
-       if (init_bootmem_done) {
-               p = alloc_bootmem_pages(PAGE_SIZE);
-       } else {
-               p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE,
-                                       __initial_memory_limit));
-       }
-       return p;
-}
-
-/* Free up now-unused memory */
-static void free_sec(unsigned long start, unsigned long end, const char *name)
-{
-       unsigned long cnt = 0;
-
-       while (start < end) {
-               ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
-               free_page(start);
-               cnt++;
-               start += PAGE_SIZE;
-       }
-       if (cnt) {
-               printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name);
-               totalram_pages += cnt;
-       }
-}
-
-void free_initmem(void)
-{
-#define FREESEC(TYPE) \
-       free_sec((unsigned long)(&__ ## TYPE ## _begin), \
-                (unsigned long)(&__ ## TYPE ## _end), \
-                #TYPE);
-
-       printk ("Freeing unused kernel memory:");
-       FREESEC(init);
-       printk("\n");
-       ppc_md.progress = NULL;
-#undef FREESEC
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (start < end)
-               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
-               free_page(start);
-               totalram_pages++;
-       }
-}
-#endif
diff --git a/arch/powerpc/mm/init64.c b/arch/powerpc/mm/init64.c
deleted file mode 100644 (file)
index c0ce6a7..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  Dave Engebretsen <engebret@us.ibm.com>
- *      Rework for PPC64 port.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
-
-#include <asm/pgalloc.h>
-#include <asm/page.h>
-#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/tlb.h>
-#include <asm/eeh.h>
-#include <asm/processor.h>
-#include <asm/mmzone.h>
-#include <asm/cputable.h>
-#include <asm/ppcdebug.h>
-#include <asm/sections.h>
-#include <asm/system.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/vdso.h>
-#include <asm/imalloc.h>
-
-#if PGTABLE_RANGE > USER_VSID_RANGE
-#warning Limited user VSID range means pagetable space is wasted
-#endif
-
-#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
-#warning TASK_SIZE is smaller than it needs to be.
-#endif
-
-int mem_init_done;
-unsigned long ioremap_bot = IMALLOC_BASE;
-static unsigned long phbs_io_bot = PHBS_IO_BASE;
-
-extern pgd_t swapper_pg_dir[];
-extern struct task_struct *current_set[NR_CPUS];
-
-unsigned long klimit = (unsigned long)_end;
-
-unsigned long _SDR1=0;
-unsigned long _ASR=0;
-
-/* max amount of RAM to use */
-unsigned long __max_memory;
-
-/* info on what we think the IO hole is */
-unsigned long  io_hole_start;
-unsigned long  io_hole_size;
-
-/*
- * Do very early mm setup.
- */
-void __init mm_init_ppc64(void)
-{
-#ifndef CONFIG_PPC_ISERIES
-       unsigned long i;
-#endif
-
-       ppc64_boot_msg(0x100, "MM Init");
-
-       /* This is the story of the IO hole... please, keep seated,
-        * unfortunately, we are out of oxygen masks at the moment.
-        * So we need some rough way to tell where your big IO hole
-        * is. On pmac, it's between 2G and 4G, on POWER3, it's around
-        * that area as well, on POWER4 we don't have one, etc...
-        * We need that as a "hint" when sizing the TCE table on POWER3
-        * So far, the simplest way that seem work well enough for us it
-        * to just assume that the first discontinuity in our physical
-        * RAM layout is the IO hole. That may not be correct in the future
-        * (and isn't on iSeries but then we don't care ;)
-        */
-
-#ifndef CONFIG_PPC_ISERIES
-       for (i = 1; i < lmb.memory.cnt; i++) {
-               unsigned long base, prevbase, prevsize;
-
-               prevbase = lmb.memory.region[i-1].base;
-               prevsize = lmb.memory.region[i-1].size;
-               base = lmb.memory.region[i].base;
-               if (base > (prevbase + prevsize)) {
-                       io_hole_start = prevbase + prevsize;
-                       io_hole_size = base  - (prevbase + prevsize);
-                       break;
-               }
-       }
-#endif /* CONFIG_PPC_ISERIES */
-       if (io_hole_start)
-               printk("IO Hole assumed to be %lx -> %lx\n",
-                      io_hole_start, io_hole_start + io_hole_size - 1);
-
-       ppc64_boot_msg(0x100, "MM Init Done");
-}
-
-void free_initmem(void)
-{
-       unsigned long addr;
-
-       addr = (unsigned long)__init_begin;
-       for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
-               memset((void *)addr, 0xcc, PAGE_SIZE);
-               ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
-               free_page(addr);
-               totalram_pages++;
-       }
-       printk ("Freeing unused kernel memory: %luk freed\n",
-               ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (start < end)
-               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
-               free_page(start);
-               totalram_pages++;
-       }
-}
-#endif
-
-static struct kcore_list kcore_vmem;
-
-static int __init setup_kcore(void)
-{
-       int i;
-
-       for (i=0; i < lmb.memory.cnt; i++) {
-               unsigned long base, size;
-               struct kcore_list *kcore_mem;
-
-               base = lmb.memory.region[i].base;
-               size = lmb.memory.region[i].size;
-
-               /* GFP_ATOMIC to avoid might_sleep warnings during boot */
-               kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);
-               if (!kcore_mem)
-                       panic("mem_init: kmalloc failed\n");
-
-               kclist_add(kcore_mem, __va(base), size);
-       }
-
-       kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
-
-       return 0;
-}
-module_init(setup_kcore);
-
-void __iomem * reserve_phb_iospace(unsigned long size)
-{
-       void __iomem *virt_addr;
-               
-       if (phbs_io_bot >= IMALLOC_BASE) 
-               panic("reserve_phb_iospace(): phb io space overflow\n");
-                       
-       virt_addr = (void __iomem *) phbs_io_bot;
-       phbs_io_bot += size;
-
-       return virt_addr;
-}
-
-static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
-{
-       memset(addr, 0, kmem_cache_size(cache));
-}
-
-static const int pgtable_cache_size[2] = {
-       PTE_TABLE_SIZE, PMD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-       "pgd_pte_cache", "pud_pmd_cache",
-};
-
-kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];
-
-void pgtable_cache_init(void)
-{
-       int i;
-
-       BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]);
-       BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]);
-       BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]);
-       BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]);
-
-       for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {
-               int size = pgtable_cache_size[i];
-               const char *name = pgtable_cache_name[i];
-
-               pgtable_cache[i] = kmem_cache_create(name,
-                                                    size, size,
-                                                    SLAB_HWCACHE_ALIGN
-                                                    | SLAB_MUST_HWCACHE_ALIGN,
-                                                    zero_ctor,
-                                                    NULL);
-               if (! pgtable_cache[i])
-                       panic("pgtable_cache_init(): could not create %s!\n",
-                             name);
-       }
-}
-
-pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
-                             unsigned long size, pgprot_t vma_prot)
-{
-       if (ppc_md.phys_mem_access_prot)
-               return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
-
-       if (!page_is_ram(addr >> PAGE_SHIFT))
-               vma_prot = __pgprot(pgprot_val(vma_prot)
-                                   | _PAGE_GUARDED | _PAGE_NO_CACHE);
-       return vma_prot;
-}
-EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
new file mode 100644 (file)
index 0000000..bf13c14
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *  PPC44x/36-bit changes by Matt Porter (mporter@mvista.com)
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/initrd.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/btext.h>
+#include <asm/tlb.h>
+#include <asm/bootinfo.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+#include <asm/sections.h>
+
+#include "mmu_decl.h"
+
+#if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL)
+/* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */
+#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE))
+#error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL"
+#endif
+#endif
+#define MAX_LOW_MEM    CONFIG_LOWMEM_SIZE
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+unsigned long total_memory;
+unsigned long total_lowmem;
+
+unsigned long ppc_memstart;
+unsigned long ppc_memoffset = PAGE_OFFSET;
+
+int boot_mapsize;
+#ifdef CONFIG_PPC_PMAC
+unsigned long agp_special_page;
+#endif
+
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+EXPORT_SYMBOL(kmap_prot);
+EXPORT_SYMBOL(kmap_pte);
+#endif
+
+void MMU_init(void);
+
+/* XXX should be in current.h  -- paulus */
+extern struct task_struct *current_set[NR_CPUS];
+
+char *klimit = _end;
+struct device_node *memory_node;
+
+extern int init_bootmem_done;
+
+/*
+ * this tells the system to map all of ram with the segregs
+ * (i.e. page tables) instead of the bats.
+ * -- Cort
+ */
+int __map_without_bats;
+int __map_without_ltlbs;
+
+/* max amount of low RAM to map in */
+unsigned long __max_low_memory = MAX_LOW_MEM;
+
+/*
+ * limit of what is accessible with initial MMU setup -
+ * 256MB usually, but only 16MB on 601.
+ */
+unsigned long __initial_memory_limit = 0x10000000;
+
+/*
+ * Check for command-line options that affect what MMU_init will do.
+ */
+void MMU_setup(void)
+{
+       /* Check for nobats option (used in mapin_ram). */
+       if (strstr(cmd_line, "nobats")) {
+               __map_without_bats = 1;
+       }
+
+       if (strstr(cmd_line, "noltlbs")) {
+               __map_without_ltlbs = 1;
+       }
+}
+
+/*
+ * MMU_init sets up the basic memory mappings for the kernel,
+ * including both RAM and possibly some I/O regions,
+ * and sets up the page tables and the MMU hardware ready to go.
+ */
+void __init MMU_init(void)
+{
+       if (ppc_md.progress)
+               ppc_md.progress("MMU:enter", 0x111);
+
+       /* 601 can only access 16MB at the moment */
+       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+               __initial_memory_limit = 0x01000000;
+
+       /* parse args from command line */
+       MMU_setup();
+
+       if (lmb.memory.cnt > 1) {
+               lmb.memory.cnt = 1;
+               lmb_analyze();
+               printk(KERN_WARNING "Only using first contiguous memory region");
+       }
+
+       total_memory = lmb_end_of_DRAM();
+       total_lowmem = total_memory;
+
+#ifdef CONFIG_FSL_BOOKE
+       /* Freescale Book-E parts expect lowmem to be mapped by fixed TLB
+        * entries, so we need to adjust lowmem to match the amount we can map
+        * in the fixed entries */
+       adjust_total_lowmem();
+#endif /* CONFIG_FSL_BOOKE */
+       if (total_lowmem > __max_low_memory) {
+               total_lowmem = __max_low_memory;
+#ifndef CONFIG_HIGHMEM
+               total_memory = total_lowmem;
+#endif /* CONFIG_HIGHMEM */
+       }
+
+       /* Initialize the MMU hardware */
+       if (ppc_md.progress)
+               ppc_md.progress("MMU:hw init", 0x300);
+       MMU_init_hw();
+
+       /* Map in all of RAM starting at KERNELBASE */
+       if (ppc_md.progress)
+               ppc_md.progress("MMU:mapin", 0x301);
+       mapin_ram();
+
+#ifdef CONFIG_HIGHMEM
+       ioremap_base = PKMAP_BASE;
+#else
+       ioremap_base = 0xfe000000UL;    /* for now, could be 0xfffff000 */
+#endif /* CONFIG_HIGHMEM */
+       ioremap_bot = ioremap_base;
+
+       /* Map in I/O resources */
+       if (ppc_md.progress)
+               ppc_md.progress("MMU:setio", 0x302);
+       if (ppc_md.setup_io_mappings)
+               ppc_md.setup_io_mappings();
+
+       /* Initialize the context management stuff */
+       mmu_context_init();
+
+       if (ppc_md.progress)
+               ppc_md.progress("MMU:exit", 0x211);
+
+#ifdef CONFIG_BOOTX_TEXT
+       /* By default, we are no longer mapped */
+               boot_text_mapped = 0;
+       /* Must be done last, or ppc_md.progress will die. */
+       map_boot_text();
+#endif
+}
+
+/* This is only called until mem_init is done. */
+void __init *early_get_page(void)
+{
+       void *p;
+
+       if (init_bootmem_done) {
+               p = alloc_bootmem_pages(PAGE_SIZE);
+       } else {
+               p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE,
+                                       __initial_memory_limit));
+       }
+       return p;
+}
+
+/* Free up now-unused memory */
+static void free_sec(unsigned long start, unsigned long end, const char *name)
+{
+       unsigned long cnt = 0;
+
+       while (start < end) {
+               ClearPageReserved(virt_to_page(start));
+               set_page_count(virt_to_page(start), 1);
+               free_page(start);
+               cnt++;
+               start += PAGE_SIZE;
+       }
+       if (cnt) {
+               printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name);
+               totalram_pages += cnt;
+       }
+}
+
+void free_initmem(void)
+{
+#define FREESEC(TYPE) \
+       free_sec((unsigned long)(&__ ## TYPE ## _begin), \
+                (unsigned long)(&__ ## TYPE ## _end), \
+                #TYPE);
+
+       printk ("Freeing unused kernel memory:");
+       FREESEC(init);
+       printk("\n");
+       ppc_md.progress = NULL;
+#undef FREESEC
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       if (start < end)
+               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               set_page_count(virt_to_page(start), 1);
+               free_page(start);
+               totalram_pages++;
+       }
+}
+#endif
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
new file mode 100644 (file)
index 0000000..c0ce6a7
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Dave Engebretsen <engebret@us.ibm.com>
+ *      Rework for PPC64 port.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/idr.h>
+#include <linux/nodemask.h>
+#include <linux/module.h>
+
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+#include <asm/rtas.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/tlb.h>
+#include <asm/eeh.h>
+#include <asm/processor.h>
+#include <asm/mmzone.h>
+#include <asm/cputable.h>
+#include <asm/ppcdebug.h>
+#include <asm/sections.h>
+#include <asm/system.h>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
+#include <asm/vdso.h>
+#include <asm/imalloc.h>
+
+#if PGTABLE_RANGE > USER_VSID_RANGE
+#warning Limited user VSID range means pagetable space is wasted
+#endif
+
+#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
+#warning TASK_SIZE is smaller than it needs to be.
+#endif
+
+int mem_init_done;
+unsigned long ioremap_bot = IMALLOC_BASE;
+static unsigned long phbs_io_bot = PHBS_IO_BASE;
+
+extern pgd_t swapper_pg_dir[];
+extern struct task_struct *current_set[NR_CPUS];
+
+unsigned long klimit = (unsigned long)_end;
+
+unsigned long _SDR1=0;
+unsigned long _ASR=0;
+
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
+/* info on what we think the IO hole is */
+unsigned long  io_hole_start;
+unsigned long  io_hole_size;
+
+/*
+ * Do very early mm setup.
+ */
+void __init mm_init_ppc64(void)
+{
+#ifndef CONFIG_PPC_ISERIES
+       unsigned long i;
+#endif
+
+       ppc64_boot_msg(0x100, "MM Init");
+
+       /* This is the story of the IO hole... please, keep seated,
+        * unfortunately, we are out of oxygen masks at the moment.
+        * So we need some rough way to tell where your big IO hole
+        * is. On pmac, it's between 2G and 4G, on POWER3, it's around
+        * that area as well, on POWER4 we don't have one, etc...
+        * We need that as a "hint" when sizing the TCE table on POWER3
+        * So far, the simplest way that seem work well enough for us it
+        * to just assume that the first discontinuity in our physical
+        * RAM layout is the IO hole. That may not be correct in the future
+        * (and isn't on iSeries but then we don't care ;)
+        */
+
+#ifndef CONFIG_PPC_ISERIES
+       for (i = 1; i < lmb.memory.cnt; i++) {
+               unsigned long base, prevbase, prevsize;
+
+               prevbase = lmb.memory.region[i-1].base;
+               prevsize = lmb.memory.region[i-1].size;
+               base = lmb.memory.region[i].base;
+               if (base > (prevbase + prevsize)) {
+                       io_hole_start = prevbase + prevsize;
+                       io_hole_size = base  - (prevbase + prevsize);
+                       break;
+               }
+       }
+#endif /* CONFIG_PPC_ISERIES */
+       if (io_hole_start)
+               printk("IO Hole assumed to be %lx -> %lx\n",
+                      io_hole_start, io_hole_start + io_hole_size - 1);
+
+       ppc64_boot_msg(0x100, "MM Init Done");
+}
+
+void free_initmem(void)
+{
+       unsigned long addr;
+
+       addr = (unsigned long)__init_begin;
+       for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
+               memset((void *)addr, 0xcc, PAGE_SIZE);
+               ClearPageReserved(virt_to_page(addr));
+               set_page_count(virt_to_page(addr), 1);
+               free_page(addr);
+               totalram_pages++;
+       }
+       printk ("Freeing unused kernel memory: %luk freed\n",
+               ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       if (start < end)
+               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               set_page_count(virt_to_page(start), 1);
+               free_page(start);
+               totalram_pages++;
+       }
+}
+#endif
+
+static struct kcore_list kcore_vmem;
+
+static int __init setup_kcore(void)
+{
+       int i;
+
+       for (i=0; i < lmb.memory.cnt; i++) {
+               unsigned long base, size;
+               struct kcore_list *kcore_mem;
+
+               base = lmb.memory.region[i].base;
+               size = lmb.memory.region[i].size;
+
+               /* GFP_ATOMIC to avoid might_sleep warnings during boot */
+               kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);
+               if (!kcore_mem)
+                       panic("mem_init: kmalloc failed\n");
+
+               kclist_add(kcore_mem, __va(base), size);
+       }
+
+       kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
+
+       return 0;
+}
+module_init(setup_kcore);
+
+void __iomem * reserve_phb_iospace(unsigned long size)
+{
+       void __iomem *virt_addr;
+               
+       if (phbs_io_bot >= IMALLOC_BASE) 
+               panic("reserve_phb_iospace(): phb io space overflow\n");
+                       
+       virt_addr = (void __iomem *) phbs_io_bot;
+       phbs_io_bot += size;
+
+       return virt_addr;
+}
+
+static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
+{
+       memset(addr, 0, kmem_cache_size(cache));
+}
+
+static const int pgtable_cache_size[2] = {
+       PTE_TABLE_SIZE, PMD_TABLE_SIZE
+};
+static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
+       "pgd_pte_cache", "pud_pmd_cache",
+};
+
+kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];
+
+void pgtable_cache_init(void)
+{
+       int i;
+
+       BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]);
+       BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]);
+       BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]);
+       BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]);
+
+       for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {
+               int size = pgtable_cache_size[i];
+               const char *name = pgtable_cache_name[i];
+
+               pgtable_cache[i] = kmem_cache_create(name,
+                                                    size, size,
+                                                    SLAB_HWCACHE_ALIGN
+                                                    | SLAB_MUST_HWCACHE_ALIGN,
+                                                    zero_ctor,
+                                                    NULL);
+               if (! pgtable_cache[i])
+                       panic("pgtable_cache_init(): could not create %s!\n",
+                             name);
+       }
+}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+                             unsigned long size, pgprot_t vma_prot)
+{
+       if (ppc_md.phys_mem_access_prot)
+               return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+
+       if (!page_is_ram(addr >> PAGE_SHIFT))
+               vma_prot = __pgprot(pgprot_val(vma_prot)
+                                   | _PAGE_GUARDED | _PAGE_NO_CACHE);
+       return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/powerpc/mm/mem64.c b/arch/powerpc/mm/mem64.c
deleted file mode 100644 (file)
index ef765a8..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- *  PowerPC version 
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  Dave Engebretsen <engebret@us.ibm.com>
- *      Rework for PPC64 port.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
-
-#include <asm/pgalloc.h>
-#include <asm/page.h>
-#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/tlb.h>
-#include <asm/eeh.h>
-#include <asm/processor.h>
-#include <asm/mmzone.h>
-#include <asm/cputable.h>
-#include <asm/ppcdebug.h>
-#include <asm/sections.h>
-#include <asm/system.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/vdso.h>
-#include <asm/imalloc.h>
-
-/*
- * This is called by /dev/mem to know if a given address has to
- * be mapped non-cacheable or not
- */
-int page_is_ram(unsigned long pfn)
-{
-       int i;
-       unsigned long paddr = (pfn << PAGE_SHIFT);
-
-       for (i=0; i < lmb.memory.cnt; i++) {
-               unsigned long base;
-
-               base = lmb.memory.region[i].base;
-
-               if ((paddr >= base) &&
-                       (paddr < (base + lmb.memory.region[i].size))) {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(page_is_ram);
-
-pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
-                             unsigned long size, pgprot_t vma_prot)
-{
-       if (ppc_md.phys_mem_access_prot)
-               return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
-
-       if (!page_is_ram(addr >> PAGE_SHIFT))
-               vma_prot = __pgprot(pgprot_val(vma_prot)
-                                   | _PAGE_GUARDED | _PAGE_NO_CACHE);
-       return vma_prot;
-}
-EXPORT_SYMBOL(phys_mem_access_prot);
-
-void show_mem(void)
-{
-       unsigned long total = 0, reserved = 0;
-       unsigned long shared = 0, cached = 0;
-       struct page *page;
-       pg_data_t *pgdat;
-       unsigned long i;
-
-       printk("Mem-info:\n");
-       show_free_areas();
-       printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-       for_each_pgdat(pgdat) {
-               for (i = 0; i < pgdat->node_spanned_pages; i++) {
-                       page = pgdat_page_nr(pgdat, i);
-                       total++;
-                       if (PageReserved(page))
-                               reserved++;
-                       else if (PageSwapCache(page))
-                               cached++;
-                       else if (page_count(page))
-                               shared += page_count(page) - 1;
-               }
-       }
-       printk("%ld pages of RAM\n", total);
-       printk("%ld reserved pages\n", reserved);
-       printk("%ld pages shared\n", shared);
-       printk("%ld pages swap cached\n", cached);
-}
-
-/*
- * This is called when a page has been modified by the kernel.
- * It just marks the page as not i-cache clean.  We do the i-cache
- * flush later when the page is given to a user process, if necessary.
- */
-void flush_dcache_page(struct page *page)
-{
-       if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
-               return;
-       /* avoid an atomic op if possible */
-       if (test_bit(PG_arch_1, &page->flags))
-               clear_bit(PG_arch_1, &page->flags);
-}
-EXPORT_SYMBOL(flush_dcache_page);
-
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
-       clear_page(page);
-
-       if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
-               return;
-       /*
-        * We shouldnt have to do this, but some versions of glibc
-        * require it (ld.so assumes zero filled pages are icache clean)
-        * - Anton
-        */
-
-       /* avoid an atomic op if possible */
-       if (test_bit(PG_arch_1, &pg->flags))
-               clear_bit(PG_arch_1, &pg->flags);
-}
-EXPORT_SYMBOL(clear_user_page);
-
-void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
-                   struct page *pg)
-{
-       copy_page(vto, vfrom);
-
-       /*
-        * We should be able to use the following optimisation, however
-        * there are two problems.
-        * Firstly a bug in some versions of binutils meant PLT sections
-        * were not marked executable.
-        * Secondly the first word in the GOT section is blrl, used
-        * to establish the GOT address. Until recently the GOT was
-        * not marked executable.
-        * - Anton
-        */
-#if 0
-       if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0))
-               return;
-#endif
-
-       if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
-               return;
-
-       /* avoid an atomic op if possible */
-       if (test_bit(PG_arch_1, &pg->flags))
-               clear_bit(PG_arch_1, &pg->flags);
-}
-
-void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
-                            unsigned long addr, int len)
-{
-       unsigned long maddr;
-
-       maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK);
-       flush_icache_range(maddr, maddr + len);
-}
-EXPORT_SYMBOL(flush_icache_user_range);
-
-/*
- * This is called at the end of handling a user page fault, when the
- * fault has been handled by updating a PTE in the linux page tables.
- * We use it to preload an HPTE into the hash table corresponding to
- * the updated linux PTE.
- * 
- * This must always be called with the mm->page_table_lock held
- */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea,
-                     pte_t pte)
-{
-       unsigned long vsid;
-       void *pgdir;
-       pte_t *ptep;
-       int local = 0;
-       cpumask_t tmp;
-       unsigned long flags;
-
-       /* handle i-cache coherency */
-       if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) &&
-           !cpu_has_feature(CPU_FTR_NOEXECUTE)) {
-               unsigned long pfn = pte_pfn(pte);
-               if (pfn_valid(pfn)) {
-                       struct page *page = pfn_to_page(pfn);
-                       if (!PageReserved(page)
-                           && !test_bit(PG_arch_1, &page->flags)) {
-                               __flush_dcache_icache(page_address(page));
-                               set_bit(PG_arch_1, &page->flags);
-                       }
-               }
-       }
-
-       /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
-       if (!pte_young(pte))
-               return;
-
-       pgdir = vma->vm_mm->pgd;
-       if (pgdir == NULL)
-               return;
-
-       ptep = find_linux_pte(pgdir, ea);
-       if (!ptep)
-               return;
-
-       vsid = get_vsid(vma->vm_mm->context.id, ea);
-
-       local_irq_save(flags);
-       tmp = cpumask_of_cpu(smp_processor_id());
-       if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp))
-               local = 1;
-
-       __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep,
-                   0x300, local);
-       local_irq_restore(flags);
-}
diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c
deleted file mode 100644 (file)
index a8816e0..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file contains the routines for handling the MMU on those
- * PowerPC implementations where the MMU substantially follows the
- * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/mmu_context.h>
-#include <asm/tlbflush.h>
-
-mm_context_t next_mmu_context;
-unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
-#ifdef FEW_CONTEXTS
-atomic_t nr_free_contexts;
-struct mm_struct *context_mm[LAST_CONTEXT+1];
-void steal_context(void);
-#endif /* FEW_CONTEXTS */
-
-/*
- * Initialize the context management stuff.
- */
-void __init
-mmu_context_init(void)
-{
-       /*
-        * Some processors have too few contexts to reserve one for
-        * init_mm, and require using context 0 for a normal task.
-        * Other processors reserve the use of context zero for the kernel.
-        * This code assumes FIRST_CONTEXT < 32.
-        */
-       context_map[0] = (1 << FIRST_CONTEXT) - 1;
-       next_mmu_context = FIRST_CONTEXT;
-#ifdef FEW_CONTEXTS
-       atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
-#endif /* FEW_CONTEXTS */
-}
-
-#ifdef FEW_CONTEXTS
-/*
- * Steal a context from a task that has one at the moment.
- * This is only used on 8xx and 4xx and we presently assume that
- * they don't do SMP.  If they do then this will have to check
- * whether the MM we steal is in use.
- * We also assume that this is only used on systems that don't
- * use an MMU hash table - this is true for 8xx and 4xx.
- * This isn't an LRU system, it just frees up each context in
- * turn (sort-of pseudo-random replacement :).  This would be the
- * place to implement an LRU scheme if anyone was motivated to do it.
- *  -- paulus
- */
-void
-steal_context(void)
-{
-       struct mm_struct *mm;
-
-       /* free up context `next_mmu_context' */
-       /* if we shouldn't free context 0, don't... */
-       if (next_mmu_context < FIRST_CONTEXT)
-               next_mmu_context = FIRST_CONTEXT;
-       mm = context_mm[next_mmu_context];
-       flush_tlb_mm(mm);
-       destroy_context(mm);
-}
-#endif /* FEW_CONTEXTS */
diff --git a/arch/powerpc/mm/mmu_context64.c b/arch/powerpc/mm/mmu_context64.c
deleted file mode 100644 (file)
index 714a84d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  MMU context allocation for 64-bit kernels.
- *
- *  Copyright (C) 2004 Anton Blanchard, IBM Corp. <anton@samba.org>
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-#include <linux/idr.h>
-
-#include <asm/mmu_context.h>
-
-static DEFINE_SPINLOCK(mmu_context_lock);
-static DEFINE_IDR(mmu_context_idr);
-
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-       int index;
-       int err;
-
-again:
-       if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
-               return -ENOMEM;
-
-       spin_lock(&mmu_context_lock);
-       err = idr_get_new_above(&mmu_context_idr, NULL, 1, &index);
-       spin_unlock(&mmu_context_lock);
-
-       if (err == -EAGAIN)
-               goto again;
-       else if (err)
-               return err;
-
-       if (index > MAX_CONTEXT) {
-               idr_remove(&mmu_context_idr, index);
-               return -ENOMEM;
-       }
-
-       mm->context.id = index;
-
-       return 0;
-}
-
-void destroy_context(struct mm_struct *mm)
-{
-       spin_lock(&mmu_context_lock);
-       idr_remove(&mmu_context_idr, mm->context.id);
-       spin_unlock(&mmu_context_lock);
-
-       mm->context.id = NO_CONTEXT;
-}
diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c
new file mode 100644 (file)
index 0000000..a8816e0
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU substantially follows the
+ * architecture specification.  This includes the 6xx, 7xx, 7xxx,
+ * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+
+mm_context_t next_mmu_context;
+unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
+#ifdef FEW_CONTEXTS
+atomic_t nr_free_contexts;
+struct mm_struct *context_mm[LAST_CONTEXT+1];
+void steal_context(void);
+#endif /* FEW_CONTEXTS */
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init
+mmu_context_init(void)
+{
+       /*
+        * Some processors have too few contexts to reserve one for
+        * init_mm, and require using context 0 for a normal task.
+        * Other processors reserve the use of context zero for the kernel.
+        * This code assumes FIRST_CONTEXT < 32.
+        */
+       context_map[0] = (1 << FIRST_CONTEXT) - 1;
+       next_mmu_context = FIRST_CONTEXT;
+#ifdef FEW_CONTEXTS
+       atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
+#endif /* FEW_CONTEXTS */
+}
+
+#ifdef FEW_CONTEXTS
+/*
+ * Steal a context from a task that has one at the moment.
+ * This is only used on 8xx and 4xx and we presently assume that
+ * they don't do SMP.  If they do then this will have to check
+ * whether the MM we steal is in use.
+ * We also assume that this is only used on systems that don't
+ * use an MMU hash table - this is true for 8xx and 4xx.
+ * This isn't an LRU system, it just frees up each context in
+ * turn (sort-of pseudo-random replacement :).  This would be the
+ * place to implement an LRU scheme if anyone was motivated to do it.
+ *  -- paulus
+ */
+void
+steal_context(void)
+{
+       struct mm_struct *mm;
+
+       /* free up context `next_mmu_context' */
+       /* if we shouldn't free context 0, don't... */
+       if (next_mmu_context < FIRST_CONTEXT)
+               next_mmu_context = FIRST_CONTEXT;
+       mm = context_mm[next_mmu_context];
+       flush_tlb_mm(mm);
+       destroy_context(mm);
+}
+#endif /* FEW_CONTEXTS */
diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c
new file mode 100644 (file)
index 0000000..714a84d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  MMU context allocation for 64-bit kernels.
+ *
+ *  Copyright (C) 2004 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+
+#include <asm/mmu_context.h>
+
+static DEFINE_SPINLOCK(mmu_context_lock);
+static DEFINE_IDR(mmu_context_idr);
+
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       int index;
+       int err;
+
+again:
+       if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
+               return -ENOMEM;
+
+       spin_lock(&mmu_context_lock);
+       err = idr_get_new_above(&mmu_context_idr, NULL, 1, &index);
+       spin_unlock(&mmu_context_lock);
+
+       if (err == -EAGAIN)
+               goto again;
+       else if (err)
+               return err;
+
+       if (index > MAX_CONTEXT) {
+               idr_remove(&mmu_context_idr, index);
+               return -ENOMEM;
+       }
+
+       mm->context.id = index;
+
+       return 0;
+}
+
+void destroy_context(struct mm_struct *mm)
+{
+       spin_lock(&mmu_context_lock);
+       idr_remove(&mmu_context_idr, mm->context.id);
+       spin_unlock(&mmu_context_lock);
+
+       mm->context.id = NO_CONTEXT;
+}
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
deleted file mode 100644 (file)
index 5792e53..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * This file contains the routines setting up the linux page tables.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-
-#include "mmu_decl.h"
-
-unsigned long ioremap_base;
-unsigned long ioremap_bot;
-int io_bat_index;
-
-#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
-#define HAVE_BATS      1
-#endif
-
-#if defined(CONFIG_FSL_BOOKE)
-#define HAVE_TLBCAM    1
-#endif
-
-extern char etext[], _stext[];
-
-#ifdef CONFIG_SMP
-extern void hash_page_sync(void);
-#endif
-
-#ifdef HAVE_BATS
-extern unsigned long v_mapped_by_bats(unsigned long va);
-extern unsigned long p_mapped_by_bats(unsigned long pa);
-void setbat(int index, unsigned long virt, unsigned long phys,
-           unsigned int size, int flags);
-
-#else /* !HAVE_BATS */
-#define v_mapped_by_bats(x)    (0UL)
-#define p_mapped_by_bats(x)    (0UL)
-#endif /* HAVE_BATS */
-
-#ifdef HAVE_TLBCAM
-extern unsigned int tlbcam_index;
-extern unsigned long v_mapped_by_tlbcam(unsigned long va);
-extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
-#else /* !HAVE_TLBCAM */
-#define v_mapped_by_tlbcam(x)  (0UL)
-#define p_mapped_by_tlbcam(x)  (0UL)
-#endif /* HAVE_TLBCAM */
-
-#ifdef CONFIG_PTE_64BIT
-/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
-#define PGDIR_ORDER    1
-#else
-#define PGDIR_ORDER    0
-#endif
-
-pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-       pgd_t *ret;
-
-       ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER);
-       return ret;
-}
-
-void pgd_free(pgd_t *pgd)
-{
-       free_pages((unsigned long)pgd, PGDIR_ORDER);
-}
-
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-       pte_t *pte;
-       extern int mem_init_done;
-       extern void *early_get_page(void);
-
-       if (mem_init_done) {
-               pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
-       } else {
-               pte = (pte_t *)early_get_page();
-               if (pte)
-                       clear_page(pte);
-       }
-       return pte;
-}
-
-struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-       struct page *ptepage;
-
-#ifdef CONFIG_HIGHPTE
-       int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
-#else
-       int flags = GFP_KERNEL | __GFP_REPEAT;
-#endif
-
-       ptepage = alloc_pages(flags, 0);
-       if (ptepage)
-               clear_highpage(ptepage);
-       return ptepage;
-}
-
-void pte_free_kernel(pte_t *pte)
-{
-#ifdef CONFIG_SMP
-       hash_page_sync();
-#endif
-       free_page((unsigned long)pte);
-}
-
-void pte_free(struct page *ptepage)
-{
-#ifdef CONFIG_SMP
-       hash_page_sync();
-#endif
-       __free_page(ptepage);
-}
-
-#ifndef CONFIG_PHYS_64BIT
-void __iomem *
-ioremap(phys_addr_t addr, unsigned long size)
-{
-       return __ioremap(addr, size, _PAGE_NO_CACHE);
-}
-#else /* CONFIG_PHYS_64BIT */
-void __iomem *
-ioremap64(unsigned long long addr, unsigned long size)
-{
-       return __ioremap(addr, size, _PAGE_NO_CACHE);
-}
-
-void __iomem *
-ioremap(phys_addr_t addr, unsigned long size)
-{
-       phys_addr_t addr64 = fixup_bigphys_addr(addr, size);
-
-       return ioremap64(addr64, size);
-}
-#endif /* CONFIG_PHYS_64BIT */
-
-void __iomem *
-__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
-{
-       unsigned long v, i;
-       phys_addr_t p;
-       int err;
-
-       /*
-        * Choose an address to map it to.
-        * Once the vmalloc system is running, we use it.
-        * Before then, we use space going down from ioremap_base
-        * (ioremap_bot records where we're up to).
-        */
-       p = addr & PAGE_MASK;
-       size = PAGE_ALIGN(addr + size) - p;
-
-       /*
-        * If the address lies within the first 16 MB, assume it's in ISA
-        * memory space
-        */
-       if (p < 16*1024*1024)
-               p += _ISA_MEM_BASE;
-
-       /*
-        * Don't allow anybody to remap normal RAM that we're using.
-        * mem_init() sets high_memory so only do the check after that.
-        */
-       if (mem_init_done && (p < virt_to_phys(high_memory))) {
-               printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
-                      __builtin_return_address(0));
-               return NULL;
-       }
-
-       if (size == 0)
-               return NULL;
-
-       /*
-        * Is it already mapped?  Perhaps overlapped by a previous
-        * BAT mapping.  If the whole area is mapped then we're done,
-        * otherwise remap it since we want to keep the virt addrs for
-        * each request contiguous.
-        *
-        * We make the assumption here that if the bottom and top
-        * of the range we want are mapped then it's mapped to the
-        * same virt address (and this is contiguous).
-        *  -- Cort
-        */
-       if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
-               goto out;
-
-       if ((v = p_mapped_by_tlbcam(p)))
-               goto out;
-
-       if (mem_init_done) {
-               struct vm_struct *area;
-               area = get_vm_area(size, VM_IOREMAP);
-               if (area == 0)
-                       return NULL;
-               v = (unsigned long) area->addr;
-       } else {
-               v = (ioremap_bot -= size);
-       }
-
-       if ((flags & _PAGE_PRESENT) == 0)
-               flags |= _PAGE_KERNEL;
-       if (flags & _PAGE_NO_CACHE)
-               flags |= _PAGE_GUARDED;
-
-       /*
-        * Should check if it is a candidate for a BAT mapping
-        */
-
-       err = 0;
-       for (i = 0; i < size && err == 0; i += PAGE_SIZE)
-               err = map_page(v+i, p+i, flags);
-       if (err) {
-               if (mem_init_done)
-                       vunmap((void *)v);
-               return NULL;
-       }
-
-out:
-       return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
-}
-
-void iounmap(volatile void __iomem *addr)
-{
-       /*
-        * If mapped by BATs then there is nothing to do.
-        * Calling vfree() generates a benign warning.
-        */
-       if (v_mapped_by_bats((unsigned long)addr)) return;
-
-       if (addr > high_memory && (unsigned long) addr < ioremap_bot)
-               vunmap((void *) (PAGE_MASK & (unsigned long)addr));
-}
-
-void __iomem *ioport_map(unsigned long port, unsigned int len)
-{
-       return (void __iomem *) (port + _IO_BASE);
-}
-
-void ioport_unmap(void __iomem *addr)
-{
-       /* Nothing to do */
-}
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-
-int
-map_page(unsigned long va, phys_addr_t pa, int flags)
-{
-       pmd_t *pd;
-       pte_t *pg;
-       int err = -ENOMEM;
-
-       spin_lock(&init_mm.page_table_lock);
-       /* Use upper 10 bits of VA to index the first level map */
-       pd = pmd_offset(pgd_offset_k(va), va);
-       /* Use middle 10 bits of VA to index the second-level map */
-       pg = pte_alloc_kernel(&init_mm, pd, va);
-       if (pg != 0) {
-               err = 0;
-               set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
-               if (mem_init_done)
-                       flush_HPTE(0, va, pmd_val(*pd));
-       }
-       spin_unlock(&init_mm.page_table_lock);
-       return err;
-}
-
-/*
- * Map in all of physical memory starting at KERNELBASE.
- */
-void __init mapin_ram(void)
-{
-       unsigned long v, p, s, f;
-
-       s = mmu_mapin_ram();
-       v = KERNELBASE + s;
-       p = PPC_MEMSTART + s;
-       for (; s < total_lowmem; s += PAGE_SIZE) {
-               if ((char *) v >= _stext && (char *) v < etext)
-                       f = _PAGE_RAM_TEXT;
-               else
-                       f = _PAGE_RAM;
-               map_page(v, p, f);
-               v += PAGE_SIZE;
-               p += PAGE_SIZE;
-       }
-}
-
-/* is x a power of 2? */
-#define is_power_of_2(x)       ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
-/* is x a power of 4? */
-#define is_power_of_4(x)       ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
-
-/*
- * Set up a mapping for a block of I/O.
- * virt, phys, size must all be page-aligned.
- * This should only be called before ioremap is called.
- */
-void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
-                            unsigned int size, int flags)
-{
-       int i;
-
-       if (virt > KERNELBASE && virt < ioremap_bot)
-               ioremap_bot = ioremap_base = virt;
-
-#ifdef HAVE_BATS
-       /*
-        * Use a BAT for this if possible...
-        */
-       if (io_bat_index < 2 && is_power_of_2(size)
-           && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
-               setbat(io_bat_index, virt, phys, size, flags);
-               ++io_bat_index;
-               return;
-       }
-#endif /* HAVE_BATS */
-
-#ifdef HAVE_TLBCAM
-       /*
-        * Use a CAM for this if possible...
-        */
-       if (tlbcam_index < num_tlbcam_entries && is_power_of_4(size)
-           && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
-               settlbcam(tlbcam_index, virt, phys, size, flags, 0);
-               ++tlbcam_index;
-               return;
-       }
-#endif /* HAVE_TLBCAM */
-
-       /* No BATs available, put it in the page tables. */
-       for (i = 0; i < size; i += PAGE_SIZE)
-               map_page(virt + i, phys + i, flags);
-}
-
-/* Scan the real Linux page tables and return a PTE pointer for
- * a virtual address in a context.
- * Returns true (1) if PTE was found, zero otherwise.  The pointer to
- * the PTE pointer is unmodified if PTE is not found.
- */
-int
-get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
-{
-        pgd_t  *pgd;
-        pmd_t  *pmd;
-        pte_t  *pte;
-        int     retval = 0;
-
-        pgd = pgd_offset(mm, addr & PAGE_MASK);
-        if (pgd) {
-                pmd = pmd_offset(pgd, addr & PAGE_MASK);
-                if (pmd_present(*pmd)) {
-                        pte = pte_offset_map(pmd, addr & PAGE_MASK);
-                        if (pte) {
-                               retval = 1;
-                               *ptep = pte;
-                               /* XXX caller needs to do pte_unmap, yuck */
-                        }
-                }
-        }
-        return(retval);
-}
-
-/* Find physical address for this virtual address.  Normally used by
- * I/O functions, but anyone can call it.
- */
-unsigned long iopa(unsigned long addr)
-{
-       unsigned long pa;
-
-       /* I don't know why this won't work on PMacs or CHRP.  It
-        * appears there is some bug, or there is some implicit
-        * mapping done not properly represented by BATs or in page
-        * tables.......I am actively working on resolving this, but
-        * can't hold up other stuff.  -- Dan
-        */
-       pte_t *pte;
-       struct mm_struct *mm;
-
-       /* Check the BATs */
-       pa = v_mapped_by_bats(addr);
-       if (pa)
-               return pa;
-
-       /* Allow mapping of user addresses (within the thread)
-        * for DMA if necessary.
-        */
-       if (addr < TASK_SIZE)
-               mm = current->mm;
-       else
-               mm = &init_mm;
-
-       pa = 0;
-       if (get_pteptr(mm, addr, &pte)) {
-               pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
-               pte_unmap(pte);
-       }
-
-       return(pa);
-}
-
-/* This is will find the virtual address for a physical one....
- * Swiped from APUS, could be dangerous :-).
- * This is only a placeholder until I really find a way to make this
- * work.  -- Dan
- */
-unsigned long
-mm_ptov (unsigned long paddr)
-{
-       unsigned long ret;
-#if 0
-       if (paddr < 16*1024*1024)
-               ret = ZTWO_VADDR(paddr);
-       else {
-               int i;
-
-               for (i = 0; i < kmap_chunk_count;){
-                       unsigned long phys = kmap_chunks[i++];
-                       unsigned long size = kmap_chunks[i++];
-                       unsigned long virt = kmap_chunks[i++];
-                       if (paddr >= phys
-                           && paddr < (phys + size)){
-                               ret = virt + paddr - phys;
-                               goto exit;
-                       }
-               }
-       
-               ret = (unsigned long) __va(paddr);
-       }
-exit:
-#ifdef DEBUGPV
-       printk ("PTOV(%lx)=%lx\n", paddr, ret);
-#endif
-#else
-       ret = (unsigned long)paddr + KERNELBASE;
-#endif
-       return ret;
-}
-
diff --git a/arch/powerpc/mm/pgtable64.c b/arch/powerpc/mm/pgtable64.c
deleted file mode 100644 (file)
index 724f97e..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- *  This file contains ioremap and related functions for 64-bit machines.
- *
- *  Derived from arch/ppc64/mm/init.c
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@samba.org)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  Dave Engebretsen <engebret@us.ibm.com>
- *      Rework for PPC64 port.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
-
-#include <asm/pgalloc.h>
-#include <asm/page.h>
-#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/tlb.h>
-#include <asm/eeh.h>
-#include <asm/processor.h>
-#include <asm/mmzone.h>
-#include <asm/cputable.h>
-#include <asm/ppcdebug.h>
-#include <asm/sections.h>
-#include <asm/system.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/vdso.h>
-#include <asm/imalloc.h>
-
-#if PGTABLE_RANGE > USER_VSID_RANGE
-#warning Limited user VSID range means pagetable space is wasted
-#endif
-
-#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
-#warning TASK_SIZE is smaller than it needs to be.
-#endif
-
-int mem_init_done;
-unsigned long ioremap_bot = IMALLOC_BASE;
-static unsigned long phbs_io_bot = PHBS_IO_BASE;
-
-extern pgd_t swapper_pg_dir[];
-extern struct task_struct *current_set[NR_CPUS];
-
-unsigned long klimit = (unsigned long)_end;
-
-/* max amount of RAM to use */
-unsigned long __max_memory;
-
-/* info on what we think the IO hole is */
-unsigned long  io_hole_start;
-unsigned long  io_hole_size;
-
-#ifdef CONFIG_PPC_ISERIES
-
-void __iomem *ioremap(unsigned long addr, unsigned long size)
-{
-       return (void __iomem *)addr;
-}
-
-extern void __iomem *__ioremap(unsigned long addr, unsigned long size,
-                      unsigned long flags)
-{
-       return (void __iomem *)addr;
-}
-
-void iounmap(volatile void __iomem *addr)
-{
-       return;
-}
-
-#else
-
-/*
- * map_io_page currently only called by __ioremap
- * map_io_page adds an entry to the ioremap page table
- * and adds an entry to the HPT, possibly bolting it
- */
-static int map_io_page(unsigned long ea, unsigned long pa, int flags)
-{
-       pgd_t *pgdp;
-       pud_t *pudp;
-       pmd_t *pmdp;
-       pte_t *ptep;
-       unsigned long vsid;
-
-       if (mem_init_done) {
-               spin_lock(&init_mm.page_table_lock);
-               pgdp = pgd_offset_k(ea);
-               pudp = pud_alloc(&init_mm, pgdp, ea);
-               if (!pudp)
-                       return -ENOMEM;
-               pmdp = pmd_alloc(&init_mm, pudp, ea);
-               if (!pmdp)
-                       return -ENOMEM;
-               ptep = pte_alloc_kernel(&init_mm, pmdp, ea);
-               if (!ptep)
-                       return -ENOMEM;
-               set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
-                                                         __pgprot(flags)));
-               spin_unlock(&init_mm.page_table_lock);
-       } else {
-               unsigned long va, vpn, hash, hpteg;
-
-               /*
-                * If the mm subsystem is not fully up, we cannot create a
-                * linux page table entry for this mapping.  Simply bolt an
-                * entry in the hardware page table.
-                */
-               vsid = get_kernel_vsid(ea);
-               va = (vsid << 28) | (ea & 0xFFFFFFF);
-               vpn = va >> PAGE_SHIFT;
-
-               hash = hpt_hash(vpn, 0);
-
-               hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
-
-               /* Panic if a pte grpup is full */
-               if (ppc_md.hpte_insert(hpteg, va, pa >> PAGE_SHIFT,
-                                      HPTE_V_BOLTED,
-                                      _PAGE_NO_CACHE|_PAGE_GUARDED|PP_RWXX)
-                   == -1) {
-                       panic("map_io_page: could not insert mapping");
-               }
-       }
-       return 0;
-}
-
-
-static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa,
-                           unsigned long ea, unsigned long size,
-                           unsigned long flags)
-{
-       unsigned long i;
-
-       if ((flags & _PAGE_PRESENT) == 0)
-               flags |= pgprot_val(PAGE_KERNEL);
-
-       for (i = 0; i < size; i += PAGE_SIZE)
-               if (map_io_page(ea+i, pa+i, flags))
-                       return NULL;
-
-       return (void __iomem *) (ea + (addr & ~PAGE_MASK));
-}
-
-
-void __iomem *
-ioremap(unsigned long addr, unsigned long size)
-{
-       return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED);
-}
-
-void __iomem * __ioremap(unsigned long addr, unsigned long size,
-                        unsigned long flags)
-{
-       unsigned long pa, ea;
-       void __iomem *ret;
-
-       /*
-        * Choose an address to map it to.
-        * Once the imalloc system is running, we use it.
-        * Before that, we map using addresses going
-        * up from ioremap_bot.  imalloc will use
-        * the addresses from ioremap_bot through
-        * IMALLOC_END
-        * 
-        */
-       pa = addr & PAGE_MASK;
-       size = PAGE_ALIGN(addr + size) - pa;
-
-       if (size == 0)
-               return NULL;
-
-       if (mem_init_done) {
-               struct vm_struct *area;
-               area = im_get_free_area(size);
-               if (area == NULL)
-                       return NULL;
-               ea = (unsigned long)(area->addr);
-               ret = __ioremap_com(addr, pa, ea, size, flags);
-               if (!ret)
-                       im_free(area->addr);
-       } else {
-               ea = ioremap_bot;
-               ret = __ioremap_com(addr, pa, ea, size, flags);
-               if (ret)
-                       ioremap_bot += size;
-       }
-       return ret;
-}
-
-#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
-
-int __ioremap_explicit(unsigned long pa, unsigned long ea,
-                      unsigned long size, unsigned long flags)
-{
-       struct vm_struct *area;
-       void __iomem *ret;
-       
-       /* For now, require page-aligned values for pa, ea, and size */
-       if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
-           !IS_PAGE_ALIGNED(size)) {
-               printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__);
-               return 1;
-       }
-       
-       if (!mem_init_done) {
-               /* Two things to consider in this case:
-                * 1) No records will be kept (imalloc, etc) that the region
-                *    has been remapped
-                * 2) It won't be easy to iounmap() the region later (because
-                *    of 1)
-                */
-               ;
-       } else {
-               area = im_get_area(ea, size,
-                       IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS);
-               if (area == NULL) {
-                       /* Expected when PHB-dlpar is in play */
-                       return 1;
-               }
-               if (ea != (unsigned long) area->addr) {
-                       printk(KERN_ERR "unexpected addr return from "
-                              "im_get_area\n");
-                       return 1;
-               }
-       }
-       
-       ret = __ioremap_com(pa, pa, ea, size, flags);
-       if (ret == NULL) {
-               printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
-               return 1;
-       }
-       if (ret != (void *) ea) {
-               printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
-               return 1;
-       }
-
-       return 0;
-}
-
-/*  
- * Unmap an IO region and remove it from imalloc'd list.
- * Access to IO memory should be serialized by driver.
- * This code is modeled after vmalloc code - unmap_vm_area()
- *
- * XXX what about calls before mem_init_done (ie python_countermeasures())
- */
-void iounmap(volatile void __iomem *token)
-{
-       void *addr;
-
-       if (!mem_init_done)
-               return;
-       
-       addr = (void *) ((unsigned long __force) token & PAGE_MASK);
-
-       im_free(addr);
-}
-
-static int iounmap_subset_regions(unsigned long addr, unsigned long size)
-{
-       struct vm_struct *area;
-
-       /* Check whether subsets of this region exist */
-       area = im_get_area(addr, size, IM_REGION_SUPERSET);
-       if (area == NULL)
-               return 1;
-
-       while (area) {
-               iounmap((void __iomem *) area->addr);
-               area = im_get_area(addr, size,
-                               IM_REGION_SUPERSET);
-       }
-
-       return 0;
-}
-
-int iounmap_explicit(volatile void __iomem *start, unsigned long size)
-{
-       struct vm_struct *area;
-       unsigned long addr;
-       int rc;
-       
-       addr = (unsigned long __force) start & PAGE_MASK;
-
-       /* Verify that the region either exists or is a subset of an existing
-        * region.  In the latter case, split the parent region to create 
-        * the exact region 
-        */
-       area = im_get_area(addr, size, 
-                           IM_REGION_EXISTS | IM_REGION_SUBSET);
-       if (area == NULL) {
-               /* Determine whether subset regions exist.  If so, unmap */
-               rc = iounmap_subset_regions(addr, size);
-               if (rc) {
-                       printk(KERN_ERR
-                              "%s() cannot unmap nonexistent range 0x%lx\n",
-                               __FUNCTION__, addr);
-                       return 1;
-               }
-       } else {
-               iounmap((void __iomem *) area->addr);
-       }
-       /*
-        * FIXME! This can't be right:
-       iounmap(area->addr);
-        * Maybe it should be "iounmap(area);"
-        */
-       return 0;
-}
-
-#endif
-
-EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
new file mode 100644 (file)
index 0000000..5792e53
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * This file contains the routines setting up the linux page tables.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+
+#include "mmu_decl.h"
+
+unsigned long ioremap_base;
+unsigned long ioremap_bot;
+int io_bat_index;
+
+#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
+#define HAVE_BATS      1
+#endif
+
+#if defined(CONFIG_FSL_BOOKE)
+#define HAVE_TLBCAM    1
+#endif
+
+extern char etext[], _stext[];
+
+#ifdef CONFIG_SMP
+extern void hash_page_sync(void);
+#endif
+
+#ifdef HAVE_BATS
+extern unsigned long v_mapped_by_bats(unsigned long va);
+extern unsigned long p_mapped_by_bats(unsigned long pa);
+void setbat(int index, unsigned long virt, unsigned long phys,
+           unsigned int size, int flags);
+
+#else /* !HAVE_BATS */
+#define v_mapped_by_bats(x)    (0UL)
+#define p_mapped_by_bats(x)    (0UL)
+#endif /* HAVE_BATS */
+
+#ifdef HAVE_TLBCAM
+extern unsigned int tlbcam_index;
+extern unsigned long v_mapped_by_tlbcam(unsigned long va);
+extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
+#else /* !HAVE_TLBCAM */
+#define v_mapped_by_tlbcam(x)  (0UL)
+#define p_mapped_by_tlbcam(x)  (0UL)
+#endif /* HAVE_TLBCAM */
+
+#ifdef CONFIG_PTE_64BIT
+/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
+#define PGDIR_ORDER    1
+#else
+#define PGDIR_ORDER    0
+#endif
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       pgd_t *ret;
+
+       ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER);
+       return ret;
+}
+
+void pgd_free(pgd_t *pgd)
+{
+       free_pages((unsigned long)pgd, PGDIR_ORDER);
+}
+
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+       pte_t *pte;
+       extern int mem_init_done;
+       extern void *early_get_page(void);
+
+       if (mem_init_done) {
+               pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+       } else {
+               pte = (pte_t *)early_get_page();
+               if (pte)
+                       clear_page(pte);
+       }
+       return pte;
+}
+
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+       struct page *ptepage;
+
+#ifdef CONFIG_HIGHPTE
+       int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
+#else
+       int flags = GFP_KERNEL | __GFP_REPEAT;
+#endif
+
+       ptepage = alloc_pages(flags, 0);
+       if (ptepage)
+               clear_highpage(ptepage);
+       return ptepage;
+}
+
+void pte_free_kernel(pte_t *pte)
+{
+#ifdef CONFIG_SMP
+       hash_page_sync();
+#endif
+       free_page((unsigned long)pte);
+}
+
+void pte_free(struct page *ptepage)
+{
+#ifdef CONFIG_SMP
+       hash_page_sync();
+#endif
+       __free_page(ptepage);
+}
+
+#ifndef CONFIG_PHYS_64BIT
+void __iomem *
+ioremap(phys_addr_t addr, unsigned long size)
+{
+       return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+#else /* CONFIG_PHYS_64BIT */
+void __iomem *
+ioremap64(unsigned long long addr, unsigned long size)
+{
+       return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+
+void __iomem *
+ioremap(phys_addr_t addr, unsigned long size)
+{
+       phys_addr_t addr64 = fixup_bigphys_addr(addr, size);
+
+       return ioremap64(addr64, size);
+}
+#endif /* CONFIG_PHYS_64BIT */
+
+void __iomem *
+__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+       unsigned long v, i;
+       phys_addr_t p;
+       int err;
+
+       /*
+        * Choose an address to map it to.
+        * Once the vmalloc system is running, we use it.
+        * Before then, we use space going down from ioremap_base
+        * (ioremap_bot records where we're up to).
+        */
+       p = addr & PAGE_MASK;
+       size = PAGE_ALIGN(addr + size) - p;
+
+       /*
+        * If the address lies within the first 16 MB, assume it's in ISA
+        * memory space
+        */
+       if (p < 16*1024*1024)
+               p += _ISA_MEM_BASE;
+
+       /*
+        * Don't allow anybody to remap normal RAM that we're using.
+        * mem_init() sets high_memory so only do the check after that.
+        */
+       if (mem_init_done && (p < virt_to_phys(high_memory))) {
+               printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
+                      __builtin_return_address(0));
+               return NULL;
+       }
+
+       if (size == 0)
+               return NULL;
+
+       /*
+        * Is it already mapped?  Perhaps overlapped by a previous
+        * BAT mapping.  If the whole area is mapped then we're done,
+        * otherwise remap it since we want to keep the virt addrs for
+        * each request contiguous.
+        *
+        * We make the assumption here that if the bottom and top
+        * of the range we want are mapped then it's mapped to the
+        * same virt address (and this is contiguous).
+        *  -- Cort
+        */
+       if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
+               goto out;
+
+       if ((v = p_mapped_by_tlbcam(p)))
+               goto out;
+
+       if (mem_init_done) {
+               struct vm_struct *area;
+               area = get_vm_area(size, VM_IOREMAP);
+               if (area == 0)
+                       return NULL;
+               v = (unsigned long) area->addr;
+       } else {
+               v = (ioremap_bot -= size);
+       }
+
+       if ((flags & _PAGE_PRESENT) == 0)
+               flags |= _PAGE_KERNEL;
+       if (flags & _PAGE_NO_CACHE)
+               flags |= _PAGE_GUARDED;
+
+       /*
+        * Should check if it is a candidate for a BAT mapping
+        */
+
+       err = 0;
+       for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+               err = map_page(v+i, p+i, flags);
+       if (err) {
+               if (mem_init_done)
+                       vunmap((void *)v);
+               return NULL;
+       }
+
+out:
+       return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
+}
+
+void iounmap(volatile void __iomem *addr)
+{
+       /*
+        * If mapped by BATs then there is nothing to do.
+        * Calling vfree() generates a benign warning.
+        */
+       if (v_mapped_by_bats((unsigned long)addr)) return;
+
+       if (addr > high_memory && (unsigned long) addr < ioremap_bot)
+               vunmap((void *) (PAGE_MASK & (unsigned long)addr));
+}
+
+void __iomem *ioport_map(unsigned long port, unsigned int len)
+{
+       return (void __iomem *) (port + _IO_BASE);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+
+int
+map_page(unsigned long va, phys_addr_t pa, int flags)
+{
+       pmd_t *pd;
+       pte_t *pg;
+       int err = -ENOMEM;
+
+       spin_lock(&init_mm.page_table_lock);
+       /* Use upper 10 bits of VA to index the first level map */
+       pd = pmd_offset(pgd_offset_k(va), va);
+       /* Use middle 10 bits of VA to index the second-level map */
+       pg = pte_alloc_kernel(&init_mm, pd, va);
+       if (pg != 0) {
+               err = 0;
+               set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
+               if (mem_init_done)
+                       flush_HPTE(0, va, pmd_val(*pd));
+       }
+       spin_unlock(&init_mm.page_table_lock);
+       return err;
+}
+
+/*
+ * Map in all of physical memory starting at KERNELBASE.
+ */
+void __init mapin_ram(void)
+{
+       unsigned long v, p, s, f;
+
+       s = mmu_mapin_ram();
+       v = KERNELBASE + s;
+       p = PPC_MEMSTART + s;
+       for (; s < total_lowmem; s += PAGE_SIZE) {
+               if ((char *) v >= _stext && (char *) v < etext)
+                       f = _PAGE_RAM_TEXT;
+               else
+                       f = _PAGE_RAM;
+               map_page(v, p, f);
+               v += PAGE_SIZE;
+               p += PAGE_SIZE;
+       }
+}
+
+/* is x a power of 2? */
+#define is_power_of_2(x)       ((x) != 0 && (((x) & ((x) - 1)) == 0))
+
+/* is x a power of 4? */
+#define is_power_of_4(x)       ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+
+/*
+ * Set up a mapping for a block of I/O.
+ * virt, phys, size must all be page-aligned.
+ * This should only be called before ioremap is called.
+ */
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
+                            unsigned int size, int flags)
+{
+       int i;
+
+       if (virt > KERNELBASE && virt < ioremap_bot)
+               ioremap_bot = ioremap_base = virt;
+
+#ifdef HAVE_BATS
+       /*
+        * Use a BAT for this if possible...
+        */
+       if (io_bat_index < 2 && is_power_of_2(size)
+           && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
+               setbat(io_bat_index, virt, phys, size, flags);
+               ++io_bat_index;
+               return;
+       }
+#endif /* HAVE_BATS */
+
+#ifdef HAVE_TLBCAM
+       /*
+        * Use a CAM for this if possible...
+        */
+       if (tlbcam_index < num_tlbcam_entries && is_power_of_4(size)
+           && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
+               settlbcam(tlbcam_index, virt, phys, size, flags, 0);
+               ++tlbcam_index;
+               return;
+       }
+#endif /* HAVE_TLBCAM */
+
+       /* No BATs available, put it in the page tables. */
+       for (i = 0; i < size; i += PAGE_SIZE)
+               map_page(virt + i, phys + i, flags);
+}
+
+/* Scan the real Linux page tables and return a PTE pointer for
+ * a virtual address in a context.
+ * Returns true (1) if PTE was found, zero otherwise.  The pointer to
+ * the PTE pointer is unmodified if PTE is not found.
+ */
+int
+get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+{
+        pgd_t  *pgd;
+        pmd_t  *pmd;
+        pte_t  *pte;
+        int     retval = 0;
+
+        pgd = pgd_offset(mm, addr & PAGE_MASK);
+        if (pgd) {
+                pmd = pmd_offset(pgd, addr & PAGE_MASK);
+                if (pmd_present(*pmd)) {
+                        pte = pte_offset_map(pmd, addr & PAGE_MASK);
+                        if (pte) {
+                               retval = 1;
+                               *ptep = pte;
+                               /* XXX caller needs to do pte_unmap, yuck */
+                        }
+                }
+        }
+        return(retval);
+}
+
+/* Find physical address for this virtual address.  Normally used by
+ * I/O functions, but anyone can call it.
+ */
+unsigned long iopa(unsigned long addr)
+{
+       unsigned long pa;
+
+       /* I don't know why this won't work on PMacs or CHRP.  It
+        * appears there is some bug, or there is some implicit
+        * mapping done not properly represented by BATs or in page
+        * tables.......I am actively working on resolving this, but
+        * can't hold up other stuff.  -- Dan
+        */
+       pte_t *pte;
+       struct mm_struct *mm;
+
+       /* Check the BATs */
+       pa = v_mapped_by_bats(addr);
+       if (pa)
+               return pa;
+
+       /* Allow mapping of user addresses (within the thread)
+        * for DMA if necessary.
+        */
+       if (addr < TASK_SIZE)
+               mm = current->mm;
+       else
+               mm = &init_mm;
+
+       pa = 0;
+       if (get_pteptr(mm, addr, &pte)) {
+               pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
+               pte_unmap(pte);
+       }
+
+       return(pa);
+}
+
+/* This is will find the virtual address for a physical one....
+ * Swiped from APUS, could be dangerous :-).
+ * This is only a placeholder until I really find a way to make this
+ * work.  -- Dan
+ */
+unsigned long
+mm_ptov (unsigned long paddr)
+{
+       unsigned long ret;
+#if 0
+       if (paddr < 16*1024*1024)
+               ret = ZTWO_VADDR(paddr);
+       else {
+               int i;
+
+               for (i = 0; i < kmap_chunk_count;){
+                       unsigned long phys = kmap_chunks[i++];
+                       unsigned long size = kmap_chunks[i++];
+                       unsigned long virt = kmap_chunks[i++];
+                       if (paddr >= phys
+                           && paddr < (phys + size)){
+                               ret = virt + paddr - phys;
+                               goto exit;
+                       }
+               }
+       
+               ret = (unsigned long) __va(paddr);
+       }
+exit:
+#ifdef DEBUGPV
+       printk ("PTOV(%lx)=%lx\n", paddr, ret);
+#endif
+#else
+       ret = (unsigned long)paddr + KERNELBASE;
+#endif
+       return ret;
+}
+
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
new file mode 100644 (file)
index 0000000..724f97e
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  This file contains ioremap and related functions for 64-bit machines.
+ *
+ *  Derived from arch/ppc64/mm/init.c
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@samba.org)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Dave Engebretsen <engebret@us.ibm.com>
+ *      Rework for PPC64 port.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/idr.h>
+#include <linux/nodemask.h>
+#include <linux/module.h>
+
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+#include <asm/rtas.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/tlb.h>
+#include <asm/eeh.h>
+#include <asm/processor.h>
+#include <asm/mmzone.h>
+#include <asm/cputable.h>
+#include <asm/ppcdebug.h>
+#include <asm/sections.h>
+#include <asm/system.h>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
+#include <asm/vdso.h>
+#include <asm/imalloc.h>
+
+#if PGTABLE_RANGE > USER_VSID_RANGE
+#warning Limited user VSID range means pagetable space is wasted
+#endif
+
+#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
+#warning TASK_SIZE is smaller than it needs to be.
+#endif
+
+int mem_init_done;
+unsigned long ioremap_bot = IMALLOC_BASE;
+static unsigned long phbs_io_bot = PHBS_IO_BASE;
+
+extern pgd_t swapper_pg_dir[];
+extern struct task_struct *current_set[NR_CPUS];
+
+unsigned long klimit = (unsigned long)_end;
+
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
+/* info on what we think the IO hole is */
+unsigned long  io_hole_start;
+unsigned long  io_hole_size;
+
+#ifdef CONFIG_PPC_ISERIES
+
+void __iomem *ioremap(unsigned long addr, unsigned long size)
+{
+       return (void __iomem *)addr;
+}
+
+extern void __iomem *__ioremap(unsigned long addr, unsigned long size,
+                      unsigned long flags)
+{
+       return (void __iomem *)addr;
+}
+
+void iounmap(volatile void __iomem *addr)
+{
+       return;
+}
+
+#else
+
+/*
+ * map_io_page currently only called by __ioremap
+ * map_io_page adds an entry to the ioremap page table
+ * and adds an entry to the HPT, possibly bolting it
+ */
+static int map_io_page(unsigned long ea, unsigned long pa, int flags)
+{
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       unsigned long vsid;
+
+       if (mem_init_done) {
+               spin_lock(&init_mm.page_table_lock);
+               pgdp = pgd_offset_k(ea);
+               pudp = pud_alloc(&init_mm, pgdp, ea);
+               if (!pudp)
+                       return -ENOMEM;
+               pmdp = pmd_alloc(&init_mm, pudp, ea);
+               if (!pmdp)
+                       return -ENOMEM;
+               ptep = pte_alloc_kernel(&init_mm, pmdp, ea);
+               if (!ptep)
+                       return -ENOMEM;
+               set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
+                                                         __pgprot(flags)));
+               spin_unlock(&init_mm.page_table_lock);
+       } else {
+               unsigned long va, vpn, hash, hpteg;
+
+               /*
+                * If the mm subsystem is not fully up, we cannot create a
+                * linux page table entry for this mapping.  Simply bolt an
+                * entry in the hardware page table.
+                */
+               vsid = get_kernel_vsid(ea);
+               va = (vsid << 28) | (ea & 0xFFFFFFF);
+               vpn = va >> PAGE_SHIFT;
+
+               hash = hpt_hash(vpn, 0);
+
+               hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+
+               /* Panic if a pte grpup is full */
+               if (ppc_md.hpte_insert(hpteg, va, pa >> PAGE_SHIFT,
+                                      HPTE_V_BOLTED,
+                                      _PAGE_NO_CACHE|_PAGE_GUARDED|PP_RWXX)
+                   == -1) {
+                       panic("map_io_page: could not insert mapping");
+               }
+       }
+       return 0;
+}
+
+
+static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa,
+                           unsigned long ea, unsigned long size,
+                           unsigned long flags)
+{
+       unsigned long i;
+
+       if ((flags & _PAGE_PRESENT) == 0)
+               flags |= pgprot_val(PAGE_KERNEL);
+
+       for (i = 0; i < size; i += PAGE_SIZE)
+               if (map_io_page(ea+i, pa+i, flags))
+                       return NULL;
+
+       return (void __iomem *) (ea + (addr & ~PAGE_MASK));
+}
+
+
+void __iomem *
+ioremap(unsigned long addr, unsigned long size)
+{
+       return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED);
+}
+
+void __iomem * __ioremap(unsigned long addr, unsigned long size,
+                        unsigned long flags)
+{
+       unsigned long pa, ea;
+       void __iomem *ret;
+
+       /*
+        * Choose an address to map it to.
+        * Once the imalloc system is running, we use it.
+        * Before that, we map using addresses going
+        * up from ioremap_bot.  imalloc will use
+        * the addresses from ioremap_bot through
+        * IMALLOC_END
+        * 
+        */
+       pa = addr & PAGE_MASK;
+       size = PAGE_ALIGN(addr + size) - pa;
+
+       if (size == 0)
+               return NULL;
+
+       if (mem_init_done) {
+               struct vm_struct *area;
+               area = im_get_free_area(size);
+               if (area == NULL)
+                       return NULL;
+               ea = (unsigned long)(area->addr);
+               ret = __ioremap_com(addr, pa, ea, size, flags);
+               if (!ret)
+                       im_free(area->addr);
+       } else {
+               ea = ioremap_bot;
+               ret = __ioremap_com(addr, pa, ea, size, flags);
+               if (ret)
+                       ioremap_bot += size;
+       }
+       return ret;
+}
+
+#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
+
+int __ioremap_explicit(unsigned long pa, unsigned long ea,
+                      unsigned long size, unsigned long flags)
+{
+       struct vm_struct *area;
+       void __iomem *ret;
+       
+       /* For now, require page-aligned values for pa, ea, and size */
+       if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
+           !IS_PAGE_ALIGNED(size)) {
+               printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__);
+               return 1;
+       }
+       
+       if (!mem_init_done) {
+               /* Two things to consider in this case:
+                * 1) No records will be kept (imalloc, etc) that the region
+                *    has been remapped
+                * 2) It won't be easy to iounmap() the region later (because
+                *    of 1)
+                */
+               ;
+       } else {
+               area = im_get_area(ea, size,
+                       IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS);
+               if (area == NULL) {
+                       /* Expected when PHB-dlpar is in play */
+                       return 1;
+               }
+               if (ea != (unsigned long) area->addr) {
+                       printk(KERN_ERR "unexpected addr return from "
+                              "im_get_area\n");
+                       return 1;
+               }
+       }
+       
+       ret = __ioremap_com(pa, pa, ea, size, flags);
+       if (ret == NULL) {
+               printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
+               return 1;
+       }
+       if (ret != (void *) ea) {
+               printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+/*  
+ * Unmap an IO region and remove it from imalloc'd list.
+ * Access to IO memory should be serialized by driver.
+ * This code is modeled after vmalloc code - unmap_vm_area()
+ *
+ * XXX what about calls before mem_init_done (ie python_countermeasures())
+ */
+void iounmap(volatile void __iomem *token)
+{
+       void *addr;
+
+       if (!mem_init_done)
+               return;
+       
+       addr = (void *) ((unsigned long __force) token & PAGE_MASK);
+
+       im_free(addr);
+}
+
+static int iounmap_subset_regions(unsigned long addr, unsigned long size)
+{
+       struct vm_struct *area;
+
+       /* Check whether subsets of this region exist */
+       area = im_get_area(addr, size, IM_REGION_SUPERSET);
+       if (area == NULL)
+               return 1;
+
+       while (area) {
+               iounmap((void __iomem *) area->addr);
+               area = im_get_area(addr, size,
+                               IM_REGION_SUPERSET);
+       }
+
+       return 0;
+}
+
+int iounmap_explicit(volatile void __iomem *start, unsigned long size)
+{
+       struct vm_struct *area;
+       unsigned long addr;
+       int rc;
+       
+       addr = (unsigned long __force) start & PAGE_MASK;
+
+       /* Verify that the region either exists or is a subset of an existing
+        * region.  In the latter case, split the parent region to create 
+        * the exact region 
+        */
+       area = im_get_area(addr, size, 
+                           IM_REGION_EXISTS | IM_REGION_SUBSET);
+       if (area == NULL) {
+               /* Determine whether subset regions exist.  If so, unmap */
+               rc = iounmap_subset_regions(addr, size);
+               if (rc) {
+                       printk(KERN_ERR
+                              "%s() cannot unmap nonexistent range 0x%lx\n",
+                               __FUNCTION__, addr);
+                       return 1;
+               }
+       } else {
+               iounmap((void __iomem *) area->addr);
+       }
+       /*
+        * FIXME! This can't be right:
+       iounmap(area->addr);
+        * Maybe it should be "iounmap(area);"
+        */
+       return 0;
+}
+
+#endif
+
+EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/ppc_mmu.c b/arch/powerpc/mm/ppc_mmu.c
deleted file mode 100644 (file)
index cef9e83..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * This file contains the routines for handling the MMU on those
- * PowerPC implementations where the MMU substantially follows the
- * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-
-#include <asm/prom.h>
-#include <asm/mmu.h>
-#include <asm/machdep.h>
-#include <asm/lmb.h>
-
-#include "mmu_decl.h"
-
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long _SDR1;
-
-union ubat {                   /* BAT register values to be loaded */
-       BAT     bat;
-#ifdef CONFIG_PPC64BRIDGE
-       u64     word[2];
-#else
-       u32     word[2];
-#endif
-} BATS[4][2];                  /* 4 pairs of IBAT, DBAT */
-
-struct batrange {              /* stores address ranges mapped by BATs */
-       unsigned long start;
-       unsigned long limit;
-       unsigned long phys;
-} bat_addrs[4];
-
-/*
- * Return PA for this VA if it is mapped by a BAT, or 0
- */
-unsigned long v_mapped_by_bats(unsigned long va)
-{
-       int b;
-       for (b = 0; b < 4; ++b)
-               if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
-                       return bat_addrs[b].phys + (va - bat_addrs[b].start);
-       return 0;
-}
-
-/*
- * Return VA for a given PA or 0 if not mapped
- */
-unsigned long p_mapped_by_bats(unsigned long pa)
-{
-       int b;
-       for (b = 0; b < 4; ++b)
-               if (pa >= bat_addrs[b].phys
-                   && pa < (bat_addrs[b].limit-bat_addrs[b].start)
-                             +bat_addrs[b].phys)
-                       return bat_addrs[b].start+(pa-bat_addrs[b].phys);
-       return 0;
-}
-
-unsigned long __init mmu_mapin_ram(void)
-{
-#ifdef CONFIG_POWER4
-       return 0;
-#else
-       unsigned long tot, bl, done;
-       unsigned long max_size = (256<<20);
-       unsigned long align;
-
-       if (__map_without_bats)
-               return 0;
-
-       /* Set up BAT2 and if necessary BAT3 to cover RAM. */
-
-       /* Make sure we don't map a block larger than the
-          smallest alignment of the physical address. */
-       /* alignment of PPC_MEMSTART */
-       align = ~(PPC_MEMSTART-1) & PPC_MEMSTART;
-       /* set BAT block size to MIN(max_size, align) */
-       if (align && align < max_size)
-               max_size = align;
-
-       tot = total_lowmem;
-       for (bl = 128<<10; bl < max_size; bl <<= 1) {
-               if (bl * 2 > tot)
-                       break;
-       }
-
-       setbat(2, KERNELBASE, PPC_MEMSTART, bl, _PAGE_RAM);
-       done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-       if ((done < tot) && !bat_addrs[3].limit) {
-               /* use BAT3 to cover a bit more */
-               tot -= done;
-               for (bl = 128<<10; bl < max_size; bl <<= 1)
-                       if (bl * 2 > tot)
-                               break;
-               setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bl, _PAGE_RAM);
-               done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1;
-       }
-
-       return done;
-#endif
-}
-
-/*
- * Set up one of the I/D BAT (block address translation) register pairs.
- * The parameters are not checked; in particular size must be a power
- * of 2 between 128k and 256M.
- */
-void __init setbat(int index, unsigned long virt, unsigned long phys,
-                  unsigned int size, int flags)
-{
-       unsigned int bl;
-       int wimgxpp;
-       union ubat *bat = BATS[index];
-
-       if (((flags & _PAGE_NO_CACHE) == 0) &&
-           cpu_has_feature(CPU_FTR_NEED_COHERENT))
-               flags |= _PAGE_COHERENT;
-
-       bl = (size >> 17) - 1;
-       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
-               /* 603, 604, etc. */
-               /* Do DBAT first */
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT | _PAGE_GUARDED);
-               wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
-               bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
-               bat[1].word[1] = phys | wimgxpp;
-#ifndef CONFIG_KGDB /* want user access for breakpoints */
-               if (flags & _PAGE_USER)
-#endif
-                       bat[1].bat.batu.vp = 1;
-               if (flags & _PAGE_GUARDED) {
-                       /* G bit must be zero in IBATs */
-                       bat[0].word[0] = bat[0].word[1] = 0;
-               } else {
-                       /* make IBAT same as DBAT */
-                       bat[0] = bat[1];
-               }
-       } else {
-               /* 601 cpu */
-               if (bl > BL_8M)
-                       bl = BL_8M;
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT);
-               wimgxpp |= (flags & _PAGE_RW)?
-                       ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
-               bat->word[0] = virt | wimgxpp | 4;      /* Ks=0, Ku=1 */
-               bat->word[1] = phys | bl | 0x40;        /* V=1 */
-       }
-
-       bat_addrs[index].start = virt;
-       bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
-       bat_addrs[index].phys = phys;
-}
-
-/*
- * Initialize the hash table and patch the instructions in hashtable.S.
- */
-void __init MMU_init_hw(void)
-{
-       unsigned int hmask, mb, mb2;
-       unsigned int n_hpteg, lg_n_hpteg;
-
-       extern unsigned int hash_page_patch_A[];
-       extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
-       extern unsigned int hash_page[];
-       extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
-
-       if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) {
-               /*
-                * Put a blr (procedure return) instruction at the
-                * start of hash_page, since we can still get DSI
-                * exceptions on a 603.
-                */
-               hash_page[0] = 0x4e800020;
-               flush_icache_range((unsigned long) &hash_page[0],
-                                  (unsigned long) &hash_page[1]);
-               return;
-       }
-
-       if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
-
-#ifdef CONFIG_PPC64BRIDGE
-#define LG_HPTEG_SIZE  7               /* 128 bytes per HPTEG */
-#define SDR1_LOW_BITS  (lg_n_hpteg - 11)
-#define MIN_N_HPTEG    2048            /* min 256kB hash table */
-#else
-#define LG_HPTEG_SIZE  6               /* 64 bytes per HPTEG */
-#define SDR1_LOW_BITS  ((n_hpteg - 1) >> 10)
-#define MIN_N_HPTEG    1024            /* min 64kB hash table */
-#endif
-
-       /*
-        * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
-        * This is less than the recommended amount, but then
-        * Linux ain't AIX.
-        */
-       n_hpteg = total_memory / (PAGE_SIZE * 8);
-       if (n_hpteg < MIN_N_HPTEG)
-               n_hpteg = MIN_N_HPTEG;
-       lg_n_hpteg = __ilog2(n_hpteg);
-       if (n_hpteg & (n_hpteg - 1)) {
-               ++lg_n_hpteg;           /* round up if not power of 2 */
-               n_hpteg = 1 << lg_n_hpteg;
-       }
-       Hash_size = n_hpteg << LG_HPTEG_SIZE;
-
-       /*
-        * Find some memory for the hash table.
-        */
-       if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-       Hash = __va(lmb_alloc_base(Hash_size, Hash_size,
-                                  __initial_memory_limit));
-       cacheable_memzero(Hash, Hash_size);
-       _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
-
-       Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
-
-       printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
-              total_memory >> 20, Hash_size >> 10, Hash);
-
-
-       /*
-        * Patch up the instructions in hashtable.S:create_hpte
-        */
-       if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
-       Hash_mask = n_hpteg - 1;
-       hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
-       mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
-       if (lg_n_hpteg > 16)
-               mb2 = 16 - LG_HPTEG_SIZE;
-
-       hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
-               | ((unsigned int)(Hash) >> 16);
-       hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
-       hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | (mb2 << 6);
-       hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | hmask;
-       hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask;
-
-       /*
-        * Ensure that the locations we've patched have been written
-        * out from the data cache and invalidated in the instruction
-        * cache, on those machines with split caches.
-        */
-       flush_icache_range((unsigned long) &hash_page_patch_A[0],
-                          (unsigned long) &hash_page_patch_C[1]);
-
-       /*
-        * Patch up the instructions in hashtable.S:flush_hash_page
-        */
-       flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
-               | ((unsigned int)(Hash) >> 16);
-       flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) | (mb << 6);
-       flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) | (mb2 << 6);
-       flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) | hmask;
-       flush_icache_range((unsigned long) &flush_hash_patch_A[0],
-                          (unsigned long) &flush_hash_patch_B[1]);
-
-       if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
-}
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
new file mode 100644 (file)
index 0000000..cef9e83
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU substantially follows the
+ * architecture specification.  This includes the 6xx, 7xx, 7xxx,
+ * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+#include <asm/prom.h>
+#include <asm/mmu.h>
+#include <asm/machdep.h>
+#include <asm/lmb.h>
+
+#include "mmu_decl.h"
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long _SDR1;
+
+union ubat {                   /* BAT register values to be loaded */
+       BAT     bat;
+#ifdef CONFIG_PPC64BRIDGE
+       u64     word[2];
+#else
+       u32     word[2];
+#endif
+} BATS[4][2];                  /* 4 pairs of IBAT, DBAT */
+
+struct batrange {              /* stores address ranges mapped by BATs */
+       unsigned long start;
+       unsigned long limit;
+       unsigned long phys;
+} bat_addrs[4];
+
+/*
+ * Return PA for this VA if it is mapped by a BAT, or 0
+ */
+unsigned long v_mapped_by_bats(unsigned long va)
+{
+       int b;
+       for (b = 0; b < 4; ++b)
+               if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
+                       return bat_addrs[b].phys + (va - bat_addrs[b].start);
+       return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long p_mapped_by_bats(unsigned long pa)
+{
+       int b;
+       for (b = 0; b < 4; ++b)
+               if (pa >= bat_addrs[b].phys
+                   && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+                             +bat_addrs[b].phys)
+                       return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+       return 0;
+}
+
+unsigned long __init mmu_mapin_ram(void)
+{
+#ifdef CONFIG_POWER4
+       return 0;
+#else
+       unsigned long tot, bl, done;
+       unsigned long max_size = (256<<20);
+       unsigned long align;
+
+       if (__map_without_bats)
+               return 0;
+
+       /* Set up BAT2 and if necessary BAT3 to cover RAM. */
+
+       /* Make sure we don't map a block larger than the
+          smallest alignment of the physical address. */
+       /* alignment of PPC_MEMSTART */
+       align = ~(PPC_MEMSTART-1) & PPC_MEMSTART;
+       /* set BAT block size to MIN(max_size, align) */
+       if (align && align < max_size)
+               max_size = align;
+
+       tot = total_lowmem;
+       for (bl = 128<<10; bl < max_size; bl <<= 1) {
+               if (bl * 2 > tot)
+                       break;
+       }
+
+       setbat(2, KERNELBASE, PPC_MEMSTART, bl, _PAGE_RAM);
+       done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
+       if ((done < tot) && !bat_addrs[3].limit) {
+               /* use BAT3 to cover a bit more */
+               tot -= done;
+               for (bl = 128<<10; bl < max_size; bl <<= 1)
+                       if (bl * 2 > tot)
+                               break;
+               setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bl, _PAGE_RAM);
+               done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1;
+       }
+
+       return done;
+#endif
+}
+
+/*
+ * Set up one of the I/D BAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ */
+void __init setbat(int index, unsigned long virt, unsigned long phys,
+                  unsigned int size, int flags)
+{
+       unsigned int bl;
+       int wimgxpp;
+       union ubat *bat = BATS[index];
+
+       if (((flags & _PAGE_NO_CACHE) == 0) &&
+           cpu_has_feature(CPU_FTR_NEED_COHERENT))
+               flags |= _PAGE_COHERENT;
+
+       bl = (size >> 17) - 1;
+       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
+               /* 603, 604, etc. */
+               /* Do DBAT first */
+               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+                                  | _PAGE_COHERENT | _PAGE_GUARDED);
+               wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+               bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+               bat[1].word[1] = phys | wimgxpp;
+#ifndef CONFIG_KGDB /* want user access for breakpoints */
+               if (flags & _PAGE_USER)
+#endif
+                       bat[1].bat.batu.vp = 1;
+               if (flags & _PAGE_GUARDED) {
+                       /* G bit must be zero in IBATs */
+                       bat[0].word[0] = bat[0].word[1] = 0;
+               } else {
+                       /* make IBAT same as DBAT */
+                       bat[0] = bat[1];
+               }
+       } else {
+               /* 601 cpu */
+               if (bl > BL_8M)
+                       bl = BL_8M;
+               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+                                  | _PAGE_COHERENT);
+               wimgxpp |= (flags & _PAGE_RW)?
+                       ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
+               bat->word[0] = virt | wimgxpp | 4;      /* Ks=0, Ku=1 */
+               bat->word[1] = phys | bl | 0x40;        /* V=1 */
+       }
+
+       bat_addrs[index].start = virt;
+       bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
+       bat_addrs[index].phys = phys;
+}
+
+/*
+ * Initialize the hash table and patch the instructions in hashtable.S.
+ */
+void __init MMU_init_hw(void)
+{
+       unsigned int hmask, mb, mb2;
+       unsigned int n_hpteg, lg_n_hpteg;
+
+       extern unsigned int hash_page_patch_A[];
+       extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
+       extern unsigned int hash_page[];
+       extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
+
+       if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) {
+               /*
+                * Put a blr (procedure return) instruction at the
+                * start of hash_page, since we can still get DSI
+                * exceptions on a 603.
+                */
+               hash_page[0] = 0x4e800020;
+               flush_icache_range((unsigned long) &hash_page[0],
+                                  (unsigned long) &hash_page[1]);
+               return;
+       }
+
+       if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
+
+#ifdef CONFIG_PPC64BRIDGE
+#define LG_HPTEG_SIZE  7               /* 128 bytes per HPTEG */
+#define SDR1_LOW_BITS  (lg_n_hpteg - 11)
+#define MIN_N_HPTEG    2048            /* min 256kB hash table */
+#else
+#define LG_HPTEG_SIZE  6               /* 64 bytes per HPTEG */
+#define SDR1_LOW_BITS  ((n_hpteg - 1) >> 10)
+#define MIN_N_HPTEG    1024            /* min 64kB hash table */
+#endif
+
+       /*
+        * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
+        * This is less than the recommended amount, but then
+        * Linux ain't AIX.
+        */
+       n_hpteg = total_memory / (PAGE_SIZE * 8);
+       if (n_hpteg < MIN_N_HPTEG)
+               n_hpteg = MIN_N_HPTEG;
+       lg_n_hpteg = __ilog2(n_hpteg);
+       if (n_hpteg & (n_hpteg - 1)) {
+               ++lg_n_hpteg;           /* round up if not power of 2 */
+               n_hpteg = 1 << lg_n_hpteg;
+       }
+       Hash_size = n_hpteg << LG_HPTEG_SIZE;
+
+       /*
+        * Find some memory for the hash table.
+        */
+       if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
+       Hash = __va(lmb_alloc_base(Hash_size, Hash_size,
+                                  __initial_memory_limit));
+       cacheable_memzero(Hash, Hash_size);
+       _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
+
+       Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+       printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+              total_memory >> 20, Hash_size >> 10, Hash);
+
+
+       /*
+        * Patch up the instructions in hashtable.S:create_hpte
+        */
+       if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+       Hash_mask = n_hpteg - 1;
+       hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
+       mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
+       if (lg_n_hpteg > 16)
+               mb2 = 16 - LG_HPTEG_SIZE;
+
+       hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+               | ((unsigned int)(Hash) >> 16);
+       hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
+       hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | (mb2 << 6);
+       hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | hmask;
+       hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask;
+
+       /*
+        * Ensure that the locations we've patched have been written
+        * out from the data cache and invalidated in the instruction
+        * cache, on those machines with split caches.
+        */
+       flush_icache_range((unsigned long) &hash_page_patch_A[0],
+                          (unsigned long) &hash_page_patch_C[1]);
+
+       /*
+        * Patch up the instructions in hashtable.S:flush_hash_page
+        */
+       flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
+               | ((unsigned int)(Hash) >> 16);
+       flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) | (mb << 6);
+       flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) | (mb2 << 6);
+       flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) | hmask;
+       flush_icache_range((unsigned long) &flush_hash_patch_A[0],
+                          (unsigned long) &flush_hash_patch_B[1]);
+
+       if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
+}
diff --git a/arch/powerpc/mm/tlb.c b/arch/powerpc/mm/tlb.c
deleted file mode 100644 (file)
index 6c3dc3c..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * This file contains the routines for TLB flushing.
- * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the
- * hash table also.
- *  -- paulus
- *
- *  Derived from arch/ppc/mm/init.c:
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
- *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- *  Derived from "arch/i386/mm/init.c"
- *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-#include <asm/tlbflush.h>
-#include <asm/tlb.h>
-
-#include "mmu_decl.h"
-
-/*
- * Called when unmapping pages to flush entries from the TLB/hash table.
- */
-void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
-{
-       unsigned long ptephys;
-
-       if (Hash != 0) {
-               ptephys = __pa(ptep) & PAGE_MASK;
-               flush_hash_pages(mm->context, addr, ptephys, 1);
-       }
-}
-
-/*
- * Called by ptep_set_access_flags, must flush on CPUs for which the
- * DSI handler can't just "fixup" the TLB on a write fault
- */
-void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr)
-{
-       if (Hash != 0)
-               return;
-       _tlbie(addr);
-}
-
-/*
- * Called at the end of a mmu_gather operation to make sure the
- * TLB flush is completely done.
- */
-void tlb_flush(struct mmu_gather *tlb)
-{
-       if (Hash == 0) {
-               /*
-                * 603 needs to flush the whole TLB here since
-                * it doesn't use a hash table.
-                */
-               _tlbia();
-       }
-}
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(vma, start, end) flushes a range of pages
- *  - flush_tlb_kernel_range(start, end) flushes kernel pages
- *
- * since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush it too.
- *    -- Cort
- */
-
-/*
- * 750 SMP is a Bad Idea because the 750 doesn't broadcast all
- * the cache operations on the bus.  Hence we need to use an IPI
- * to get the other CPU(s) to invalidate their TLBs.
- */
-#ifdef CONFIG_SMP_750
-#define FINISH_FLUSH   smp_send_tlb_invalidate(0)
-#else
-#define FINISH_FLUSH   do { } while (0)
-#endif
-
-static void flush_range(struct mm_struct *mm, unsigned long start,
-                       unsigned long end)
-{
-       pmd_t *pmd;
-       unsigned long pmd_end;
-       int count;
-       unsigned int ctx = mm->context;
-
-       if (Hash == 0) {
-               _tlbia();
-               return;
-       }
-       start &= PAGE_MASK;
-       if (start >= end)
-               return;
-       end = (end - 1) | ~PAGE_MASK;
-       pmd = pmd_offset(pgd_offset(mm, start), start);
-       for (;;) {
-               pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
-               if (pmd_end > end)
-                       pmd_end = end;
-               if (!pmd_none(*pmd)) {
-                       count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
-                       flush_hash_pages(ctx, start, pmd_val(*pmd), count);
-               }
-               if (pmd_end == end)
-                       break;
-               start = pmd_end + 1;
-               ++pmd;
-       }
-}
-
-/*
- * Flush kernel TLB entries in the given range
- */
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       flush_range(&init_mm, start, end);
-       FINISH_FLUSH;
-}
-
-/*
- * Flush all the (user) entries for the address space described by mm.
- */
-void flush_tlb_mm(struct mm_struct *mm)
-{
-       struct vm_area_struct *mp;
-
-       if (Hash == 0) {
-               _tlbia();
-               return;
-       }
-
-       for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
-               flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
-       FINISH_FLUSH;
-}
-
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-       struct mm_struct *mm;
-       pmd_t *pmd;
-
-       if (Hash == 0) {
-               _tlbie(vmaddr);
-               return;
-       }
-       mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
-       pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
-       if (!pmd_none(*pmd))
-               flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
-       FINISH_FLUSH;
-}
-
-/*
- * For each address in the range, find the pte for the address
- * and check _PAGE_HASHPTE bit; if it is set, find and destroy
- * the corresponding HPTE.
- */
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                    unsigned long end)
-{
-       flush_range(vma->vm_mm, start, end);
-       FINISH_FLUSH;
-}
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
new file mode 100644 (file)
index 0000000..6c3dc3c
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * This file contains the routines for TLB flushing.
+ * On machines where the MMU uses a hash table to store virtual to
+ * physical translations, these routines flush entries from the
+ * hash table also.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+
+#include "mmu_decl.h"
+
+/*
+ * Called when unmapping pages to flush entries from the TLB/hash table.
+ */
+void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
+{
+       unsigned long ptephys;
+
+       if (Hash != 0) {
+               ptephys = __pa(ptep) & PAGE_MASK;
+               flush_hash_pages(mm->context, addr, ptephys, 1);
+       }
+}
+
+/*
+ * Called by ptep_set_access_flags, must flush on CPUs for which the
+ * DSI handler can't just "fixup" the TLB on a write fault
+ */
+void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr)
+{
+       if (Hash != 0)
+               return;
+       _tlbie(addr);
+}
+
+/*
+ * Called at the end of a mmu_gather operation to make sure the
+ * TLB flush is completely done.
+ */
+void tlb_flush(struct mmu_gather *tlb)
+{
+       if (Hash == 0) {
+               /*
+                * 603 needs to flush the whole TLB here since
+                * it doesn't use a hash table.
+                */
+               _tlbia();
+       }
+}
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes kernel pages
+ *
+ * since the hardware hash table functions as an extension of the
+ * tlb as far as the linux tables are concerned, flush it too.
+ *    -- Cort
+ */
+
+/*
+ * 750 SMP is a Bad Idea because the 750 doesn't broadcast all
+ * the cache operations on the bus.  Hence we need to use an IPI
+ * to get the other CPU(s) to invalidate their TLBs.
+ */
+#ifdef CONFIG_SMP_750
+#define FINISH_FLUSH   smp_send_tlb_invalidate(0)
+#else
+#define FINISH_FLUSH   do { } while (0)
+#endif
+
+static void flush_range(struct mm_struct *mm, unsigned long start,
+                       unsigned long end)
+{
+       pmd_t *pmd;
+       unsigned long pmd_end;
+       int count;
+       unsigned int ctx = mm->context;
+
+       if (Hash == 0) {
+               _tlbia();
+               return;
+       }
+       start &= PAGE_MASK;
+       if (start >= end)
+               return;
+       end = (end - 1) | ~PAGE_MASK;
+       pmd = pmd_offset(pgd_offset(mm, start), start);
+       for (;;) {
+               pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
+               if (pmd_end > end)
+                       pmd_end = end;
+               if (!pmd_none(*pmd)) {
+                       count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
+                       flush_hash_pages(ctx, start, pmd_val(*pmd), count);
+               }
+               if (pmd_end == end)
+                       break;
+               start = pmd_end + 1;
+               ++pmd;
+       }
+}
+
+/*
+ * Flush kernel TLB entries in the given range
+ */
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       flush_range(&init_mm, start, end);
+       FINISH_FLUSH;
+}
+
+/*
+ * Flush all the (user) entries for the address space described by mm.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       struct vm_area_struct *mp;
+
+       if (Hash == 0) {
+               _tlbia();
+               return;
+       }
+
+       for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
+               flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
+       FINISH_FLUSH;
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       struct mm_struct *mm;
+       pmd_t *pmd;
+
+       if (Hash == 0) {
+               _tlbie(vmaddr);
+               return;
+       }
+       mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
+       pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
+       if (!pmd_none(*pmd))
+               flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
+       FINISH_FLUSH;
+}
+
+/*
+ * For each address in the range, find the pte for the address
+ * and check _PAGE_HASHPTE bit; if it is set, find and destroy
+ * the corresponding HPTE.
+ */
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                    unsigned long end)
+{
+       flush_range(vma->vm_mm, start, end);
+       FINISH_FLUSH;
+}