]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.51pre1 2.1.51pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:46 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:46 +0000 (15:13 -0500)
326 files changed:
CREDITS
MAINTAINERS
Makefile
arch/i386/defconfig
arch/i386/kernel/i386_ksyms.c
arch/m68k/kernel/Makefile
arch/m68k/kernel/bios32.c [deleted file]
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/signal.c
arch/mips/Makefile
arch/mips/boot/Makefile
arch/mips/config.in
arch/mips/defconfig
arch/mips/deskstation/hw-access.c
arch/mips/deskstation/setup.c
arch/mips/jazz/g364.c
arch/mips/jazz/hw-access.c
arch/mips/jazz/jazzdma.c
arch/mips/jazz/setup.c
arch/mips/kernel/gdb-stub.c
arch/mips/kernel/irix5sys.h
arch/mips/kernel/irixioctl.c
arch/mips/kernel/irixsig.c
arch/mips/kernel/irq.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/signal.c
arch/mips/kernel/syscall.c
arch/mips/kernel/syscalls.h
arch/mips/kernel/sysirix.c
arch/mips/kernel/sysmips.c
arch/mips/kernel/time.c
arch/mips/kernel/traps.c
arch/mips/lib/Makefile
arch/mips/lib/checksum.c
arch/mips/lib/dump_tlb.c
arch/mips/mm/Makefile
arch/mips/mm/andes.c
arch/mips/mm/fault.c
arch/mips/mm/loadmmu.c
arch/mips/mm/r2300.c
arch/mips/mm/r4xx0.c
arch/mips/mm/r6000.c
arch/mips/mm/tfp.c
arch/mips/mm/umap.c [new file with mode: 0644]
arch/mips/sgi/kernel/setup.c
arch/mips/sni/hw-access.c
arch/mips/sni/setup.c
arch/ppc/Makefile
arch/ppc/boot/Makefile
arch/ppc/boot/head.S
arch/ppc/boot/misc.c
arch/ppc/boot/mkprep.c
arch/ppc/coffboot/Makefile [new file with mode: 0644]
arch/ppc/coffboot/crt0.S [new file with mode: 0644]
arch/ppc/coffboot/elfextract.c [new file with mode: 0644]
arch/ppc/coffboot/hack-coff.c [new file with mode: 0644]
arch/ppc/coffboot/ld.script [new file with mode: 0644]
arch/ppc/coffboot/main.c [new file with mode: 0644]
arch/ppc/coffboot/misc.S [new file with mode: 0644]
arch/ppc/coffboot/nonstdio.h [new file with mode: 0644]
arch/ppc/coffboot/rs6000.h [new file with mode: 0644]
arch/ppc/coffboot/start.c [new file with mode: 0644]
arch/ppc/coffboot/string.S [new file with mode: 0644]
arch/ppc/coffboot/zlib.c [new file with mode: 0644]
arch/ppc/coffboot/zlib.h [new file with mode: 0644]
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/kernel/checks.c
arch/ppc/kernel/head.S
arch/ppc/kernel/idle.c [new file with mode: 0644]
arch/ppc/kernel/irq.c
arch/ppc/kernel/ksyms.c [deleted file]
arch/ppc/kernel/misc.S
arch/ppc/kernel/mk_defs.c
arch/ppc/kernel/pci-bridge.c [new file with mode: 0644]
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/pmac_support.c
arch/ppc/kernel/pmac_time.c
arch/ppc/kernel/port_io.c [deleted file]
arch/ppc/kernel/ppc_asm.tmpl
arch/ppc/kernel/ppc_defs.h [deleted file]
arch/ppc/kernel/ppc_htab.c [new file with mode: 0644]
arch/ppc/kernel/ppc_ksyms.c [new file with mode: 0644]
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/prep_time.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c [new file with mode: 0644]
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/setup.c [new file with mode: 0644]
arch/ppc/kernel/signal.c
arch/ppc/kernel/strcase.c [deleted file]
arch/ppc/kernel/syscalls.c
arch/ppc/kernel/time.c [new file with mode: 0644]
arch/ppc/kernel/time.h [new file with mode: 0644]
arch/ppc/kernel/traps.c
arch/ppc/ld.script [deleted file]
arch/ppc/lib/Makefile
arch/ppc/lib/checksum.S [new file with mode: 0644]
arch/ppc/lib/checksum.c [deleted file]
arch/ppc/lib/cksum_support.S [deleted file]
arch/ppc/lib/strcase.c [new file with mode: 0644]
arch/ppc/lib/string.S
arch/ppc/mkdist
arch/ppc/mktar
arch/ppc/mm/Makefile
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/pmac_defconfig [new file with mode: 0644]
arch/ppc/prep_defconfig
arch/ppc/vmlinux.lds [new file with mode: 0644]
arch/sparc/ap1000/aplib.c
arch/sparc/ap1000/mpp.c
arch/sparc/ap1000/msc.c
arch/sparc/ap1000/tnet.c
arch/sparc/defconfig
arch/sparc/kernel/process.c
arch/sparc/kernel/ptrace.c
arch/sparc/kernel/rtrap.S
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/mm/srmmu.c
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/central.c [new file with mode: 0644]
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/dtlb_miss.S
arch/sparc64/kernel/dtlb_prot.S
arch/sparc64/kernel/ebus.c [new file with mode: 0644]
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/etrap.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/ioport.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/psycho.c [new file with mode: 0644]
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/ttable.S
arch/sparc64/kernel/winfixup.S
arch/sparc64/lib/Makefile
arch/sparc64/lib/VISbzero.S
arch/sparc64/lib/VIScopy.S
arch/sparc64/lib/VIScsum.S
arch/sparc64/lib/VIScsumcopy.S [new file with mode: 0644]
arch/sparc64/lib/VISmemset.S
arch/sparc64/lib/blockops.S
arch/sparc64/lib/checksum.S
arch/sparc64/lib/locks.S
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/prom/p1275.c
arch/sparc64/prom/ranges.c
arch/sparc64/prom/tree.c
arch/sparc64/vmlinux.lds
drivers/Makefile
drivers/block/Makefile
drivers/block/floppy.c
drivers/block/genhd.c
drivers/block/ll_rw_blk.c
drivers/block/swim3.c [new file with mode: 0644]
drivers/macintosh/Makefile [new file with mode: 0644]
drivers/macintosh/adb.c [new file with mode: 0644]
drivers/macintosh/ati-gt.h [new file with mode: 0644]
drivers/macintosh/ati-vt.h [new file with mode: 0644]
drivers/macintosh/aty.c [new file with mode: 0644]
drivers/macintosh/aty.h [new file with mode: 0644]
drivers/macintosh/control.c [new file with mode: 0644]
drivers/macintosh/control.h [new file with mode: 0644]
drivers/macintosh/imstt.c [new file with mode: 0644]
drivers/macintosh/imstt.h [new file with mode: 0644]
drivers/macintosh/mac_keyb.c [new file with mode: 0644]
drivers/macintosh/mackeymap.c [new file with mode: 0644]
drivers/macintosh/mackeymap.map [new file with mode: 0644]
drivers/macintosh/macserial.c [new file with mode: 0644]
drivers/macintosh/macserial.h [new file with mode: 0644]
drivers/macintosh/nvram.c [new file with mode: 0644]
drivers/macintosh/platinum.c [new file with mode: 0644]
drivers/macintosh/platinum.h [new file with mode: 0644]
drivers/macintosh/pmac-cons.c [new file with mode: 0644]
drivers/macintosh/pmac-cons.h [new file with mode: 0644]
drivers/macintosh/valkyrie.c [new file with mode: 0644]
drivers/macintosh/valkyrie.h [new file with mode: 0644]
drivers/macintosh/via-cuda.c [new file with mode: 0644]
drivers/net/mace.c [new file with mode: 0644]
drivers/net/mace.h [new file with mode: 0644]
drivers/sbus/char/creator.c
drivers/sbus/char/tcx.c
drivers/sbus/char/weitek.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/hosts.c
drivers/scsi/mac53c94.c [new file with mode: 0644]
drivers/scsi/mac53c94.h [new file with mode: 0644]
drivers/scsi/mesh.c [new file with mode: 0644]
drivers/scsi/mesh.h [new file with mode: 0644]
drivers/scsi/sr.c
fs/Config.in
fs/affs/file.c
fs/affs/inode.c
fs/affs/namei.c
fs/autofs/inode.c
fs/binfmt_elf.c
fs/dcache.c
fs/exec.c
fs/isofs/namei.c
fs/isofs/symlink.c
fs/namei.c
fs/ncpfs/file.c
fs/ncpfs/inode.c
fs/ncpfs/mmap.c
fs/ncpfs/sock.c
fs/nfs/dir.c
fs/nfs/symlink.c
fs/open.c
fs/proc/Makefile
fs/proc/openpromfs.c
fs/proc/proc_devtree.c [new file with mode: 0644]
fs/proc/root.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/mmap.c
fs/smbfs/sock.c
include/asm-m68k/pgtable.h
include/asm-mips/bitops.h
include/asm-mips/checksum.h
include/asm-mips/floppy.h
include/asm-mips/gfx.h [new file with mode: 0644]
include/asm-mips/jazzdma.h
include/asm-mips/keyboard.h
include/asm-mips/ng1.h [new file with mode: 0644]
include/asm-mips/pgtable.h
include/asm-mips/rrm.h [new file with mode: 0644]
include/asm-mips/shmiq.h [new file with mode: 0644]
include/asm-mips/string.h
include/asm-mips/system.h
include/asm-ppc/bitops.h
include/asm-ppc/byteorder.h
include/asm-ppc/checksum.h
include/asm-ppc/cuda.h [new file with mode: 0644]
include/asm-ppc/current.h
include/asm-ppc/dbdma.h [new file with mode: 0644]
include/asm-ppc/dma.h
include/asm-ppc/elf.h
include/asm-ppc/ide.h
include/asm-ppc/io.h
include/asm-ppc/ioctls.h
include/asm-ppc/ipc.h
include/asm-ppc/irq.h
include/asm-ppc/linux_logo.h [new file with mode: 0644]
include/asm-ppc/mmu.h
include/asm-ppc/mmu_context.h
include/asm-ppc/namei.h
include/asm-ppc/nvram.h
include/asm-ppc/page.h
include/asm-ppc/pci-bridge.h [new file with mode: 0644]
include/asm-ppc/pgtable.h
include/asm-ppc/poll.h
include/asm-ppc/processor.h
include/asm-ppc/prom.h [new file with mode: 0644]
include/asm-ppc/ptrace.h
include/asm-ppc/residual.h
include/asm-ppc/resource.h
include/asm-ppc/scatterlist.h
include/asm-ppc/semaphore.h
include/asm-ppc/socket.h
include/asm-ppc/string.h
include/asm-ppc/system.h
include/asm-ppc/termbits.h
include/asm-sparc/pgtable.h
include/asm-sparc64/atomic.h
include/asm-sparc64/bitops.h
include/asm-sparc64/checksum.h
include/asm-sparc64/delay.h
include/asm-sparc64/ebus.h [new file with mode: 0644]
include/asm-sparc64/fhc.h [new file with mode: 0644]
include/asm-sparc64/firehose.h
include/asm-sparc64/hardirq.h
include/asm-sparc64/head.h
include/asm-sparc64/ioctls.h
include/asm-sparc64/iommu.h
include/asm-sparc64/irq.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/openprom.h
include/asm-sparc64/page.h
include/asm-sparc64/pbm.h [new file with mode: 0644]
include/asm-sparc64/pgtable.h
include/asm-sparc64/psycho.h [new file with mode: 0644]
include/asm-sparc64/sab82532.h [new file with mode: 0644]
include/asm-sparc64/sbus.h
include/asm-sparc64/semaphore.h
include/asm-sparc64/shmparam.h
include/asm-sparc64/smp.h
include/asm-sparc64/smp_lock.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/sysio.h
include/asm-sparc64/system.h
include/asm-sparc64/termbits.h
include/asm-sparc64/ttable.h [new file with mode: 0644]
include/asm-sparc64/uaccess.h
include/linux/blk.h
include/linux/dcache.h
include/linux/proc_fs.h
include/linux/tty.h
kernel/ksyms.c
net/ipv4/fib.c
net/socket.c

diff --git a/CREDITS b/CREDITS
index fdd8b9159baa2ccb6ec1b402f6ff7ed9e44f7140..f770a485180dad3629a559b26ec8f1c179b2e3a4 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -586,11 +586,9 @@ S: 34131 Kassel
 S: Germany
 
 N: Richard Henderson
-E: rth@tamu.edu
+E: richard@gnu.ai.mit.edu
+E: rth@cygnus.com
 D: Alpha/ELF, gcc, binutils, and glibc
-S: 304 E. North Ave.
-S: Bryan, Texas  77801-3431
-S: USA
 
 N: Sebastian Hetze
 E: she@lunetix.de
@@ -929,6 +927,13 @@ S: Australian National University
 S: Canberra  ACT  0200
 S: AUSTRALIA
 
+N: Pavel Machek
+E: pavel@atrey.karlin.mff.cuni.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
+S: Volkova 1131
+S: 198 00 Praha 9
+S: Czech Republic
+
 N: James B. MacLean
 E: macleajb@ednet.ns.ca
 W: http://www.ednet.ns.ca/~macleajb/dosemu.html
@@ -1156,7 +1161,7 @@ E: orc@pell.chi.il.us
 D: improved memory detection code.
 
 N: Avery Pennarun
-E: apenwarr@foxnet.net
+E: apenwarr@bond.net
 D: ARCnet driver
 D: "make xconfig" improvements
 D: Various minor hacking
@@ -1655,6 +1660,14 @@ S: Oosterstraat 23
 S: 2611 TT Delft
 S: The Netherlands
 
+N: David Woodhouse
+E: dwmw2@cam.ac.uk
+D: Extensive ARCnet rewrite
+D: ARCnet COM20020, COM90xx IO-MAP drivers
+S: Robinson College, Grange Road
+S: Cambridge. CB3 9AN
+S: England
+
 N: Frank Xia
 E: qx@math.columbia.edu
 D: Xiafs filesystem [defunct]
index e6764e5c139f36cbdba863733a37c21fbf8110be..9606d4d26488afd5a54fb30a0236b8ebd1adb423 100644 (file)
@@ -95,6 +95,13 @@ M:   phil@tazenda.demon.co.uk
 L:     linux-net@vger.rutgers.edu
 S:     Maintained
 
+NI5010 NETWORK DRIVER
+P:     Jan-Pascal van Best and Andreas Mohr
+M:     jvbest@qv3pluto.leidenuniv.nl (Best)
+M:     100.30936@germany.net (Mohr)
+L:     linux-net@vger.rutgers.edu
+S:     Maintained
+
 TLAN NETWORK DRIVER
 P:     James Banks
 M:     james.banks@caldera.com
@@ -259,9 +266,8 @@ L:  linux-m68k@phil.uni-sb.de
 S:     Maintained
 
 MODULE SUPPORT [GENERAL], KERNELD
-P:     Bjorn Ekwall
-M:     bj0rn@blox.se
-W:     http://www.pi.se/blox/modules/
+P:     Richard Henderson
+M:     richard@gnu.ai.mit.edu
 L:     linux-kernel@vger.rutgers.edu
 S:     Maintained
 
index abae70b2b43cb1cb927d81ffbf7ae43f9f122740..0d9f013b93e91d58f256c02b512e5441c72cd243 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 50
+SUBLEVEL = 51
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
@@ -149,6 +149,10 @@ ifdef CONFIG_SBUS
 DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
 endif
 
+ifdef CONFIG_PPC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
+endif
+
 ifdef CONFIG_PNP
 DRIVERS := $(DRIVERS) drivers/pnp/pnp.a
 endif
index e3e50886cfccdd304f6236f2ec38051b775f2f7a..953fecf23d2c1774c30df6acc174094fcfe98eff 100644 (file)
@@ -148,6 +148,8 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # Network device support
@@ -214,6 +216,7 @@ CONFIG_ISO9660_FS=y
 # CONFIG_ROMFS_FS is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Character devices
index a711d9a4050bb7bfba847fbb2eadbc6a6f7e8c34..b740eb0ce72ab70767029de028a6db829e06f8a7 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
+#include <linux/smp_lock.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -49,6 +50,7 @@ EXPORT_SYMBOL_NOVERS(kernel_flag);
 EXPORT_SYMBOL_NOVERS(active_kernel_processor);
 EXPORT_SYMBOL(smp_invalidate_needed);
 EXPORT_SYMBOL_NOVERS(__lock_kernel);
+EXPORT_SYMBOL(lk_lockmsg);
 
 /* Global SMP irq stuff */
 EXPORT_SYMBOL(synchronize_irq);
index 67d87c1b9dcb27557a6f49ec19a18a200b2cdbc7..a4fc10ab019c6d3d22b2eacc366c82f0640c98dd 100644 (file)
@@ -13,7 +13,7 @@
 all: kernel.o head.o
 O_TARGET := kernel.o
 O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
-         setup.o bios32.o sys_m68k.o time.o
+         setup.o sys_m68k.o time.o
 ifdef CONFIG_VT
 O_OBJS += console.o
 endif
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
deleted file mode 100644 (file)
index 1fe61fa..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * bios 32 replacement
- */
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-       return memory_start;
-}
index 27883a86ef012888721bed09562badd51afc3838..f07a6a0383b111d5f22eb8b110ea33a531184c2c 100644 (file)
@@ -65,7 +65,7 @@ asmlinkage int sys_idle(void)
        current->priority = -100;
        current->counter = -100;
        for (;;){
-               if (!need_resched)
+               if (!resched_needed())
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
                        /* block out HSYNC on the atari (falcon) */
                        __asm__("stop #0x2200" : : : "cc");
index be4149cbb2c67a75b3420603c13d8c56f60ddd3e..6b660118a8dcf90ad8fa80ce9f4a2837f0140eaf 100644 (file)
@@ -526,7 +526,7 @@ asmlinkage void syscall_trace(void)
                goto out;
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
-       notify_parent(current);
+       notify_parent(current, SIGCHLD);
        schedule();
        /*
         * this isn't the same as continuing with a signal, but it will do
index 52c13445df26c3f09541dfea0ebf908b2534095d..ab887801c088fc3f9fa019f96e4fc24b593a4610 100644 (file)
@@ -441,7 +441,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
                                        regs->pc -= 2;
                                }
                        }
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code)) {
                        discard_frame:
@@ -489,7 +489,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
                                current->exit_code = signr;
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
                                      SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
index 7eb56f4bf98eafcc6ba9633b1ff5e975846fdd21..773a24355d179722f6fed1aa691ac2c595e340b6 100644 (file)
 # Copyright (C) 1994, 1995, 1996 by Ralf Baechle
 # DECStation modifications by Paul M. Antoine, 1996
 #
-# $Id: Makefile,v 1.7 1997/06/30 15:52:03 ralf Exp $
+# $Id: Makefile,v 1.8 1997/08/08 18:11:35 miguel Exp $
 #
 
 #
 # Select the object file format to substitute into the linker script.
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE = mipsel-linux-
+CROSS_COMPILE  = mipsel-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat               = ecoff-littlemips
+oformat                = ecoff-littlemips
 else
-oformat               = elf32-littlemips
+oformat                = elf32-littlemips
 endif
 else
-CROSS_COMPILE = mips-linux-
+CROSS_COMPILE  = mips-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat               = ecoff-bigmips
+oformat                = ecoff-bigmips
 else
-oformat               = elf32-bigmips
+oformat                = elf32-bigmips
 endif
 endif
 
 LINKFLAGS      = -static -N
+MODFLAGS       += -mlong-calls
 
 #
 # The new ELF GCC uses -G0 -mabicalls -fpic as default.  We don't need PIC
index dd834efd95fcb1100f3954de0967f82761794ac7..f632508f0651c811094104bdb88c6283ddc50812 100644 (file)
@@ -41,7 +41,6 @@ zdisk:        zImage
        fi
 
 dep:
-       $(CPP) -M *.[cS] > .depend
 
 clean:
        rm -f zImage zImage.tmp mkboot
index f9f93542f69857c7837467bf7bb88b926c33b56f..ce6f78937e1e88a700129adf44de4c95bb58490a 100644 (file)
@@ -27,6 +27,9 @@ if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Support for SGI workstations' CONFIG_SGI
+  if [ "$CONFIG_SGI" = "y" ]; then
+     bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
+  fi
 fi
 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
 if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \
@@ -69,6 +72,7 @@ else
 fi
 if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
   define_bool CONFIG_BINFMT_IRIX y
+  define_bool CONFIG_FORWARD_KEYBOARD y
 fi
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_BINFMT_AOUT n
@@ -93,12 +97,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 
-#
-# All SGI block devices are SCSI based AFAIK. -davem
-#
-if [ "$CONFIG_SGI" != "y" ]; then
-  source drivers/block/Config.in
-fi
+source drivers/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
@@ -215,3 +214,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
+
+define_bool CONFIG_VGA_CONSOLE y
index 099cb84069d1b12179434d0b742d0823f5a7349c..b1892eba6d204029da072f33a26a26274ceb5f69 100644 (file)
@@ -38,7 +38,7 @@ CONFIG_BINFMT_ELF=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
-# CONFIG_PNP_PARPORT is not set
+# CONFIG_PARPORT is not set
 
 #
 # Loadable module support
@@ -133,6 +133,7 @@ CONFIG_PCNET32=y
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
@@ -154,9 +155,6 @@ CONFIG_PCNET32=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_FAT_FS is not set
@@ -194,6 +192,7 @@ CONFIG_SERIAL=y
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
index 418bac5f6b49f2e38a595d9a0fd2542c6dcba424..47a0c6bd70a5484682bd4673b5b6d326c4abf9c8 100644 (file)
@@ -5,10 +5,13 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:11:57 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -194,3 +197,32 @@ struct feature deskstation_rpc44_feature = {
        rtc_write_data
 };
 #endif
+
+static unsigned char dtc_read_input(void)
+{
+       return inb(KBD_DATA_REG);
+}
+
+static void dtc_write_output(unsigned char val)
+{
+       outb(val, KBD_DATA_REG);
+}
+
+static void dtc_write_command(unsigned char val)
+{
+       outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char dtc_read_status(void)
+{
+       return inb(KBD_STATUS_REG);
+}
+
+static void dtc_rm200_keyboard_setup(void)
+{
+       kbd_read_input = dtc_read_input;
+       kbd_write_output = dtc_write_output;
+       kbd_write_command = dtc_write_command;
+       kbd_read_status = dtc_read_status;
+       request_region(0x60, 16, "keyboard");
+}
index 8b70a656c4c6f52d926019464ab197fcfc66c0ce..fe9abd4a817fd44399d148889f87cf17d200de06 100644 (file)
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: setup.c,v 1.2 1997/08/08 18:11:59 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -102,6 +104,7 @@ __initfunc(void deskstation_setup(void))
 #endif
        }
        fd_cacheflush = deskstation_fd_cacheflush;
+       keyboard_setup = dtc_keyboard_setup;
        request_region(0x00,0x20,"dma1");
        request_region(0x40,0x20,"timer");
        request_region(0x70,0x10,"rtc");
index 1503cc559ffe7916e34fa7e25fd1dc96e9f39645..b544eb4d03f769d9d481d85dce312e492f5eb508 100644 (file)
@@ -45,13 +45,13 @@ unsigned video_res_x;
 /* 
  * Various defines for the G364
  */
-#define G364_MEM_BASE   0xe0800000
-#define G364_PORT_BASE  0xe0200000
-#define ID_REG                 0xe0200000      /* Read only */
-#define BOOT_REG       0xe0280000
-#define TIMING_REG     0xe0280108      /* to 0x080170 - DON'T TOUCH! */
-#define MASK_REG       0xe0280200
-#define CTLA_REG       0xe0280300
+#define G364_MEM_BASE   0xe4400000
+#define G364_PORT_BASE  0xe4000000
+#define ID_REG                 0xe4000000      /* Read only */
+#define BOOT_REG       0xe4080000
+#define TIMING_REG     0xe4080108      /* to 0x080170 - DON'T TOUCH! */
+#define MASK_REG       0xe4080200
+#define CTLA_REG       0xe4080300
 #define CURS_TOGGLE    0x800000
 #define BIT_PER_PIX    0x700000        /* bits 22 to 20 of Control A */
 #define DELAY_SAMPLE    0x080000
@@ -72,14 +72,14 @@ unsigned video_res_x;
 #define INTL_STAND     0x000004
 #define SCRN_FORM      0x000002
 #define ENABLE_VTG     0x000001        
-#define TOP_REG        0xe0280400
-#define CURS_PAL_REG   0xe0280508      /* to 0x080518 */
-#define CHKSUM_REG     0xe0280600      /* to 0x080610 - unused */
-#define CURS_POS_REG   0xe0280638
-#define CLR_PAL_REG    0xe0280800      /* to 0x080ff8 */
-#define CURS_PAT_REG   0xe0281000      /* to 0x081ff8 */
-#define MON_ID_REG     0xe0300000      /* unused */
-#define RESET_REG      0xe0380000      /* Write only */
+#define TOP_REG        0xe4080400
+#define CURS_PAL_REG   0xe4080508      /* to 0x080518 */
+#define CHKSUM_REG     0xe4080600      /* to 0x080610 - unused */
+#define CURS_POS_REG   0xe4080638
+#define CLR_PAL_REG    0xe4080800      /* to 0x080ff8 */
+#define CURS_PAT_REG   0xe4081000      /* to 0x081ff8 */
+#define MON_ID_REG     0xe4100000      /* unused */
+#define RESET_REG      0xe4180000      /* Write only */
 
 /*
  * built-in font management constants
index 52a61165f14327fd8ce5d78025d4d11202da438d..4cb45ea89abc2068aa9198153da30f47eac838fb 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  */
 #include <linux/delay.h>
 #include <linux/linkage.h>
@@ -15,6 +15,7 @@
 #include <asm/vector.h>
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
+#include <asm/keyboard.h>
 #include <asm/pgtable.h>
 #include <asm/mc146818rtc.h>
 
@@ -146,3 +147,35 @@ struct feature jazz_feature = {
        rtc_read_data,
        rtc_write_data
 };
+
+static volatile keyboard_hardware *jazz_kh = (keyboard_hardware *)JAZZ_KEYBOARD_ADDRESS;
+
+static unsigned char jazz_read_input(void)
+{
+       return jazz_kh->data;
+}
+
+static void jazz_write_output(unsigned char val)
+{
+       jazz_kh->data = val;
+}
+
+static void jazz_write_command(unsigned char val)
+{
+       jazz_kh->command = val;
+}
+
+static unsigned char jazz_read_status(void)
+{
+       return jazz_kh->command;
+}
+
+void jazz_keyboard_setup(void)
+{
+       kbd_read_input = jazz_read_input;
+       kbd_write_output = jazz_write_output;
+       kbd_write_command = jazz_write_command;
+       kbd_read_status = jazz_read_status;
+       request_region(0x60, 16, "keyboard");
+        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | JAZZ_IE_KEYBOARD);
+}
index 7d4f3b3e31195fee58a46de599ab5deb122cffec..988499c7980a1defd4ace277f3dd43df20e6e29d 100644 (file)
@@ -514,3 +514,18 @@ int vdma_get_residue(int channel)
   
     return residual;
 }
+
+/*
+ * Get DMA channel enable register
+ */
+int vdma_get_enable(int channel)
+{
+    int enable;
+    
+    enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+    
+    if (vdma_debug)
+       printk("vdma_get_enable: channel %d: enable=%d\n",channel,enable);
+    
+    return enable;
+}
index e7550e7ad4b8c627cb1d69cd18da797a9afe288a..3bbf849479f9660c8e9c1c867fcd2d2e2b99fb4b 100644 (file)
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
 #include <asm/bootinfo.h>
+#include <asm/keyboard.h>
 #include <asm/irq.h>
 #include <asm/jazz.h>
 #include <asm/ptrace.h>
 #include <asm/reboot.h>
 #include <asm/vector.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 
 /*
  * Initial irq handlers.
@@ -32,6 +35,7 @@ static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
 extern asmlinkage void jazz_handle_int(void);
 extern asmlinkage void jazz_fd_cacheflush(const void *addr, size_t size);
 extern struct feature jazz_feature;
+extern void jazz_keyboard_setup(void);
 
 extern void jazz_machine_restart(char *command);
 extern void jazz_machine_halt(void);
@@ -94,8 +98,13 @@ __initfunc(void jazz_setup(void))
        }
     }
 
+        add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
+        add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
+        add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
+
        irq_setup = jazz_irq_setup;
        fd_cacheflush = jazz_fd_cacheflush;
+       keyboard_setup = jazz_keyboard_setup;
        feature = &jazz_feature;                        // Will go away
        port_base = JAZZ_PORT_BASE;
        isa_slot_offset = 0xe3000000;
index 452e419e3bae5bd6a1ecbfb62823614144852a6b..f6a18522313f5f117828038bc69cc68dfab89d25 100644 (file)
@@ -12,7 +12,7 @@
  *
  *  Copyright (C) 1995 Andreas Busse
  *
- * $Id: gdb-stub.c,v 1.4 1997/06/30 15:52:25 ralf Exp $
+ * $Id: gdb-stub.c,v 1.5 1997/08/08 18:12:15 miguel Exp $
  */
 
 /*
  */
 
 #include <linux/string.h>
-#include <linux/signal.h>
 #include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
 
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
-#include <asm/cachectl.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/gdb-stub.h>
 
@@ -98,13 +100,11 @@ extern void adel(void);
 
 static void getpacket(char *buffer);
 static void putpacket(char *buffer);
-static void set_mem_fault_trap(int enable);
 static int computeSignal(int tt);
 static int hex(unsigned char ch);
 static int hexToInt(char **ptr, int *intValue);
 static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
 void handle_exception(struct gdb_regs *regs);
-static void show_gdbregs(struct gdb_regs *regs);
 
 /*
  * BUFMAX defines the maximum number of characters in inbound/outbound buffers
@@ -241,6 +241,21 @@ static void putpacket(char *buffer)
  */
 static volatile int mem_err = 0;
 
+
+#if 0
+static void set_mem_fault_trap(int enable)
+{
+  mem_err = 0;
+
+#if 0
+  if (enable)
+    exceptionHandler(9, fltr_set_mem_err);
+  else
+    exceptionHandler(9, trap_low);
+#endif  
+}
+#endif /* dead code */
+
 /*
  * Convert the memory pointed to by mem into hex, placing result in buf.
  * Return a pointer to the last char put in buf (null), in case of mem fault,
@@ -362,19 +377,6 @@ extern void fltr_set_mem_err(void)
   /* FIXME: Needs to be written... */
 }
 
-
-static void set_mem_fault_trap(int enable)
-{
-  mem_err = 0;
-
-#if 0
-  if (enable)
-    exceptionHandler(9, fltr_set_mem_err);
-  else
-    exceptionHandler(9, trap_low);
-#endif  
-}
-
 /*
  * Convert the MIPS hardware trap type code to a unix signal number.
  */
@@ -415,6 +417,38 @@ static int hexToInt(char **ptr, int *intValue)
        return (numChars);
 }
 
+
+#if 0
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+void show_gdbregs(struct gdb_regs * regs)
+{
+       /*
+        * Saved main processor registers
+        */
+       printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              regs->reg0, regs->reg1, regs->reg2, regs->reg3,
+               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+       printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+       printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+       printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              regs->reg24, regs->reg25, regs->reg26, regs->reg27,
+              regs->reg28, regs->reg29, regs->reg30, regs->reg31);
+
+       /*
+        * Saved cp0 registers
+        */
+       printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
+              regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+#endif /* dead code */
+
 /*
  * This function does all command processing for interfacing to gdb.  It
  * returns 1 if you should skip the instruction at the trap address, 0
@@ -726,32 +760,3 @@ void adel(void)
                        lw      $9,0($8)
        ");
 }
-
-/*
- * Print registers (on target console)
- * Used only to debug the stub...
- */
-void show_gdbregs(struct gdb_regs * regs)
-{
-       /*
-        * Saved main processor registers
-        */
-       printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-              regs->reg0, regs->reg1, regs->reg2, regs->reg3,
-               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
-       printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-              regs->reg8, regs->reg9, regs->reg10, regs->reg11,
-               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
-       printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-              regs->reg16, regs->reg17, regs->reg18, regs->reg19,
-               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
-       printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-              regs->reg24, regs->reg25, regs->reg26, regs->reg27,
-              regs->reg28, regs->reg29, regs->reg30, regs->reg31);
-
-       /*
-        * Saved cp0 registers
-        */
-       printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
-              regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-}
index 7c49b1971b265fea9fac4e449d7fe7d8f85da515..8f00cf8876f851dda90f92747d8e26c5d80e14b9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irix5sys.h,v 1.1 1997/06/06 09:32:29 ralf Exp $
+/* $Id: irix5sys.h,v 1.2 1997/08/08 18:12:17 miguel Exp $
  * irix5sys.h: 32-bit IRIX5 ABI system call table.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
index 94fcf6337870f3733c971a20483e45b4a40af6ab..2a8a34b74d394dafd582e789b5bc7917046fb953 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irixioctl.c,v 1.1 1997/06/06 09:32:33 ralf Exp $
+/* $Id: irixioctl.c,v 1.2 1997/08/08 18:12:19 miguel Exp $
  * irixioctl.c: A fucking mess...
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
index 09c1f66a97498118cd1014094b8811183361dfb3..396d6646643ad7939b5f75a34ba67cf4557c0ada 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irixsig.c,v 1.2 1997/06/13 10:11:22 ralf Exp $
+/* $Id: irixsig.c,v 1.4 1997/08/08 18:12:21 miguel Exp $
  * irixsig.c: WHEEE, IRIX signals!  YOW, am I compatable or what?!?!
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -142,7 +142,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -180,7 +180,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
                                current->exit_code = signr;
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
                                                SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
@@ -593,7 +593,6 @@ out:
 #define P_ALL    7
 
 extern int getrusage(struct task_struct *, int, struct rusage *);
-extern void release(struct task_struct * p);
 
 #define W_EXITED     1
 #define W_TRAPPED    2
@@ -680,7 +679,7 @@ repeat:
                                        REMOVE_LINKS(p);
                                        p->p_pptr = p->p_opptr;
                                        SET_LINKS(p);
-                                       notify_parent(p);
+                                       notify_parent(p, SIGCHLD);
                                } else
                                        release(p);
                                goto end_waitsys;
index 89631b41614f0b944fa19abda71c2462a4d4fd70..8899f6dad699ccc4c5fc8236b488cf0daf5fe955 100644 (file)
@@ -11,7 +11,7 @@
  *
  * Mips support by Ralf Baechle and Andreas Busse
  *
- * $Id: irq.c,v 1.6 1997/06/30 15:52:34 ralf Exp $
+ * $Id: irq.c,v 1.7 1997/08/08 18:12:24 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -51,6 +51,9 @@ unsigned long spurious_count = 0;
 static inline void mask_irq(unsigned int irq_nr)
 {
        unsigned char mask;
+    
+        if (irq_nr >= 16)
+           return;
 
        mask = 1 << (irq_nr & 7);
        if (irq_nr < 8) {
@@ -66,6 +69,9 @@ static inline void unmask_irq(unsigned int irq_nr)
 {
        unsigned char mask;
 
+        if (irq_nr >= 16)
+           return;
+
        mask = ~(1 << (irq_nr & 7));
        if (irq_nr < 8) {
                cache_21 &= mask;
index abcb1946e665e33089ac838fa4baf5dd5ac11011..2106923ad88cff658a21b41d18e98da13ecb7eb0 100644 (file)
@@ -5,40 +5,69 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: mips_ksyms.c,v 1.2 1997/08/08 18:12:26 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/in6.h>
+
+#include <asm/checksum.h>
 #include <asm/dma.h>
 #include <asm/floppy.h>
 #include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sgihpc.h>
 #include <asm/softirq.h>
+#include <asm/uaccess.h>
 
 EXPORT_SYMBOL(EISA_bus);
 
 /*
  * String functions
  */
+EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(strcat);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strtok);
 
+EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__mips_bh_counter);
 EXPORT_SYMBOL(local_irq_count);
 
+/*
+ * Userspace access stuff.
+ */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(active_ds);
+
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
 
 /*
  * Functions to control caches.
  */
+EXPORT_SYMBOL(flush_page_to_ram);
 EXPORT_SYMBOL(fd_cacheflush);
 
 /*
  * Base address of ports for Intel style I/O.
  */
 EXPORT_SYMBOL(port_base);
+
+#ifdef CONFIG_SGI
+EXPORT_SYMBOL(hpc3c0);
+#endif
index e619115495a88bb8feedeea3848681ba374599ab..97a11abc447034d7679ebdd707ab93c610aa76b6 100644 (file)
@@ -488,7 +488,7 @@ asmlinkage void syscall_trace(void)
                return;
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
-       notify_parent(current);
+       notify_parent(current, SIGCHLD);
        schedule();
        /*
         * this isn't the same as continuing with a signal, but it will do
index 8c6cde991b30ab9b4c8ecec43945731a0fee871c..41f437f895abdab14c155283d22076ab9ab20df7 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1994, 1995, 1996  Ralf Baechle
  *
- * $Id: signal.c,v 1.7 1997/06/25 19:25:08 ralf Exp $
+ * $Id: signal.c,v 1.8 1997/08/08 18:12:30 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -292,7 +292,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -332,7 +332,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                                current->exit_code = signr;
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
                                                SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
index f1b117a63c909d96cffa81fa666cf83d5e1bc1d4..1346e0fba8e3c4f889765255795e960767814622 100644 (file)
@@ -88,7 +88,7 @@ asmlinkage int sys_idle(void)
                 *        possible.  Should help alot for battery powered
                 *        R4200/4300i systems.
                 */
-               if (wait_available && !need_resched)
+               if (wait_available && !resched_needed())
                        __asm__(".set\tmips3\n\t"
                                "wait\n\t"
                                ".set\tmips0\n\t");
index c66b680755f368d088bf6f14b114c4f5b4d1e50c..065f166fab63c8f289c595267f07584e73d1f3fb 100644 (file)
@@ -5,9 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
+ * $Id: syscalls.h,v 1.7 1997/08/08 18:12:32 miguel Exp $
  */
 
 /*
@@ -210,3 +210,5 @@ SYS(sys_poll, 3)
 SYS(sys_nfsservctl, 3)
 SYS(sys_setresgid, 3)                          /* 4190 */
 SYS(sys_getresgid, 3)
+SYS(sys_setresgid, 3)                          /* 4190 */
+SYS(sys_getresgid, 3)
index 1036bfcc49d95f2d2dbbd2b0dce9de4a8ba16a27..6fbf47e84c2cd170b7679024668e96f60312bb4f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
+/* $Id: sysirix.c,v 1.4 1997/08/08 18:12:35 miguel Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -751,6 +751,8 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
        }
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -1514,6 +1516,8 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
 
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -1877,6 +1881,8 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
 
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
index 0b128f1b34d31d47b1a38d0e5a6a3c3c20d49e95..59ef88e22c08e6a00bd8216dca21466807e21240 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
+ * $Id: sysmips.c,v 1.6 1997/08/08 18:12:38 miguel Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
index e00ebc76d1b3d7ef008702a57378e9f61da1a00d..209fa1baa4f831cbe15554dee1cc2c93ad7347bf 100644 (file)
@@ -6,7 +6,7 @@
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
  *
- * $Id: time.c,v 1.4 1997/06/30 15:52:40 ralf Exp $
+ * $Id: time.c,v 1.5 1997/08/08 18:12:39 miguel Exp $
  */
 #include <linux/errno.h>
 #include <linux/init.h>
index cdbcacb434822eaa4d38e5f984d0ea7c20fee948..b7ceea080b01a546e300cb64ae88a0dc523d871d 100644 (file)
@@ -196,6 +196,8 @@ static void default_be_board_handler(struct pt_regs *regs)
        /*
         * Assume it would be too dangerous to continue ...
         */
+       printk ("BE HANDLER\n");
+       show_regs (regs);
        force_sig(SIGBUS, current);
 }
 
index 9c0639250c717f150968ce1efc84057a3030e0e3..32afe92dd43bf71103b8ccefd0ea6ac8fe9a97ba 100644 (file)
@@ -1,6 +1,12 @@
 #
 # Makefile for MIPS-specific library files..
 #
+# Many of these routines are just left over debugging trash of ancient
+# times when I just make my Tyne beep and so ...
+#
+# ...and for when I need to get the DECStation to use the boot prom to
+# do things... Paul M. Antoine.
+#
 
 .S.s:
        $(CPP) $(CFLAGS) $< -o $*.s
@@ -8,8 +14,8 @@
        $(CC) $(CFLAGS) -c $< -o $*.o
 
 L_TARGET = lib.a
-L_OBJS = checksum.o copy_user.o csum.o dump_tlb.o io.o \
-         memset.o memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
+L_OBJS = beep.o checksum.o copy_user.o csum.o dump_tlb.o io.o memset.o \
+         memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
 
 ifdef CONFIG_DECSTATION
 L_OBJS += pmaxcon.o pmaxio.o
index 208c0c3cc81eca01f35830be8711a0f37331a731..ffbdb7329b113eb814ec2a9d8271a6122b840e05 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             MIPS specific IP/TCP/UDP checksumming routines
  *
- * Authors:    Ralf Baechle, <ralf@waldorf-gmbh.de>
+ * Authors:    Ralf Baechle, <ralf@gnu.ai.mit.edu>
  *             Lots of code moved from tcp.c and ip.c; see those files
  *             for more names.
  *
@@ -14,7 +14,7 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * $Id: checksum.c,v 1.4 1997/07/03 09:43:16 ralf Exp $
+ * $Id: checksum.c,v 1.5 1997/08/08 18:12:51 miguel Exp $
  */
 #include <net/checksum.h>
 #include <linux/types.h>
index 553508056da4e9b03ea02cfa3479fd6cc7db3143..0c7f818774911818b4dd45cc5ee0e76e6db528c7 100644 (file)
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+static char *region_map [] = {
+       "u", "s", "k", "!"
+};
+
+static char *cache_map [] = {
+       "c/nc/wt/nwa,",
+       "c/nc/wt/wa, ",
+       "uncached,   ",
+       "c/nc/wb,    "
+       "unknown,    ",
+       "unknown,    ",
+       "unknown,    ",
+       "unknown,    "
+};
+
 void
 dump_tlb(int first, int last)
 {
        int     i;
        int     wired;
-       unsigned int pagemask;
+       unsigned int pagemask, c0, c1, r;
        unsigned long long entryhi, entrylo0, entrylo1;
 
        wired = read_32bit_cp0_register(CP0_WIRED);
@@ -48,14 +63,25 @@ dump_tlb(int first, int last)
                        /*
                         * Only print entries in use
                         */
-                       printk("\nIndex: %2d  %08x", i, pagemask);
-
-                       printk("  %08x %08x", (unsigned int)(entryhi >> 32),
-                                             (unsigned int) entryhi);
-                       printk("  %08x %08x", (unsigned int)(entrylo0 >> 32),
-                                             (unsigned int) entrylo0);
-                       printk("  %08x %08x", (unsigned int)(entrylo1 >> 32),
-                                             (unsigned int) entrylo1);
+                       printk("\nIndex: %2d pgmask=%08x ", i, pagemask);
+
+                       r  = entryhi >> 62;
+                       c0 = (entrylo0 >> 3) & 7;
+                       c1 = (entrylo1 >> 3) & 7;
+
+                       printk("%s vpn2=%08x "
+                              "[pfn=%06x c=%d d=%d v=%d g=%d]"
+                              "[pfn=%06x c=%d d=%d v=%d g=%d]",
+                              region_map [r], (entryhi >> 13) & 0xffffffff,
+                              (entrylo0 >> 6) & 0xffffff, c0,
+                              (entrylo0 & 4) ? 1 : 0,
+                              (entrylo0 & 2) ? 1 : 0,
+                              (entrylo0 & 1),
+                              (entrylo1 >> 6) & 0xffffff, c1,
+                              (entrylo1 & 4) ? 1 : 0,
+                              (entrylo1 & 2) ? 1 : 0,
+                              (entrylo1 & 1));
+                              
                }
        }
        printk("\n");
index 1205b2bf394b5f4cc2515c7e554561062a6c735f..19060aec78c60131d2b1b89302ebba8a5c5a4828 100644 (file)
@@ -11,4 +11,8 @@ O_TARGET := mm.o
 O_OBJS  := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \
             andes.o loadmmu.o
 
+ifdef CONFIG_SGI
+O_OBJS   += umap.o
+endif
+
 include $(TOPDIR)/Rules.make
index 5623c98fbfe977cb206bbb6be00c3529c5163f2b..fc7f29d90bc99ffd518c32cdf3de16a2dbbd1436 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: andes.c,v 1.1 1997/06/06 09:34:31 ralf Exp $
+/* $Id: andes.c,v 1.2 1997/08/08 18:13:01 miguel Exp $
  * andes.c: MMU and cache operations for the R10000 (ANDES).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -79,6 +79,12 @@ static void andes_pgd_init(unsigned long page)
 {
 }
 
+static void andes_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                                 unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_andes(void)
 {
        flush_cache_all = andes_flush_cache_all;
@@ -92,6 +98,8 @@ void ld_mmu_andes(void)
        flush_tlb_mm = andes_flush_tlb_mm;
        flush_tlb_range = andes_flush_tlb_range;
        flush_tlb_page = andes_flush_tlb_page;
+    
+        add_wired_entry = andes_add_wired_entry;
 
        load_pgd = andes_load_pgd;
        pgd_init = andes_pgd_init;
index f1ebab648617209df9fc047e79a3b39b1bc28958..72e13336b93692c57dd568de9e977884e583953f 100644 (file)
@@ -117,7 +117,8 @@ bad_area:
         * terminate things with extreme prejudice.
         */
        printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
-              "address %08lx, epc == %08lx\n", address, regs->cp0_epc);
+              "address %08lx, epc == %08lx, ra == %08lx\n",
+              address, regs->cp0_epc, regs->regs[31]);
        die_if_kernel("Oops", regs, writeaccess);
        do_exit(SIGKILL);
 out:
index 43eb70ee117a0849edb5b713e21e292bd35a8ab0..3357bbcd29a5499ba4fde0e76478d34426af6cac 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.1 1997/06/06 09:34:51 ralf Exp $
+/* $Id: loadmmu.c,v 1.2 1997/08/08 18:13:05 miguel Exp $
  * loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -41,6 +41,10 @@ void (*update_mmu_cache)(struct vm_area_struct * vma,
                         unsigned long address, pte_t pte);
 
 void (*show_regs)(struct pt_regs *);
+
+void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+                       unsigned long entryhi, unsigned long pagemask);
+
 asmlinkage void (*resume)(void *tsk);
 
 extern void ld_mmu_r2300(void);
index bbf8fbe1a474611fcffc90ca2f44f71c358b9e65..a8aab4c4e4c0c8ff13a57ffa0e1c371b010cb1b0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300.c,v 1.2 1997/06/30 15:52:51 ralf Exp $
+ * $Id: r2300.c,v 1.3 1997/08/08 18:13:06 miguel Exp $
  */
 
 #include <linux/kernel.h>
@@ -245,6 +245,14 @@ static void r2300_show_regs(struct pt_regs * regs)
               (unsigned int) regs->cp0_cause);
 }
 
+static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                                 unsigned long entryhi, unsigned long pagemask)
+{
+        /*
+        * FIXME, to be done
+        */
+}
+
 void ld_mmu_r2300(void)
 {
        clear_page = r2300_clear_page;
@@ -267,6 +275,8 @@ void ld_mmu_r2300(void)
        update_mmu_cache = r2300_update_mmu_cache;
 
        show_regs = r2300_show_regs;
+    
+        add_wired_entry = r2300_add_wired_entry;
 
        flush_tlb_all();
 }
index c4eb3cd82d799355bd1d1d446fbba3974a826373..311d11fb679ead1ed0b0c3b406d9723ded444bda 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4xx0.c,v 1.4 1997/06/30 15:52:53 ralf Exp $
+ * $Id: r4xx0.c,v 1.5 1997/08/08 18:13:07 miguel Exp $
  */
 #include <linux/config.h>
 
@@ -1856,7 +1856,7 @@ static inline void r4k_flush_tlb_all(void)
        set_entrylo1(0);
        BARRIER;
 
-       entry = 0;
+       entry = get_wired();
 
        /* Blast 'em all away. */
        while(entry < NTLB_ENTRIES) {
@@ -1943,7 +1943,7 @@ static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
                int oldpid, newpid, idx;
 
 #ifdef DEBUG_TLB
-               printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+               printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
 #endif
                newpid = (vma->vm_mm->context & 0xff);
                page &= (PAGE_MASK << 1);
@@ -2122,6 +2122,37 @@ static void r4k_show_regs(struct pt_regs * regs)
        printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\n",
               regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
 }
+                       
+static void r4k_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                                     unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+        flush_tlb_all();    
+        restore_flags(flags);
+}
 
 /* Detect and size the various r4k caches. */
 static void probe_icache(unsigned long config)
@@ -2567,6 +2598,8 @@ try_again:
        update_mmu_cache = r4k_update_mmu_cache;
 
        show_regs = r4k_show_regs;
+    
+        add_wired_entry = r4k_add_wired_entry;
 
        flush_cache_all();
        write_32bit_cp0_register(CP0_WIRED, 0);
index 25132d7ff05d48898cef4b5b8381b1becca332be..6e8ad763d8eb1d33025c1762118cfdb98ceea049 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: r6000.c,v 1.1 1997/06/06 09:35:31 ralf Exp $
+/* $Id: r6000.c,v 1.2 1997/08/08 18:13:11 miguel Exp $
  * r6000.c: MMU and cache routines for the R6000 processors.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -156,6 +156,12 @@ static void r6000_show_regs(struct pt_regs * regs)
               (unsigned int) regs->cp0_cause);
 }
 
+static void r6000_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                                 unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_r6000(void)
 {
        flush_cache_all = r6000_flush_cache_all;
@@ -175,6 +181,8 @@ void ld_mmu_r6000(void)
        update_mmu_cache = r6000_update_mmu_cache;
 
        show_regs = r6000_show_regs;
+    
+        add_wired_entry = r6000_add_wired_entry;
 
        flush_cache_all();
        flush_tlb_all();
index bd52c9b1f799fb37e80cf2c788c7517e1850c318..4ae5ffd6e0e95d954f7065662b13fe9a3c7a530a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tfp.c,v 1.1 1997/06/06 09:35:39 ralf Exp $
+/* $Id: tfp.c,v 1.2 1997/08/08 18:13:13 miguel Exp $
  * tfp.c: MMU and cache routines specific to the r8000 (TFP).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -79,6 +79,12 @@ static void tfp_pgd_init(unsigned long page)
 {
 }
 
+static void tfp_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                               unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_tfp(void)
 {
        flush_cache_all = tfp_flush_cache_all;
@@ -93,9 +99,11 @@ void ld_mmu_tfp(void)
        flush_tlb_range = tfp_flush_tlb_range;
        flush_tlb_page = tfp_flush_tlb_page;
 
+        add_wired_entry = tfp_add_wired_entry;
+
        load_pgd = tfp_load_pgd;
        pgd_init = tfp_pgd_init;
-
+    
        flush_cache_all();
        flush_tlb_all();
 }
diff --git a/arch/mips/mm/umap.c b/arch/mips/mm/umap.c
new file mode 100644 (file)
index 0000000..7ce0d8e
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * arch/mips/mm/umap.c
+ *
+ * (C) Copyright 1994 Linus Torvalds
+ *
+ * Changes:
+ *
+ * Modified from Linus source to removing active mappings from any
+ * task.  This is required for implementing the virtual graphics
+ * interface for direct rendering on the SGI - miguel.
+ *
+ * Added a routine to map a vmalloc()ed area into user space, this one
+ * is required by the /dev/shmiq driver - miguel.
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/swap.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+static inline void
+remove_mapping_pte_range (pmd_t *pmd, unsigned long address, unsigned long size)
+{
+       pte_t *pte;
+       unsigned long end;
+
+       if (pmd_none (*pmd))
+               return;
+       if (pmd_bad (*pmd)){
+               printk ("remove_graphics_pte_range: bad pmd (%08lx)\n", pmd_val (*pmd));
+               pmd_clear (pmd);
+               return;
+       }
+       pte = pte_offset (pmd, address);
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               pte_t entry = *pte;
+               if (pte_present (entry))
+                       set_pte (pte, pte_modify (entry, PAGE_NONE));
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+                                                 
+}
+
+static inline void
+remove_mapping_pmd_range (pgd_t *pgd, unsigned long address, unsigned long size)
+{
+       pmd_t *pmd;
+       unsigned long end;
+
+       if (pgd_none (*pgd))
+               return;
+
+       if (pgd_bad (*pgd)){
+               printk ("remove_graphics_pmd_range: bad pgd (%08lx)\n", pgd_val (*pgd));
+               pgd_clear (pgd);
+               return;
+       }
+       pmd = pmd_offset (pgd, address);
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               remove_mapping_pte_range (pmd, address, end - address);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+               
+}
+
+/*
+ * This routine is called from the page fault handler to remove a
+ * range of active mappings at this point
+ */
+void
+remove_mapping (struct task_struct *task, unsigned long start, unsigned long end)
+{
+       unsigned long beg = start;
+       pgd_t *dir;
+
+       down (&task->mm->mmap_sem);
+       dir = pgd_offset (task->mm, start);
+       flush_cache_range (task->mm, beg, end);
+       while (start < end){
+               remove_mapping_pmd_range (dir, start, end - start);
+               start = (start + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       }
+       flush_tlb_range (task->mm, beg, end);
+       up (&task->mm->mmap_sem);
+}
+
+void *vmalloc_uncached (unsigned long size)
+{
+       return vmalloc_prot (size, PAGE_KERNEL_UNCACHED);
+}
+
+static inline void free_pte(pte_t page)
+{
+       if (pte_present(page)) {
+               unsigned long addr = pte_page(page);
+               if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+                       return;
+               free_page(addr);
+               if (current->mm->rss <= 0)
+                       return;
+               current->mm->rss--;
+               return;
+       }
+       swap_free(pte_val(page));
+}
+
+static inline void forget_pte(pte_t page)
+{
+       if (!pte_none(page)) {
+               printk("forget_pte: old mapping existed!\n");
+               free_pte(page);
+       }
+}
+
+/*
+ * maps a range of vmalloc()ed memory into the requested pages. the old
+ * mappings are removed. 
+ */
+static inline void
+vmap_pte_range (pte_t *pte, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+       unsigned long end;
+       pgd_t *vdir;
+       pmd_t *vpmd;
+       pte_t *vpte;
+       
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               pte_t oldpage = *pte;
+               unsigned long page;
+               pte_clear(pte);
+
+               vdir = pgd_offset_k (vaddr);
+               vpmd = pmd_offset (vdir, vaddr);
+               vpte = pte_offset (vpmd, vaddr);
+               page = pte_page (*vpte);
+               
+               set_pte(pte, mk_pte_phys(page, PAGE_USERIO));
+               forget_pte(oldpage);
+               address += PAGE_SIZE;
+               vaddr += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+}
+
+static inline int
+vmap_pmd_range (pmd_t *pmd, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       vaddr -= address;
+       do {
+               pte_t * pte = pte_alloc(pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               vmap_pte_range(pte, address, end - address, address + vaddr);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+       return 0;
+}
+
+int
+vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr)
+{
+       int error = 0;
+       pgd_t * dir;
+       unsigned long beg = from;
+       unsigned long end = from + size;
+
+       vaddr -= from;
+       dir = pgd_offset(current->mm, from);
+       flush_cache_range(current->mm, beg, end);
+       while (from < end) {
+               pmd_t *pmd = pmd_alloc(dir, from);
+               error = -ENOMEM;
+               if (!pmd)
+                       break;
+               error = vmap_pmd_range(pmd, from, end - from, vaddr + from);
+               if (error)
+                       break;
+               from = (from + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       }
+       flush_tlb_range(current->mm, beg, end);
+       return error;
+}
index cec9f360095417f4ec9d8a84fe40e3d76f16fc5c..f63b8c37ddfe84f4676476385208895eecbe7241 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: setup.c,v 1.2 1997/06/30 15:26:24 ralf Exp $
+/*
  * setup.c: SGI specific setup, including init of the feature struct.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: setup.c,v 1.3 1997/08/08 18:13:22 miguel Exp $
  */
 #ifndef __GOGOGO__
 #error "... about to fuckup your Indy?"
@@ -9,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
+#include <asm/addrspace.h>
+#include <asm/keyboard.h>
 #include <asm/reboot.h>
 #include <asm/vector.h>
 #include <asm/sgialib.h>
@@ -26,6 +30,36 @@ extern void sgi_machine_power_off(void);
 struct feature sgi_feature = {
 };
 
+static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+
+static unsigned char sgi_read_input(void)
+{
+       return sgi_kh->data;
+}
+
+static void sgi_write_output(unsigned char val)
+{
+       sgi_kh->data = val;
+}
+
+static void sgi_write_command(unsigned char val)
+{
+       sgi_kh->command = val;
+}
+
+static unsigned char sgi_read_status(void)
+{
+       return sgi_kh->command;
+}
+
+static void sgi_keyboard_setup(void)
+{
+       kbd_read_input = sgi_read_input;
+       kbd_write_output = sgi_write_output;
+       kbd_write_command = sgi_write_command;
+       kbd_read_status = sgi_read_status;
+}
+
 static void sgi_irq_setup(void)
 {
        sgint_init();
@@ -52,6 +86,7 @@ void sgi_setup(void)
 
        irq_setup = sgi_irq_setup;
        feature = &sgi_feature;
+       keyboard_setup = sgi_keyboard_setup;
 
        _machine_restart = sgi_machine_restart;
        _machine_halt = sgi_machine_halt;
index 39cbec4102208e180e98fedb36f87db58f31a76f..192a33371270ef9ba1ab718539f91a849315c062 100644 (file)
@@ -5,9 +5,12 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:13:27 miguel Exp $
  */
 #include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -15,6 +18,7 @@
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
 #include <asm/dma.h>
+#include <asm/keyboard.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mc146818rtc.h>
@@ -157,3 +161,32 @@ struct feature sni_rm200_pci_feature = {
        rtc_read_data,
        rtc_write_data
 };
+
+static unsigned char sni_read_input(void)
+{
+       return inb(KBD_DATA_REG);
+}
+
+static void sni_write_output(unsigned char val)
+{
+       outb(val, KBD_DATA_REG);
+}
+
+static void sni_write_command(unsigned char val)
+{
+       outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char sni_read_status(void)
+{
+       return inb(KBD_STATUS_REG);
+}
+
+void sni_rm200_keyboard_setup(void)
+{
+       kbd_read_input = sni_read_input;
+       kbd_write_output = sni_write_output;
+       kbd_write_command = sni_write_command;
+       kbd_read_status = sni_read_status;
+       request_region(0x60, 16, "keyboard");
+}
index 7fa76a490e3e6e5bfa49acc07b539627e1b3d95b..b73c857b471027baadd990ccbdc57091252ebfd7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/timex.h>
 #include <linux/pci.h>
 #include <asm/bootinfo.h>
+#include <asm/keyboard.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
@@ -36,6 +37,7 @@ static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
 extern asmlinkage void sni_rm200_pci_handle_int(void);
 extern asmlinkage void sni_fd_cacheflush(const void *addr, size_t size);
 extern struct feature sni_rm200_pci_feature;
+extern void sni_rm200_keyboard_setup(void);
 
 extern void sni_machine_restart(char *command);
 extern void sni_machine_halt(void);
@@ -127,6 +129,7 @@ __initfunc(void sni_rm200_pci_setup(void))
        fd_cacheflush = sni_fd_cacheflush;      // Will go away
        feature = &sni_rm200_pci_feature;
        port_base = SNI_PORT_BASE;
+       keyboard_setup = sni_rm200_keyboard_setup;
 
        /*
         * Setup (E)ISA I/O memory access stuff
index ac271997766721757f2b6300b191dedb2947e612..8c114a02100d192445320698d577f919ae4c1f59 100644 (file)
 #
 # Copyright (C) 1994 by Linus Torvalds
 # Changes for PPC by Gary Thomas
-# Modified by Cort Dougan
+# Modified by Cort Dougan and Paul Mackerras
 #
 
+ifeq ($(CONFIG_PMAC),y)
+KERNELBASE     =0xc0000000
+else
+KERNELBASE     =0x90000000
+endif
+
 # PowerPC (cross) tools
-SUFFIX         = 
-AS             = as$(SUFFIX)
-ASFLAGS                = 
-LD             = ld$(SUFFIX)
-LINKFLAGS      = -T arch/ppc/ld.script -Ttext 0x90000000 
-HOSTCC         = gcc
-CC             = gcc$(SUFFIX)
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE  =powerpc-eabi-
+endif
+
+ASFLAGS                =
+LINKFLAGS      = -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic
 CFLAGSINC      = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS         = $(CFLAGSINC) \
-               -Wstrict-prototypes -fomit-frame-pointer \
+               -Wall -Wstrict-prototypes -Wno-uninitialized \
                -fno-builtin \
-               -finhibit-size-directive \
-               -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
-# -fverbose-asm 
+               -fsigned-char \
+               -msoft-float \
+               -O2 -pipe
 CPP            = $(CC) -E $(CFLAGS)
-AR             = ar$(SUFFIX)
-RANLIB         = ranlib$(SUFFIX)
-STRIP          = strip$(SUFFIX)
-NM             = nm$(SUFFIX)
 
 ifdef CONFIG_601
 CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
@@ -55,59 +56,38 @@ SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
 ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
 CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc/xmon
+CORE_FILES += arch/ppc/xmon/x.o
+endif
+
+ifdef CONFIG_PMAC
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
+else
+# PReP systems
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+endif
 
 checks:
        @$(MAKE) -C arch/$(ARCH)/kernel checks
 
-netboot: checks vmlinux
-       @$(MAKEBOOT) netboot
-
-znetboot: checks vmlinux
-       @$(MAKEBOOT) znetboot
-
-#rcpboot: checks vmlinux
-#      @$(MAKEBOOT) rcpboot
+BOOT_TARGETS = netboot znetboot zImage floppy install \
+       vmlinux.coff znetboot.initrd zImage.initrd
 
-zImage: checks vmlinux
-       @$(MAKEBOOT) zImage
+$(BOOT_TARGETS): checks vmlinux
+       @$(MAKEBOOT) $@
 
-floppy: checks vmlinux
-       @$(MAKEBOOT) floppy
-
-install: checks vmlinux
-       @$(MAKEBOOT) install
-
-vmlinux.coff : checks vmlinux
-       $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
-
-arch/ppc/kernel: dummy
-       $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
-
-arch/ppc/mm: dummy
-       $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/mm
-
-arch/ppc/lib: dummy
-       $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
-
-diffs:
-       arch/ppc/mkdiff
-
-tar:
-       arch/ppc/mktar
+tags:
+       etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
 
 archclean:
-       rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
-       rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
-       rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+       rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
+       rm -f arch/ppc/kernel/checks
+       find arch/ppc/ -name '*.o' -exec /bin/rm -f '{}' \;
+       find arch/ppc/ -name '*~' -exec /bin/rm -f '{}' \;
+       find arch/ppc/ -name '*.a' -exec /bin/rm -f '{}' \;
        @$(MAKEBOOT) clean
 
 archdep:
-       $(MAKE) -C arch/ppc/boot fastdep
-       $(MAKE) -C arch/ppc/kernel fastdep
-       $(MAKE) -C arch/ppc/mm fastdep
-       $(MAKE) -C arch/ppc/lib fastdep
-
-tags :
-       etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c 
+       $(MAKEBOOT) fastdep
 
index 5dcac750e4136d1c586594f203e25ac2659b00e1..16ceec16a29503576be562414dfc30bc38256ae9 100644 (file)
        $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 
-ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
 GZIP_FLAGS = -v9
 
 SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
-
+OBJECTS = head.o inflate.o unzip.o misc.o vreset.o #kbd.o
 CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+OBJCOPY = objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
 
 all:   $(TOPDIR)/zImage
 
@@ -39,41 +40,40 @@ mkprep : mkprep.c
 find_name : find_name.c
        $(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
 
-mk_type41: mk_type41.c
-       $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
-
-piggyback: piggyback.c
-       $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
 floppy: $(TOPDIR)/vmlinux zImage 
        dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
 
-netboot : $(TOPDIR)/vmlinux mkprep
-       mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+floppy.initrd: $(TOPDIR)/vmlinux zImage 
+       dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b
 
-znetboot : zvmlinux mkprep
-       mkprep zvmlinux $(TOPDIR)/znetboot
-       cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
+znetboot : zImage mkprep
+       cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux
 
-rcpboot : znetboot
-       rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+znetboot.initrd : zImage.initrd mkprep
+       cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux
 
 zImage: zvmlinux mkprep
        mkprep -pbp zvmlinux $(TOPDIR)/zImage
 
-install: zImage
-       dd if=$(TOPDIR)/zImage of=/dev/sda4
-       ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
-       cp $(TOPDIR)/System.map $(INSTALL_PATH)/        
+zImage.initrd: zvmlinux.initrd mkprep
+       mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd
+
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep  find_name vmlinux.gz
+       $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+               zvmlinux.tmp $@
+       rm zvmlinux.tmp
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+       dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz
 
-zvmlinux: $(OBJECTS) $(SYSTEM) mkprep  find_name
-       mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
-       $(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
-       rm -f piggy.o
+zvmlinux.initrd: zvmlinux
+       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+               zvmlinux $@
 
 clean:
-       rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
-       rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+       rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name
+       rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*}
 
 fastdep:
        $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
index 6b25cb15736ffe278fd95b443036abac85f40b15..d613cbc03cd3a5f19db3668060aeb72c56543d27 100644 (file)
 start:
        bl      start_
 start_:
-/* TEMP - No residual data on BeBox (yet) */
-#if 0  
-#define IS_BE_BOX      0x42654278      /* 'BeBx' */
-       lis     r2,IS_BE_BOX>>16
-       ori     r2,r2,IS_BE_BOX&0xFFFF
-       cmp     0,r30,r2
-       bne     notBeBox
-       li      r3,0
-#endif 
-notBeBox:
-/* TEMP */
        mr      r11,r3          /* Save pointer to residual data */
        mfmsr   r3              /* Turn off interrupts */
        li      r4,0
@@ -48,7 +37,9 @@ notBeBox:
        mtlr    r21
        mtctr   r22
        bctr                    /* Jump to code */
-/* Relocate code to final resting spot */
+/* 
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
 relocate:
        mflr    r3              /* Compute code bias */
        subi    r3,r3,4
@@ -98,13 +89,26 @@ start_ldr:
        mr      r5,r6                   /* Checksum */
        mr      r6,r11                  /* Residual data */
        bl      decompress_kernel
-       /*mr    r29,r3*/                        /* R3 = TotalMemory */
-       /*lis   r28,hold_residual@h
-       ori     r28,r28,hold_residual@l*/
+       
        /* changed to use r3 (as firmware does) for kernel
           as ptr to residual -- Cort*/
-       li      r5,0x100                /* Kernel code starts here */
-       mtlr    r5
+       lis     r6,cmd_line@h
+       ori     r6,r6,cmd_line@l
+       subi    r7,r7,1
+00:    lbzu    r2,1(r12)
+       cmpi    0,r2,0
+       bne     00b
+
+       /* r4,r5 have initrd_start, size */
+       lis     r2,initrd_start@h
+       ori     r2,r2,initrd_start@l
+       lwz     r4,0(r2)
+       lis     r2,initrd_end@h
+       ori     r2,r2,initrd_end@l
+       lwz     r5,0(r2)
+               
+       li      r9,0x00c                /* Kernel code starts here */
+       mtlr    r9
        blr     
 hang:
        b       hang    
@@ -141,6 +145,45 @@ _put_HID0:
        mtspr   HID0,r3
        blr
 
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+       .globl  udelay
+udelay:                
+       mfspr   r4,PVR
+       srwi    r4,r4,16
+       cmpi    0,r4,1          /* 601 ? */
+       bne     .udelay_not_601
+00:    li      r0,86   /* Instructions / microsecond? */
+       mtctr   r0
+10:    addi    r0,r0,0 /* NOP */
+       bdnz    10b
+       subic.  r3,r3,1
+       bne     00b
+       blr
+
+.udelay_not_601:               
+       mulli   r4,r3,1000      /* nanoseconds */
+       addi    r4,r4,59
+       li      r5,60
+       divw    r4,r4,r5        /* BUS ticks */
+1:     mftbu   r5
+       mftb    r6
+       mftbu   r7
+       cmp     0,r5,r7
+       bne     1b              /* Get [synced] base time */
+       addc    r9,r6,r4        /* Compute end time */
+       addze   r8,r5
+2:     mftbu   r5
+       cmp     0,r5,r8
+       blt     2b
+       bgt     3f
+       mftb    r6
+       cmp     0,r6,r9
+       blt     2b
+3:     blr             
+       
 /*
  * This space [buffer] is used to forceably flush the data cache when
  * running in copyback mode.  This is necessary IFF the data cache could
index a983ea106ee7e49f7b374302fd87a795c2c04ee5..618a52cded37f1e61426b8c9d798dc2bfc7a28c9 100644 (file)
@@ -8,13 +8,23 @@
  * puts by Nick Holloway 1993
  *
  * Adapted for PowerPC by Gary Thomas
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
  */
 
 #include "gzip.h"
 #include "lzw.h"
 #include "asm/residual.h"
+#include <elf.h>
 
 RESIDUAL hold_residual;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+extern char input_data[];
+extern int input_len;
+void cksum_text(void);
+void verify_data(unsigned long load_addr);
+
 void dump_buf(unsigned char *p, int s);
 #define EOF -1
 
@@ -26,8 +36,7 @@ unsigned outcnt;
 unsigned insize;
 unsigned inptr;
 
-extern char input_data[];
-extern int input_len;
+char cmd_line[256];
 
 int input_ptr;
 
@@ -56,6 +65,9 @@ int lines, cols;
 int orig_x, orig_y;
 
 void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
 
 void *malloc(int size)
 {
@@ -77,7 +89,7 @@ void *malloc(int size)
         */
           
        if (free_mem_ptr < (long)&end) {
-               if (free_mem_ptr > (long)&input_data[input_ptr])
+               if (free_mem_ptr > (long)&zimage_start[input_ptr])
                        error("\nOut of memory\n");
 
                return p;
@@ -87,7 +99,7 @@ void *malloc(int size)
 #endif 
        return p;
        puts("large kernel, low 1M tight...");
-       free_mem_ptr = (long)input_data;
+       free_mem_ptr = (long)zimage_start;
        }
 }
 
@@ -114,6 +126,53 @@ static void scroll()
        for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
                vidmem[i] = ' ';
 }
+#if 0
+tstc(void)
+{
+       return (CRT_tstc() );
+}
+
+getc(void)
+{
+       while (1) {
+               if (CRT_tstc()) return (CRT_getc());
+       }
+}
+#endif
+void 
+putc(const char c)
+{
+       int x,y;
+
+       x = orig_x;
+       y = orig_y;
+
+       if ( c == '\n' ) {
+               x = 0;
+               if ( ++y >= lines ) {
+                       scroll();
+                       y--;
+               }
+       } else if (c == '\b') {
+               if (x > 0) {
+                       x--;
+               }
+       } else {
+               vidmem [ ( x + cols * y ) * 2 ] = c; 
+               if ( ++x >= cols ) {
+                       x = 0;
+                       if ( ++y >= lines ) {
+                               scroll();
+                               y--;
+                       }
+               }
+       }
+
+       cursor(x, y);
+
+       orig_x = x;
+       orig_y = y;
+}
 
 void puts(const char *s)
 {
@@ -229,10 +288,10 @@ puts("*");
     insize = 0;
     do {
        len = INBUFSIZ-insize;
-       if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+       if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1;
         if (len == 0 || len == EOF) break;
 
-        for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+        for (i=0;i<len;i++) inbuf[insize+i] = zimage_start[input_ptr+i];
        insize += len;
        input_ptr += len;
     } while (insize < INBUFSIZ);
@@ -313,7 +372,14 @@ void error(char *x)
 unsigned long
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
 {
-  unsigned long TotalMemory;
+  int timer;
+  char *cp, ch;
+  Elf32_Ehdr *eh;
+  Elf32_Shdr *sh, *strtab_shdr;
+  char *strtab;
+  unsigned long i;
+
+  
   output_data = (char *)0x0;   /* Points to 0 */
   lines = 25;
   cols = 80;
@@ -339,33 +405,102 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
   clear_bufs();
   makecrc();
 
-  puts("Loaded at ");  puthex(load_addr);  puts(", ");  puthex(num_words);  puts(" words");
-  puts(", cksum = ");  puthex(cksum);  puts("\n");
+  puts("Loaded at: ");  puthex(load_addr); puts(" ");  puthex(num_words+load_addr);
+  puts("\n");
+  /*puts("Relocated to start: ");  puthex(start); puts(" ");
+  puthex(num_words+start);
+  puts("\n");*/
+  puts("Cksum: ");  puthex(cksum);  puts("\n");
   if (residual) {
-    _bcopy(residual, &hold_residual, sizeof(hold_residual));
-    puts("Residual data at ");  puthex(residual);  puts("\n");
-    show_residual_data(residual);
-    TotalMemory = residual->TotalMemory;
-  } else {
-    TotalMemory = 0x01000000;
+    _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual));
+    puts("Residual data at: ");  puthex((unsigned long)residual); puts(" ");
+    puthex((unsigned long)(residual->ResidualLength + residual));  puts("\n");
   }
 
-  puts("Uncompressing Linux...");
+  /*
+   * Take care of initrd if we have one
+   */
+  /*
+   * the _actual_ load addr is 64k (elf hdr size) lower but the
+   * firmware gives us the starting exec point not the load ptr
+   * -- Cort
+   */
+  eh = (Elf32_Ehdr *)(load_addr - 65536);
+  sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+  /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/
+  
+  /* find string table */
+  for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+  {
+         /*puts("Section: "); puthex(i);
+         puts(" type: "); puthex(sh->sh_type);
+         puts(" offset: "); puthex(sh->sh_offset);
+         puts("\n");*/
+
+         if ( sh->sh_type == SHT_STRTAB )
+         {
+                 strtab_shdr = sh;
+                 strtab = (char *)(sh->sh_offset + (unsigned long)eh);
+                 /*puts("Found strtab at: "); puthex((unsigned long)strtab);
+                 puts("\n");*/
+                 break;
+         }
+  }  
 
-  method = get_method(0);
+  /* find the initrd and image sections */
+  if ( strtab_shdr )
+  {
+         sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+         for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+         {
+                 if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) )
+                 {
+                         initrd_start = (unsigned long)eh + sh->sh_offset;
+                         initrd_end =  initrd_start + sh->sh_size;
+                         puts("Found initrd at: "); puthex(initrd_start);
+                         puts(" "); puthex(initrd_end);
+                         puts("\n");
+                 }
+                 if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) )
+                 {
+                         zimage_start = (char *)((unsigned long)eh + sh->sh_offset);
+                         zimage_size =  sh->sh_size;
+                         puts("Found zimage at: "); puthex((unsigned long)zimage_start);
+                         puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+                         puts("\n");
+                 }
+         }
+  }
+  else
+  {
+         puts("Couldn't find string table for boot image!\n");
+  }
+  
+  /* relocate initrd */
+  if ( initrd_start )
+  {
+         memcpy ((void *)0x00D00000,(void *)initrd_start,
+                 initrd_end - initrd_start );
+         initrd_end = 0x00D00000 + initrd_end - initrd_start;
+         initrd_start = 0x00D00000;
+         puts("Moved initrd to: "); puthex(initrd_start);
+         puts(" "); puthex(initrd_end); puts("\n");
+  }
 
+  /* make the moto firmware print something */
+  
+  puts("Uncompressing Linux...");
+  method = get_method(0);
   work(0, 0);
-
   puts("done.\n");
+  
   puts("Now booting the kernel\n");
-  /*return (TotalMemory);*/              /* Later this can be a pointer to saved residual data */
-  return &hold_residual;
+  return (unsigned long)&hold_residual;
 }
 
 show_residual_data(RESIDUAL *res)
 {
   puts("Residual data: ");  puthex(res->ResidualLength);  puts(" bytes\n");
-  puts("Total memory: ");  puthex(res->TotalMemory);  puts("\n");
 #if 0
   puts("Residual structure = ");  puthex(sizeof(*res));  puts(" bytes\n");
   dump_buf(&hold_residual, 32);
@@ -407,14 +542,14 @@ cksum_data()
 {
   unsigned int *ptr, len, cksum, cnt;
   cksum = cnt = 0;
-  ptr = input_data;
+  ptr = (unsigned int *)zimage_start;
   puts("Checksums: ");
-  for (len = 0;  len < input_len;  len += 4) {
+  for (len = 0;  len < zimage_size;  len += 4) {
     cksum ^= *ptr++;
     if (len && ((len & 0x0FFF) == 0)) {
       if (cnt == 0) {
        puts("\n  [");
-       puthex(ptr-1);
+       puthex((unsigned long)ptr-1);
        puts("] ");
       }
       puthex(cksum);
@@ -429,7 +564,7 @@ cksum_data()
   puts("Data cksum = ");  puthex(cksum);  puts("\n");
 }
 
-cksum_text()
+void cksum_text(void)
 {
   extern int start, etext;
   unsigned int *ptr, len, text_len, cksum, cnt;
@@ -442,7 +577,7 @@ cksum_text()
     if (len && ((len & 0x0FFF) == 0)) {
       if (cnt == 0) {
        puts("\n  [");
-       puthex(ptr-1);
+       puthex((unsigned long)ptr-1);
        puts("] ");
       }
       puthex(cksum);
@@ -457,24 +592,24 @@ cksum_text()
   puts("TEXT cksum = ");  puthex(cksum);  puts("\n");
 }
 
-verify_data(unsigned long load_addr)
+void verify_data(unsigned long load_addr)
 {
   extern int start, etext;
   unsigned int *orig_ptr, *copy_ptr, len, errors;
   errors = 0;
-  copy_ptr = input_data;
-  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
-  for (len = 0;  len < input_len;  len += 4) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  len += 4) {
     if (*copy_ptr++ != *orig_ptr++) {
       errors++;
     }    
   }
-  copy_ptr = input_data;
-  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
-  for (len = 0;  len < input_len;  len += 4) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  len += 4) {
     if (*copy_ptr++ != *orig_ptr++) {
-      dump_buf(copy_ptr-1, 128);
-      dump_buf(orig_ptr-1, 128);
+      dump_buf((unsigned char *) (copy_ptr-1), 128);
+      dump_buf((unsigned char *) (orig_ptr-1), 128);
       puts("Total errors = ");  puthex(errors*4);  puts("\n");
       while (1) ;
     }    
@@ -486,9 +621,9 @@ test_data(unsigned long load_addr)
   extern int start, etext;
   unsigned int *orig_ptr, *copy_ptr, len, errors;
   errors = 0;
-  copy_ptr = input_data;
-  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
-  for (len = 0;  len < input_len;  len += 4) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  len += 4) {
     if (*copy_ptr++ != *orig_ptr++) {
       errors++;
     }    
@@ -532,7 +667,7 @@ void dump_buf(unsigned char *p, int s)
    }
    while (s > 0)
    {
-      puthex(p);  puts(": ");
+      puthex((unsigned long)p);  puts(": ");
       for (i = 0;  i < 16;  i++)
       {
          if (i < s)
index 4173346703a5583eea904153abfd4a05679171ac..06b08df98cf7c7c4fd6009edf5d3785c9380ea61 100644 (file)
@@ -131,17 +131,18 @@ int main(int argc, char *argv[])
   argptr++;
 
   /* skip elf header in input file */
-  lseek(in_fd, elfhdr_size, SEEK_SET);
+  if ( !prep )
+         lseek(in_fd, elfhdr_size, SEEK_SET);
   
   /* write prep partition if necessary */
   if ( prep )
-    write_prep_partition( in_fd, out_fd );
+         write_prep_partition( in_fd, out_fd );
 
   /* write input image to bootimage */
   if ( asmoutput )
-    write_asm_data( in_fd, out_fd );
+         write_asm_data( in_fd, out_fd );
   else
-    copy_image(in_fd, out_fd);
+         copy_image(in_fd, out_fd);
   
   return 0;
 }
@@ -161,28 +162,11 @@ void write_prep_partition(int in, int out)
   }
   
   bzero( block, sizeof block );
-
  
-  /* set entry point and boot image size */
-  *entry = cpu_to_le32(0x400);
-  /* need use size - elfheader? */
+  /* set entry point and boot image size skipping over elf header */
+  *entry = cpu_to_le32(0x400+65536);
   *length = cpu_to_le32(info.st_size+0x400);
 
-  /*
-   * Writes the "boot record", which contains the partition table, to the
-   * diskette, followed by the dummy PC boot block and load image descriptor
-   * block.  It returns the number of bytes it has written to the load
-   * image.
-   *
-   * The boot record is the first block of the diskette and identifies the
-   * "PReP" partition.  The "PReP" partition contains the "load image" starting
-   * at offset zero within the partition.  The first block of the load image is
-   * a dummy PC boot block.  The second block is the "load image descriptor"
-   * which contains the size of the load image and the entry point into the
-   * image.  The actual boot image starts at offset 1024 bytes (third sector)
-   * in the partition.
-   */
-  
   /* sets magic number for msdos partition (used by linux) */
   block[510] = 0x55;
   block[511] = 0xAA;
@@ -220,7 +204,7 @@ void write_prep_partition(int in, int out)
   /* This has to be 0 on the PowerStack? */   
   pe->beginning_sector  = cpu_to_le32(0);
 #endif    
-/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+  pe->number_of_sectors = cpu_to_le32(2*18*80-1);
 
   write( out, block, sizeof(block) );
   write( out, entry, sizeof(*entry) );
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
new file mode 100644 (file)
index 0000000..e145411
--- /dev/null
@@ -0,0 +1,50 @@
+# Makefile for making XCOFF bootable images for booting on PowerMacs
+# using Open Firmware.
+#
+# Paul Mackerras       January 1997
+
+# PowerPC (cross) tools
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE  =powerpc-eabi-
+endif
+
+HOSTCC = gcc
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC     = $(CROSS_COMPILE)gcc
+LD     = $(CROSS_COMPILE)ld
+CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
+       --add-section=image=zImage
+LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+GZIP = gzip -9
+
+OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+LIBS = $(TOPDIR)/lib/lib.a
+
+vmlinux.coff: coffboot hack-coff zImage
+       $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+       ./hack-coff $@
+
+vmlinux.coff.initrd: coffboot hack-coff zImage ramdisk.image.gz
+       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+               coffboot $@
+       ./hack-coff $@
+
+coffboot: $(OBJS) ld.script
+       $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: $(TOPDIR)/vmlinux elfextract
+       ./elfextract $(TOPDIR)/vmlinux | $(GZIP) >zImage
+
+hack-coff: hack-coff.c
+       $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+
+elfextract: elfextract.c
+       $(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c
+
+clean:
+       rm -f elfextract hack-coff coffboot zImage vmlinux.coff
+
+fastdep:
diff --git a/arch/ppc/coffboot/crt0.S b/arch/ppc/coffboot/crt0.S
new file mode 100644 (file)
index 0000000..43ae4e0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+       .text
+       .globl  _start
+_start:
+       .long   __start,0,0
+
+       .globl  __start
+__start:
+       lis     9,_start@h
+       lis     8,_etext@ha
+       addi    8,8,_etext@l
+1:     dcbf    0,9
+       icbi    0,9
+       addi    9,9,0x20
+       cmplwi  0,9,8
+       blt     1b
+       b       start
diff --git a/arch/ppc/coffboot/elfextract.c b/arch/ppc/coffboot/elfextract.c
new file mode 100644 (file)
index 0000000..1b50ca4
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Extract the loadable program segment from an elf file.
+ *
+ * Copyright 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 <stdio.h>
+#include <linux/elf.h>
+
+FILE *fi, *fo;
+char *ni, *no;
+char buf[65536];
+
+void
+rd(void *buf, int len)
+{
+    int nr;
+
+    nr = fread(buf, 1, len, fi);
+    if (nr == len)
+       return;
+    if (ferror(fi))
+       fprintf(stderr, "%s: read error\n", ni);
+    else
+       fprintf(stderr, "%s: short file\n", ni);
+    exit(1);
+}
+
+main(int ac, char **av)
+{
+    unsigned nb, len;
+    Elf32_Ehdr eh;
+    Elf32_Phdr ph;
+
+    if (ac > 3 || ac > 1 && av[1][0] == '-') {
+       fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
+       exit(0);
+    }
+
+    fi = stdin;
+    ni = "(stdin)";
+    fo = stdout;
+    no = "(stdout)";
+
+    if (ac > 1) {
+       ni = av[1];
+       fi = fopen(ni, "rb");
+       if (fi == NULL) {
+           perror(ni);
+           exit(1);
+       }
+    }
+
+    rd(&eh, sizeof(eh));
+    if (eh.e_ident[EI_MAG0] != ELFMAG0
+       || eh.e_ident[EI_MAG1] != ELFMAG1
+       || eh.e_ident[EI_MAG2] != ELFMAG2
+       || eh.e_ident[EI_MAG3] != ELFMAG3) {
+       fprintf(stderr, "%s: not an ELF file\n", ni);
+       exit(1);
+    }
+
+    fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0);
+    rd(&ph, sizeof(ph));
+    if (ph.p_type != PT_LOAD) {
+       fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
+       exit(1);
+    }
+
+    if (ac > 2) {
+       no = av[2];
+       fo = fopen(no, "wb");
+       if (fo == NULL) {
+           perror(no);
+           exit(1);
+       }
+    }
+
+    fseek(fi, ph.p_offset, 0);
+    for (len = ph.p_filesz; len != 0; len -= nb) {
+       nb = len;
+       if (nb > sizeof(buf))
+           nb = sizeof(buf);
+       rd(buf, nb);
+       if (fwrite(buf, 1, nb, fo) != nb) {
+           fprintf(stderr, "%s: write error\n", no);
+           exit(1);
+       }
+    }
+
+    fclose(fo);
+    fclose(fi);
+    exit(0);
+}
diff --git a/arch/ppc/coffboot/hack-coff.c b/arch/ppc/coffboot/hack-coff.c
new file mode 100644 (file)
index 0000000..3dfa8d8
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdio.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC     0x010b
+
+#define get_16be(x)    ((((unsigned char *)(x))[0] << 8) \
+                        + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+                        ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x)    ((((unsigned char *)(x))[0] << 24) \
+                        + (((unsigned char *)(x))[1] << 16) \
+                        + (((unsigned char *)(x))[2] << 8) \
+                        + ((unsigned char *)(x))[3])
+
+main(int ac, char **av)
+{
+    int fd;
+    int i, nsect;
+    int aoutsz;
+    struct external_filehdr fhdr;
+    AOUTHDR aout;
+    struct external_scnhdr shdr;
+
+    if (ac != 2) {
+       fprintf(stderr, "Usage: hack-coff coff-file\n");
+       exit(1);
+    }
+    if ((fd = open(av[1], 2)) == -1) {
+       perror(av[2]);
+       exit(1);
+    }
+    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+       goto readerr;
+    i = get_16be(fhdr.f_magic);
+    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+       fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+       exit(1);
+    }
+    aoutsz = get_16be(fhdr.f_opthdr);
+    if (read(fd, &aout, aoutsz) != aoutsz)
+       goto readerr;
+    nsect = get_16be(fhdr.f_nscns);
+    for (i = 0; i < nsect; ++i) {
+       if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+           goto readerr;
+       if (strcmp(shdr.s_name, ".text") == 0) {
+           put_16be(aout.o_snentry, i+1);
+           put_16be(aout.o_sntext, i+1);
+       } else if (strcmp(shdr.s_name, ".data") == 0) {
+           put_16be(aout.o_sndata, i+1);
+       } else if (strcmp(shdr.s_name, ".bss") == 0) {
+           put_16be(aout.o_snbss, i+1);
+       }
+    }
+    put_16be(aout.magic, AOUT_MAGIC);
+    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+       || write(fd, &aout, aoutsz) != aoutsz) {
+       fprintf(stderr, "%s: write error\n", av[1]);
+       exit(1);
+    }
+    close(fd);
+    exit(0);
+
+readerr:
+    fprintf(stderr, "%s: read error or file too short\n", av[1]);
+    exit(1);
+}
diff --git a/arch/ppc/coffboot/ld.script b/arch/ppc/coffboot/ld.script
new file mode 100644 (file)
index 0000000..2469ed6
--- /dev/null
@@ -0,0 +1,68 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .rel.text      : { *(.rel.text)              }
+  .rela.text     : { *(.rela.text)     }
+  .rel.data      : { *(.rel.data)              }
+  .rela.data     : { *(.rela.data)     }
+  .rel.rodata    : { *(.rel.rodata)    }
+  .rela.rodata   : { *(.rela.rodata)   }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  .init          : { *(.init)  } =0
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.rodata)
+    *(.rodata1)
+    *(.got1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  _etext = .;
+  PROVIDE (etext = .);
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+
diff --git a/arch/ppc/coffboot/main.c b/arch/ppc/coffboot/main.c
new file mode 100644 (file)
index 0000000..ab0ee6c
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 "nonstdio.h"
+#include "rs6000.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x)    (*(unsigned short *)(x))
+#define get_32be(x)    (*(unsigned *)(x))
+
+#define RAM_START      0xc0000000
+#define RAM_END                0xc0800000      /* only 8M mapped with BATs */
+
+#define RAM_FREE       0xc0540000      /* after image of coffboot */
+
+char *avail_ram;
+char *end_avail;
+
+coffboot(int a1, int a2, void *prom)
+{
+    void *options;
+    unsigned loadbase;
+    struct external_filehdr *eh;
+    struct external_scnhdr *sp;
+    struct external_scnhdr *isect, *rsect;
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+
+    printf("coffboot starting\n");
+    options = finddevice("/options");
+    if (options == (void *) -1)
+       exit();
+    if (getprop(options, "load-base", &loadbase, sizeof(loadbase))
+       != sizeof(loadbase)) {
+       printf("error getting load-base\n");
+       exit();
+    }
+    setup_bats();
+
+    eh = (struct external_filehdr *) loadbase;
+    ns = get_16be(eh->f_nscns);
+    oh = get_16be(eh->f_opthdr);
+
+    sp = (struct external_scnhdr *) (loadbase + sizeof(struct external_filehdr) + oh);
+    isect = rsect = NULL;
+    for (i = 0; i < ns; ++i, ++sp) {
+       if (strcmp(sp->s_name, "image") == 0)
+           isect = sp;
+       else if (strcmp(sp->s_name, "initrd") == 0)
+           rsect = sp;
+    }
+    if (isect == NULL) {
+       printf("image section not found\n");
+       exit();
+    }
+
+    if (rsect != NULL && (initrd_size = get_32be(rsect->s_size)) != 0) {
+       initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+       a1 = initrd_start;
+       a2 = initrd_size;
+       printf("initial ramdisk at %x (%u bytes)\n",
+              initrd_start, initrd_size);
+       memcpy((char *) initrd_start,
+              (char *) (loadbase + get_32be(rsect->s_scnptr)),
+              initrd_size);
+       end_avail = (char *) initrd_start;
+    } else {
+       end_avail = (char *) RAM_END;
+    }
+       
+    im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
+    len = get_32be(isect->s_size);
+    dst = (void *) RAM_START;
+
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+       void *cp = (void *) RAM_FREE;
+       avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
+       memcpy(cp, im, len);
+       printf("gunzipping... ");
+       gunzip(dst, 0x400000, cp, &len);
+       printf("done\n");
+
+    } else {
+       memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+
+    sa = *(unsigned *)dst + RAM_START;
+    printf("start address = 0x%x\n", sa);
+
+#if 0
+    pause();
+#endif
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+       printf("oops... out of memory\n");
+       pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+       printf("bad gzipped data\n");
+       exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+       i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & COMMENT) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & HEAD_CRC) != 0)
+       i += 2;
+    if (i >= *lenp) {
+       printf("gunzip: ran out of data in header\n");
+       exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+       printf("inflateInit2 returned %d\n", r);
+       exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+       printf("inflate returned %d\n", r);
+       exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S
new file mode 100644 (file)
index 0000000..ae08ee2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+       .text
+
+/*
+ * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ */
+       .globl  setup_bats
+setup_bats:
+       mfpvr   3
+       rlwinm  3,3,16,16,31            /* r3 = 1 for 601, 4 for 604 */
+       cmpi    0,3,1
+       lis     4,0xc000
+       bne     4f
+       ori     4,4,4                   /* set up BAT registers for 601 */
+       li      5,0x7f
+       b       5f
+4:     ori     4,4,0xff                /* set up BAT registers for 604 */
+       li      5,2
+       mtdbatu 0,4
+       mtdbatl 0,5
+5:     mtibatu 0,4
+       mtibatl 0,5
+       isync
+       blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+       .global flush_cache
+flush_cache:
+       addi    4,4,0x1f        /* len = (len + 0x1f) / 0x20 */
+       rlwinm. 4,4,27,5,31
+       mtctr   4
+       beqlr
+1:     dcbf    0,3
+       icbi    0,3
+       addi    3,3,0x20
+       bdnz    1b
+       sync
+       isync
+       blr
diff --git a/arch/ppc/coffboot/nonstdio.h b/arch/ppc/coffboot/nonstdio.h
new file mode 100644 (file)
index 0000000..664b838
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+typedef int    FILE;
+extern FILE *stdin, *stdout;
+#define NULL   ((void *)0)
+#define EOF    (-1)
+#define fopen(n, m)    NULL
+#define fflush(f)      0
+#define fclose(f)      0
+extern char *fgets();
+
+#define perror(s)      printf("%s: no files!\n", (s))
diff --git a/arch/ppc/coffboot/rs6000.h b/arch/ppc/coffboot/rs6000.h
new file mode 100644 (file)
index 0000000..0def1d9
--- /dev/null
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+   Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+   FIXME: Can someone provide a transliteration of this name into ASCII?
+   Using the following chars caused a compiler warning on HIUX (so I replaced
+   them with octal escapes), and isn't useful without an understanding of what
+   character set it is.
+   Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+   and John Gilmore of Cygnus Support.  */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+       char f_magic[2];        /* magic number                 */
+       char f_nscns[2];        /* number of sections           */
+       char f_timdat[4];       /* time & date stamp            */
+       char f_symptr[4];       /* file pointer to symtab       */
+       char f_nsyms[4];        /* number of symtab entries     */
+       char f_opthdr[2];       /* sizeof(optional hdr)         */
+       char f_flags[2];        /* flags                        */
+};
+
+        /* IBM RS/6000 */
+#define U802WRMAGIC     0730    /* writeable text segments **chh**      */
+#define U802ROMAGIC     0735    /* readonly sharable text segments      */
+#define U802TOCMAGIC    0737    /* readonly text segments and TOC       */
+
+#define BADMAG(x)      \
+       ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+        (x).f_magic != U802TOCMAGIC)
+
+#define        FILHDR  struct external_filehdr
+#define        FILHSZ  20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct 
+{
+  unsigned char        magic[2];       /* type of file                 */
+  unsigned char        vstamp[2];      /* version stamp                */
+  unsigned char        tsize[4];       /* text size in bytes, padded to FW bdry */
+  unsigned char        dsize[4];       /* initialized data "  "        */
+  unsigned char        bsize[4];       /* uninitialized data "   "     */
+  unsigned char        entry[4];       /* entry pt.                    */
+  unsigned char        text_start[4];  /* base of text used for this file */
+  unsigned char        data_start[4];  /* base of data used for this file */
+  unsigned char        o_toc[4];       /* address of TOC */
+  unsigned char        o_snentry[2];   /* section number of entry point */
+  unsigned char        o_sntext[2];    /* section number of .text section */
+  unsigned char        o_sndata[2];    /* section number of .data section */
+  unsigned char        o_sntoc[2];     /* section number of TOC */
+  unsigned char        o_snloader[2];  /* section number of .loader section */
+  unsigned char        o_snbss[2];     /* section number of .bss section */
+  unsigned char        o_algntext[2];  /* .text alignment */
+  unsigned char        o_algndata[2];  /* .data alignment */
+  unsigned char        o_modtype[2];   /* module type (??) */
+  unsigned char o_cputype[2];  /* cpu type */
+  unsigned char        o_maxstack[4];  /* max stack size (??) */
+  unsigned char o_maxdata[4];  /* max data size (??) */
+  unsigned char        o_resv2[12];    /* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define        RS6K_AOUTHDR_OMAGIC     0x0107  /* old: text & data writeable */
+#define        RS6K_AOUTHDR_NMAGIC     0x0108  /* new: text r/o, data r/w */
+#define        RS6K_AOUTHDR_ZMAGIC     0x010B  /* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+       char            s_name[8];      /* section name                 */
+       char            s_paddr[4];     /* physical address, aliased s_nlib */
+       char            s_vaddr[4];     /* virtual address              */
+       char            s_size[4];      /* section size                 */
+       char            s_scnptr[4];    /* file ptr to raw data for section */
+       char            s_relptr[4];    /* file ptr to relocation       */
+       char            s_lnnoptr[4];   /* file ptr to line numbers     */
+       char            s_nreloc[2];    /* number of relocation entries */
+       char            s_nlnno[2];     /* number of line number entries*/
+       char            s_flags[4];     /* flags                        */
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT  ".text"
+#define _DATA  ".data"
+#define _BSS   ".bss"
+#define _PAD   ".pad"
+#define _LOADER        ".loader"
+
+#define        SCNHDR  struct external_scnhdr
+#define        SCNHSZ  40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER.  */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG.  */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+   another section header with STYP_OVRFLO set.  */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+       union {
+               char l_symndx[4];       /* function name symbol index, iff l_lnno == 0*/
+               char l_paddr[4];        /* (physical) address of line number    */
+       } l_addr;
+       char l_lnno[2]; /* line number          */
+};
+
+
+#define        LINENO  struct external_lineno
+#define        LINESZ  6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN     8       /* # characters in a symbol name        */
+#define E_FILNMLEN     14      /* # characters in a file name          */
+#define E_DIMNUM       4       /* # array dimensions in auxiliary entry */
+
+struct external_syment 
+{
+  union {
+    char e_name[E_SYMNMLEN];
+    struct {
+      char e_zeroes[4];
+      char e_offset[4];
+    } e;
+  } e;
+  char e_value[4];
+  char e_scnum[2];
+  char e_type[2];
+  char e_sclass[1];
+  char e_numaux[1];
+};
+
+
+
+#define N_BTMASK       (017)
+#define N_TMASK                (060)
+#define N_BTSHFT       (4)
+#define N_TSHIFT       (2)
+  
+
+union external_auxent {
+       struct {
+               char x_tagndx[4];       /* str, un, or enum tag indx */
+               union {
+                       struct {
+                           char  x_lnno[2]; /* declaration line number */
+                           char  x_size[2]; /* str/union/array size */
+                       } x_lnsz;
+                       char x_fsize[4];        /* size of function */
+               } x_misc;
+               union {
+                       struct {                /* if ISFCN, tag, or .bb */
+                           char x_lnnoptr[4];  /* ptr to fcn line # */
+                           char x_endndx[4];   /* entry ndx past block end */
+                       } x_fcn;
+                       struct {                /* if ISARY, up to 4 dimen. */
+                           char x_dimen[E_DIMNUM][2];
+                       } x_ary;
+               } x_fcnary;
+               char x_tvndx[2];                /* tv index */
+       } x_sym;
+
+       union {
+               char x_fname[E_FILNMLEN];
+               struct {
+                       char x_zeroes[4];
+                       char x_offset[4];
+               } x_n;
+       } x_file;
+
+       struct {
+               char x_scnlen[4];                       /* section length */
+               char x_nreloc[2];       /* # relocation entries */
+               char x_nlinno[2];       /* # line numbers */
+       } x_scn;
+
+        struct {
+               char x_tvfill[4];       /* tv fill value */
+               char x_tvlen[2];        /* length of .tv */
+               char x_tvran[2][2];     /* tv range */
+       } x_tv;         /* info about .tv section (in auxent of symbol .tv)) */
+
+       struct {
+               unsigned char x_scnlen[4];
+               unsigned char x_parmhash[4];
+               unsigned char x_snhash[2];
+               unsigned char x_smtyp[1];
+               unsigned char x_smclas[1];
+               unsigned char x_stab[4];
+               unsigned char x_snstab[2];
+       } x_csect;
+
+};
+
+#define        SYMENT  struct external_syment
+#define        SYMESZ  18      
+#define        AUXENT  union external_auxent
+#define        AUXESZ  18
+#define DBXMASK 0x80           /* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_size[1];
+  char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/ppc/coffboot/start.c b/arch/ppc/coffboot/start.c
new file mode 100644 (file)
index 0000000..363e659
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdarg.h>
+
+int (*prom)();
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+
+void
+start(int a1, int a2, void *promptr)
+{
+    prom = (int (*)()) promptr;
+    chosen_handle = finddevice("/chosen");
+    if (chosen_handle == (void *) -1)
+       exit();
+    if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+       exit();
+    stderr = stdout;
+    if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+       exit();
+
+    coffboot(a1, a2, promptr);
+    for (;;)
+       exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       void *ihandle;
+       void *addr;
+       int len;
+       int actual;
+    } args;
+
+    args.service = "write";
+    args.nargs = 3;
+    args.nret = 1;
+    args.ihandle = handle;
+    args.addr = ptr;
+    args.len = nb;
+    args.actual = -1;
+    (*prom)(&args);
+    return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       void *ihandle;
+       void *addr;
+       int len;
+       int actual;
+    } args;
+
+    args.service = "read";
+    args.nargs = 3;
+    args.nret = 1;
+    args.ihandle = handle;
+    args.addr = ptr;
+    args.len = nb;
+    args.actual = -1;
+    (*prom)(&args);
+    return args.actual;
+}
+
+void
+exit()
+{
+    struct prom_args {
+       char *service;
+    } args;
+
+    for (;;) {
+       args.service = "exit";
+       (*prom)(&args);
+    }
+}
+
+void
+pause()
+{
+    struct prom_args {
+       char *service;
+    } args;
+
+    args.service = "enter";
+    (*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       const char *devspec;
+       void *phandle;
+    } args;
+
+    args.service = "finddevice";
+    args.nargs = 1;
+    args.nret = 1;
+    args.devspec = name;
+    args.phandle = (void *) -1;
+    (*prom)(&args);
+    return args.phandle;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       void *phandle;
+       const char *name;
+       void *buf;
+       int buflen;
+       int size;
+    } args;
+
+    args.service = "getprop";
+    args.nargs = 4;
+    args.nret = 1;
+    args.phandle = phandle;
+    args.name = name;
+    args.buf = buf;
+    args.buflen = buflen;
+    args.size = -1;
+    (*prom)(&args);
+    return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+    char ch = c;
+
+    if (c == '\n')
+       putc('\r', f);
+    return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+    return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+    int n = strlen(str);
+
+    return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar()
+{
+    char ch;
+
+    for (;;) {
+       switch (read(stdin, &ch, 1)) {
+       case 1:
+           return ch;
+       case -1:
+           printk("read(stdin) returned -1\r\n");
+           return -1;
+       }
+    }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar()
+{
+    int c;
+
+    if (lineleft == 0) {
+       lineptr = line;
+       for (;;) {
+           c = readchar();
+           if (c == -1 || c == 4)
+               break;
+           if (c == '\r' || c == '\n') {
+               *lineptr++ = '\n';
+               putchar('\n');
+               break;
+           }
+           switch (c) {
+           case 0177:
+           case '\b':
+               if (lineptr > line) {
+                   putchar('\b');
+                   putchar(' ');
+                   putchar('\b');
+                   --lineptr;
+               }
+               break;
+           case 'U' & 0x1F:
+               while (lineptr > line) {
+                   putchar('\b');
+                   putchar(' ');
+                   putchar('\b');
+                   --lineptr;
+               }
+               break;
+           default:
+               if (lineptr >= &line[sizeof(line) - 1])
+                   putchar('\a');
+               else {
+                   putchar(c);
+                   *lineptr++ = c;
+               }
+           }
+       }
+       lineleft = lineptr - line;
+       lineptr = line;
+    }
+    if (lineleft == 0)
+       return -1;
+    --lineleft;
+    return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+       va_list args;
+       int n;
+
+       va_start(args, fmt);
+       n = vsprintf(sprint_buf, fmt, args);
+       va_end(args);
+       write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+       va_list args;
+       int n;
+
+       va_start(args, fmt);
+       n = vsprintf(sprint_buf, fmt, args);
+       va_end(args);
+       write(stdout, sprint_buf, n);
+       return n;
+}
diff --git a/arch/ppc/coffboot/string.S b/arch/ppc/coffboot/string.S
new file mode 100644 (file)
index 0000000..ba83591
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+#define r0     0
+#define r3     3
+#define r4     4
+#define r5     5
+#define r6     6
+#define r7     7
+#define r8     8
+
+       .globl  strcpy
+strcpy:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strncpy
+strncpy:
+       cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r6)
+       bdnzf   2,1b            /* dec ctr, branch if ctr != 0 && !cr0.eq */
+       blr
+
+       .globl  strcat
+strcat:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r5)
+       cmpwi   0,r0,0
+       bne     1b
+       addi    r5,r5,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strcmp
+strcmp:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r5)
+       cmpwi   1,r3,0
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       beqlr   1
+       beq     1b
+       blr
+
+       .globl  strlen
+strlen:
+       addi    r4,r3,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       bne     1b
+       subf    r3,r3,r4
+       blr
+
+       .globl  memset
+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
+       rlwinm  r0,r5,32-2,2,31
+       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
+
+       .globl  bcopy
+bcopy:
+       mr      r6,r3
+       mr      r3,r4
+       mr      r4,r6
+       b       memcpy
+
+       .globl  memmove
+memmove:
+       cmplw   0,r3,r4
+       bgt     backwards_memcpy
+       /* fall through */
+
+       .globl  memcpy
+memcpy:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = 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
+
+       .globl  backwards_memcpy
+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
+
+       .globl  memcmp
+memcmp:
+       cmpwi   0,r5,0
+       blelr
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r6)
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       bdnzt   2,1b
+       blr
diff --git a/arch/ppc/coffboot/zlib.c b/arch/ppc/coffboot/zlib.c
new file mode 100644 (file)
index 0000000..5d67e39
--- /dev/null
@@ -0,0 +1,2143 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c,v 1.1 1997/07/31 07:16:14 paulus Exp $
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL   ((void *) 0)
+#endif
+
+        /* common constants */
+
+#define DEFLATED   8
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+         /* functions */
+
+#include <string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len)    memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void   zcfree  OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size)        \
+          (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+    z_stream *z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+local int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));                      /* initial return code */
+
+local void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_stream *));
+
+local int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt Nalloc;       /* number of these allocated here */
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+local int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_stream *));               /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_stream *));
+
+local int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+local void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state, sizeof(struct internal_state));
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+/*  if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/*  if (z->zfree == Z_NULL) z->zfree = zcfree; */
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+       inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+  return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = "unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      if ((b = NEXTBYTE) & 0x20)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid reserved bit";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      z->state->mode = BLOCKS;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+         r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+       return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,     /* finished last block, done */
+      BADB}      /* got a data error--stuck here */
+    mode;               /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+      int nblens;              /* # elements allocated at blens */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl, *td;    /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s, sizeof(struct inflate_blocks_state));
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = "invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if (((~b) >> 16) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = "invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : TYPE;
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = "too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      s->sub.trees.nblens = t;
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BADB;
+            z->msg = "invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window, s->end - s->window);
+  ZFREE(z, s, sizeof(struct inflate_blocks_state));
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+       return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+       return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+       t = n;  /* how many to do */
+       /* is there room until end of buffer? */
+       if (t > m) t = m;
+       /* update check information */
+       if (s->checkfn != Z_NULL)
+           s->check = (*s->checkfn)(s->check, q, t);
+       zmemcpy(q, p, t);
+       q += t;
+       p += t;
+       n -= t;
+       z->total_out += t;
+       s->read = q;    /* drag read pointer forward */
+/*      WRAP  */       /* expand WRAP macro by hand to handle s->read */
+       if (q == s->end) {
+           s->read = q = s->window;
+           m = WAVAIL;
+       }
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+       return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    uIntf *,            /* list of base values for non-simple codes */
+    uIntf *,            /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_stream *));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+local void ffree OF((
+    voidpf q,           /* opaque pointer (not used) */
+    voidpf p,           /* what to free (not used) */
+    uInt n));          /* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+uIntf *d;               /* list of base values for non-simple codes */
+uIntf *e;               /* list of extra bits for non-simple codes */  
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_stream *zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+   over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (uInt)l ? l : z;      /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+       q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = "oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = "incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;        /* opaque pointer (not used) */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+         "inflate_trees falloc overflow");
+  if (q) s++; /* to make some compilers happy */
+  fixed_left -= n;
+  return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+  Assert(0, "inflate_trees ffree called!");
+  if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not built already--lock out other instances */
+  while (++fixed_lock > 1)
+    fixed_lock--;
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = ffree;
+    z.opaque = Z_NULL;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    fixed_built = 1;
+  }
+  fixed_lock--;
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_stream *z;            /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register inflate_huft *p, *q;
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+    p = q;
+  } 
+  return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+  ZFREE(z, c, sizeof(struct inflate_codes_state));
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt n;
+  Bytef *p, *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (q - s->window);  /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = "invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = "invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end",          /* Z_STREAM_END    1 */
+"",                    /* Z_OK            0 */
+"file error",          /* Z_ERRNO        (-1) */
+"stream error",        /* Z_STREAM_ERROR (-2) */
+"data error",          /* Z_DATA_ERROR   (-3) */
+"insufficient memory", /* Z_MEM_ERROR    (-4) */
+"buffer error",        /* Z_BUF_ERROR    (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf)  {s1 += *buf++; s2 += s1;}
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+            k -= 16;
+        }
+        if (k != 0) do {
+            DO1(buf);
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff --git a/arch/ppc/coffboot/zlib.h b/arch/ppc/coffboot/zlib.h
new file mode 100644 (file)
index 0000000..f3bee01
--- /dev/null
@@ -0,0 +1,432 @@
+/*     $Id: zlib.h,v 1.1 1997/07/31 07:16:15 paulus Exp $      */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 0.95, Aug 16th, 1995.
+
+  Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */       /* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+#  if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+#    define STDC
+#  endif
+#endif
+
+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+#  include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidp      opaque;  /* private data object passed to zalloc and zfree */
+
+    Byte     data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH    2
+#define Z_SYNC_FLUSH    3 /* experimental: partial_flush + byte align */
+#define Z_FINISH        4
+#define Z_PACKET_FLUSH 5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Used to set the data_type field */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+ */
+
+                        /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/* 
+     Initializes the internal stream state for decompression. The fields
+   zalloc and zfree must be initialized before by the caller.  If zalloc and
+   zfree are set to Z_NULL, inflateInit updates them to use default allocation
+   functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory.  msg is set to null if there is no error message.
+   inflateInit does not perform any decompression: this will be done by
+   inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() always provides as much output as possible
+    (until there is no more input data or no more space in the output buffer).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate().
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+  the stream structure was inconsistent (for example if next_in or next_out
+  was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+  progress is possible or if there was not enough room in the output buffer
+  when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+  call inflateSync to look for a good compression block.  */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+                            int  windowBits));
+/*   
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc and zfree must be initialized before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* checksum functions */
+
+/*
+     This function is not related to compression but is exported
+   anyway because it might be useful in applications using the
+   compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
index 9df35fa24cdc8520cb3806a5275f0487f366fe25..beac5e6dcd70e7cec67a88df018b44721237c52f 100644 (file)
@@ -1,9 +1,13 @@
-#
+# $Id: config.in,v 1.16 1997/08/11 08:37:49 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
+mainmenu_option next_comment
+comment 'Platform support'
+define_bool CONFIG_PPC y
+
 if [ "`uname`" != "Linux" ]; then
   define_bool CONFIG_CROSSCOMPILE y
 else
@@ -12,25 +16,28 @@ fi
 
 bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
 bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
-bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+
 choice 'Processor type' \
        "Common         CONFIG_MCOMMON \
         601            CONFIG_M601     \
         603            CONFIG_M603     \
         604            CONFIG_M604" Common
+endmenu
 
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 
-
-mainmenu_option next_comment
 define_bool CONFIG_PCI y
-bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+if [ "$CONFIG_PREP" = "y" ]; then
+  bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+fi
 bool 'Networking support' CONFIG_NET
 bool 'Sysctl support' CONFIG_SYSCTL
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -41,6 +48,22 @@ define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 
+if [ "$CONFIG_PMAC" = "y" ]; then
+  define_bool CONFIG_PMAC_CONSOLE y
+  define_bool CONFIG_MAC_KEYBOARD y
+  define_bool CONFIG_MAC_FLOPPY        y
+  bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+  bool 'Include xmon kernel debugger' CONFIG_XMON
+fi
+
+if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
+  bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO
+  bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO
+else
+  define_bool CONFIG_VGA_CONSOLE y
+fi
+
+endmenu
 
 source drivers/pnp/Config.in
 source drivers/block/Config.in
@@ -83,6 +106,7 @@ fi
 endmenu
 
 source fs/Config.in
+
 source drivers/char/Config.in
 
 mainmenu_option next_comment
@@ -93,12 +117,12 @@ if [ "$CONFIG_SOUND" != "n" ]; then
 fi
 endmenu
 
-mainmenu_option next_comment
+#mainmenu_option next_comment
 #comment 'Kernel hacking'
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 #bool 'Kernel profiling support' CONFIG_PROFILE
 #if [ "$CONFIG_PROFILE" = "y" ]; then
 #  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 #fi
-endmenu
+#endmenu
 
index bd955c7515cb4cd426be8dc7eec37609be963ba0..a0b37564de45ad45c560e6ada5482a668b62726c 100644 (file)
@@ -1,30 +1,31 @@
 #
 # Automatically generated by make menuconfig: don't edit
 #
+
+#
+# Platform support
+#
 CONFIG_NATIVE=y
 # CONFIG_PMAC is not set
 CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
 CONFIG_MCOMMON=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
 
 #
 # Plug and Play support
@@ -46,10 +47,10 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -100,7 +101,6 @@ CONFIG_SCSI_NCR53C7xx=y
 # CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
 
 #
 # Network device support
@@ -117,6 +117,7 @@ CONFIG_INET=y
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 CONFIG_PATH_MTU_DISCOVERY=y
@@ -155,6 +156,7 @@ CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
 # CONFIG_ES3210 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
@@ -183,16 +185,13 @@ CONFIG_PPP=y
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -205,7 +204,6 @@ CONFIG_ISO9660_FS=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
 
 #
 # Character devices
@@ -213,12 +211,7 @@ CONFIG_HFS_FS=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
@@ -227,13 +220,39 @@ CONFIG_MOUSE=y
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
index 941cd9e38150bd1a095623820feb5131e6c6275a..ccc15c1aede95a82bba5dfd921d0cf9b1e5d9e7f 100644 (file)
@@ -7,40 +7,25 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-       $(CC) $(CFLAGS) -S $<
-.s.o:
-       $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
-       $(CC) $(CFLAGS) -c $<
-.S.s:
-       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
 .S.o:
-       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-       $(AS) $(ASFLAGS) -o $*.o $*.s
-       rm $*.s
+       $(CC) -D__ASSEMBLY__ -c $< -o $*.o
 
-HOST_CC = gcc
-
-OBJS  = misc.o port_io.o pci.o traps.o process.o \
-       signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
+O_TARGET := kernel.o
+O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
+         align.o ptrace.o irq.o bitops.o ppc_htab.o idle.o prom.o \
+         time.o prep_time.o pmac_time.o \
+         setup.o pmac_setup.o pmac_support.o \
+         pci.o prep_pci.o pmac_pci.o
+OX_OBJS := ppc_ksyms.o
 
 all: head.o kernel.o
+
 head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
 
 ifeq ($(CONFIG_PREP),y)
-OBJS += prep_setup.o prep_time.o
-endif
-
-ifeq ($(CONFIG_PMAC),y)
-OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+O_OBJS += prep_setup.o #prep_time.o
 endif
 
-ifeq ($(CONFIG_MODULES),y)
-OBJS = ksyms.o
-endif
-
-
 ppc_defs.h: mk_defs.c ppc_defs.head \
                $(TOPDIR)/include/asm/mmu.h \
                $(TOPDIR)/include/asm/processor.h \
@@ -53,24 +38,6 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
 
 checks: checks.c
        $(HOSTCC) ${CFLAGS} -o checks checks.c
-       checks
-
-kernel.o: $(OBJS)
-       $(LD) -r -o kernel.o $(OBJS)
+       ./checks
 
-fastdep:
-       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
-       $(CPP) -M *.S *.c > .depend
-
-modules: 
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
index 9e0bd3aa982840f5296a161fb644023cdc89f077..31222955285a3aeaac0ea56ecf584ccb1b7faf53 100644 (file)
@@ -25,7 +25,7 @@
 int main(void)
 {
        int ret = 0;
-       
+#if 0
        if ( sizeof(struct thread_struct) % 16 )
        {
                printf("Thread struct is not modulo 16 bytes: "
@@ -34,6 +34,7 @@ int main(void)
                        sizeof(struct thread_struct)%16);
                ret = -1;
        }
+#endif 
 
        if ( sizeof(struct pt_regs) % 16 )
        {
index 25f2dd8a0a2e0a5d2dd78e4b675ca3c9f04d9bf9..1060b3344aef5cfba161855c3045b828b26cde7f 100644 (file)
 
 #define TOPHYS(x)      (x - KERNELBASE)
 
-
 /* this is a very kludgey way of loading up the BATs on the
    prep system.  I'll kill this horrible macro and write
    something clean when I have a chance -- Cort
  */    
 #define LOAD_BATS(RA,RB) \
        mfspr   RA,PVR          ; \
-       srwi    r5,r5,16        ; \
+       srwi    RA,RA,16        ; \
        cmpi    0,RA,1          ; \
        beq     199f            ; \
        /* load bats for 60x */ ; \
        mtspr   DBAT3L,RB       ; \
 200:
        
-
-
-       
        .text
        .globl  _stext
 _stext:
 
-#ifdef CONFIG_PREP     
-       . = 0x100
-_GLOBAL(HardReset)
-       b       _start
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
 /*
  * _start is defined this way because the XCOFF loader in the OpenFirmware
  * on the powermac expects the entry point to be a procedure descriptor.
@@ -156,7 +144,7 @@ _GLOBAL(HardReset)
 _start:
        .long   TOPHYS(__start),0,0
 
-/*
+/* 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
@@ -165,41 +153,81 @@ _start:
  * pointer (r1) points to just below the end of the half-meg region
  * from 0x380000 - 0x400000, which is mapped in already.
  */
+/* 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:
 
 /*
- * Use the first pair of BAT registers to map the 1st 8MB
+ * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.
  */
        mfspr   r9,PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
        cmpi    0,r9,1
-       lis     r7,KERNELBASE@h
+       lis     r11,KERNELBASE@h
        bne     4f
-       ori     r7,r7,4                 /* set up BAT registers for 601 */
+       ori     r11,r11,4               /* set up BAT registers for 601 */
        li      r8,0x7f
+       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   IBAT1U,r9
+       mtspr   IBAT1L,r10
        b       5f
-4:     ori     r7,r7,0xff              /* set up BAT registers for 604 */
+4:     ori     r11,r11,0x1ff           /* set up BAT registers for 604 */
        li      r8,2
-       mtspr   DBAT0U,r7
+       mtspr   DBAT0U,r11
        mtspr   DBAT0L,r8
-5:     mtspr   IBAT0U,r7
+5:     mtspr   IBAT0U,r11
        mtspr   IBAT0L,r8
        isync
 
+#if 0  
 /*
  * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
  * refer to addresses of data items, procedures, etc. normally.
  */
-       lis     r7,start_here@ha        /* jump up to our copy at KERNELBASE */
-       addi    r7,r7,start_here@l
-       mtlr    r7
+       lis     r10,start_here@ha       /* jump up to our copy at KERNELBASE */
+       addi    r10,r10,start_here@l
+       mtlr    r10
        blr
-#endif /* CONFIG_PMAC */
-
-
+#endif
+/*
+ * 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
+ */
+       mfmsr   r0
+       ori     r0,r0,MSR_DR|MSR_IR
+       mtspr   SRR1,r0
+       lis     r0,start_here@h
+       ori     r0,r0,start_here@l
+       mtspr   SRR0,r0
+       SYNC
+       rfi                             /* enables MMU */
+               
 
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't.  To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD        64
        
 /*
  * Macros for storing registers into and loading registers from
@@ -286,10 +314,8 @@ label:                                             \
        .long   hdlr;                           \
        .long   int_return
 
-#ifndef CONFIG_PREP
 /* System reset */
        STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif /* ndef CONFIG_PREP */
 
 /* Machine check */
        STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -319,7 +345,7 @@ DataAccess:
 
 /* Instruction access exception */
        . = 0x400
-InstructionAccess:     
+InstructionAccess:
        EXCEPTION_PROLOG
        andis.  r0,r23,0x4000           /* no pte found? */
        beq     1f                      /* if so, try to put a PTE */
@@ -338,7 +364,7 @@ InstructionAccess:
        .long   int_return
 
 /* External interrupt */
-       STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+       STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
 
 /* Alignment exception */
        . = 0x600
@@ -376,21 +402,7 @@ FPUnavailable:
        .long   KernelFP
        .long   int_return
 
-/* Decrementer */
-#ifdef CONFIG_PREP
-/* - ignored for now... */
-_ORG(0x0900)
-       mtspr   SPRG0,r1
-       lis     r1,0x7FFF
-       ori     r1,r1,0xFFFF
-       mtspr   DEC,r1
-       mfspr   r1,SPRG0
-       rfi
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
        STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
-#endif /* CONFIG_PMAC */
-
        STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
        STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
 
@@ -596,11 +608,6 @@ transfer_to_handler:
        andi.   r23,r23,MSR_PR
        mfspr   r23,SPRG3               /* if from user, fix up tss */
        beq     2f
-#ifdef CONFIG_PMAC     
-       lwz     r24,GPR1(r21)
-       stw     r22,LAST_PC(r23)
-       stw     r24,USER_STACK(r23)
-#endif /* CONFIG_PMAC */
        addi    r24,r1,STACK_FRAME_OVERHEAD
        stw     r24,PT_REGS(r23)
 2:     addi    r2,r23,-TSS             /* set r2 to current */
@@ -630,7 +637,7 @@ load_up_fpu:
        REST_32FPRS(0, r5)
 
 /* use last_task_used_math instead of fpu_tss */
-       lis     r3,last_task_used_math@h/*a*/
+       lis     r3,last_task_used_math@ha
        addis   r3,r3,-KERNELBASE@h
        subi    r4,r5,TSS
        addis   r4,r4,KERNELBASE@h
@@ -654,7 +661,7 @@ load_up_fpu:
        REST_GPR(20, r21)
        REST_2GPRS(22, r21)
        lwz     r21,GPR21(r21)
-       SYNC
+       SYNC
        rfi
 
 /*
@@ -682,14 +689,15 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
        .globl  hash_page
 hash_page:
        /* Get PTE (linux-style) and check access */
-       lwz     r5,PG_TABLES(r5)        /* task's page tables */
-       lis     r2,-KERNELBASE@h
-       add     r5,r5,r2                /* convert to phys addr */
+       lwz     r5,MM-TSS(r5)           
+       addis   r5,r5,-KERNELBASE@h     /* get physical current->mm */
+       lwz     r5,PGD(r5)              /* get current->mm->pgd */      
+       addis   r5,r5,-KERNELBASE@h     /* convert to phys addr */
        rlwimi  r5,r3,12,20,29          /* insert top 10 bits of address */
        lwz     r5,0(r5)                /* get pmd entry */
        rlwinm. r5,r5,0,0,19            /* extract address of pte page */
        beqlr-                          /* return if no mapping */
-       add     r2,r5,r2
+       addis   r2,r5,-KERNELBASE@h
        rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
        lwz     r6,0(r2)                /* get linux-style pte */
        ori     r4,r4,1                 /* set _PAGE_PRESENT bit in access */
@@ -819,58 +827,64 @@ start_here:
        rlwinm  r9,r9,16,16,31
        cmpi    0,r9,1
        beq     4f                      /* not needed for 601 */
-       mfspr   r7,HID0
-       andi.   r0,r7,HID0_DCE
-       ori     r7,r7,HID0_ICE|HID0_DCE
-       ori     r8,r7,HID0_ICFI
+       mfspr   r11,HID0
+       andi.   r0,r11,HID0_DCE
+       ori     r11,r11,HID0_ICE|HID0_DCE
+       ori     r8,r11,HID0_ICFI
        bne     3f                      /* don't invalidate the D-cache */
        ori     r8,r8,HID0_DCI          /* unless it wasn't enabled */
-3:     sync
+3:
+       /* I haven't tested this yet so it's off now - Cort */
+       /* turn on dpm for 603 */
+       cmpi    0,r9,3
+       bne     10f
+       oris    r11,r11,HID0_DPM@h
+10:    
+       sync
        mtspr   HID0,r8                 /* enable and invalidate caches */
        sync
-       mtspr   HID0,r                /* enable caches */
+       mtspr   HID0,r11                /* enable caches */
        sync
        isync
        cmpi    0,r9,4                  /* check for 604 */
        cmpi    1,r9,9                  /* or 604e */
        cror    2,2,6
        bne     4f
-       ori     r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
-       mtspr   HID0,r                /* superscalar exec & br history tbl */
+       ori     r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+       mtspr   HID0,r11                /* superscalar exec & br history tbl */
 4:
        /* ptr to current */
        lis     r2,init_task_union@h
        ori     r2,r2,init_task_union@l
        /* ptr to phys current tss */
-       addis   r3,r2,-KERNELBASE@h
-       addi    r3,r3,TSS       /* init task's TSS */
-       mtspr   SPRG3,r3
+       addis   r11,r2,-KERNELBASE@h
+       addi    r11,r11,TSS     /* init task's TSS */
+       mtspr   SPRG3,r11
        /* stack */
        addi    r1,r2,TASK_UNION_SIZE
        li      r0,0
        stwu    r0,-STACK_FRAME_OVERHEAD(r1)
 
        /* Clear out the BSS */
-       lis     r7,_end@ha
-       addi    r7,r7,_end@l
+       lis     r11,_end@ha
+       addi    r11,r11,_end@l
        lis     r8,__bss_start@ha
        addi    r8,r8,__bss_start@l
-       subf    r7,r8,r7
-       addi    r7,r7,3
-       rlwinm. r7,r7,30,2,31
+       subf    r11,r8,r11
+       addi    r11,r11,3
+       rlwinm. r11,r11,30,2,31
        beq     2f
        addi    r8,r8,-4
-       mtctr   r7
+       mtctr   r11
        li      r0,0
 3:     stwu    r0,4(r8)
        bdnz    3b
 2:
 /*
- * Initialize the prom stuff (powermacs only) and the MMU.
+ * Initialize the prom stuff and the MMU.
  */
-#ifdef CONFIG_PMAC
+       bl      identify_machine
        bl      prom_init
-#endif /* CONFIG_PMAC */
        bl      MMU_init
 
 /*
@@ -889,11 +903,6 @@ start_here:
        rfi
 /* Load up the kernel context */
 2:
-#ifdef CONFIG_PREP
-       /* reload the bats now that MMU_init() has setup them up -- Cort */
-       LOAD_BATS(r3,r0)
-#endif
-
        SYNC                    /* Force all PTE updates to finish */
        tlbia                   /* Clear all TLB entries */
        mtspr   SDR1,r6
@@ -905,8 +914,19 @@ start_here:
        addi    r3,r3,1         /* increment VSID */
        addis   r4,r4,0x1000    /* address of next segment */
        bdnz    3b
-#ifdef CONFIG_PMAC
-       li      r0,0            /* zot the BATs */
+
+       lis     r3,_machine@ha
+       addis   r3,r3,-KERNELBASE@h
+       lwz     r0,_machine@l(r3)
+       cmpi    0,r0,_MACH_Pmac
+       beq     99f
+       
+/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
+       LOAD_BATS(r3,r14)
+       b       100f
+       
+/* on pmac clear the bats out */       
+99:    li      r0,0            /* zot the BATs */
 #if 1
        mtspr   IBAT0U,r0
        mtspr   IBAT0L,r0
@@ -925,7 +945,7 @@ start_here:
        mtspr   IBAT3L,r0
        mtspr   DBAT3U,r0
        mtspr   DBAT3L,r0
-#endif
+100:   
 /* Now turn on the MMU for real! */
        li      r4,MSR_KERNEL
        lis     r3,start_kernel@h
@@ -934,61 +954,6 @@ start_here:
        mtspr   SRR1,r4
        rfi                     /* enable MMU and jump to start_kernel */
 
-#ifdef CONFIG_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: End of image
- *   R4: Start of image - 0x400
- *   R11: Start of command line string
- *   R12: 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:       
-       .globl _start
-_start:        
-       lis     r7,0xF000               /* To mask upper 4 bits */
-/* save pointer to residual data */
-       lis     r1,resptr@h
-       ori     r1,r1,resptr@l
-       addis   r1,r1,-KERNELBASE@h
-       stw     r3,0(r1)
-/* save argument string */
-       li      r0,0            /* Null terminate string */
-       stb     r0,0(r12)
-       lis     r1,cmd_line@h
-       ori     r1,r1,cmd_line@l
-       addis   r1,r1,-KERNELBASE@h
-       subi    r1,r1,1
-       subi    r11,r11,1
-00:    lbzu    r0,1(r11)
-       cmpi    0,r0,0
-       stbu    r0,1(r1)
-       bne     00b
-/* setup the msr with sane values */
-       li      r0,MSR_
-       mtmsr   r0
-/* turn on the mmu with bats covering kernel enough to get started */
-       LOAD_BATS(r3,r0)
-       mfmsr   r3
-       ori     r3,r3,MSR_DR|MSR_IR
-       mtspr   SRR1,r3
-       lis     r3,10f@h
-       ori     r3,r3,10f@l
-       mtspr   SRR0,r3
-       SYNC
-       rfi                             /* enables MMU */
-10:    lis     r7,start_here@ha        /* jump up to our copy at KERNELBASE */
-       addi    r7,r7,start_here@l
-       mtlr    r7
-       blr
-#endif /* CONFIG_PREP */
-       
 /*
  * FP unavailable trap from kernel - print a message, but let
  * the task use FP in the kernel until it returns to user mode.
@@ -1022,31 +987,23 @@ giveup_fpu_unmapped:
 giveup_fpu:
        li      r6,0
 1:
-       addis   r3,r6,last_task_used_math@h/*a*/
+       addis   r3,r6,last_task_used_math@ha
        lwz     r4,last_task_used_math@l(r3)
-#if 0          
-       addis   r3,r6,fpu_tss@ha
-       lwz     r4,fpu_tss@l(r3)
-#endif 
        mfmsr   r5
        ori     r5,r5,MSR_FP
        SYNC
        mtmsr   r5                      /* enable use of fpu now */
        SYNC
        cmpi    0,r4,0
+       beqlr-                          /* if no previous owner, done */
        add     r4,r4,r6
-       beqlr                           /* if no previous owner, done */
        addi    r4,r4,TSS               /* want TSS of last_task_used_math */
        li      r5,0
        stw     r5,last_task_used_math@l(r3)
-#if 0  
-       stw     r5,fpu_tss@l(r3)
-#endif
        SAVE_32FPRS(0, r4)
        mffs    fr0
        stfd    fr0,TSS_FPSCR-4(r4)
        lwz     r5,PT_REGS(r4)
-       lwz     r5,PT_REGS(r4)
        add     r5,r5,r6
        lwz     r3,_MSR-STACK_FRAME_OVERHEAD(r5)
        li      r4,MSR_FP
@@ -1268,7 +1225,7 @@ int_return:
        cmpi    0,r4,0
        beq+    1f
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      handle_IRQ
+       bl      do_IRQ
        b       3b
 1:     lis     r4,bh_mask@ha
        lwz     r4,bh_mask@l(r4)
@@ -1341,7 +1298,7 @@ _GLOBAL(fake_interrupt)
        li      r0,0x0fac
        stw     r0,TRAP(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      handle_IRQ
+       bl      do_IRQ
        addi    r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
        lwz     r0,4(r1)
        mtlr    r0
@@ -1384,11 +1341,11 @@ _GLOBAL(flush_instruction_cache)
  * and invalidate the corresponding instruction cache blocks.
  * This is a no-op on the 601.
  *
- * store_cache_range(unsigned long start, unsigned long stop)
+ * flush_icache_range(unsigned long start, unsigned long stop)
  */
 CACHE_LINE_SIZE = 32
 LG_CACHE_LINE_SIZE = 5
-_GLOBAL(store_cache_range)
+_GLOBAL(flush_icache_range)
        mfspr   r5,PVR
        rlwinm  r5,r5,16,16,31
        cmpi    0,r5,1
@@ -1521,7 +1478,6 @@ _GLOBAL(flush_hash_page)
 _GLOBAL(__main)
        blr
 
-#ifdef CONFIG_PMAC
 /*
  * These exception handlers are used when we have called a prom
  * routine after we have taken over the exception vectors and MMU.
@@ -1716,7 +1672,6 @@ enter_prom:
        lwz     r31,28(r1)
        lwz     r1,0(r1)
        blr
-#endif
 
 /*
  * We put a few things here that have to be page-aligned.
@@ -1726,7 +1681,6 @@ enter_prom:
        .data
        .globl  sdata
 sdata:
-       .space  2*4096
        .globl  empty_zero_page
 empty_zero_page:
        .space  4096
@@ -1735,7 +1689,6 @@ empty_zero_page:
 swapper_pg_dir:
        .space  4096    
 
-#ifdef CONFIG_PREP
 /*
  * 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.
@@ -1743,5 +1696,4 @@ swapper_pg_dir:
        .globl  cmd_line
 cmd_line:
        .space  512
-#endif /* CONFIG_PREP */
 
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
new file mode 100644 (file)
index 0000000..18a3c86
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * $Id: idle.c,v 1.3 1997/08/10 04:49:08 davem Exp $
+ *
+ * Idle daemon for PowerPC.  Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * 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.
+ */
+#define __KERNEL_SYSCALLS__
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+#include <asm/processor.h>
+
+int zero_paged(void *unused);
+int power_saved(void *unused);
+
+asmlinkage int sys_idle(void)
+{
+       int ret = -EPERM;
+
+       if (current->pid != 0)
+               goto out;
+
+       /*
+        * want one per cpu since it would be nice to have all
+        * processors who aren't doing anything
+        * zero-ing pages since this daemon is lock-free
+        * -- Cort
+        */
+       kernel_thread(zero_paged, NULL, 0);
+       /* no powersaving modes on 601 */
+       /*if(  (_get_PVR()>>16) != 1 )
+               kernel_thread(power_saved, NULL, 0);*/
+
+       /* endless loop with no priority at all */
+       current->priority = -100;
+       current->counter = -100;
+       for (;;)
+       {
+               schedule();
+       }
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0;   /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0;   /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0;   /* # currently pre-zero'd pages */
+unsigned long zerototal = 0;   /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0;     /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
+static struct wait_queue * page_zerod_wait = NULL;
+#define PAGE_THRESHOLD 96       /* how many pages to keep pre-zero'd */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
+{
+       unsigned long page;
+
+       atomic_inc((atomic_t *)&zeropage_calls);
+       if ( zero_list )
+       {
+               /* atomically remove this page from the list */
+               asm (   "101:lwarx  %1,0,%2\n"  /* reserve zero_list */
+                       "    lwz    %0,0(%1)\n" /* get next -- new zero_list */
+                       "    stwcx. %0,0,%2\n"  /* update zero_list */
+                       "    bne-   101b\n"     /* if lost reservation try again */
+                       : "=&r" (zero_list), "=&r" (page)
+                       : "r" (&zero_list)
+                       : "cc" );
+               /* we can update zerocount after the fact since it is not
+                * used for anything but control of a loop which doesn't
+                * matter since it won't effect anything if it zero's one
+                * less page -- Cort
+                */
+               atomic_inc((atomic_t *)&zeropage_hits);
+               atomic_dec((atomic_t *)&zerocount);
+               wake_up(&page_zerod_wait);
+               resched_force();
+               
+               /* zero out the pointer to next in the page */
+               *(unsigned long *)page = 0;
+               return page;
+       }
+       return 0;
+}
+
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+
+int zero_paged(void *unused)
+{
+       extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+       pgd_t *dir;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       sprintf(current->comm, "zero_paged (idle)");
+       current->blocked = ~0UL;
+       
+       printk("Started zero_paged\n");
+       
+       __sti();
+       while ( 1 )
+       {
+               /* don't want to be pre-empted by swapper or power_saved */
+               current->priority = -98;
+               current->counter = -98;
+               /* we don't want to run until we have something to do */
+               while ( zerocount >= PAGE_THRESHOLD )
+                       sleep_on(&page_zerod_wait);
+               /*
+                * Mark a page as reserved so we can mess with it
+                * If we're interrupted we keep this page and our place in it
+                * since we validly hold it and it's reserved for us.
+                */
+               pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+               if ( !pageptr )
+               {
+                       printk("!pageptr in zero_paged\n");
+                       goto retry;
+               }
+               
+               if ( resched_needed() )
+                       schedule();
+               
+               /*
+                * Make the page no cache so we don't blow our cache with 0's
+                */
+               dir = pgd_offset( init_task.mm, pageptr );
+               if (dir)
+               {
+                       pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+                       if (pmd && pmd_present(*pmd))
+                       {
+                               pte = pte_offset(pmd, pageptr & PAGE_MASK);
+                               if (pte && pte_present(*pte))
+                               {                       
+                                       pte_uncache(*pte);
+                                       flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+                               }
+                       }
+               }
+       
+               /*
+                * Important here to not take time away from real processes.
+                */
+               for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+               {
+                       if ( resched_needed() )
+                               schedule();
+                       *(unsigned long *)(bytecount + pageptr) = 0;
+               }
+               
+               /*
+                * If we finished zero-ing out a page add this page to
+                * the zero_list atomically -- we can't use
+                * down/up since we can't sleep in idle.
+                * Disabling interrupts is also a bad idea since we would
+                * steal time away from real processes.
+                * We can also have several zero_paged's running
+                * on different processors so we can't interfere with them.
+                * So we update the list atomically without locking it.
+                * -- Cort
+                */
+               /* turn cache on for this page */
+               pte_cache(*pte);
+               flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+               
+               /* atomically add this page to the list */
+               asm (   "101:lwarx  %0,0,%1\n"  /* reserve zero_list */
+                       "    stw    %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+                       "    sync\n"            /* let store settle */
+#endif                 
+                       "    mr     %0,%2\n"    /* update zero_list in reg */
+                       "    stwcx. %2,0,%1\n"  /* update zero_list in mem */
+                       "    bne-   101b\n"     /* if lost reservation try again */
+                       : "=&r" (zero_list)
+                       : "r" (&zero_list), "r" (pageptr)
+                       : "cc" );
+               /*
+                * This variable is used in the above loop and nowhere
+                * else so the worst that could happen is we would
+                * zero out one more or one less page than we want
+                * per processor on the machine.  This is because
+                * we could add our page to the list but not have
+                * zerocount updated yet when another processor
+                * reads it.  -- Cort
+                */
+               atomic_inc((atomic_t *)&zerocount);
+               atomic_inc((atomic_t *)&zerototal);
+retry: 
+               schedule();
+       }
+}
+
+int power_saved(void *unused)
+{
+       unsigned long msr, hid0;
+       sprintf(current->comm, "power_saved (idle)");
+       current->blocked = ~0UL;
+       
+       printk("Power saving daemon started\n");
+       
+       __sti();
+       while (1)
+       {
+               /* don't want to be pre-empted by swapper */
+               current->priority = -99;
+               current->counter = -99;
+               /* go ahead and wakeup page_zerod() */
+               wake_up(&page_zerod_wait);
+               schedule();
+               asm volatile(
+                       /* clear powersaving modes and set nap mode */
+                       "mfspr %3,1008 \n\t"
+                       "andc  %3,%3,%4 \n\t"
+                       "or    %3,%3,%5 \n\t"
+                       "mtspr 1008,%3 \n\t"
+                       /* enter the mode */
+                       "mfmsr %0 \n\t"
+                       "oris  %0,%0,%2 \n\t"
+                       "sync \n\t"
+                       "mtmsr %0 \n\t"
+                       "isync \n\t"
+                       : "=&r" (msr)
+                       : "0" (msr), "i" (MSR_POW>>16),
+                       "r" (hid0),
+                       "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+                       "r" (HID0_NAP));
+               /*
+                * The ibm carolina spec says that the eagle memory
+                * controller will detect the need for a snoop
+                * and wake up the processor so we don't need to
+                * check for cache operations that need to be
+                * snooped.  The ppc book says the run signal
+                * must be asserted while napping for this though.
+                *
+                * Paul, what do you know about the pmac here?
+                * -- Cort
+                */
+               schedule();
+       }
+}
index 171bfaa5c3ea39745c2b3837fd2b09b050bada65..7e0135240412e56bec766a44a9992f60ea3080ef 100644 (file)
@@ -1,13 +1,13 @@
 /*
  *  arch/ppc/kernel/irq.c
  *
- *  Power Macintosh version
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
  *  Derived from arch/i386/kernel/irq.c
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
  */
-       
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
+
 
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/config.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-#define IRQ_FLAG       ((unsigned *)0xf3000020)
-#define IRQ_ENABLE     ((unsigned *)0xf3000024)
-#define IRQ_ACK                ((unsigned *)0xf3000028)
-#define IRQ_LEVEL      ((unsigned *)0xf300002c)
-
-#define KEYBOARD_IRQ   20      /* irq number for command-power interrupt */
-
-#undef SHOW_IRQ 1
+#undef SHOW_IRQ
 
 unsigned lost_interrupts = 0;
 
@@ -51,100 +42,114 @@ unsigned int local_irq_count[NR_CPUS];
 static struct irqaction irq_action[32];
 
 /*
- * This contains the irq mask for both irq controllers
+ * These are set to the appropriate functions by init_IRQ()
  */
-static unsigned int cached_irq_mask = 0xffff;
-
-#define cached_21      (((char *)(&cached_irq_mask))[0])
-#define cached_A1      (((char *)(&cached_irq_mask))[1])
-
+void (*mask_and_ack_irq)(int irq_nr);
+void (*set_irq_mask)(int irq_nr);
 
+static unsigned int cached_irq_mask = 0xffffffff;
+#define cached_21      (((char *)(&cached_irq_mask))[3])
+#define cached_A1      (((char *)(&cached_irq_mask))[2])
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 int __ppc_bh_counter;
 
-void *null_handler(int,void *,struct pt_regs *);
+/* prep */
+#define PREP_IRQ_MASK  (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
+extern unsigned long route_pci_interrupts(void);
 
-/*
- * disable and enable intrs in software.  This is used
- * from the non-realtime parts of Linux to disable interrupts.
- * The realtime part disables/enables intrs in the hardware.
- * -- Cort
- */
-unsigned long soft_intr_enable = 1;
-void _soft_cli(void)
-{
-       soft_intr_enable = 0;
-}
+/* pmac */
+#define IRQ_FLAG       ((unsigned *)0xf3000020)
+#define IRQ_ENABLE     ((unsigned *)0xf3000024)
+#define IRQ_ACK                ((unsigned *)0xf3000028)
+#define IRQ_LEVEL      ((unsigned *)0xf300002c)
+#define KEYBOARD_IRQ   20      /* irq number for command-power interrupt */
+#define PMAC_IRQ_MASK  (~ld_le32(IRQ_ENABLE))
 
-void _soft_sti(void)
+void prep_mask_and_ack_irq(int irq_nr)
 {
-       soft_intr_enable = 1;
-       if ( lost_interrupts )
-       {
-               printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
-               fake_interrupt();
+       spin_lock(&irq_controller_lock);
+       cached_irq_mask |= 1 << irq_nr;
+       if (irq_nr > 7) {
+               inb(0xA1);      /* DUMMY */
+               outb(cached_A1,0xA1);
+               outb(0x62,0x20);        /* Specific EOI to cascade */
+               /*outb(0x20,0xA0);*/
+               outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
+       } else {
+               inb(0x21);      /* DUMMY */
+               outb(cached_21,0x21);
+               /*outb(0x20,0x20);*/
+               outb(0x60|irq_nr,0x20); /* specific eoi */
+                 
        }
+       spin_unlock(&irq_controller_lock);
 }
 
-void *
-null_handler(int a, void *b, struct pt_regs *regs)
+void pmac_mask_and_ack_irq(int irq_nr)
 {
-       /*printk("irq.c: null_handler() called.  Should not have happened.\n");*/
+       spin_lock(&irq_controller_lock);
+       cached_irq_mask |= 1 << irq_nr;
+       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+       out_le32(IRQ_ACK, 1U << irq_nr);
+       spin_unlock(&irq_controller_lock);
 }
 
-void
-disable_irq(unsigned int irq_nr)
+void prep_set_irq_mask(int irq_nr)
 {
-       int s = _disable_interrupts();
-       unsigned char mask;
-
-#ifdef CONFIG_PMAC
-       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-#else /* CONFIG_PMAC */
-       mask = 1 << (irq_nr & 7);
-       if (irq_nr < 8)
-       {
-               cached_21 |= mask;
-               outb(cached_21,0x21);
-       } else
-       {
-               cached_A1 |= mask;
+       if (irq_nr > 7) {
                outb(cached_A1,0xA1);
-       }       
-#endif /* CONFIG_PMAC */
-       _enable_interrupts(s);
+       } else {
+               outb(cached_21,0x21);
+       }
 }
 
-void
-enable_irq(unsigned int irq_nr)
+void pmac_set_irq_mask(int irq_nr)
 {
-       int s = _disable_interrupts();
-#ifdef CONFIG_PMAC
-       unsigned bit = 1U << irq_nr;
-       
-       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
-
+       /* this could be being enabled or disabled - so use cached_irq_mask */
+       out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
        /*
         * Unfortunately, setting the bit in the enable register
         * when the device interrupt is already on *doesn't* set
         * the bit in the flag register or request another interrupt.
         */
-       if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
-               lost_interrupts |= bit;
-#else /* CONFIG_PMAC */
-       if (irq_nr < 8) {
-               cached_21 &= ~(1 << (irq_nr & 7));
-               outb(cached_21,0x21);
-       } else
-       {
-               cached_A1 &= ~(1 << (irq_nr-8 & 7));
-               outb(cached_A1,0xA1);
-       }       
-#endif /* CONFIG_PMAC */
+       if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
+               lost_interrupts |= (1UL<<irq_nr);
+}
 
-       _enable_interrupts(s);
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+       cached_irq_mask |= 1 << irq_nr;
+       set_irq_mask(irq_nr);
 }
 
+static inline void unmask_irq(unsigned int irq_nr)
+{
+       cached_irq_mask &= ~(1 << irq_nr);
+       set_irq_mask(irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&irq_controller_lock, flags);
+       mask_irq(irq_nr);
+       spin_unlock_irqrestore(&irq_controller_lock, flags);
+       synchronize_irq();
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&irq_controller_lock, flags);
+       unmask_irq(irq_nr);
+       spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
 
 int get_irq_list(char *buf)
 {
@@ -153,7 +158,7 @@ int get_irq_list(char *buf)
 
        for (i = 0 ; i < NR_IRQS ; i++) {
                action = irq_action + i;
-               if (!action || !action->handler) 
+               if (!action || !action->handler)
                        continue;
                len += sprintf(buf+len, "%2d: %10u   %s",
                        i, kstat.interrupts[i], action->name);
@@ -162,152 +167,99 @@ int get_irq_list(char *buf)
                }
                len += sprintf(buf+len, "\n");
        }
-/*
- *     Linus - should you add NMI counts here ?????
- */
 #ifdef __SMP_PROF__
        len+=sprintf(buf+len, "IPI: %8lu received\n",
                ipi_count);
-#endif         
+#endif
        return len;
 }
 
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs)
 {
        int irq;
-       unsigned bits;
+       unsigned long bits;
        struct irqaction *action;
        int cpu = smp_processor_id();
+       int status;
 
        hardirq_enter(cpu);
 
-#ifdef CONFIG_PMAC 
-       bits = ld_le32(IRQ_FLAG) | lost_interrupts;
-       lost_interrupts = 0;
-       
-       for (irq = NR_IRQS; irq >= 0; --irq)
-               if (bits & (1U << irq))
-                       break;
-#else /* CONFIG_PMAC */
-#if 1
-       if ( lost_interrupts )
+       if ( _machine == _MACH_Pmac )
        {
-               irq = ffz(~lost_interrupts);
-               lost_interrupts &= ~irq;
-               goto retry;
+               bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+               lost_interrupts = 0;
        }
-       outb(0x0C, 0x20);
-       irq = inb(0x20) & 7;
-       if (irq == 2)
+       else /* prep */
        {
-retry_cascade:         
-               outb(0x0C, 0xA0);
-               irq = inb(0xA0);
-               /* if no intr left */
-               if ( !(irq & 128 ) )
-                       goto out;
-               irq = (irq&7) + 8;
-       }
-retry:
+#if 1
+               outb(0x0C, 0x20);
+               irq = inb(0x20) & 7;
+               if (irq == 2)
+               {
+retry_cascade:
+                       outb(0x0C, 0xA0);
+                       irq = inb(0xA0);
+                       /* if no intr left */
+                       if ( !(irq & 128 ) )
+                               goto out;
+                       irq = (irq&7) + 8;
+               }
+               bits = 1UL << irq;
 #else
-       /* get the irr from the intr controller */
-       outb(0x0A, 0x20);
-       bits = inb(0x20);
-       /* handle cascade */
-       if ( bits  ) 
-       {
-               bits &= 4;
-               outb(0x0A, 0xA0);
-               bits = inb(0xA0)<<8;
+               /*
+                * get the isr from the intr controller since
+                * the bit in the irr has been cleared
+                */
+               outb(0x0a, 0x20);
+               bits = inb(0x20)&0xff;
+               /* handle cascade */
+               if ( bits & 4 )
+               {
+                       bits &= ~4UL;
+                       outb(0x0a, 0xA0);
+                       bits |= inb(0xA0)<<8;
+               }
+               /* ignore masked irqs */
+               bits &= ~cached_irq_mask;
+#endif
        }
-       /* get lost interrupts */
-       bits |= lost_interrupts;
-       /* save intrs that are masked out */
-       lost_interrupts = bits & cached_irq_mask;
-       /* get rid of intrs being masked */
-       bits &= ~cached_irq_mask;
-        /* non-specifc eoi */
-       outb(0x20,0x20);
-       if ( bits & 0xff00 )
-               outb(0x20,0xA0);
        
-       printk("bits %04X lost %04X mask %04x\n",
-              bits, lost_interrupts,cached_irq_mask);
-       
-       for (irq = NR_IRQS; irq >= 0; --irq)
+       for (irq = NR_IRQS - 1; irq >= 0; --irq)
                if (bits & (1U << irq))
                        break;
-#endif
-#endif /* CONFIG_PMAC */
-       
+
        if (irq < 0) {
-               printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+               printk("Bogus interrupt from PC = %lx\n", regs->nip);
                goto out;
        }
 
-#ifdef CONFIG_PMAC 
-       out_le32(IRQ_ACK, 1U << irq);
-#else /* CONFIG_PMAC */
-        /* mask out the irq while handling it */       
-       disable_irq(irq); 
-       /*
-        * send eoi to interrupt controller right away or lower
-        * priority intrs would be ignored even if with intrs enabled
-        */
-       if (irq > 7)
-       {
-               outb(0xE0|(irq-8), 0xA0);
-               outb(0xE2, 0x20);
-       } else
-       {
-               outb(0xE0|irq, 0x20);
-       }
-#endif /* !CONFIG_PMAC */
+       mask_and_ack_irq(irq);
 
-       /*
-        * now that we've acked the irq, if intrs are disabled in software
-        * we're in the real-time system and non-rt linux has disabled them
-        * so we just queue it up and return -- Cort
-        */
-       if ( ! soft_intr_enable ) 
-       {
-               lost_interrupts |= 1UL << irq;
-               /* can't printk - kernel expects intrs off! */
-               /*printk("irq %d while intrs soft disabled\n", irq);*/
-               goto out;
-       }
-       
-       action = irq + irq_action;
+       status = 0;
+       action = irq_action + irq;
        kstat.interrupts[irq]++;
-       if (action->handler) {
+       if ( action )
+       {
+               if (!(action->flags & SA_INTERRUPT))
+                       __sti();
+               status |= action->flags;
                action->handler(irq, action->dev_id, regs);
-               _disable_interrupts(); /* in case the handler turned them on */
+               /*if (status & SA_SAMPLE_RANDOM)
+                       add_interrupt_randomness(irq);*/
+               __cli(); /* in case the handler turned them on */
+               spin_lock(&irq_controller_lock);
+               unmask_irq(irq);
+               spin_unlock(&irq_controller_lock);
        } else {
                disable_irq( irq );
        }
-#ifdef CONFIG_PREP
-       /* re-enable if the interrupt was good and isn't one-shot */
-       if ( action->handler && !(action->flags & SA_ONESHOT) )
-               enable_irq(irq);
+       
        /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-       if ( irq > 7 )
+       if ( (_machine != _MACH_Pmac)/*prep*/ && (irq > 7) )
                goto retry_cascade;
-#endif
-       
-       hardirq_exit(cpu);
-       /*
-        * This should be conditional: we should really get
-        * a return code from the irq handler to tell us
-        * whether the handler wants us to do software bottom
-        * half handling or not..
-        */
-       if (1)
-               if (bh_active & bh_mask)
-                       do_bottom_half();
-        return;
+       /* do_bottom_half is called if necessary from int_return in head.S */
 out:
        hardirq_exit(cpu);
-
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -315,13 +267,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
 {
        struct irqaction * action;
        unsigned long flags;
-       
-#ifdef SHOW_IRQ        
+
+#ifdef SHOW_IRQ
        printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
               irq,handler,devname,dev_id);
 #endif /* SHOW_IRQ */
-       
-       if (irq > NR_IRQS)
+
+       if (irq >= NR_IRQS)
                return -EINVAL;
        action = irq + irq_action;
        if (action->handler)
@@ -339,17 +291,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        restore_flags(flags);
        return 0;
 }
-               
 void free_irq(unsigned int irq, void *dev_id)
 {
        struct irqaction * action = irq + irq_action;
        unsigned long flags;
 
-#ifdef SHOW_IRQ        
+#ifdef SHOW_IRQ
        printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
 #endif /* SHOW_IRQ */
-       
-       if (irq > NR_IRQS) {
+
+       if (irq >= NR_IRQS) {
                printk("Trying to free IRQ%d\n",irq);
                return;
        }
@@ -370,114 +321,85 @@ void free_irq(unsigned int irq, void *dev_id)
 
 unsigned long probe_irq_on (void)
 {
-       unsigned int i, irqs = 0, irqmask;
-       unsigned long delay;
-
-       /* first, snaffle up any unassigned irqs */
-       for (i = 15; i > 0; i--) {
-               if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
-                       enable_irq(i);
-                       irqs |= (1 << i);
-               }
-       }
-
-       /* wait for spurious interrupts to mask themselves out again */
-       for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
-
-       /* now filter out any obviously spurious interrupts */
-       irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
-       for (i = 15; i > 0; i--) {
-               if (irqs & (1 << i) & irqmask) {
-                       irqs ^= (1 << i);
-                       free_irq(i, NULL);
-               }
-       }
-#ifdef DEBUG
-       printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
-       return irqs;
+       return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-       unsigned int i, irqmask;
-
-       irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
-       for (i = 15; i > 0; i--) {
-               if (irqs & (1 << i)) {
-                       free_irq(i, NULL);
-               }
-       }
-#ifdef SHOW_IRQ
-       printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
-       irqs &= irqmask;
-       if (!irqs)
-               return 0;
-       i = ffz(~irqs);
-       if (irqs != (irqs & (1 << i)))
-               i = -i;
-       return i;
+       return 0;
 }
 
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
 {
-#ifdef CONFIG_PMAC  
        extern void xmon_irq(int, void *, struct pt_regs *);
 
-       *IRQ_ENABLE = 0;
-       request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
-#else /* CONFIG_PMAC */
-       /* Initialize interrupt controllers */
-       outb(0x11, 0x20); /* Start init sequence */
-       outb(0x40, 0x21); /* Vector base */
-#if 1
-       outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-#else
-       outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif 
-       
-       outb(0x01, 0x21); /* Select 8086 mode */
-       outb(0xFF, 0x21); /* Mask all */
-
-       outb(0x11, 0xA0); /* Start init sequence */
-       outb(0x48, 0xA1); /* Vector base */
-#if 1
-       outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-#else
-       outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
-       outb(0x01, 0xA1); /* Select 8086 mode */
-       outb(0xFF, 0xA1); /* Mask all */
+       if ( _machine == _MACH_Pmac )
+       {
+               mask_and_ack_irq = pmac_mask_and_ack_irq;
+               set_irq_mask = pmac_set_irq_mask;
+               
+               *IRQ_ENABLE = 0;
+#ifdef CONFIG_XMON
+               request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+       }
+       else /* prep */
+       {
+               mask_and_ack_irq = prep_mask_and_ack_irq;
+               set_irq_mask = prep_set_irq_mask;
+               
+               /* init master interrupt controller */
+               outb(0x11, 0x20); /* Start init sequence */
+               outb(0x40, 0x21); /* Vector base */
+               /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
+               outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+               outb(0x01, 0x21); /* Select 8086 mode */
+               outb(0xFF, 0x21); /* Mask all */
+
+               /* init slave interrupt controller */
+               outb(0x11, 0xA0); /* Start init sequence */
+               outb(0x48, 0xA1); /* Vector base */
+               /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
+               outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+               outb(0x01, 0xA1); /* Select 8086 mode */
+               outb(0xFF, 0xA1); /* Mask all */
+
+               /*
+                * According to the Carolina spec from ibm irq's 0,1,2, and 8
+                * must be edge triggered.  Also, the pci intrs must be level
+                * triggered and _only_ isa intrs can be level sensitive
+                * which are 3-7,9-12,14-15. 13 is special - it can be level.
+                *
+                * power on default is 0's in both regs - all edge.
+                *
+                * These edge/level control regs allow edge/level status
+                * to be decided on a irq basis instead of on a PIC basis.
+                * It's still pretty ugly.
+                * - Cort
+                */
+               {
+                       unsigned char irq_mode1 = 0, irq_mode2 = 0;
+                       irq_mode1 = 0; /* to get rid of compiler warnings */
+                       /*
+                        * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
+                        */
+                       if ( _machine == _MACH_IBM )
+                               irq_mode2 |= 0xa0;
+                       /*
+                        * Sound on the Powerstack reportedly needs to be edge triggered
+                        */
+                       if ( _machine == _MACH_Motorola )
+                       {}
+
+                       /*outb( irq_mode1 , 0x4d0 );
+                         outb( irq_mode2 , 0x4d1 );*/
+               }
+               outb(cached_A1, 0xA1);
+               outb(cached_21, 0x21);
+               if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+                       panic("Could not allocate cascade IRQ!");
+               enable_irq(2);  /* Enable cascade interrupt */
 
-       /*
-        * Program level mode for irq's that 'can' be level triggered.
-        * This does not effect irq's 0,1,2 and 8 since they must be
-        * edge triggered. This is not the PIC controller.  The default
-        * here is for edge trigger mode.  -- Cort
-        */
-#if 0  
-       outb(0xf8, 0x4d0); /* level triggered */
-       outb(0xff, 0x4d1);
-#endif
-#if 0  
-       outb(0x00, 0x4D0); /* All edge triggered */
-       outb(0xCF, 0x4D1); /* Trigger mode */
-#endif
-       outb(cached_A1, 0xA1);
-       outb(cached_21, 0x21);
-       if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
-               printk("Unable to get IRQ2 for cascade\n");
-       enable_irq(2);  /* Enable cascade interrupt */
-       
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-       /* set timer to periodic mode */
-       outb_p(0x34,TIMER_CONTROL);             /* binary, mode 2, LSB/MSB, ch 0 */
-       /* set the clock to ~100 Hz */
-       outb_p(LATCH & 0xff , TIMER0_COUNT);    /* LSB */
-       outb(LATCH >> 8 , TIMER0_COUNT);        /* MSB */
-
-       route_pci_interrupts();
-#endif /* CONFIG_PMAC */
+               route_pci_interrupts();
+       }
 }
diff --git a/arch/ppc/kernel/ksyms.c b/arch/ppc/kernel/ksyms.c
deleted file mode 100644 (file)
index b246fa6..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-void transfer_to_handler();
-void int_return();
-void syscall_trace();
-void handle_IRQ();
-void MachineCheckException();
-void AlignmentException();
-void ProgramCheckException();
-void SingleStepException();
-void FloatingPointCheckException();
-void sys_sigreturn();
-unsigned long sys_call_table[];
-
-extern struct task_struct *current_set[1];
-
-/* platform dependent support */
-EXPORT_SYMBOL(current_set);
-EXPORT_SYMBOL(do_signal);
-EXPORT_SYMBOL(syscall_trace);
-EXPORT_SYMBOL(transfer_to_handler);
-EXPORT_SYMBOL(int_return);
-EXPORT_SYMBOL(handle_IRQ);
-EXPORT_SYMBOL(init_task_union);
-EXPORT_SYMBOL(MachineCheckException);
-EXPORT_SYMBOL(AlignmentException);
-EXPORT_SYMBOL(ProgramCheckException);
-EXPORT_SYMBOL(SingleStepException);
-EXPORT_SYMBOL(FloatingPointCheckException);
-EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(sys_call_table);
index 430cd7a5d7025eda92eca5c61b92e2cf34615395..9c6d013b61ffe80c5bd892574faa31b533c012ab 100644 (file)
@@ -64,6 +64,7 @@ _GLOBAL(_hard_sti)
        mtmsr   r3              /* Update machine state */
        blr
 
+#if 0
 /*
  * Restore 'flags'
  *     __restore_flags(long val)
@@ -79,11 +80,13 @@ _GLOBAL(__restore_flags)
        mtmsr   r3
        isync
        blr
-
+#endif
+       
 /*
  * We were about to enable interrupts but we have to simulate
  * some interrupts that were lost by enable_irq first.
  */
+       .globl do_lost_interrupts
 do_lost_interrupts:
        stwu    r1,-16(r1)
        mflr    r0
@@ -243,7 +246,6 @@ _GLOBAL(_outsl)
        bdnz    00b
        blr     
 
-#ifdef CONFIG_PMAC
 _GLOBAL(ide_insw)
        mtctr   r5
        subi    r4,r4,2
@@ -259,7 +261,6 @@ _GLOBAL(ide_outsw)
        sthx    r5,0,r3 
        bdnz    00b
        blr     
-#endif
 
 /*
  * Extended precision shifts
@@ -298,7 +299,7 @@ _GLOBAL(abs)
 _GLOBAL(_get_SP)
        mr      r3,r1           /* Close enough */
        blr
-       
+
 _GLOBAL(_get_PVR)
        mfspr   r3,PVR
        blr
@@ -308,6 +309,7 @@ cvt_fd:
        lfs     0,0(r3)
        stfd    0,0(r4)
        blr
+
 /*
  * Fetch the current SR register
  *   get_SR(int index)
@@ -317,7 +319,6 @@ _GLOBAL(get_SR)
        mr      r3,r4
        blr
 
-       
 _GLOBAL(cvt_df)
 cvt_df:
        lfd     0,0(r3)
index 3f404a37a81a3abd024d055c29c0a11276546914..80f10c59eaa245f70cc0cc8e79faa351671985c2 100644 (file)
@@ -29,7 +29,6 @@
 void
 main(void)
 {
-       /*DEFINE(KERNELBASE, KERNELBASE);*/
        DEFINE(STATE, offsetof(struct task_struct, state));
        DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
        DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -37,54 +36,20 @@ main(void)
        DEFINE(SIGNAL, offsetof(struct task_struct, signal));
        DEFINE(TSS, offsetof(struct task_struct, tss));
        DEFINE(KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
-#ifdef CONFIG_PMAC     
-       DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
-       DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
-#endif 
+       /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
+       DEFINE(MM, offsetof(struct task_struct, mm));
+       DEFINE(PGD, offsetof(struct mm_struct, pgd));
        DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
        DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
        DEFINE(PF_TRACESYS, PF_TRACESYS);
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
-#if 0
-       DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
-       DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
-       DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
-       DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
-       DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
-       DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
-       DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
-       DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
-       DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
-       DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
-       DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
-       DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
-       DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
-       DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
-       DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
-       DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
-       DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
-       DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
-       DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
-       DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
-       DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
-       DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
-       DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
-       DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
-       DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
-       DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
-       DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
-       DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
-       DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
-       DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
-       DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
-#endif
        DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
        /* Interrupt register frame */
        DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
        DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
        DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+       /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
        DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
        DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
        DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
diff --git a/arch/ppc/kernel/pci-bridge.c b/arch/ppc/kernel/pci-bridge.c
new file mode 100644 (file)
index 0000000..0e44203
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+       volatile unsigned int *cfg_addr;
+       volatile unsigned char *cfg_data;
+       void *io_base;
+       int bus_number;
+       int max_bus;
+       struct bridge_data *next;
+       struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID   0x106b
+#define BANDIT_DEVID   1
+#define BANDIT_REVID   3
+
+#define BANDIT_DEVNUM  11
+#define BANDIT_MAGIC   0x50
+#define BANDIT_COHERENT        0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+       unsigned int vendev, magic;
+       int rev;
+
+       /* read the word at offset 0 in config space for device 11 */
+       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+       udelay(2);
+       vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+       if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+               printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+               return;
+       }
+
+       /* read the revision id */
+       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+       udelay(2);
+       rev = in_8(bp->cfg_data);
+       if (rev != BANDIT_REVID)
+               printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+                      rev, bp->io_base);
+
+       /* read the word at offset 0x50 */
+       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+       udelay(2);
+       magic = in_le32((volatile unsigned int *)bp->cfg_data);
+       if ((magic & BANDIT_COHERENT) != 0)
+               return;
+       magic |= BANDIT_COHERENT;
+       udelay(2);
+       out_le32((volatile unsigned int *)bp->cfg_data, magic);
+       printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+              bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+       int bus;
+       struct bridge_data *bridge;
+
+       bridge_list = 0;
+       max_bus = 0;
+       add_bridges(find_devices("bandit"), &mem_start);
+       add_bridges(find_devices("chaos"), &mem_start);
+       bridges = (struct bridge_data **) mem_start;
+       mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+       memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+       for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+               for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+                       bridges[bus] = bridge;
+
+       return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+       int *bus_range;
+       int len;
+       struct bridge_data *bp;
+
+       for (; dev != NULL; dev = dev->next) {
+               if (dev->n_addrs < 1) {
+                       printk(KERN_WARNING "Can't use %s: no address\n",
+                              dev->full_name);
+                       continue;
+               }
+               bus_range = (int *) get_property(dev, "bus-range", &len);
+               if (bus_range == NULL || len < 2 * sizeof(int)) {
+                       printk(KERN_WARNING "Can't get bus-range for %s\n",
+                              dev->full_name);
+                       continue;
+               }
+               if (bus_range[1] == bus_range[0])
+                       printk(KERN_INFO "PCI bus %d", bus_range[0]);
+               else
+                       printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+                              bus_range[1]);
+               printk(" controlled by %s at %x\n",
+                      dev->name, dev->addrs[0].address);
+               bp = (struct bridge_data *) *mem_ptr;
+               *mem_ptr += sizeof(struct bridge_data);
+               bp->cfg_addr = (volatile unsigned int *)
+                       (dev->addrs[0].address + 0x800000);
+               bp->cfg_data = (volatile unsigned char *)
+                       (dev->addrs[0].address + 0xc00000);
+               bp->io_base = (void *) dev->addrs[0].address;
+               ioremap(dev->addrs[0].address, 0x800000);
+               bp->bus_number = bus_range[0];
+               bp->max_bus = bus_range[1];
+               bp->next = bridge_list;
+               bp->node = dev;
+               bridge_list = bp;
+               if (bp->max_bus > max_bus)
+                       max_bus = bp->max_bus;
+
+               if (strcmp(dev->name, "bandit") == 0)
+                       init_bandit(bp);
+       }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+       struct bridge_data *bp;
+
+       if (bus > max_bus || (bp = bridges[bus]) == 0)
+               return 0;
+       return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+                  unsigned char *devfn_ptr)
+{
+       unsigned int *reg;
+       int len;
+
+       reg = (unsigned int *) get_property(dev, "reg", &len);
+       if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+               /* doesn't look like a PCI device */
+               *bus_ptr = 0xff;
+               *devfn_ptr = 0xff;
+               return -1;
+       }
+       *bus_ptr = reg[0] >> 16;
+       *devfn_ptr = reg[0] >> 8;
+       return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned char *val)
+{
+       struct bridge_data *bp;
+
+       *val = 0xff;
+       if (bus > max_bus || (bp = bridges[bus]) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + (offset & ~3));
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+       }
+       udelay(2);
+       *val = in_8(bp->cfg_data + (offset & 3));
+
+       if (offset == PCI_INTERRUPT_LINE) {
+               /*
+                * Open Firmware often doesn't initialize this
+                * register properly, so we find the node and see
+                * if it has an AAPL,interrupts property.
+                */
+               struct device_node *node;
+               unsigned int *reg;
+
+               for (node = bp->node->child; node != 0; node = node->sibling) {
+                       reg = (unsigned int *) get_property(node, "reg", 0);
+                       if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+                               continue;
+                       /* this is the node, see if it has interrupts */
+                       if (node->n_intrs > 0)
+                               *val = node->intrs[0];
+                       break;
+               }
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned short *val)
+{
+       struct bridge_data *bp;
+
+       *val = 0xffff;
+       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + (offset & ~3));
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+       }
+       udelay(2);
+       *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned int *val)
+{
+       struct bridge_data *bp;
+
+       *val = 0xffffffff;
+       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + offset);
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+       }
+       udelay(2);
+       *val = in_le32((volatile unsigned int *)bp->cfg_data);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned char val)
+{
+       struct bridge_data *bp;
+
+       if (bus > max_bus || (bp = bridges[bus]) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + (offset & ~3));
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+       }
+       udelay(2);
+       out_8(bp->cfg_data + (offset & 3), val);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned short val)
+{
+       struct bridge_data *bp;
+
+       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + (offset & ~3));
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+       }
+       udelay(2);
+       out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                                   unsigned char offset, unsigned int val)
+{
+       struct bridge_data *bp;
+
+       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (bus == bp->bus_number) {
+               if (dev_fn < (11 << 3))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               out_le32(bp->cfg_addr,
+                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+                        + offset);
+       } else {
+               out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+       }
+       udelay(2);
+       out_le32((volatile unsigned int *)bp->cfg_data, val);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+                            unsigned short index, unsigned char *bus_ptr,
+                            unsigned char *dev_fn_ptr)
+{
+       int bus, unit, fn, num, devfn;
+       unsigned int x, vendev;
+       unsigned char h;
+
+       if (vendor == 0xffff)
+               return PCIBIOS_BAD_VENDOR_ID;
+       vendev = (dev_id << 16) + vendor;
+       num = 0;
+       for (bus = 0; bus <= max_bus; ++bus) {
+               if (bridges[bus] == 0)
+                       continue;
+               unit = fn = 0;
+               if (bus == bridges[bus]->bus_number)
+                       unit = 11;
+               while (unit < 32) {
+                       devfn = PCI_DEVFN(unit, fn);
+                       if (pcibios_read_config_dword(bus, devfn,
+                                                     PCI_VENDOR_ID, &x)
+                           == PCIBIOS_SUCCESSFUL && x == vendev) {
+                               if (index == num) {
+                                       *bus_ptr = bus;
+                                       *dev_fn_ptr = devfn;
+                                       return PCIBIOS_SUCCESSFUL;
+                               }
+                               ++num;
+                       }
+                       if (fn != 0) {
+                               if (++fn >= 8) {
+                                       ++unit;
+                                       fn = 0;
+                               }
+                               continue;
+                       }
+                       if (pcibios_read_config_byte(bus, devfn,
+                                                    PCI_HEADER_TYPE, &h)
+                           == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+                               ++fn;
+                       else
+                               ++unit;
+               }
+       }
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+                           unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+       int bus, unit, fn, num, devfn;
+       unsigned int x;
+       unsigned char h;
+
+       num = 0;
+       for (bus = 0; bus <= max_bus; ++bus) {
+               if (bridges[bus] == 0)
+                       continue;
+               unit = fn = 0;
+               if (bus == bridges[bus]->bus_number)
+                       unit = 11;
+               while (unit < 32) {
+                       devfn = PCI_DEVFN(unit, fn);
+                       if (pcibios_read_config_dword(bus, devfn,
+                                                     PCI_CLASS_REVISION, &x)
+                           == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+                               if (index == num) {
+                                       *bus_ptr = bus;
+                                       *dev_fn_ptr = devfn;
+                                       return PCIBIOS_SUCCESSFUL;
+                               }
+                               ++num;
+                       }
+                       if (fn != 0) {
+                               if (++fn >= 8) {
+                                       ++unit;
+                                       fn = 0;
+                               }
+                               continue;
+                       }
+                       if (pcibios_read_config_byte(bus, devfn,
+                                                    PCI_HEADER_TYPE, &h)
+                           == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+                               ++fn;
+                       else
+                               ++unit;
+               }
+       }
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+       return 0;
+}
index 612a24bffaaeeb39a5b8be1325e839231085cef5..2d7561be55a50252089163209304b5787c4bb8fe 100644 (file)
 /*
- * PCI support
- * -- rough emulation of "PCI BIOS" functions
- *
- * Note: these are very motherboard specific!  Some way needs to
- * be worked out to handle the differences.
+ * $Id: pci.c,v 1.11 1997/08/13 03:06:14 cort Exp $
+ * Common pmac/prep pci routines. -- Cort
  */
 
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/bios32.h>
+#include <linux/kernel.h>
 #include <linux/pci.h>
+/*#include <linux/bios32.h>*/
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
 
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
 #include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
 
-/*
- * PCI interrupt configuration.  This is motherboard specific.
- */
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
-
-/* Tables for known hardware */   
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] =
-{
-       0,      /* Slot 0  - unused */
-       0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
-       3,      /* Slot 12 - SCSI */
-       0,      /* Slot 13 - unused */
-       1,      /* Slot 14 - Ethernet */
-       0,      /* Slot 15 - unused */
-};
-
-static char Blackhawk_pci_IRQ_routes[] =
-{
-       0,      /* Line 0 - Unused */
-       9,      /* Line 1 */
-       11,     /* Line 2 */
-       14,     /* Line 3 */
-       15      /* Line 4 */
-};
-   
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] =
-{
-       0,      /* Slot 0  - unused */
-       0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
-       3,      /* Slot 12 - SCSI */
-       0,      /* Slot 13 - unused */
-       1,      /* Slot 14 - Ethernet */
-       0,      /* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] =
-{
-       0,      /* Line 0 - Unused */
-       10,     /* Line 1 */
-       11,     /* Line 2 */
-       14,     /* Line 3 */
-       15      /* Line 4 */
-};
-   
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] =
-{
-       0,      /* Slot 0  - unused */
-       0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
-       3,      /* Slot 12 - SCSI */
-       0,      /* Slot 13 - unused */
-       1,      /* Slot 14 - Ethernet */
-       0,      /* Slot 15 - unused */
-};
-
-static char Comet_pci_IRQ_routes[] =
-{
-       0,      /* Line 0 - Unused */
-       10,     /* Line 1 */
-       11,     /* Line 2 */
-       14,     /* Line 3 */
-       15      /* Line 4 */
-};
-
-/* BeBox */
-static char BeBox_pci_IRQ_map[16] =
-{
-       0,      /* Slot 0  - unused */
-       0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
-       16,     /* Slot 12 - SCSI */
-       0,      /* Slot 13 - unused */
-       0,      /* Slot 14 - unused */
-       0,      /* Slot 15 - unused */
-};
-
-static char BeBox_pci_IRQ_routes[] =
-{
-       0,      /* Line 0 - Unused */
-       9,      /* Line 1 */
-       11,     /* Line 2 */
-       14,     /* Line 3 */
-       15      /* Line 4 */
-};
-
-/* IBM Nobis */
-static char Nobis_pci_IRQ_map[16] =
-{
-       0,      /* Slot 0  - unused */
-       0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
-       3,      /* Slot 12 - SCSI */
-       0,      /* Slot 13 - unused */
-       0,      /* Slot 14 - unused */
-       0,      /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] =
-{
-       0,      /* Line 0 - Unused */
-       13,     /* Line 1 */
-       13,     /* Line 2 */
-       13,     /* Line 3 */
-       13      /* Line 4 */
-};
-
+unsigned long io_base;
 
 /*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
+ * It would be nice if we could create a include/asm/pci.h and have just
+ * function ptrs for all these in there, but that isn't the case.
+ * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
+ * which has been setup by pcibios_init().  This is all to avoid a check
+ * for pmac/prep every time we call one of these.  It should also make the move
+ * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
+ * and create pci.h
+ *   -- Cort
  */
-static char ibm8xx_pci_IRQ_map[23] = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - FireCoral */
-        4, /* Slot 12 - Ethernet  PCIINTD# */
-        2, /* Slot 13 - PCI Slot #2 */
-        2, /* Slot 14 - S3 Video PCIINTD# */
-        0, /* Slot 15 - onboard SCSI (INDI) [1] */
-        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-static char ibm8xx_pci_IRQ_routes[] = {
-        0,      /* Line 0 - unused */
-        13,     /* Line 1 */
-        10,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
- * it really needs some logic to set them to unique IRQ's, or even
- * add some logic to the drivers to ask an irq.c routine to re-map
- * the IRQ if it needs one to itself...
- */
-static char Carolina_PIRQ_routes[] = {
-   0xad,       /* INTB# = 10, INTA# = 13 */
-   0xff                /* INTD# = 15, INTC# = 15 */
-};
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
-#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */
-#define PCI_DEVICE_ID_IBM_CORAL                0x000a
-
-#undef  PCI_DEBUG
-
-#ifdef PCI_STATS
-int PCI_conversions[2];
-#endif
-
-
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
-{
-       return mem_start;
+int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned char *val);
+int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned short *val);
+int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned int *val);
+int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned char val);
+int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned short val);
+int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
+                              unsigned char offset, unsigned int val);
+int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
+                       unsigned short index, unsigned char *bus_ptr,
+                       unsigned char *dev_fn_ptr);
+int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
+                      unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned char *val);
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned int *val);
+extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned char val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned short val);
+extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                              unsigned char offset, unsigned int val);
+extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+                       unsigned short index, unsigned char *bus_ptr,
+                       unsigned char *dev_fn_ptr);
+extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+                      unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned char *val);
+extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned short *val);
+extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned int *val);
+extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned char val);
+extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned short val);
+extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                              unsigned char offset, unsigned int val);
+extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+                       unsigned short index, unsigned char *bus_ptr,
+                       unsigned char *dev_fn_ptr);
+extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
+                      unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned char *val)
+{
+       return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_present (void)
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                            unsigned char offset, unsigned short *val)
 {
-#ifdef PCI_DEBUG       
-       printk("PCI [BIOS] present?\n");
-#endif 
-       return (1);
+       return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_read_config_dword (unsigned char bus,
-                          unsigned char dev, unsigned char offset, unsigned int *val)
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned int *val)
 {
-       unsigned long _val;
-       unsigned long *ptr;
-       dev >>= 3;
-#ifdef PCI_DEBUG       
-       printk("PCI Read config dword[%d.%d.%x] = ", bus, dev, offset);
-#endif 
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               *val = 0xFFFFFFFF;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG       
-               printk("[%x] ", ptr);
-#endif         
-               _val = le32_to_cpu(*ptr);
-       }
-#ifdef PCI_DEBUG       
-       printk("%x\n", _val);
-#endif 
-       *val = _val;
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_read_config_word (unsigned char bus,
-                         unsigned char dev, unsigned char offset, unsigned short *val)
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned char val)
 {
-       unsigned short _val;
-       unsigned short *ptr;
-       dev >>= 3;
-#ifdef PCI_DEBUG
-       printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
-#endif 
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               *val = (unsigned short)0xFFFFFFFF;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
-               printk("[%x] ", ptr);
-#endif         
-               _val = le16_to_cpu(*ptr);
-       }
-#ifdef PCI_DEBUG
-       printk("%x\n", _val);
-#endif         
-       *val = _val;
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_read_config_byte (unsigned char bus,
-                         unsigned char dev, unsigned char offset, unsigned char *val)
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                             unsigned char offset, unsigned short val)
 {
-       unsigned char _val;
-       volatile unsigned char *ptr;
-       dev >>= 3;
-       /* Note: the configuration registers don't always have this right! */
-       if (offset == PCI_INTERRUPT_LINE)
-       {
-               if (Motherboard_map[dev] <= 4)
-               {
-                       *val = Motherboard_routes[Motherboard_map[dev]];
-                       /*printk("dev %d map %d route %d\n",
-                         dev,Motherboard_map[dev],
-                         Motherboard_routes[Motherboard_map[dev]]);*/
-               } else
-               { /* Pseudo interrupts [for BeBox] */
-                       *val = Motherboard_map[dev];
-               }
-#ifdef PCI_DEBUG       
-               printk("PCI Read Interrupt Line[%d.%d] = %d\n", bus, dev, *val);
-#endif         
-               return PCIBIOS_SUCCESSFUL;
-       }
-#ifdef PCI_DEBUG       
-       printk("PCI Read config byte[%d.%d.%x] = ", bus, dev, offset);
-#endif         
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               *val = 0xFFFFFFFF;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-#ifdef PCI_DEBUG       
-               printk("[%x] ", ptr);
-#endif         
-               _val = *ptr;
-       }
-#ifdef PCI_DEBUG       
-       printk("%x\n", _val);
-#endif
-       *val = _val;
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_write_config_dword (unsigned char bus,
-                           unsigned char dev, unsigned char offset, unsigned int val)
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                              unsigned char offset, unsigned int val)
 {
-       unsigned long _val;
-       unsigned long *ptr;
-       dev >>= 3;
-       _val = le32_to_cpu(val);
-#ifdef PCI_DEBUG       
-       printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif         
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-               *ptr = _val;
-       }
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
 }
-
-int
-pcibios_write_config_word (unsigned char bus,
-                          unsigned char dev, unsigned char offset, unsigned short val)
+int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+                       unsigned short index, unsigned char *bus_ptr,
+                       unsigned char *dev_fn_ptr)
 {
-       unsigned short _val;
-       unsigned short *ptr;
-       dev >>= 3;
-       _val = le16_to_cpu(val);
-#ifdef PCI_DEBUG       
-       printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif         
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-               *ptr = _val;
-       }
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
 }
-
-int
-pcibios_write_config_byte (unsigned char bus,
-                          unsigned char dev, unsigned char offset, unsigned char val)
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+                      unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
 {
-       unsigned char _val;
-       unsigned char *ptr;
-       dev >>= 3;
-       _val = val;
-#ifdef PCI_DEBUG       
-       printk("PCI Write config byte[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif         
-       if ((bus != 0) || (dev < 11) || (dev > 16))
-       {
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       } else
-       {
-               ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-               *ptr = _val;
-       }
-       return PCIBIOS_SUCCESSFUL;
+       return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
 }
 
-int
-pcibios_find_device (unsigned short vendor, unsigned short device_id,
-                    unsigned short index, unsigned char *bus,
-                    unsigned char *dev)
+int pcibios_present(void)
 {
-       unsigned long w, desired = (device_id << 16) | vendor;
-       int devnr;
-
-       if (vendor == 0xffff) {
-               return PCIBIOS_BAD_VENDOR_ID;
-       }
-
-       for (devnr = 11;  devnr < 16;  devnr++)
-       {
-               pcibios_read_config_dword(0, devnr<<3, PCI_VENDOR_ID, &w);
-               if (w == desired) {
-                       if (index == 0) {
-                               *bus = 0;
-                               *dev = devnr<<3;
-                               return PCIBIOS_SUCCESSFUL;
-                       }
-                       --index;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
+       return 1;
 }
 
-int
-pcibios_find_class (unsigned int class_code, unsigned short index, 
-                   unsigned char *bus, unsigned char *dev)
+__initfunc(unsigned long
+pcibios_init(unsigned long mem_start,unsigned long mem_end))
 {
-       int dev_nr, class, indx;
-       indx = 0;
-#ifdef PCI_DEBUG       
-       printk("pcibios_find_class - class: %x, index: %x", class_code, index);
-#endif 
-       for (dev_nr = 11;  dev_nr < 16;  dev_nr++)
+       if ( _machine == _MACH_Pmac )
        {
-               pcibios_read_config_dword(0, dev_nr<<3, PCI_CLASS_REVISION, &class);
-               if ((class>>8) == class_code)
-               {
-                       if (index == indx)
-                       {
-                               *bus = 0;
-                               *dev = dev_nr<<3;
-#ifdef PCI_DEBUG
-                               printk(" - device: %x\n", dev_nr);
-#endif 
-                               return (0);
-                       }
-                       indx++;
-               }
+               ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
+               ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
+               ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
+               ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
+               ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
+               ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
+               ptr_pcibios_find_device = pmac_pcibios_find_device;
+               ptr_pcibios_find_class = pmac_pcibios_find_class;
        }
-#ifdef PCI_DEBUG
-       printk(" - not found\n");
-#endif 
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}    
-
-const char *pcibios_strerror(int error)
-{
-       static char buf[32];
-       switch (error)
-       {       case PCIBIOS_SUCCESSFUL:
-               return ("PCI BIOS: no error");
-       case PCIBIOS_FUNC_NOT_SUPPORTED:
-               return ("PCI BIOS: function not supported");
-       case PCIBIOS_BAD_VENDOR_ID:
-               return ("PCI BIOS: bad vendor ID");
-       case PCIBIOS_DEVICE_NOT_FOUND:
-               return ("PCI BIOS: device not found");
-       case PCIBIOS_BAD_REGISTER_NUMBER:
-               return ("PCI BIOS: bad register number");
-       case PCIBIOS_SET_FAILED:
-               return ("PCI BIOS: set failed");
-       case PCIBIOS_BUFFER_TOO_SMALL:
-               return ("PCI BIOS: buffer too small");
-       default:
-               sprintf(buf, "PCI BIOS: invalid error #%d", error);
-               return(buf);
+       else /* prep */
+       {
+               ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
+               ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
+               ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
+               ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
+               ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
+               ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
+               ptr_pcibios_find_device = prep_pcibios_find_device;
+               ptr_pcibios_find_class = prep_pcibios_find_class;
        }
-}
-
-/*
- * Note: This routine has to access the PCI configuration space
- * for the PCI bridge chip (Intel 82378).
- */
-unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
-{
        return mem_start;
 }
 
-unsigned long route_pci_interrupts(void)
+__initfunc(unsigned long
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
 {
-       unsigned char *ibc_pirq = (unsigned char *)0x80800860;
-       unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
-       extern unsigned long isBeBox[];
-       int i;
-       
-       if ( _machine == _MACH_Motorola)
-       { 
-               switch (inb(0x800) & 0xF0)
-               {
-               case 0x10: /* MVME16xx */
-                       Motherboard_map_name = "Genesis";
-                       Motherboard_map = Genesis_pci_IRQ_map;
-                       Motherboard_routes = Genesis_pci_IRQ_routes;
-                       break;
-               case 0x20: /* Series E */
-                       Motherboard_map_name = "Series E";
-                       Motherboard_map = Comet_pci_IRQ_map;
-                       Motherboard_routes = Comet_pci_IRQ_routes;
-                       break;
-               case 0x40: /* PowerStack */
-               default: /* Can't hurt, can it? */
-                       Motherboard_map_name = "Blackhawk (Powerstack)";
-                       Motherboard_map = Blackhawk_pci_IRQ_map;
-                       Motherboard_routes = Blackhawk_pci_IRQ_routes;
-                       break;
-               }
-       } else
-       {
-               if ( _machine == _MACH_IBM )
-               {
-                       unsigned char pl_id;
-                       unsigned long flags;
-                       unsigned index;
-                       unsigned char fn, bus;
-                       unsigned int addr;
-                       unsigned char dma_mode, ide_mode;
-                       int i;
-                       
-                       Motherboard_map_name = "IBM 8xx (Carolina)";
-                       Motherboard_map = ibm8xx_pci_IRQ_map;
-                       Motherboard_routes = ibm8xx_pci_IRQ_routes;
-ll_printk("before loop\n");                    
-                       
-                       for (index = 0;
-                            !pcibios_find_device (PCI_VENDOR_ID_IBM, 
-                                                  PCI_DEVICE_ID_IBM_CORAL, 
-                                                  index, &bus, &fn); ++index)
-                       {
-                               pcibios_read_config_dword(bus, fn, 0x10, &addr);
-                               addr &= ~0x3;
-                               outb(0x26, addr);
-                               dma_mode = inb(addr+4);
-                               outb(0x25, addr);
-                               ide_mode = inb(addr+4);
-                               /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x", 
-                                      addr, dma_mode, ide_mode);*/
-                               /* Make CDROM non-DMA */
-                               ide_mode = (ide_mode & 0x0F) | 0x20;
-                               outb(0x25, addr);
-                               outb(ide_mode, addr+4);
-                               dma_mode = dma_mode & ~0x80;
-                               outb(0x26, addr);
-                               outb(dma_mode, addr+4);
-                               outb(0x26, addr);
-                               dma_mode = inb(addr+4);
-                               outb(0x25, addr);
-                               ide_mode = inb(addr+4);
-                               /*printk("=> DMA mode: %x, IDE mode: %x\n", 
-                                      dma_mode, ide_mode);*/
-                       }
-                       
-                       /* Setup the PCI INT mappings for the Carolina */
-                       /* These are PCI Interrupt Route Control [1|2] Register */
-                       outb(Carolina_PIRQ_routes[0], 0x0890);
-                       outb(Carolina_PIRQ_routes[1], 0x0891);
-                       
-                       pl_id=inb(0x0852);
-                       /*printk("CPU Planar ID is %#0x\n", pl_id);*/
-                       
-                       if (pl_id == 0x0C) {
-                               /* INDI */
-                               Motherboard_map[12] = 1;
-                       }
-ll_printk("before edge/level\n");                      
-#if 0                  
-                       /*printk("Changing IRQ mode\n");*/
-                       pl_id=inb(0x04d0);
-                       /*printk("Low mask is %#0x\n", pl_id);*/
-                       outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-                       
-                       pl_id=inb(0x04d1);
-                       /*printk("Hi mask is  %#0x\n", pl_id);*/
-                       outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
-                       pl_id=inb(0x04d1);
-                       /*printk("Hi mask now %#0x\n", pl_id);*/
-#endif                 
-               }
-       }
-       
-       /* Set up mapping from slots */
-       for (i = 1;  i <= 4;  i++)
-       {
-               ibc_pirq[i-1] = Motherboard_routes[i];
-       }
-       /* Enable PCI interrupts */
-       *ibc_pcicon |= 0x20;
+       return mem_start;
 }
index 468025f5abab75cb06b40ee66a7fc6a28a05d3fa..ef30a86296ddbbfebcd0d1981d27d3df87788c2d 100644 (file)
@@ -21,6 +21,7 @@
  * bootup setup stuff..
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/major.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include "time.h"
+
+/*
+ * A magic address and value to put into it on machines with the
+ * "ohare" I/O controller.  This makes the IDE CD work on Starmaxes.
+ * Contributed by Harry Eaton.
+ */
+#define OMAGICPLACE    ((volatile unsigned *) 0xf3000038)
+#define OMAGICCONT     0xbeff7a
 
 extern int root_mountflags;
 
 extern char command_line[];
-char saved_command_line[256];
+extern char saved_command_line[256];
 
-unsigned char aux_device_present;      /* XXX */
-unsigned char kbd_read_mask;
 unsigned char drive_info;
 
 #define DEFAULT_ROOT_DEVICE 0x0801     /* sda1 - slightly silly choice */
 
 extern unsigned long find_available_memory(void);
 
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-       return memory_start;
-}
-
-void setup_arch(char **cmdline_p,
+void pmac_setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
        extern unsigned long *end_of_DRAM;
@@ -84,6 +89,8 @@ void setup_arch(char **cmdline_p,
                if (fp != 0) {
                        switch (_get_PVR() >> 16) {
                        case 4:         /* 604 */
+                       case 9:         /* 604e */
+                       case 20:        /* 620 */
                                loops_per_sec = *fp;
                                break;
                        default:        /* 601, 603, etc. */
@@ -102,13 +109,19 @@ int boot_part;
 kdev_t boot_dev;
 
 unsigned long
-pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+powermac_init(unsigned long mem_start, unsigned long mem_end)
 {
-       struct device_node *chosen_np;
+       struct device_node *chosen_np, *ohare_np;
 
-       nvram_init();
+       mem_start = pmac_find_bridges(mem_start, mem_end);
+       ohare_np = find_devices("ohare");
+       if (ohare_np != NULL) {
+               printk(KERN_INFO "Twiddling the magic ohare bits\n");
+               out_le32(OMAGICPLACE, OMAGICCONT);
+       }
+       pmac_nvram_init();
        via_cuda_init();
-       read_rtc_time();
+       pmac_read_rtc_time();
        pmac_find_display();
        bootpath = NULL;
        chosen_np = find_devices("chosen");
@@ -147,7 +160,7 @@ note_scsi_host(struct device_node *node, void *host)
        }
 }
 
-void find_scsi_boot()
+void find_boot_device(void)
 {
        int dev;
 
@@ -156,10 +169,28 @@ void find_scsi_boot()
        ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
        if (boot_host == NULL)
                return;
+#ifdef CONFIG_SCSI
        dev = sd_find_target(boot_host, boot_target);
        if (dev == 0)
                return;
        boot_dev = to_kdev_t(dev + boot_part);
+#endif
+       /* XXX should cope with booting from IDE also */
+}
+
+void note_bootable_part(kdev_t dev, int part)
+{
+       static int found_boot = 0;
+
+       if (!found_boot) {
+               find_boot_device();
+               found_boot = 1;
+       }
+       if (dev == boot_dev) {
+               ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+               boot_dev = NODEV;
+               printk(" (root)");
+       }
 }
 
 void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
@@ -186,41 +217,18 @@ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
        if (np->n_intrs == 0) {
                printk("ide: no intrs for device %s, using 13\n",
                       np->full_name);
-               np->intrs[0] = 13;
+               *irq = 13;
+       } else {
+               *irq = np->intrs[0];
        }
        base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
        for (i = 0; i < 8; ++i)
                *p++ = base + i * 0x10;
        *p = base + 0x160;
-       *irq = np->intrs[0];
-}
-
-int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-       return -EIO;
-}
-
-#if 0
-extern char builtin_ramdisk_image;
-extern long builtin_ramdisk_size;
-#endif
-
-void
-builtin_ramdisk_init(void)
-{
-#if 0
-       if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
-       {
-               rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
-       } else
-#endif
-       {  /* Not ramdisk - assume root needs to be mounted read only */
-               root_mountflags |= MS_RDONLY;
-       }
 }
 
 int
-get_cpuinfo(char *buffer)
+pmac_get_cpuinfo(char *buffer)
 {
        int pvr = _get_PVR();
        char *model;
@@ -251,10 +259,13 @@ get_cpuinfo(char *buffer)
        case 7:
                model = "603ev";
                break;
+       case 9:
+               model = "604e";
+               break;
        default:
                model = "unknown";
                break;
        }
        return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
-                          (pvr & 0xff) >> 8, pvr & 0xff);
+                          (pvr & 0xff00) >> 8, pvr & 0xff);
 }
index ad2c0fb4a4b18822f8eadfea789392334b511edb..3c1895088516117f0cb4535f95ce01c1b68bd73e 100644 (file)
@@ -3,30 +3,14 @@
  */
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/cuda.h>
 #include <asm/system.h>
 #include <asm/prom.h>
 
-void hard_reset_now(void)
-{
-       struct cuda_request req;
-
-       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
-       for (;;)
-               cuda_poll();
-}
-
-void poweroff_now(void)
-{
-       struct cuda_request req;
-
-       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
-       for (;;)
-               cuda_poll();
-}
-
 /*
  * Read and write the non-volatile RAM on PowerMacs.
  */
@@ -34,26 +18,29 @@ static int nvram_naddrs;
 static volatile unsigned char *nvram_addr;
 static volatile unsigned char *nvram_data;
 
-void nvram_init(void)
+void pmac_nvram_init(void)
 {
        struct device_node *dp;
 
        dp = find_devices("nvram");
-       if (dp == NULL)
-               panic("Can't find NVRAM device");
+       if (dp == NULL) {
+               printk(KERN_ERR "Can't find NVRAM device\n");
+               nvram_naddrs = 0;
+               return;
+       }
        nvram_naddrs = dp->n_addrs;
-       if (nvram_naddrs == 1)
+       if (nvram_naddrs == 1) {
                nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-       else if (nvram_naddrs == 2) {
+       else if (nvram_naddrs == 2) {
                nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
                nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
        } else {
-               printk("Found %d addresses for NVRAM\n", nvram_naddrs);
-               panic("don't understand NVRAM");
+               printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+                      nvram_naddrs);
        }
 }
 
-int nvram_readb(int addr)
+unsigned char nvram_read_byte(int addr)
 {
        switch (nvram_naddrs) {
        case 1:
@@ -63,10 +50,10 @@ int nvram_readb(int addr)
                eieio();
                return nvram_data[(addr & 0x1f) << 4];
        }
-       return -1;
+       return 0;
 }
 
-void nvram_writeb(int addr, int val)
+void nvram_write_byte(unsigned char val, int addr)
 {
        switch (nvram_naddrs) {
        case 1:
index 25df5ff3a93dce34d91232ebcd71bb9f5a67ba07..69a17321d4ee2f312ebef129045dd6198f61380b 100644 (file)
 #include <asm/prom.h>
 #include <asm/system.h>
 
-static int get_dec(void);
-static void set_dec(int);
-static unsigned long get_rtc_time(void);
+#include "time.h"
+
 
 /* Apparently the RTC stores seconds since 1 Jan 1904 */
 #define RTC_OFFSET     2082844800
 
-/* Accessor functions for the decrementer register. */
-static inline int
-get_dec()
-{
-    int ret;
-
-    asm volatile("mfspr %0,22" : "=r" (ret) :);
-    return ret;
-}
-
-static inline void
-set_dec(int val)
-{
-    asm volatile("mtspr 22,%0" : : "r" (val));
-}
-
-/* The decrementer counts down by 128 every 128ns on a 601. */
-#define DECREMENTER_COUNT_601  (1000000000 / HZ)
-#define COUNT_PERIOD_NUM_601   1
-#define COUNT_PERIOD_DEN_601   1000
-
-unsigned decrementer_count;    /* count value for 1e6/HZ microseconds */
-unsigned count_period_num;     /* 1 decrementer count equals */
-unsigned count_period_den;     /* count_period_num / count_period_den us */
-
 /*
- * This version of gettimeofday has microsecond resolution.
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
  */
-void do_gettimeofday(struct timeval *tv)
+void pmac_calibrate_decr(void)
 {
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       *tv = xtime;
-       tv->tv_usec += (decrementer_count - get_dec())
-           * count_period_num / count_period_den;
-       if (tv->tv_usec >= 1000000) {
-               tv->tv_usec -= 1000000;
-               tv->tv_sec++;
-       }
-       restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       int frac_tick;
+       struct device_node *cpu;
+       int freq, *fp, divisor;
 
-       frac_tick = tv->tv_usec % (1000000 / HZ);
-       save_flags(flags);
-       cli();
-       xtime.tv_sec = tv->tv_sec;
-       xtime.tv_usec = tv->tv_usec - frac_tick;
-       set_dec(frac_tick * count_period_den / count_period_num);
-       restore_flags(flags);
+       /*
+        * The cpu node should have a timebase-frequency property
+        * to tell us the rate at which the decrementer counts.
+        */
+       cpu = find_type_devices("cpu");
+       if (cpu == 0)
+               panic("can't find cpu node in time_init");
+       fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+       if (fp == 0)
+               panic("can't get cpu timebase frequency");
+       freq = *fp * 60;        /* try to make freq/1e6 an integer */
+       divisor = 60;
+       printk("time_init: decrementer frequency = %d/%d\n",
+              freq, divisor);
+       decrementer_count = freq / HZ / divisor;
+       count_period_num = divisor;
+       count_period_den = freq / 1000000;
 }
 
-/*
- * timer_interrupt - gets called when the decrementer overflows,
- * with interrupts disabled.
- * We set it up to overflow again in 1/HZ seconds.
- */
-void timer_interrupt(struct pt_regs * regs)
+unsigned long
+pmac_get_rtc_time(void)
 {
-       int dval, d;
-
-       while ((dval = get_dec()) < 0) {
-               /*
-                * Wait for the decrementer to change, then jump
-                * in and add decrementer_count to its value
-                * (quickly, before it changes again!)
-                */
-               while ((d = get_dec()) == dval)
-                       ;
-               set_dec(d + decrementer_count);
-               do_timer(regs);
-       }
+       struct cuda_request req;
 
+       /* Get the time from the RTC */
+       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+       while (!req.got_reply)
+               cuda_poll();
+       if (req.reply_len != 7)
+               printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+                     req.reply_len);
+       return (req.reply[3] << 24) + (req.reply[4] << 16)
+               + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
 }
 
-void
-time_init(void)
+int pmac_set_rtc_time(unsigned long nowtime)
 {
-       struct device_node *cpu;
-       int freq, *fp, divisor;
-
-       if ((_get_PVR() >> 16) == 1) {
-               /* 601 processor: dec counts down by 128 every 128ns */
-               decrementer_count = DECREMENTER_COUNT_601;
-               count_period_num = COUNT_PERIOD_NUM_601;
-               count_period_den = COUNT_PERIOD_DEN_601;
-       } else {
-               /*
-                * The cpu node should have a timebase-frequency property
-                * to tell us the rate at which the decrementer counts.
-                */
-               cpu = find_type_devices("cpu");
-               if (cpu == 0)
-                       panic("can't find cpu node in time_init");
-               fp = (int *) get_property(cpu, "timebase-frequency", NULL);
-               if (fp == 0)
-                       panic("can't get cpu timebase frequency");
-               freq = *fp * 60;        /* try to make freq/1e6 an integer */
-               divisor = 60;
-               printk("time_init: decrementer frequency = %d/%d\n",
-                      freq, divisor);
-               decrementer_count = freq / HZ / divisor;
-               count_period_num = divisor;
-               count_period_den = freq / 1000000;
-       }
-       set_dec(decrementer_count);
+       return 0;
 }
 
 /*
@@ -145,24 +80,8 @@ time_init(void)
  * been called at that stage.
  */
 void
-read_rtc_time(void)
+pmac_read_rtc_time(void)
 {
-       xtime.tv_sec = get_rtc_time();
+       xtime.tv_sec = pmac_get_rtc_time();
        xtime.tv_usec = 0;
 }
-
-static unsigned long
-get_rtc_time()
-{
-       struct cuda_request req;
-
-       /* Get the time from the RTC */
-       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
-       while (!req.got_reply)
-               cuda_poll();
-       if (req.reply_len != 7)
-               panic("get_rtc_time: didn't expect %d byte reply",
-                     req.reply_len);
-       return (req.reply[3] << 24) + (req.reply[4] << 16)
-               + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
-}
diff --git a/arch/ppc/kernel/port_io.c b/arch/ppc/kernel/port_io.c
deleted file mode 100644 (file)
index cc8626a..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * I/O 'port' access routines
- */
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#define inb_asm(port) {( \
-  unsigned char ret; \
-  asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
-  return ret; \
-})
-
-inline unsigned char
-inb(int port)
-{
-  unsigned char ret;
-  asm("/*inb*/\n");
-  asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
-  return ret;
-}
-
-inline unsigned short
-inw(int port)
-{
-  unsigned short ret;
-  asm("/*inw*/\n");
-  asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
-  return ret;
-}
-
-inline unsigned long
-inl(int port)
-{
-  unsigned long ret;
-  asm("/*inl*/\n");
-  asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
-  return ret;
-}
-
-inline unsigned char
-outb(unsigned char val,int port)
-{
-  asm("/*outb*/\n");
-  asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
-  return (val);
-}
-
-inline unsigned short
-outw(unsigned short val,int port)
-{
-  asm("/*outw*/\n");
-  asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
-  return (val);
-}
-
-inline unsigned long
-outl(unsigned long val,int port)
-{
-  asm("/*outl*/\n");
-  asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
-  return (val);
-}
-
-void insb(int port, char *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
-}
-
-void insw(int port, short *ptr, int len)
-{
-  asm ("mtctr  %2 \n\t"
-       "subi   %1,%1,2 \n\t"
-       "00:\n\t"
-       "lhbrx  %2,0,%0 \n\t"
-       "sthu   %2,2(%1) \n\t"
-       "bdnz 00b \n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insw_unswapped(int port, short *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
-}
-
-void insl(int port, long *ptr, int len)
-{
-  asm ("mtctr  %2 \n\t"
-       "subi   %1,%1,4 \n\t"
-       "00:\n\t"
-       "lhbrx  %2,0,%0 \n\t"
-       "sthu   %2,4(%1) \n\t"
-       "bdnz 00b \n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsb(int port, char *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
-}
-
-void outsw(int port, short *ptr, int len)
-{
-  asm ("mtctr  %2\n\t"
-       "subi   %1,%1,2\n\t"
-       "00:lhzu        %2,2(%1)\n\t"
-       "sthbrx %2,0,%0\n\t"
-       "bdnz   00b\n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsw_unswapped(int port, short *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );  
-}
-
-void outsl(int port, long *ptr, int len)
-{
-  asm ("mtctr  %2\n\t"
-       "subi   %1,%1,4\n\t"
-       "00:lwzu        %2,4(%1)\n\t"
-       "sthbrx %2,0,%0\n\t"
-       "bdnz   00b\n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insl_unswapped(int port, long *ptr, int len)
-{
-        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-        /* Ensure I/O operations complete */
-        __asm__ volatile("eieio");
-        while (len-- > 0)
-        {
-                *ptr++ = (*io_ptr);
-        }
-}
-
-void outsl_unswapped(int port, long *ptr, int len)
-{
-        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-        /* Ensure I/O operations complete */
-        __asm__ volatile("eieio");
-        while (len-- > 0)
-        {
-                *io_ptr = (*ptr++);
-        }
-}
index e31dea266bd4bdf7641a39dc06e287a224033113..7036f4a6294b08fb494fc4732ae320aba02e10e9 100644 (file)
@@ -187,7 +187,3 @@ n:
 #define REST_8FPRS(n, base)    REST_4FPRS(n, base); REST_4FPRS(n+4, base)
 #define REST_16FPRS(n, base)   REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)   REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/* Missing instructions */
-#define bdne   bc 0,2,
-
diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h
deleted file mode 100644 (file)
index 2accaa4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define        STATE   0
-#define        NEXT_TASK       68
-#define        COUNTER 4
-#define        BLOCKED 16
-#define        SIGNAL  12
-#define        TSS     544
-#define        KSP     0
-#define        PG_TABLES       4
-#define        LAST_SYSCALL    288
-#define        PT_REGS 280
-#define        PF_TRACESYS     32
-#define        TASK_FLAGS      20
-#define        TSS_FPR0        16
-#define        TSS_FPSCR       12
-#define        TASK_UNION_SIZE 8192
-#define        STACK_FRAME_OVERHEAD    16
-#define        INT_FRAME_SIZE  192
-#define        GPR0    16
-#define        GPR1    20
-#define        GPR2    24
-#define        GPR3    28
-#define        GPR4    32
-#define        GPR5    36
-#define        GPR6    40
-#define        GPR7    44
-#define        GPR8    48
-#define        GPR9    52
-#define        GPR10   56
-#define        GPR11   60
-#define        GPR12   64
-#define        GPR13   68
-#define        GPR14   72
-#define        GPR15   76
-#define        GPR16   80
-#define        GPR17   84
-#define        GPR18   88
-#define        GPR19   92
-#define        GPR20   96
-#define        GPR21   100
-#define        GPR22   104
-#define        GPR23   108
-#define        GPR24   112
-#define        GPR25   116
-#define        GPR26   120
-#define        GPR27   124
-#define        GPR28   128
-#define        GPR29   132
-#define        GPR30   136
-#define        GPR31   140
-#define        _NIP    144
-#define        _MSR    148
-#define        _CTR    152
-#define        _LINK   156
-#define        _CCR    160
-#define        _XER    164
-#define        _DAR    168
-#define        _DSISR  172
-#define        ORIG_GPR3       176
-#define        RESULT  180
-#define        TRAP    184
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
new file mode 100644 (file)
index 0000000..b034d7f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * $Id: ppc_htab.c,v 1.4 1997/08/12 04:24:54 cort Exp $
+ * PowerPC hash table management proc entry.  Will show information
+ * about the current hash table and will allow changes to it.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * 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/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+static long ppc_htab_read(struct inode * inode, struct file * file,
+                          char * buf, unsigned long nbytes);
+static long ppc_htab_write(struct inode * inode, struct file * file,
+                           const char * buffer, unsigned long count);
+static long long ppc_htab_lseek(struct inode * inode, struct file * file, 
+                                long long offset, int orig);
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+
+static struct file_operations ppc_htab_operations = {
+    ppc_htab_lseek,    /* lseek   */
+    ppc_htab_read,     /* read    */
+    ppc_htab_write,    /* write   */
+    NULL,              /* readdir */
+    NULL,              /* poll    */
+    NULL,              /* ioctl   */
+    NULL,              /* mmap    */
+    NULL,              /* no special open code    */
+    NULL,              /* no special release code */
+    NULL               /* can't fsync */
+};
+
+/*
+ * proc files can do almost nothing..
+ */
+struct inode_operations proc_ppc_htab_inode_operations = {
+    &ppc_htab_operations,  /* default proc file-ops */
+    NULL,          /* create      */
+    NULL,          /* lookup      */
+    NULL,          /* link        */
+    NULL,          /* unlink      */
+    NULL,          /* symlink     */
+    NULL,          /* mkdir       */
+    NULL,          /* rmdir       */
+    NULL,          /* mknod       */
+    NULL,          /* rename      */
+    NULL,          /* readlink    */
+    NULL,          /* follow_link */
+    NULL,          /* readpage    */
+    NULL,          /* writepage   */
+    NULL,          /* bmap        */
+    NULL,          /* truncate    */
+    NULL           /* permission  */
+};
+
+
+/*
+ * print some useful info about the hash table.  This function
+ * is _REALLY_ slow (see the nested for loops below) but nothing
+ * in here should be really timing critical. -- Cort
+ */
+static long ppc_htab_read(struct inode * inode, struct file * file,
+                          char * buf, unsigned long nbytes)
+{
+       int n = 0, valid;
+       unsigned int kptes = 0, overflow = 0, uptes = 0;
+       PTE *ptr;
+       struct task_struct *p;
+       
+       if (nbytes < 0)
+               return -EINVAL;
+
+       /*
+        * compute user/kernel pte's table this info can be
+        * misleading since there can be valid (v bit set) entries
+        * in the table but their vsid is used by no process (mm->context)
+        * due to the way tlb invalidation is handled on the ppc
+        * -- Cort
+        */
+       for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr+=sizeof(PTE))
+       {
+               if (ptr->v)
+               {
+                       /* make sure someone is using this context/vsid */
+                       for_each_task(p)
+                       {
+                               if ( (ptr->vsid >> 4) == p->mm->context )
+                               {
+                                       valid = 1;
+                                       break;
+                               }
+                       }
+                       if ( !valid )
+                               continue;
+                       /* user not allowed read or write */
+                       if (ptr->pp == PP_RWXX)
+                               kptes++;
+                       else
+                               uptes++;
+                       if (ptr->h == 1)
+                               overflow++;
+               }
+       }
+       n += sprintf( buf,
+                     "Size\t\t: %luKb\n"
+                     "Buckets\t\t: %lu\n"
+                     "Address\t\t: %08lx\n"
+                     "Entries\t\t: %lu\n"
+                     "User ptes\t: %u\n"
+                     "Kernel ptes\t: %u\n"
+                     "Overflows\t: %u\n"
+                     "Percent full\t: %%%lu\n",
+                      (unsigned long)(Hash_size>>10),
+                     (Hash_size/(sizeof(PTE)*8)),
+                     (unsigned long)Hash,
+                     Hash_size/sizeof(PTE),
+                      uptes,
+                     kptes,
+                     overflow,
+                     ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+               );
+       /* if we're trying to read part of the file that isn't there */
+       if ( file->f_pos > n )
+               return -ENOMEM;
+       file->f_pos += n;
+       return n;
+}
+
+/*
+ * Can't _yet_ adjust the hash table size while running. -- Cort
+ */
+static long
+ppc_htab_write(struct inode * inode, struct file * file,
+               const char * buffer, unsigned long count)
+{
+       if ( current->uid != 0 )
+               return -EACCES;
+       else
+               return -ENOSYS;
+       return 0;
+}
+
+
+static long long
+ppc_htab_lseek(struct inode * inode, struct file * file, 
+                                long long offset, int orig)
+{
+    switch (orig) {
+    case 0:
+       file->f_pos = offset;
+       return(file->f_pos);
+    case 1:
+       file->f_pos += offset;
+       return(file->f_pos);
+    case 2:
+       return(-EINVAL);
+    default:
+       return(-EINVAL);
+    }
+}
+
+
+#if 0
+/*
+  for root.c
+  */
+static struct proc_dir_entry proc_root_ppc_htab = {
+       PROC_PPC_HTAB, 8, "ppc_htab",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_ppc_htab_inode_operations
+};
+#ifdef __powerpc__
+       proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+
+
+/* add to proc_fs.h
+       PROC_PPC_HTAB,*/
+#endif
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
new file mode 100644 (file)
index 0000000..fd2ad89
--- /dev/null
@@ -0,0 +1,140 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bios32.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void do_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+extern unsigned lost_interrupts;
+extern void do_lost_interrupts(unsigned long);
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(lost_interrupts);
+EXPORT_SYMBOL(do_lost_interrupts);
+
+EXPORT_SYMBOL(atomic_add);
+EXPORT_SYMBOL(atomic_sub);
+EXPORT_SYMBOL(atomic_inc);
+EXPORT_SYMBOL(atomic_inc_return);
+EXPORT_SYMBOL(atomic_dec);
+EXPORT_SYMBOL(atomic_dec_return);
+EXPORT_SYMBOL(atomic_dec_and_test);
+
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(test_and_change_bit);
+#if 0
+EXPORT_SYMBOL(ffz);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strspn);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(memcmp);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(strlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(ioremap);
+
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__cli);
+EXPORT_SYMBOL(__sti);
+/*EXPORT_SYMBOL(__restore_flags);*/
+EXPORT_SYMBOL(_disable_interrupts);
+EXPORT_SYMBOL(_enable_interrupts);
+EXPORT_SYMBOL(flush_instruction_cache);
+EXPORT_SYMBOL(_get_PVR);
+EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(xchg_u32);
+
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(abort);
+EXPORT_SYMBOL(call_prom);
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(note_scsi_host);
index 8784e95bc0221277f3f9a5422458b731adfddee6..b7e8ed761e2fae7cd63c8a9f3e6c6fc3b49bc4ef 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -42,7 +44,7 @@ extern int probingmem;
 extern unsigned long loops_per_sec;
 
 unsigned long empty_zero_page[1024];
-unsigned char aux_device_present;
+extern unsigned char aux_device_present;
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
@@ -50,19 +52,8 @@ extern int rd_prompt;                /* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;     /* starting block # of image */
 #endif
 
-/* copy of the residual data */
-RESIDUAL res;
-/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
-unsigned long resptr = 0;
-int _machine;
-extern unsigned long _TotalMemory;
 
-#define COMMAND_LINE_SIZE 256
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-char saved_command_line[COMMAND_LINE_SIZE];
-#ifdef HASHSTATS
-unsigned long evicts;
-#endif
+extern char saved_command_line[256];
 
 struct screen_info screen_info = {
        0, 25,                  /* orig-x, orig-y */
@@ -76,49 +67,31 @@ struct screen_info screen_info = {
        16                      /* orig-video-points */
 };
 
-void machine_halt(void)
+
+/*
+ * these are here to get by until the pmac/prep merge is done
+ */
+int pmac_display_supported(char *name)
 {
-       machine_restart(NULL);
+       return 0;
 }
-
-void machine_power_off(void)
+int sd_find_target(void *a, int b)
 {
-       machine_restart(NULL);
+       return 0;
 }
-
-void machine_restart(char *cmd)
+void pmac_find_display(void)
 {
-       unsigned char ctl;
-       unsigned long flags;
-       unsigned long i = 10000;
-       
-       _disable_interrupts();
-
-       /* set exception prefix high - to the prom */
-       save_flags( flags );
-       restore_flags( flags|MSR_IP );
-
-       /* make sure bit 0 (reset) is a 0 */
-       outb( inb(0x92) & ~1L , 0x92 );
-       /* signal a reset to system control port A - soft reset */
-       outb( inb(0x92) | 1 , 0x92 );
-
-       while ( i != 0 ) i++;
-       panic("restart failed\n");
 }
 
 int
-get_cpuinfo(char *buffer)
+prep_get_cpuinfo(char *buffer)
 {
        extern char *Motherboard_map_name;
+       extern RESIDUAL res;
        int i;
        int pvr = _get_PVR();
        int len;
        char *model;
-       PTE *ptr;
-       unsigned long kptes = 0, uptes = 0, overflow = 0;
-       unsigned int ti;
-  
   
        switch (pvr>>16)
        {
@@ -226,8 +199,6 @@ get_cpuinfo(char *buffer)
        /* L2 */
        if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
        {
-               int size;
-    
                len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
                               ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
                               (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
@@ -246,61 +217,25 @@ get_cpuinfo(char *buffer)
         * Ooh's and aah's info about zero'd pages in idle task
         */ 
        {
-               extern unsigned int zerocount, zerototal, zeropage_hits;
+               extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
                len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
-                              "current: %u (%uKb) hits: %u\n",
+                              "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
                               zerototal, (zerototal*PAGE_SIZE)>>10,
                               zerocount, (zerocount*PAGE_SIZE)>>10,
-                              zeropage_hits);
+                              zeropage_hits,zeropage_calls,
+                              /* : 1 below is so we don't div by zero */
+                              (zeropage_hits*100) /
+                                   ((zeropage_calls)?zeropage_calls:1));
        }
-
-
-       /* ram/hash table info */
-       len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
-                      Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
-
-       /* if booted print info about hash table use (overflows, etc) */
-#ifdef HASHSTATS
-       for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
-       {
-               if (ptr->v)
-               {
-                       /* user not allowed read or write */
-                       if (ptr->pp == PP_RWXX)
-                               kptes++;
-                       else
-                               uptes++;
-                       if (ptr->h == 1)
-                               overflow++;
-               }
-       }
-       /*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
-         Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
-       /*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
-         "(%d%%)/%d (%d%% full)\n",
-         uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
-         kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
-         Hash_size/sizeof(PTE),
-         ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
-         len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
-         overflow,evicts);*/
-#endif /* HASHSTATS */
        return len;
 }
 
-__initfunc(unsigned long
-bios32_init(unsigned long memory_start, unsigned long memory_end))
-{
-       return memory_start;
-}
-
 __initfunc(void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
           unsigned long * memory_end_p))
 {
        extern char cmd_line[];
        extern char _etext[], _edata[], _end[];
-       unsigned char reg;
        extern int panic_timeout;
 
        /* Save unparsed command line copy for /proc/cmdline */
@@ -308,13 +243,13 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
        *cmdline_p = cmd_line;
   
        *memory_start_p = (unsigned long) Hash+Hash_size;
-       (unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+       (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
 
        /* init to some ~sane value until calibrate_delay() runs */
        loops_per_sec = 50000000;
        
        /* reboot on panic */   
-       /*panic_timeout = 180;*/
+       panic_timeout = 180;
        
        init_task.mm->start_code = PAGE_OFFSET;
        init_task.mm->end_code = (unsigned long) _etext;
@@ -332,23 +267,7 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
                ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
                break;
        }
-       /*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
-#if 0
-       strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
-#endif
        
-#if 0  
-       if ( _machine == _MACH_Motorola )
-       {
-               /* get root via nfs from gordito -- only used for testing */
-               ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);   /* nfs */
-               /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
-               strcpy(cmd_line+strlen(cmd_line),
-                      "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
-                      "pandora nfsroot=/usr/src/root/");
-       }
-#endif
-  
 #ifdef CONFIG_BLK_DEV_RAM
 #if 0
        ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
@@ -356,7 +275,20 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
        rd_doload = 1;
        rd_image_start = 0;
 #endif
+       /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+       if ( initrd_start )
+       {
+               if (initrd_end > *memory_end_p)
+               {
+                       printk("initrd extends beyond end of memory "
+                              "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                              initrd_end,*memory_end_p);
+                       initrd_start = 0;
+               }
+       }
 #endif
+
+       printk("Boot arguments: %s\n", cmd_line);
        
        request_region(0x20,0x20,"pic1");
        request_region(0xa0,0x20,"pic2");
@@ -365,4 +297,3 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
        request_region(0x80,0x10,"dma page reg");
        request_region(0xc0,0x20,"dma2");
 }
-
index 8d1384cc4af8f19b508bb654c205819a0441157c..74cee028dcab560c37908a6ed95b1958fc9bffab 100644 (file)
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/nvram.h>
 
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-static int set_rtc_mmss(unsigned long nowtime);
-unsigned long get_cmos_time(void);
-static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+#include "time.h"
+
+inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
                                   unsigned int, unsigned int, unsigned int);
-#define TIMER_IRQ 0
 
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d).  The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro.  This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18  addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+                      MOTO_RTC_MINUTES,0 /* alarm */,
+                      MOTO_RTC_HOURS,0 /* alarm */,                 /*  4,5 */
+                      MOTO_RTC_DAY_OF_WEEK,
+                      MOTO_RTC_DAY_OF_MONTH,
+                      MOTO_RTC_MONTH,
+                      MOTO_RTC_YEAR,                    /* 9 */
+                      MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+       if ( _machine == _MACH_IBM )
+               return CMOS_READ(addr);
+       else if ( _machine == _MACH_Motorola )
+       {
+               outb(clock_transl[addr]>>8, NVRAM_AS1);
+               outb(clock_transl[addr], NVRAM_AS0);
+               return (inb(NVRAM_DATA));
+       }
+
+       printk("Unknown machine in prep_cmos_clock_read()!\n");
+       return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+       if ( _machine == _MACH_IBM )
+       {
+               CMOS_WRITE(val,addr);
+               return;
+       }
+       else if ( _machine == _MACH_Motorola )
+       {
+               outb(clock_transl[addr]>>8, NVRAM_AS1);
+               outb(clock_transl[addr], NVRAM_AS0);
+               outb(val,NVRAM_DATA);
+               return;
+       }
+       printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
 
 #define TICK_SIZE tick
 #define FEBRUARY       2
@@ -49,6 +103,7 @@ static int      month_days[12] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+#if 0
 static unsigned long do_slow_gettimeoffset(void)
 {
        int count;
@@ -69,7 +124,6 @@ static unsigned long do_slow_gettimeoffset(void)
        count = (count + LATCH/2) / LATCH;
        return offset + count;
 }
-
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
 /*
@@ -106,6 +160,8 @@ void do_settimeofday(struct timeval *tv)
        sti();
 }
 
+#endif
+
 void to_tm(int tim, struct rtc_time * tm)
 {
        register int    i;
@@ -139,20 +195,20 @@ void to_tm(int tim, struct rtc_time * tm)
 /*
  * Set the hardware clock. -- Cort
  */
-static int set_rtc_mmss(unsigned long nowtime)
+int prep_set_rtc_time(unsigned long nowtime)
 {
-       int retval = 0;
-       int real_seconds, real_minutes, cmos_minutes;
        unsigned char save_control, save_freq_select;
        struct rtc_time tm;
 
        to_tm(nowtime, &tm);
 
-       save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+       save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
 
-       save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+       prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+       save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+       
+       prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
         tm.tm_year -= 1900;
        if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -163,12 +219,12 @@ static int set_rtc_mmss(unsigned long nowtime)
                BIN_TO_BCD(tm.tm_mday);
                BIN_TO_BCD(tm.tm_year);
        }
-       CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
-       CMOS_WRITE(tm.tm_min,RTC_MINUTES);
-       CMOS_WRITE(tm.tm_hour,RTC_HOURS);
-       CMOS_WRITE(tm.tm_mon,RTC_MONTH);
-       CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
-       CMOS_WRITE(tm.tm_year,RTC_YEAR);
+       prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+       prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+       prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+       prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+       prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+       prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
        
        /* The following flags have to be released exactly in this order,
         * otherwise the DS12887 (popular MC146818A clone with integrated
@@ -177,15 +233,15 @@ static int set_rtc_mmss(unsigned long nowtime)
         * the Dallas Semiconductor data sheets, but who believes data
         * sheets anyway ...                           -- Markus Kuhn
         */
-       CMOS_WRITE(save_control, RTC_CONTROL);
-       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+       prep_cmos_clock_write(save_control, RTC_CONTROL);
+       prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
 
        if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
                time_state = TIME_OK;
        return 0;
 }
 
-unsigned long get_cmos_time(void)
+unsigned long prep_get_rtc_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        int i;
@@ -197,20 +253,20 @@ unsigned long get_cmos_time(void)
         */
        /* read RTC exactly on falling edge of update flag */
        for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
-               if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+               if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
                        break;
        for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
-               if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+               if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
                        break;
        do { /* Isn't this overkill ? UIP above should guarantee consistency */
-               sec = CMOS_READ(RTC_SECONDS);
-               min = CMOS_READ(RTC_MINUTES);
-               hour = CMOS_READ(RTC_HOURS);
-               day = CMOS_READ(RTC_DAY_OF_MONTH);
-               mon = CMOS_READ(RTC_MONTH);
-               year = CMOS_READ(RTC_YEAR);
-       } while (sec != CMOS_READ(RTC_SECONDS));
-       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+               sec = prep_cmos_clock_read(RTC_SECONDS);
+               min = prep_cmos_clock_read(RTC_MINUTES);
+               hour = prep_cmos_clock_read(RTC_HOURS);
+               day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+               mon = prep_cmos_clock_read(RTC_MONTH);
+               year = prep_cmos_clock_read(RTC_YEAR);
+       } while (sec != prep_cmos_clock_read(RTC_SECONDS));
+       if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
          {
            BCD_TO_BIN(sec);
            BCD_TO_BIN(min);
@@ -224,19 +280,68 @@ unsigned long get_cmos_time(void)
        return mktime(year, mon, day, hour, min, sec);
 }
 
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+                                  unsigned int day, unsigned int hour,
+                                  unsigned int min, unsigned int sec)
+{
+       
+       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
+               mon += 12;      /* Puts Feb last since it has leap day */
+               year -= 1;
+       }
+       return (((
+               (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+               year*365 - 719499
+               )*24 + hour /* now have hours */
+               )*60 + min /* now have minutes */
+               )*60 + sec; /* finally seconds */
+}
+
+#if 0
+void time_init(void)
+{
+       void (*irq_handler)(int, void *,struct pt_regs *);
+       
+       xtime.tv_sec = prep_get_rtc_time();
+       xtime.tv_usec = 0;
+       
+       prep_calibrate_decr();
+       
+       /* If we have the CPU hardware time counters, use them */
+       irq_handler = timer_interrupt;
+       if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+               panic("Could not allocate timer IRQ!");
+}
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
 static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
+       prep_calibrate_decr_handler(irq,dev,regs);
        do_timer(regs);
 
        /* update the hw clock if:
         * the time is marked out of sync (TIME_ERROR)
         * or ~11 minutes have expired since the last update -- Cort
         * If we have an externally synchronized Linux clock, then update
-        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
        if ( time_state == TIME_BAD ||
@@ -244,7 +349,7 @@ static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
        /*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
            xtime.tv_usec > 500000 - (tick >> 1) &&
            xtime.tv_usec < 500000 + (tick >> 1))*/
-               if (set_rtc_mmss(xtime.tv_sec) == 0)
+               if (prep_set_rtc_time(xtime.tv_sec) == 0)
                        last_rtc_update = xtime.tv_sec;
                else
                        last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
@@ -269,47 +374,4 @@ static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
        }
 #endif
 }
-
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
-                                  unsigned int day, unsigned int hour,
-                                  unsigned int min, unsigned int sec)
-{
-       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
-               mon += 12;      /* Puts Feb last since it has leap day */
-               year -= 1;
-       }
-       return (((
-               (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-               year*365 - 719499
-               )*24 + hour /* now have hours */
-               )*60 + min /* now have minutes */
-               )*60 + sec; /* finally seconds */
-}
-
-void time_init(void)
-{
-       void (*irq_handler)(int, void *,struct pt_regs *);
-       xtime.tv_sec = get_cmos_time();
-       xtime.tv_usec = 0;
-
-       /* If we have the CPU hardware time counters, use them */
-       irq_handler = timer_interrupt;
-       if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-               panic("Could not allocate timer IRQ!");
-}
+#endif
index f248720632cb58f1a29efa23dfd363e07266c129..5e194fedb34d3709103f9d718ff2563020345825 100644 (file)
@@ -7,7 +7,7 @@
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
  *
- *  Modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
  *  Paul Mackerras (paulus@cs.anu.edu.au)
  *
  *  This program is free software; you can redistribute it and/or
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
 #include <linux/config.h>
+#include <linux/elf.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/smp_lock.h>
+#include <asm/processor.h>
 
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
 extern unsigned long _get_SP(void);
 
+
 #undef SHOW_TASK_SWITCHES 1
 #undef CHECK_STACK 1
 #undef IDLE_ZERO 1
@@ -59,7 +59,7 @@ task_top(struct task_struct *tsk)
 {
        return ((unsigned long)tsk) + sizeof(struct task_struct);
 }
-       
+
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -69,9 +69,12 @@ struct mm_struct init_mm = INIT_MM;
 union task_union init_task_union = { INIT_TASK };
 
 int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 {
-       return (1);
+       if (last_task_used_math == current)
+               giveup_fpu();
+       memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
+       return 1;
 }
 
 /* check to make sure the kernel stack is healthy */
@@ -80,7 +83,6 @@ int check_stack(struct task_struct *tsk)
        unsigned long stack_top = kernel_stack_top(tsk);
        unsigned long tsk_top = task_top(tsk);
        int ret = 0;
-       unsigned long *i;
 
 #if 0  
        /* check tss magic */
@@ -98,7 +100,7 @@ int check_stack(struct task_struct *tsk)
        if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
        {
                printk("stack out of bounds: %s/%d\n"
-                      " tsk_top %08x ksp %08x stack_top %08x\n",
+                      " tsk_top %08lx ksp %08lx stack_top %08lx\n",
                       tsk->comm,tsk->pid,
                       tsk_top, tsk->tss.ksp, stack_top);
                ret |= 2;
@@ -108,7 +110,7 @@ int check_stack(struct task_struct *tsk)
        if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
        {
                printk("current stack ptr out of bounds: %s/%d\n"
-                      " tsk_top %08x sp %08x stack_top %08x\n",
+                      " tsk_top %08lx sp %08lx stack_top %08lx\n",
                       current->comm,current->pid,
                       tsk_top, _get_SP(), stack_top);
                ret |= 4;
@@ -143,15 +145,12 @@ switch_to(struct task_struct *prev, struct task_struct *new)
 {
        struct thread_struct *new_tss, *old_tss;
        int s = _disable_interrupts();
-       struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
 
 #if CHECK_STACK
        check_stack(prev);
        check_stack(new);
 #endif
-        /* turn off fpu for task last to run */
-       /*prev->tss.regs->msr &= ~MSR_FP;*/
-       
+
 #ifdef SHOW_TASK_SWITCHES
        printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
               prev->comm,prev->pid,prev->tss.regs->nip,
@@ -160,289 +159,29 @@ switch_to(struct task_struct *prev, struct task_struct *new)
        new_tss = &new->tss;
        old_tss = &current->tss;
        _switch(old_tss, new_tss, new->mm->context);
-        /* turn off fpu for task last to run */        
        _enable_interrupts(s);
 }
-       
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
-       struct task_struct *p;
-       printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
-       printk("last %x\n", last_task_used_math);
-       printk("cur %x regs %x/%x tss %x/%x\n",
-              current, current->tss.regs,regs,&current->tss,current->tss);
-       for_each_task(p)
-       {
-               if ((long)p < KERNELBASE)
-               {
-                       printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
-                       print_mm_info();
-                       __cli();
-                       while(1);
-               }
-       }
-       return regs->gpr[3];
-#endif
-#if 0
-       /* set the time in the cmos clock */
-       unsigned long hwtime, nowtime;
-       struct rtc_time tm;
-       
-       hwtime = get_cmos_time();
-       to_tm(hwtime, &tm);
-       printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n", 
-              tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
-              tm.tm_mday, tm.tm_year);
-       return;
-#endif
-}
 
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0;   /* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0;   /* pointer into the currently being zero'd page */
-unsigned long zerocount = 0;   /* # currently pre-zero'd pages */
-unsigned long zerototal = 0;   /* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0;     /* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
 {
-       unsigned long page;
-       unsigned long s;
-
-       if ( zero_list )
-       {
-               /* atomically remove this page from the list */
-               asm (   "101:lwarx  %1,0,%2\n"  /* reserve zero_list */
-                       "    lwz    %0,0(%1)\n" /* get next -- new zero_list */
-                       "    stwcx. %0,0,%2\n"  /* update zero_list */
-                       "    bne-   101b\n"     /* if lost reservation try again */
-                       : "=&r" (zero_list), "=&r" (page)
-                       : "r" (&zero_list)
-                       : "cc" );
-               /* we can update zerocount after the fact since it is not
-                * used for anything but control of a loop which doesn't
-                * matter since it won't effect anything if it zero's one
-                * less page -- Cort
-                */
-               atomic_inc((atomic_t *)&zeropage_hits);
-               atomic_dec((atomic_t *)&zerocount);
-               /* zero out the pointer to next in the page */
-               *(unsigned long *)page = 0;
-               return page;
-       }
        return 0;
 }
 
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
-       extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
-       unsigned long tmp;
-       pte_t ptep;
-       pgd_t *dir;
-       pmd_t *pmd;
-       pte_t *pte;
-
-       sprintf(current->comm, "zero_paged");
-       printk("Started zero_paged\n");
-       /* want priority over idle task and powerd */
-       current->priority = -98;
-       current->counter = -98;
-       __sti();
-       
-       while ( zerocount < 128 )
-       {
-               /*
-                * Mark a page as reserved so we can mess with it
-                * If we're interrupted we keep this page and our place in it
-                * since we validly hold it and it's reserved for us.
-                */
-               pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
-               if ( !pageptr )
-               {
-                       printk("!pageptr in zero_paged\n");
-                       goto retry;
-               }
-               
-               if ( need_resched )
-                       schedule();
-               
-               /*
-                * Make the page no cache so we don't blow our cache with 0's
-                */
-               dir = pgd_offset( init_task.mm, pageptr );
-               if (dir)
-               {
-                       pmd = pmd_offset(dir, pageptr & PAGE_MASK);
-                       if (pmd && pmd_present(*pmd))
-                       {
-                               pte = pte_offset(pmd, pageptr & PAGE_MASK);
-                               if (pte && pte_present(*pte))
-                               {                       
-                                       pte_uncache(*pte);
-                                       flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-                               }
-                       }
-               }
-       
-               /*
-                * Important here to not take time away from real processes.
-                */
-               for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
-               {
-                       if ( need_resched )
-                               schedule();
-                       *(unsigned long *)(bytecount + pageptr) = 0;
-               }
-               
-               /*
-                * If we finished zero-ing out a page add this page to
-                * the zero_list atomically -- we can't use
-                * down/up since we can't sleep in idle.
-                * Disabling interrupts is also a bad idea since we would
-                * steal time away from real processes.
-                * We can also have several zero_paged's running
-                * on different processors so we can't interfere with them.
-                * So we update the list atomically without locking it.
-                * -- Cort
-                */
-               /* turn cache on for this page */
-               pte_cache(*pte);
-               flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-               
-               /* atomically add this page to the list */
-               asm (   "101:lwarx  %0,0,%1\n"  /* reserve zero_list */
-                       "    stw    %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
-                       "    sync\n"            /* let store settle */
-#endif                 
-                       "    mr     %0,%2\n"    /* update zero_list in reg */
-                       "    stwcx. %2,0,%1\n"  /* update zero_list in mem */
-                       "    bne-   101b\n"     /* if lost reservation try again */
-                       : "=&r" (zero_list)
-                       : "r" (&zero_list), "r" (pageptr)
-                       : "cc" );
-               /*
-                * This variable is used in the above loop and nowhere
-                * else so the worst that could happen is we would
-                * zero out one more or one less page than we want
-                * per processor on the machine.  This is because
-                * we could add our page to the list but not have
-                * zerocount updated yet when another processor
-                * reads it.  -- Cort
-                */
-               atomic_inc((atomic_t *)&zerocount);
-               atomic_inc((atomic_t *)&zerototal);
-retry: 
-               schedule();
-       }
-}
-
-void powerd(void)
-{
-       unsigned long msr, hid0;
-
-       sprintf(current->comm, "powerd");
-       __sti();
-       while (1)
-       {
-               /* want priority over idle task 'swapper' -- Cort */
-               current->priority = -99;
-               current->counter = -99;
-               asm volatile(
-                       /* clear powersaving modes and set nap mode */
-                       "mfspr %3,1008 \n\t"
-                       "andc  %3,%3,%4 \n\t"
-                       "or    %3,%3,%5 \n\t"
-                       "mtspr 1008,%3 \n\t"
-                       /* enter the mode */
-                       "mfmsr %0 \n\t"
-                       "oris  %0,%0,%2 \n\t"
-                       "sync \n\t"
-                       "mtmsr %0 \n\t"
-                       "isync \n\t"
-                       : "=&r" (msr)
-                       : "0" (msr), "i" (MSR_POW>>16),
-                       "r" (hid0),
-                       "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
-                       "r" (HID0_NAP));
-               if ( need_resched )
-                       schedule();
-               /*
-                * The ibm carolina spec says that the eagle memory
-                * controller will detect the need for a snoop
-                * and wake up the processor so we don't need to
-                * check for cache operations that need to be
-                * snooped.  The ppc book says the run signal
-                * must be asserted while napping for this though.
-                * -- Cort
-                */
-       }
-}
-       
-asmlinkage int sys_idle(void)
-{
-       int ret = -EPERM;
-       if (current->pid != 0)
-               goto out;
-
-#ifdef IDLE_ZERO
-       /*
-        * want one per cpu since it would be nice to have all
-        * processors who aren't doing anything
-        * zero-ing pages since this daemon is lock-free
-        * -- Cort
-        */
-       kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
-       /* no powersaving modes on 601 - one per processor */
-       if(  (_get_PVR()>>16) != 1 )
-               kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-       
-       /* endless loop with no priority at all */
-       current->priority = -100;
-       current->counter = -100;
-       for (;;) 
-       {
-               schedule();
-       }
-       ret = 0;
-out:
-       return ret;
-}
-
 void show_regs(struct pt_regs * regs)
 {
        int i;
 
-       printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+       printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
               regs->nip, regs->xer, regs->link, regs,regs->trap);
-       printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+       printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
               regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
               regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
               regs->msr&MSR_IR ? 1 : 0,
               regs->msr&MSR_DR ? 1 : 0);
-       printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+       printk("TASK = %p[%d] '%s' mm->pgd %p ",
               current, current->pid, current->comm, current->mm->pgd);
-       printk("Last syscall: %d ", current->tss.last_syscall);
-       printk("\nlast math %08X\n", last_task_used_math);
+       printk("Last syscall: %ld ", current->tss.last_syscall);
+       printk("\nlast math %p\n", last_task_used_math);
        for (i = 0;  i < 32;  i++)
        {
                long r;
@@ -451,9 +190,9 @@ void show_regs(struct pt_regs * regs)
                        printk("GPR%02d: ", i);
                }
 
-               if ( get_user(r, &(regs->gpr[i])) )
+               if ( __get_user(r, &(regs->gpr[i])) )
                    goto out;
-               printk("%08X ", r);
+               printk("%08lX ", r);
                if ((i % 8) == 7)
                {
                        printk("\n");
@@ -480,14 +219,14 @@ release_thread(struct task_struct *t)
 }
 
 /*
 * Copy a thread..
 */
+ * Copy a thread..
+ */
 int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
            struct task_struct * p, struct pt_regs * regs)
 {
-       int i;
        struct pt_regs * childregs;
+
        /* Copy registers */
        childregs = ((struct pt_regs *)
                     ((unsigned long)p + sizeof(union task_union)
@@ -497,13 +236,13 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        if ((childregs->msr & MSR_PR) == 0)
                childregs->gpr[2] = (unsigned long) p;  /* `current' in new task */
        childregs->gpr[3] = 0;  /* Result from fork() */
-       p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
-       p->tss.regs = (struct pt_regs *)(childregs);
-       if (usp >= (unsigned long)regs)
-       { /* Stack is in kernel space - must adjust */
-               childregs->gpr[1] = (long)(childregs+1);
-       } else
-       { /* Provided stack is in user space */
+       p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+       p->tss.regs = childregs;
+       if (usp >= (unsigned long) regs) {
+               /* Stack is in kernel space - must adjust */
+               childregs->gpr[1] = (unsigned long)(childregs + 1);
+       } else {
+               /* Provided stack is in user space */
                childregs->gpr[1] = usp;
        }
 
@@ -511,24 +250,75 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 
        /*
         * copy fpu info - assume lazy fpu switch now always
-        * this should really be conditional on whether or
-        * not the process has used the fpu
         *  -- Cort
         */
        if ( last_task_used_math == current )
                giveup_fpu();
-       
+
        memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
        p->tss.fpscr = current->tss.fpscr;
        childregs->msr &= ~MSR_FP;
-       
+
        return 0;
 }
 
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+       int argc;
+       char *p;
+       unsigned long e;
+       unsigned long aux_start, offset;
+
+       if (__get_user(argc, (int *)sp))
+               return;
+       sp += sizeof(int) + (argc + 1) * sizeof(char *);
+       /* skip over the environment pointers */
+       do {
+               if (__get_user(p, (char **)sp))
+                       return;
+               sp += sizeof(char *);
+       } while (p != NULL);
+       aux_start = sp;
+       /* skip to the end of the auxiliary table */
+       do {
+               if (__get_user(e, (unsigned long *)sp))
+                       return;
+               sp += 2 * sizeof(unsigned long);
+       } while (e != AT_NULL);
+       offset = ((aux_start + 15) & ~15) - aux_start;
+       if (offset != 0) {
+               do {
+                       sp -= sizeof(unsigned long);
+                       if (__get_user(e, (unsigned long *)sp)
+                           || __put_user(e, (unsigned long *)(sp + offset)))
+                               return;
+               } while (sp > aux_start);
+       }
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+       set_fs(USER_DS);
+       regs->nip = nip;
+       regs->gpr[1] = sp;
+       regs->msr = MSR_USER;
+       shove_aux_table(sp);
+}
+
+
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
                        struct pt_regs *regs)
 {
        int ret;
+
        lock_kernel();
        ret = do_fork(SIGCHLD, regs->gpr[1], regs);
        unlock_kernel();
@@ -541,26 +331,26 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
 {
        int error;
        char * filename;
-       filename = (int) getname((char *) a0);
+       
+       filename = getname((char *) a0);
        error = PTR_ERR(filename);
-       if(IS_ERR(filename))
+       if (IS_ERR(filename))
                goto out;
        if ( last_task_used_math == current )
                last_task_used_math = NULL;
        error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
        putname(filename);
-
 out:
        unlock_kernel();
        return error;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+                        struct pt_regs *regs)
 {
        unsigned long clone_flags = p1;
        int res;
-       
+
        lock_kernel();
        res = do_fork(clone_flags, regs->gpr[1], regs);
        unlock_kernel();
@@ -571,34 +361,23 @@ void
 print_backtrace(unsigned long *sp)
 {
        int cnt = 0;
-       int i;
+       unsigned long i;
+
        printk("Call backtrace: ");
-       while ( !get_user(i, sp) && i)
-       {
-               if ( get_user( i, &sp[1] ) )
-                       return;
-               printk("%08X ", i);
-               if ( get_user( (ulong)sp, sp) )
-                   return;
-               if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
-               if (++cnt == 8)
-               {
+       while (sp) {
+               if (__get_user( i, &sp[1] ))
+                       break;
+               if (cnt++ % 7 == 0)
                        printk("\n");
-               }
+               printk("%08lX ", i);
                if (cnt > 32) break;
+               if (__get_user(sp, (unsigned long **)sp))
+                       break;
        }
        printk("\n");
 }
 
-inline void start_thread(struct pt_regs * regs,
-                         unsigned long eip, unsigned long esp)
-{
-       set_fs(USER_DS);
-       regs->nip = eip;
-       regs->gpr[1] = esp;
-       regs->msr = MSR_USER;
-}
-
+#if 0
 /*
  * Low level print for debugging - Cort
  */
@@ -651,3 +430,4 @@ void ll_puts(const char *s)
        orig_x = x;
        orig_y = y;
 }
+#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
new file mode 100644 (file)
index 0000000..dedfd66
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+
+#define getpromprop(node, name, buf, len)      \
+       ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
+
+ihandle prom_stdout;
+ihandle prom_chosen;
+
+char command_line[256];
+int screen_initialized = 0;
+
+char prom_display_path[128];
+
+struct prom_args {
+       const char *service;
+       int nargs;
+       int nret;
+       void *args[10];
+} prom_args;
+
+struct pci_address {
+       unsigned a_hi;
+       unsigned a_mid;
+       unsigned a_lo;
+};
+
+struct pci_reg_property {
+       struct pci_address addr;
+       unsigned size_hi;
+       unsigned size_lo;
+};
+
+struct pci_range {
+       struct pci_address addr;
+       unsigned phys;
+       unsigned size_hi;
+       unsigned size_lo;
+};
+
+void (*prom_entry)(void *);
+extern int prom_trashed;
+
+static int prom_callback(struct prom_args *);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+                                 unsigned long, unsigned long);
+static void check_display(void);
+static int prom_next_node(phandle *);
+
+extern int pmac_display_supported(const char *);
+extern void enter_prom(void *);
+
+void
+prom_exit()
+{
+       struct prom_args args;
+
+       args.service = "exit";
+       args.nargs = 0;
+       args.nret = 0;
+       enter_prom(&args);
+       for (;;)                        /* should never get here */
+               ;
+}
+
+void *
+call_prom(const char *service, int nargs, int nret, ...)
+{
+       va_list list;
+       int i;
+
+       if (prom_trashed)
+               panic("prom called after its memory was reclaimed");
+       prom_args.service = service;
+       prom_args.nargs = nargs;
+       prom_args.nret = nret;
+       va_start(list, nret);
+       for (i = 0; i < nargs; ++i)
+               prom_args.args[i] = va_arg(list, void *);
+       va_end(list);
+       for (i = 0; i < nret; ++i)
+               prom_args.args[i + nargs] = 0;
+       enter_prom(&prom_args);
+       return prom_args.args[nargs];
+}
+
+void
+prom_print(const char *msg)
+{
+       const char *p, *q;
+       const char *crlf = "\r\n";
+
+       if (screen_initialized)
+               return;
+       for (p = msg; *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n'; ++q)
+                       ;
+               if (q > p)
+                       call_prom("write", 3, 1, prom_stdout, p, q - p);
+               if (*q != 0) {
+                       ++q;
+                       call_prom("write", 3, 1, prom_stdout, crlf, 2);
+               }
+       }
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+void
+prom_init(char *params, int unused, void (*pp)(void *))
+{
+       /* First get a handle for the stdout device */
+       if ( _machine != _MACH_Pmac ) /* prep */
+               return;
+       prom_entry = pp;
+       prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
+       if (prom_chosen == (void *)-1)
+               prom_exit();
+       call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
+                 (void *) sizeof(prom_stdout));
+
+       /*
+        * If we were booted via quik, params points to the physical address
+        * of the command-line parameters.
+        * If we were booted from an xcoff image (i.e. netbooted or
+        * booted from floppy), we get the command line from the bootargs
+        * property of the /chosen node.  If an initial ramdisk is present,
+        * params and unused are used for initrd_start and initrd_size,
+        * otherwise they contain 0xdeadbeef.  
+        */
+       command_line[0] = 0;
+       if ((unsigned long) params >= 0x4000
+           && (unsigned long) params < 0x800000
+           && unused == 0) {
+               strncpy(command_line, params+KERNELBASE, sizeof(command_line));
+       } else {
+#ifdef CONFIG_BLK_DEV_INITRD
+               if ((unsigned long) params - KERNELBASE < 0x800000
+                   && unused != 0 && unused != 0xdeadbeef) {
+                       initrd_start = (unsigned long) params;
+                       initrd_end = initrd_start + unused;
+                       ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+               }
+#endif
+               call_prom("getprop", 4, 1, prom_chosen, "bootargs",
+                         command_line, sizeof(command_line));
+       }
+       command_line[sizeof(command_line) - 1] = 0;
+
+       check_display();
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF may fall over if we do that after
+ * we've taken over the MMU and done set_prom_callback.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void
+check_display()
+{
+       phandle node;
+       ihandle ih;
+       char type[16], name[64], path[128];
+
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               getpromprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, "display") != 0)
+                       continue;
+               name[0] = 0;
+               getpromprop(node, "name", name, sizeof(name));
+               if (pmac_display_supported(name))
+                       /* we have a supported display */
+                       return;
+       }
+       printk(KERN_INFO "No supported display found\n");
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               getpromprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, "display") != 0)
+                       continue;
+               /* It seems OF doesn't null-terminate the path :-( */
+               memset(path, 0, sizeof(path));
+               if ((int) call_prom("package-to-path", 3, 1,
+                                   node, path, sizeof(path) - 1) < 0) {
+                       printk(KERN_WARNING "can't get path for display %p\n",
+                              node);
+                       continue;
+               }
+               ih = call_prom("open", 1, 1, path);
+               if (ih == 0 || ih == (ihandle) -1) {
+                       printk(KERN_WARNING "couldn't open display %s\n",
+                              path);
+                       continue;
+               }
+               printk(KERN_INFO "Opened display device %s using "
+                      "Open Firmware\n", path);
+               strcpy(prom_display_path, path);
+               break;
+       }
+}
+
+static int
+prom_next_node(phandle *nodep)
+{
+       phandle node;
+
+       if ((node = *nodep) != 0
+           && (*nodep = call_prom("child", 1, 1, node)) != 0)
+               return 1;
+       if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+               return 1;
+       for (;;) {
+               if ((node = call_prom("parent", 1, 1, node)) == 0)
+                       return 0;
+               if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+                       return 1;
+       }
+}
+
+/*
+ * Callback routine for the PROM to call us.
+ * No services are implemented yet :-)
+ */
+static int
+prom_callback(struct prom_args *argv)
+{
+       printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
+              argv->nargs, argv->nret);
+       return -1;
+}
+
+/*
+ * Register a callback with the Open Firmware PROM so it can ask
+ * us to map/unmap memory, etc.
+ */
+void
+set_prom_callback()
+{
+       call_prom("set-callback", 1, 1, prom_callback);
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+       xmon(0);
+#endif
+       prom_exit();
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+
+static struct device_node *allnodes;
+static struct device_node **allnextp;
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+unsigned long
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+       phandle root;
+
+       root = call_prom("peer", 1, 1, (phandle)0);
+       if (root == (phandle)0)
+               panic("couldn't get device tree root\n");
+       allnextp = &allnodes;
+       mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+       *allnextp = 0;
+       return mem_start;
+}
+
+static unsigned long
+inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
+            unsigned long mem_start, unsigned long mem_end)
+{
+       struct reg_property *reg, *rp;
+       struct pci_reg_property *pci_addrs;
+       int l, i;
+       phandle child;
+       struct device_node *np;
+       struct property *pp, **prev_propp;
+       char *prev_name;
+
+       np = (struct device_node *) mem_start;
+       mem_start += sizeof(struct device_node);
+       memset(np, 0, sizeof(*np));
+       np->node = node;
+       *allnextp = np;
+       allnextp = &np->allnext;
+       np->parent = dad;
+       if (dad != 0) {
+               /* we temporarily use the `next' field as `last_child'. */
+               if (dad->next == 0)
+                       dad->child = np;
+               else
+                       dad->next->sibling = np;
+               dad->next = np;
+       }
+
+       /* get and store all properties */
+       prev_propp = &np->properties;
+       prev_name = 0;
+       for (;;) {
+               pp = (struct property *) mem_start;
+               pp->name = (char *) (pp + 1);
+               if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+                                   pp->name) <= 0)
+                       break;
+               mem_start = ALIGN((unsigned long)pp->name
+                                 + strlen(pp->name) + 1);
+               pp->value = (unsigned char *) mem_start;
+               pp->length = (int)
+                       call_prom("getprop", 4, 1, node, pp->name, pp->value,
+                                 mem_end - mem_start);
+               if (pp->length < 0)
+                       panic("hey, where did property %s go?", pp->name);
+               mem_start = ALIGN(mem_start + pp->length);
+               prev_name = pp->name;
+               *prev_propp = pp;
+               prev_propp = &pp->next;
+       }
+       *prev_propp = 0;
+
+       np->name = get_property(np, "name", 0);
+       np->type = get_property(np, "device_type", 0);
+
+       /* get all the device addresses and interrupts */
+       reg = (struct reg_property *) mem_start;
+       pci_addrs = (struct pci_reg_property *)
+               get_property(np, "assigned-addresses", &l);
+       i = 0;
+       if (pci_addrs != 0) {
+               while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+                       /* XXX assumes PCI addresses mapped 1-1 to physical */
+                       reg[i].address = pci_addrs[i].addr.a_lo;
+                       reg[i].size = pci_addrs[i].size_lo;
+                       ++i;
+               }
+       } else {
+               rp = (struct reg_property *) get_property(np, "reg", &l);
+               if (rp != 0) {
+                       while ((l -= sizeof(struct reg_property)) >= 0) {
+                               reg[i].address = rp[i].address + base_address;
+                               reg[i].size = rp[i].size;
+                               ++i;
+                       }
+               }
+       }
+       if (i > 0) {
+               np->addrs = reg;
+               np->n_addrs = i;
+               mem_start += i * sizeof(struct reg_property);
+       }
+
+       np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+       if (np->intrs != 0)
+               np->n_intrs = l / sizeof(int);
+
+       /* get the node's full name */
+       l = (int) call_prom("package-to-path", 3, 1, node,
+                           (char *) mem_start, mem_end - mem_start);
+       if (l >= 0) {
+               np->full_name = (char *) mem_start;
+               np->full_name[l] = 0;
+               mem_start = ALIGN(mem_start + l + 1);
+       }
+
+       if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+               base_address = np->addrs[0].address;
+
+       child = call_prom("child", 1, 1, node);
+       while (child != (void *)0) {
+               mem_start = inspect_node(child, np, base_address,
+                                        mem_start, mem_end);
+               child = call_prom("peer", 1, 1, child);
+       }
+
+       return mem_start;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+                       *prevp = np;
+                       prevp = &np->next;
+               }
+       }
+       *prevp = 0;
+       return head;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+                       *prevp = np;
+                       prevp = &np->next;
+               }
+       }
+       *prevp = 0;
+       return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+                       return np;
+       return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+       struct property *pp;
+
+       for (pp = np->properties; pp != 0; pp = pp->next)
+               if (strcmp(pp->name, name) == 0) {
+                       if (lenp != 0)
+                               *lenp = pp->length;
+                       return pp->value;
+               }
+       return 0;
+}
+
+void
+print_properties(struct device_node *np)
+{
+       struct property *pp;
+       char *cp;
+       int i, n;
+
+       for (pp = np->properties; pp != 0; pp = pp->next) {
+               printk(KERN_INFO "%s", pp->name);
+               for (i = strlen(pp->name); i < 16; ++i)
+                       printk(" ");
+               cp = (char *) pp->value;
+               for (i = pp->length; i > 0; --i, ++cp)
+                       if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+                           || (i == 1 && *cp != 0))
+                               break;
+               if (i == 0 && pp->length > 1) {
+                       /* looks like a string */
+                       printk(" %s\n", (char *) pp->value);
+               } else {
+                       /* dump it in hex */
+                       n = pp->length;
+                       if (n > 64)
+                               n = 64;
+                       if (pp->length % 4 == 0) {
+                               unsigned int *p = (unsigned int *) pp->value;
+
+                               n /= 4;
+                               for (i = 0; i < n; ++i) {
+                                       if (i != 0 && (i % 4) == 0)
+                                               printk("\n                ");
+                                       printk(" %08x", *p++);
+                               }
+                       } else {
+                               unsigned char *bp = pp->value;
+
+                               for (i = 0; i < n; ++i) {
+                                       if (i != 0 && (i % 16) == 0)
+                                               printk("\n                ");
+                                       printk(" %02x", *bp++);
+                               }
+                       }
+                       printk("\n");
+                       if (pp->length > 64)
+                               printk("                 ... (length = %d)\n",
+                                      pp->length);
+               }
+       }
+}
index a5ec62d204e7b51e32ea1fc62c7d65e35c301abb..8a5839d1f6e3a3e68d73841abc443ff98e05f743 100644 (file)
@@ -171,8 +171,11 @@ repeat:
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) < max_mapnr)
-               *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+       if (MAP_NR(page) < max_mapnr) {
+               unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+               *(unsigned long *) phys_addr = data;
+               flush_icache_range(phys_addr, phys_addr+4);
+       }
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
        set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -364,7 +367,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_PEEKUSR: {
                        unsigned long tmp;
                        
-                       if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+                       if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
                                ret = -EIO;
                                goto out;
                        }
@@ -378,13 +381,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        if (addr < PT_FPR0) {
                                tmp = get_reg(child, addr);
                        }
-#if 1
-                       else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+                       else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
                                if (last_task_used_math == child)
                                        giveup_fpu();
                                tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
                        }
-#endif
                        else
                                ret = -EIO;
                        if (!ret)
@@ -400,7 +401,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
                        ret = -EIO;
-                       if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+                       if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
                                goto out;
 
                        addr = addr >> 2; /* temporary hack. */
@@ -508,7 +509,7 @@ asmlinkage void syscall_trace(void)
                goto out;
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
-       notify_parent(current);
+       notify_parent(current, SIGCHLD);
        schedule();
        /*
         * this isn't the same as continuing with a signal, but it will do
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
new file mode 100644 (file)
index 0000000..19cd5d3
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * $Id: setup.c,v 1.12 1997/08/13 03:06:17 cort Exp $
+ * Common prep/pmac boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/cuda.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+/* copy of the residual data */
+RESIDUAL res;
+int _machine;
+
+/*
+ * 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() )
+ */
+unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+                              unsigned long r6, unsigned long r7)
+{
+       extern unsigned long initrd_start, initrd_end;
+       extern char cmd_line[256];
+#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
+       _machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+       if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+               _machine = _MACH_IBM;
+       else
+               _machine = _MACH_Motorola;
+#endif /* CONFIG_PREP */
+       
+       if ( _machine == _MACH_Pmac )
+       {
+               io_base = 0;
+       }
+       else if ( is_prep ) /* prep */
+       {
+               io_base = 0x80000000;
+               /* make a copy of residual data */
+               if ( r3 )
+                       memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
+               /* take care of initrd if we have one */
+               if ( r4 )
+               {
+                       initrd_start = r4 + KERNELBASE;
+                       initrd_end = r5 + KERNELBASE;
+               }
+               /* take care of cmd line */
+               if ( r6 )
+               {
+                       
+                       *(char *)(r7+KERNELBASE) = 0;
+                       strcpy(cmd_line, (char *)(r6+KERNELBASE));
+               }
+       }
+       else
+       {
+               printk("Unknown machine type in identify_machine!\n");
+       }
+       return 0;
+}
+
+/* cmd is ignored for now... */
+void machine_restart(char *cmd)
+{
+       struct cuda_request req;
+       unsigned long flags;
+       unsigned long i = 10000;
+
+       if ( _machine == _MACH_Pmac )
+       {
+               cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+               for (;;)
+                       cuda_poll();
+       }
+       else /* prep */
+       {
+               _disable_interrupts();
+               
+               /* set exception prefix high - to the prom */
+               save_flags( flags );
+               restore_flags( flags|MSR_IP );
+               
+               /* make sure bit 0 (reset) is a 0 */
+               outb( inb(0x92) & ~1L , 0x92 );
+               /* signal a reset to system control port A - soft reset */
+               outb( inb(0x92) | 1 , 0x92 );
+               
+               while ( i != 0 ) i++;
+               panic("restart failed\n");
+       }
+
+}
+
+void machine_power_off(void)
+{
+       struct cuda_request req;
+
+       if ( _machine == _MACH_Pmac )
+       {
+               cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+               for (;;)
+                       cuda_poll();
+       }
+       else /* prep */
+       {
+               machine_restart(NULL);
+       }
+}
+
+void machine_halt(void)
+{
+       if ( _machine == _MACH_Pmac )
+       {
+#if 0
+               prom_exit();            /* doesn't work because prom is trashed */
+#else
+               machine_power_off();    /* for now */
+#endif
+       }
+       else /* prep */
+               machine_restart(NULL);
+
+}
+
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+       return memory_start;
+}
+
+/*
+ * Will merge more into here later  -- Cort
+ */
+int get_cpuinfo(char *buffer)
+{
+       extern int pmac_get_cpuinfo(char *);    
+       extern int prep_get_cpuinfo(char *);
+       
+       if ( _machine == _MACH_Pmac )
+               return pmac_get_cpuinfo(buffer);
+#ifdef CONFIG_PREP
+       else /* prep */
+               return prep_get_cpuinfo(buffer);
+#endif /* CONFIG_PREP */
+}
+
+__initfunc(void setup_arch(char **cmdline_p,
+       unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+       extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
+       extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+       
+       if ( _machine == _MACH_Pmac )
+               pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#ifdef CONFIG_PREP
+       else /* prep */
+               prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#endif /* CONFIG_PREP */
+}
+
+
index 2f602059c6c635a0fe808eb3d4d4f796a2fbd824..3151d266a34c102e3f115dba02021c4aa65c0e35 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/wait.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
+#include <linux/elf.h>
 #include <asm/uaccess.h>
 
 #define _S(nr) (1<<((nr)-1))
 #define PAUSE_AFTER_SIGNAL
 #undef  PAUSE_AFTER_SIGNAL
 
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 
 /*
@@ -71,32 +76,52 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg
        }
 }
 
+/* 
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+
 /*
  * This sets regs->esp even though we don't actually use sigstacks yet..
  */
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
-       struct sigcontext_struct *sc;
-       struct pt_regs *int_regs;
-       int signo, ret;
+       struct sigcontext_struct *sc, sigctx;
+       int ret;
+       elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 
-#if 1  
-       if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
-           || (regs->gpr[1] >= KERNELBASE))
+       sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+       if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
                goto badframe;
-#endif 
-       sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
-       get_user(current->blocked, &sc->oldmask);
-       current->blocked &= _BLOCKABLE;
-       get_user(int_regs, &sc->regs);
-       get_user(signo, &sc->signal);
+       current->blocked = sigctx.oldmask & _BLOCKABLE;
        sc++;                   /* Pop signal 'context' */
 #ifdef DEBUG_SIGNALS
-printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+       printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
+              sigctx.signal);
 #endif
-       if (sc == (struct sigcontext_struct *)(int_regs)) {
-               /* Last stacked signal */
-               memcpy(regs, int_regs, sizeof(*regs));
+       if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+               /* Last stacked signal - restore registers */
+               if (last_task_used_math == current)
+                       giveup_fpu();
+               if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+                       goto badframe;
+               saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+                       | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+               memcpy(regs, saved_regs, 
+                      MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+
+               if (copy_from_user(current->tss.fpr,
+                                  (unsigned long *)sigctx.regs + ELF_NGREG,
+                                  ELF_NFPREG * sizeof(double)))
+                       goto badframe;
+
                if (regs->trap == 0x0C00 /* System Call! */ &&
                    ((int)regs->result == -ERESTARTNOHAND ||
                     (int)regs->result == -ERESTARTSYS ||
@@ -106,15 +131,17 @@ printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
                        regs->result = 0;
                }
                ret = regs->result;
+
        } else {
                /* More signals to go */
-               regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
-               get_user(regs->gpr[3], &sc->signal);
-               get_user(int_regs, (struct pt_regs **) &sc->regs);
-               regs->gpr[4] = (unsigned long) int_regs;
-               regs->link = (unsigned long) (int_regs+1);
-               get_user(regs->nip, &sc->handler);
-               ret = regs->gpr[3];
+               regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+               if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+                       goto badframe;
+               regs->gpr[3] = ret = sigctx.signal;
+               regs->gpr[4] = (unsigned long) sigctx.regs;
+               regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
+                       + ELF_NFPREG * sizeof(double);
+               regs->nip = sigctx.handler;
        }
        return ret;
 
@@ -142,6 +169,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        unsigned long *frame = NULL;
        unsigned long *trampoline;
        unsigned long *regs_ptr;
+       double *fpregs_ptr;
        unsigned long nip = 0;
        unsigned long signr;
        struct sigcontext_struct *sc;
@@ -164,7 +192,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -204,7 +232,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                                current->exit_code = signr;
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
                                                SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
@@ -257,18 +285,33 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        nip = regs->nip;
        frame = (unsigned long *) regs->gpr[1];
 
-       /* Build trampoline code on stack */
-       frame -= 2;
+       /*
+        * Build trampoline code on stack, and save gp and fp regs.
+        * The 56 word hole is because programs using the rs6000/xcoff
+        * style calling sequence can save up to 19 gp regs and 18 fp regs
+        * on the stack before decrementing sp.
+        */
+       frame -= 2 + 56;
        trampoline = frame;
-       /* verify stack is valid for writing regs struct */
-       if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
-           || ((unsigned long) frame >= KERNELBASE ))
-               goto badframe;
-       put_user(0x38007777UL, trampoline);      /* li r0,0x7777 */
-       put_user(0x44000002UL, trampoline+1);    /* sc           */
-       frame -= sizeof(*regs) / sizeof(long);
+       frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
+       fpregs_ptr = (double *) frame;
+       frame -= ELF_NGREG;
        regs_ptr = frame;
-       copy_to_user(regs_ptr, regs, sizeof(*regs));
+       /* verify stack is valid for writing to */
+       if (verify_area(VERIFY_WRITE, frame,
+                       (ELF_NGREG + 2) * sizeof(long)
+                       + ELF_NFPREG * sizeof(double)))
+               goto badframe;
+       if (last_task_used_math == current)
+               giveup_fpu();
+       if (__copy_to_user(regs_ptr, regs, 
+                          MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
+           || __copy_to_user(fpregs_ptr, current->tss.fpr,
+                             ELF_NFPREG * sizeof(double))
+           || __put_user(0x38007777UL, trampoline)     /* li r0,0x7777 */
+           || __put_user(0x44000002UL, trampoline+1))  /* sc           */
+               goto badframe;
+
        signr = 1;
        sa = current->sig->action;
 
@@ -279,24 +322,29 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                        continue;
 
                frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-               if (verify_area(VERIFY_WRITE,(void *)frame,
-                               sizeof(struct sigcontext_struct)/sizeof(long)))
+               if (verify_area(VERIFY_WRITE, frame,
+                               sizeof(struct sigcontext_struct)))
                        goto badframe;
                sc = (struct sigcontext_struct *)frame;
                nip = (unsigned long) sa->sa_handler;
                if (sa->sa_flags & SA_ONESHOT)
                        sa->sa_handler = NULL;
-               put_user(nip, &sc->handler);
-               put_user(oldmask, &sc->oldmask); /* was current->blocked */
-               put_user(regs_ptr, &sc->regs);
-               put_user(signr, &sc->signal);
+               if (__put_user(nip, &sc->handler)
+                   || __put_user(oldmask, &sc->oldmask)
+                   || __put_user(regs_ptr, &sc->regs)
+                   || __put_user(signr, &sc->signal))
+                       goto badframe;
                current->blocked |= sa->sa_mask;
                regs->gpr[3] = signr;
-               regs->gpr[4] = (unsigned long)regs_ptr;
+               regs->gpr[4] = (unsigned long) regs_ptr;
        }
+
+       frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
+       if (put_user(regs->gpr[1], frame))
+               goto badframe;
        regs->link = (unsigned long)trampoline;
        regs->nip = nip;
-       regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+       regs->gpr[1] = (unsigned long) frame;
 
        /* The DATA cache must be flushed here to insure coherency */
        /* between the DATA & INSTRUCTION caches.  Since we just */
@@ -305,8 +353,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        /* cache for new data, we have to force the data to go on to */
        /* memory and flush the instruction cache to force it to look */
        /* there.  The following function performs this magic */
-       store_cache_range((unsigned long) trampoline,
-                         (unsigned long) (trampoline + 2));
+       flush_icache_range((unsigned long) trampoline,
+                          (unsigned long) (trampoline + 2));
        return 1;
 
 badframe:
diff --git a/arch/ppc/kernel/strcase.c b/arch/ppc/kernel/strcase.c
deleted file mode 100644 (file)
index a9e40bc..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/ctype.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
-       int c1, c2;
-
-       do {
-               c1 = tolower(*s1++);
-               c2 = tolower(*s2++);
-       } while (c1 == c2 && c1 != 0);
-       return c1 - c2;
-}
index bfdccdee6b81b85a8ea50612a849bb29da6e22eb..b7bac7a6a081a9163db5753ed2bfe09ad5ee8e70 100644 (file)
@@ -1,15 +1,25 @@
 /*
  * linux/arch/ppc/kernel/sys_ppc.c
  *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
  * Adapted from the i386 version by Gary Thomas
  * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
  *
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/PPC
  * platform.
+ *
+ *  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/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/sys.h>
 #include <linux/ipc.h>
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
-
 void
 check_bugs(void)
 {
@@ -32,32 +42,32 @@ check_bugs(void)
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-       printk("sys_ioperm()\n");
+       printk(KERN_ERR "sys_ioperm()\n");
        return -EIO;
 }
 
 int sys_iopl(int a1, int a2, int a3, int a4)
 {
        lock_kernel();
-       printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+       printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return (ENOSYS);
+       return (-ENOSYS);
 }
 
 int sys_vm86(int a1, int a2, int a3, int a4)
 {
        lock_kernel();
-       printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+       printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return (ENOSYS);
+       return (-ENOSYS);
 }
 
 int sys_modify_ldt(int a1, int a2, int a3, int a4)
 {
        lock_kernel();
-       printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+       printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return (ENOSYS);
+       return (-ENOSYS);
 }
 
 /*
@@ -65,7 +75,8 @@ int sys_modify_ldt(int a1, int a2, int a3, int a4)
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int 
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
        int version, ret;
 
@@ -73,138 +84,113 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
        version = call >> 16; /* hack for backward compatibility */
        call &= 0xffff;
 
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       ret = sys_semop (first, (struct sembuf *)ptr, second);
-                       goto out;
-               case SEMGET:
-                       ret = sys_semget (first, second, third);
-                       goto out;
-               case SEMCTL: {
-                       union semun fourth;
-                       ret = -EINVAL;
-                       if (!ptr)
-                               goto out;
-                       ret = -EFAULT;
-                       if (get_user(fourth.__pad, (void **) ptr))
-                               goto out;       
-                       ret = sys_semctl (first, second, third, fourth);
-                       goto out;
-               }
-               default:
-                       ret = -EINVAL;
-                       goto out;
+       ret = -EINVAL;
+       switch (call) {
+       case SEMOP:
+               ret = sys_semop (first, (struct sembuf *)ptr, second);
+               break;
+       case SEMGET:
+               ret = sys_semget (first, second, third);
+               break;
+       case SEMCTL: {
+               union semun fourth;
+
+               if (!ptr)
+                       break;
+               if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+                   || (ret = get_user(fourth.__pad, (void **)ptr)))
+                       break;
+               ret = sys_semctl (first, second, third, fourth);
+               break;
                }
-       if (call <= MSGCTL) 
-               switch (call) {
-               case MSGSND:
-                       ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
-                                         second, third);
-                       goto out;
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               ret = -EINVAL;
-                               if (!ptr)
-                                       goto out;
-                               ret = -EFAULT;
-                               if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, 
-                                                  sizeof (tmp)))
-                                       goto out;       
-                               ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
-                               goto out;
-                       }
-                       case 1: default:
-                               ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
-                               goto out;
+       case MSGSND:
+               ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+               break;
+       case MSGRCV:
+               switch (version) {
+               case 0: {
+                       struct ipc_kludge tmp;
+
+                       if (!ptr)
+                               break;
+                       if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+                           || (ret = copy_from_user(&tmp,
+                                               (struct ipc_kludge *) ptr,
+                                               sizeof (tmp))))
+                               break;
+                       ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+                                         third);
+                       break;
                        }
-               case MSGGET:
-                       ret = sys_msgget ((key_t) first, second);
-                       goto out;
-               case MSGCTL:
-                       ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
-                       goto out;
                default:
-                       ret = -EINVAL;
-                       goto out;
+                       ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+                                         second, fifth, third);
+                       break;
                }
-       if (call <= SHMCTL) 
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       case 0: default: {
-                               ulong raddr;
-                               ret = sys_shmat (first, (char *) ptr, second, &raddr);
-                               if (ret)
-                                       goto out;
-                               ret = put_user (raddr, (ulong *) third);
-                               goto out;
+               break;
+       case MSGGET:
+               ret = sys_msgget ((key_t) first, second);
+               break;
+       case MSGCTL:
+               ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+               break;
+       case SHMAT:
+               switch (version) {
+               default: {
+                       ulong raddr;
+
+                       if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+                                              sizeof(ulong))))
+                               break;
+                       ret = sys_shmat (first, (char *) ptr, second, &raddr);
+                       if (ret)
+                               break;
+                       ret = put_user (raddr, (ulong *) third);
+                       break;
                        }
-                       case 1: /* iBCS2 emulator entry point */
-                               ret = -EINVAL;
-                               if (get_fs() != get_ds())
-                                       goto out;
-                               ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
-                               goto out;
-                       }
-               case SHMDT: 
-                       ret = sys_shmdt ((char *)ptr);
-                       goto out;
-               case SHMGET:
-                       ret = sys_shmget (first, second, third);
-                       goto out;
-               case SHMCTL:
-                       ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
-                       goto out;
-               default:
-                       ret = -EINVAL;
-                       goto out;
+               case 1: /* iBCS2 emulator entry point */
+                       if (get_fs() != get_ds())
+                               break;
+                       ret = sys_shmat (first, (char *) ptr, second,
+                                        (ulong *) third);
+                       break;
                }
-       else
-               ret = -EINVAL;
-out:
-       unlock_kernel();
-       return ret;
-}
-
+               break;
+       case SHMDT: 
+               ret = sys_shmdt ((char *)ptr);
+               break;
+       case SHMGET:
+               ret = sys_shmget (first, second, third);
+               break;
+       case SHMCTL:
+               ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+               break;
+       }
 
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
-       lock_kernel();
-       panic("scsi_register_module");
-       unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
-       lock_kernel();
-       panic("scsi_unregister_module");
        unlock_kernel();
+       return ret;
 }
-#endif
 
 /*
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
  */
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(int *fildes)
 {
        int fd[2];
        int error;
 
-       error = verify_area(VERIFY_WRITE,fildes,8);
+       error = verify_area(VERIFY_WRITE, fildes, 8);
        if (error)
                return error;
+       lock_kernel();
        error = do_pipe(fd);
+       unlock_kernel();
        if (error)
                return error;
-       put_user(fd[0],0+fildes);
-       put_user(fd[1],1+fildes);
+       if (__put_user(fd[0],0+fildes)
+           || __put_user(fd[1],1+fildes))
+               return -EFAULT; /* should we close the fds? */
        return 0;
 }
 
@@ -213,13 +199,18 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
                                  unsigned long fd, off_t offset)
 {
        struct file * file = NULL;
+       int ret = -EBADF;
+
+       lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
                if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-                       return -EBADF;
+                       goto out;
        }
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       return do_mmap(file, addr, len, prot, flags, offset);
+       ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+       unlock_kernel();
+       return ret;
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -233,15 +224,15 @@ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timev
 asmlinkage int 
 ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-       int err;
        if ( (unsigned long)n >= 4096 )
        {
                unsigned long *buffer = (unsigned long *)n;
-               if ( get_user(n, buffer) ||
-                    get_user(inp,buffer+1) ||
-                    get_user(outp,buffer+2) ||
-                    get_user(exp,buffer+3) ||
-                    get_user(tvp,buffer+4) )
+               if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+                   || __get_user(n, buffer)
+                   || __get_user(inp, ((fd_set **)(buffer+1)))
+                   || __get_user(outp, ((fd_set **)(buffer+2)))
+                   || __get_user(exp, ((fd_set **)(buffer+3)))
+                   || __get_user(tvp, ((struct timeval **)(buffer+4))))
                        return -EFAULT;
        }
        return sys_select(n, inp, outp, exp, tvp);
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
new file mode 100644 (file)
index 0000000..acc9787
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * $Id: time.c,v 1.8 1997/08/11 08:37:51 cort Exp $
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/* this is set to the appropriate pmac/prep func in init_IRQ() */
+int (*set_rtc_time)(unsigned long);
+
+/* keep track of when we need to update the rtc */
+unsigned long last_rtc_update = 0;
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601  (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601   1
+#define COUNT_PERIOD_DEN_601   1000
+
+unsigned decrementer_count;    /* count value for 1e6/HZ microseconds */
+unsigned count_period_num;     /* 1 decrementer count equals */
+unsigned count_period_den;     /* count_period_num / count_period_den us */
+
+/* Accessor functions for the decrementer register. */
+inline unsigned long
+get_dec(void)
+{
+       int ret;
+
+       asm volatile("mfspr %0,22" : "=r" (ret) :);
+       return ret;
+}
+
+inline void
+set_dec(int val)
+{
+       asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+       int dval, d;
+       while ((dval = get_dec()) < 0) {
+               /*
+                * Wait for the decrementer to change, then jump
+                * in and add decrementer_count to its value
+                * (quickly, before it changes again!)
+                */
+               while ((d = get_dec()) == dval)
+                       ;
+               set_dec(d + decrementer_count);
+               do_timer(regs);
+               /*
+                * update the rtc when needed
+                */
+               if ( xtime.tv_sec > last_rtc_update + 660 )
+                       if (set_rtc_time(xtime.tv_sec) == 0)
+                               last_rtc_update = xtime.tv_sec;
+                       else
+                               last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+       }
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       *tv = xtime;
+       tv->tv_usec += (decrementer_count - get_dec())
+           * count_period_num / count_period_den;
+       if (tv->tv_usec >= 1000000) {
+               tv->tv_usec -= 1000000;
+               tv->tv_sec++;
+       }
+       restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       int frac_tick;
+       
+       last_rtc_update = 0; /* so the rtc gets updated soon */
+       
+       frac_tick = tv->tv_usec % (1000000 / HZ);
+       save_flags(flags);
+       cli();
+       xtime.tv_sec = tv->tv_sec;
+       xtime.tv_usec = tv->tv_usec - frac_tick;
+       set_dec(frac_tick * count_period_den / count_period_num);
+       restore_flags(flags);
+}
+
+
+void
+time_init(void)
+{
+#ifdef CONFIG_PREP
+       /* pmac hasn't yet called via_cuda_init() */
+       if ( _machine != _MACH_Pmac ) /* prep */
+       {
+               xtime.tv_sec = prep_get_rtc_time();
+               xtime.tv_usec = 0;
+               /*
+                * mark the rtc/on-chip timer as in sync
+                * so we don't update right away
+                */
+               last_rtc_update = xtime.tv_sec;
+       }
+#endif /* CONFIG_PREP */
+       if ((_get_PVR() >> 16) == 1) {
+               /* 601 processor: dec counts down by 128 every 128ns */
+               decrementer_count = DECREMENTER_COUNT_601;
+               count_period_num = COUNT_PERIOD_NUM_601;
+               count_period_den = COUNT_PERIOD_DEN_601;
+       } else {
+               /*
+                * These should setup decrementer_count 
+                */
+               if ( _machine == _MACH_Pmac )
+                       pmac_calibrate_decr();
+#ifdef CONFIG_PREP
+               else /* PReP */
+                       prep_calibrate_decr();
+#endif /* CONFIG_PREP */
+       }
+
+       if ( _machine == _MACH_Pmac )
+               set_rtc_time = pmac_set_rtc_time;
+#ifdef CONFIG_PREP
+       else /* prep */
+               set_rtc_time = prep_set_rtc_time;
+#endif /* CONFIG_PREP */
+               
+       set_dec(decrementer_count);
+}
+
+#ifdef CONFIG_PREP
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems.  On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+void prep_calibrate_decr(void)
+{
+       unsigned long flags;
+       
+       save_flags(flags);
+       
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+       /* set timer to periodic mode */
+       outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+       /* set the clock to ~100 Hz */
+       outb_p(LATCH & 0xff , TIMER0_COUNT);    /* LSB */
+       outb(LATCH >> 8 , TIMER0_COUNT);        /* MSB */
+       
+       if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+               panic("Could not allocate timer IRQ!");
+       __sti();
+       while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+        restore_flags(flags);
+       free_irq( 0, NULL);
+}
+
+void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
+{
+       int freq, divisor;
+       static unsigned long t1 = 0, t2 = 0;
+
+       if ( !t1 )
+               t1 = get_dec();
+       else if (!t2)
+       {
+               t2 = get_dec();
+               t2 = t1-t2;  /* decr's in 1/HZ */
+               t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
+               freq = t2 * 60; /* try to make freq/1e6 an integer */
+               divisor = 60;
+               printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+                      freq, divisor,t2>>20);
+               decrementer_count = freq / HZ / divisor;
+               count_period_num = divisor;
+               count_period_den = freq / 1000000;
+               *done_ptr = 1;
+       }
+}
+#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
new file mode 100644 (file)
index 0000000..a371f77
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * $Id: time.h,v 1.3 1997/08/12 08:22:14 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+/* time.c */
+__inline__ unsigned long get_dec(void);
+__inline__ void set_dec(int val);
+void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
+void prep_calibrate_decr(void);
+void pmac_calibrate_decr(void);
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+
+/* pmac/prep_time.c */
+unsigned long prep_get_rtc_time(void);
+unsigned long pmac_get_rtc_time(void);
+int prep_set_rtc_time(unsigned long nowtime);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+
index 84ce1c5ca39affd5b0e1d975393f41620c9b2953..edfcb4d63de2267bdc5043fcb6b08ad1b01c0dc3 100644 (file)
@@ -1,9 +1,15 @@
 /*
  *  linux/arch/ppc/kernel/traps.c
  *
- *  Copyright (C) 1995  Gary Thomas
- *  Adapted for PowerPC by Gary Thomas
+ *  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.
+ *
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  and Paul Mackerras (paulus@cs.anu.edu.au)
  */
 
 /*
 #include <linux/config.h>
 
 #include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
 
 /*
  * Trap & Exception support
@@ -43,40 +61,53 @@ _exception(int signr, struct pt_regs *regs)
        if (!user_mode(regs))
        {
                show_regs(regs);
-               print_backtrace(regs->gpr[1]);
-               panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+               print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+               xmon(regs);
+#endif
+               panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
        }
        force_sig(signr, current);
 }
 
+void
 MachineCheckException(struct pt_regs *regs)
 {
        if ( !user_mode(regs) )
        {
+#ifdef CONFIG_XMON
+               if (xmon_fault_handler) {
+                       xmon_fault_handler(regs);
+                       return;
+               }
+#endif
                printk("Machine check in kernel mode.\n");
                printk("Caused by (from msr): ");
-               printk("regs %08x ",regs);
+               printk("regs %p ",regs);
                switch( regs->msr & 0x0000F000)
                {
                case (1<<12) :
                        printk("Machine check signal - probably due to mm fault\n"
                                "with mmu off\n");
-               break;
+                       break;
                case (1<<13) :
                        printk("Transfer error ack signal\n");
-               break;
+                       break;
                case (1<<14) :
                        printk("Data parity signal\n");
-               break;
+                       break;
                case (1<<15) :
                        printk("Address parity signal\n");
-               break;
+                       break;
                default:
                        printk("Unknown values in msr\n");
                }
                show_regs(regs);
-               print_backtrace(regs->gpr[1]);
-               panic("");
+               print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+               xmon(regs);
+#endif
+               panic("machine check");
        }
        _exception(SIGSEGV, regs);      
 }
@@ -105,33 +136,71 @@ RunModeException(struct pt_regs *regs)
        _exception(SIGTRAP, regs);      
 }
 
+void
 ProgramCheckException(struct pt_regs *regs)
 {
-       if (current->flags & PF_PTRACED)
+       if (regs->msr & 0x100000) {
+               /* IEEE FP exception */
+               _exception(SIGFPE, regs);
+       } else if (regs->msr & 0x20000) {
+               /* trap exception */
+#ifdef CONFIG_XMON
+               if (xmon_bpt(regs))
+                       return;
+#endif
                _exception(SIGTRAP, regs);
-       else
+       } else {
                _exception(SIGILL, regs);
+       }
 }
 
+void
 SingleStepException(struct pt_regs *regs)
 {
        regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+       if (xmon_sstep(regs))
+               return;
+#endif
        _exception(SIGTRAP, regs);      
 }
 
+void
 AlignmentException(struct pt_regs *regs)
 {
+       int fixed;
+
+       if (last_task_used_math == current)
+               giveup_fpu();
+       fixed = fix_alignment(regs);
+       if (fixed == 1) {
+               regs->nip += 4; /* skip over emulated instruction */
+               return;
+       }
+       if (fixed == -EFAULT) {
+               /* fixed == -EFAULT means the operand address was bad */
+               bad_page_fault(regs, regs->dar);
+               return;
+       }
        _exception(SIGBUS, regs);       
 }
 
+void
+PromException(struct pt_regs *regs, int trap)
+{
+       regs->trap = trap;
+#ifdef CONFIG_XMON
+       xmon(regs);
+#endif
+       printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+              regs->trap, regs->nip, regs->msr);
+       /* probably should turn up the toes here */
+}
+
+void
 trace_syscall(struct pt_regs *regs)
 {
-       static int count;
-       printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+       printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
               current, current->pid, regs->nip, regs->link, regs->gpr[0],
               regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
-       if (++count == 20)
-       {
-               count = 0;
-       }
 }
diff --git a/arch/ppc/ld.script b/arch/ppc/ld.script
deleted file mode 100644 (file)
index ab5b070..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-OUTPUT_ARCH(powerpc)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
-/* Do we need any of these for elf?
-   __DYNAMIC = 0;    */
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = + SIZEOF_HEADERS;
-  .interp : { *(.interp) }
-  .hash          : { *(.hash)          }
-  .dynsym        : { *(.dynsym)                }
-  .dynstr        : { *(.dynstr)                }
-  .rel.text      : { *(.rel.text)              }
-  .rela.text     : { *(.rela.text)     }
-  .rel.data      : { *(.rel.data)              }
-  .rela.data     : { *(.rela.data)     }
-  .rel.rodata    : { *(.rel.rodata)    }
-  .rela.rodata   : { *(.rela.rodata)   }
-  .rel.got       : { *(.rel.got)               }
-  .rela.got      : { *(.rela.got)              }
-  .rel.ctors     : { *(.rel.ctors)     }
-  .rela.ctors    : { *(.rela.ctors)    }
-  .rel.dtors     : { *(.rel.dtors)     }
-  .rela.dtors    : { *(.rela.dtors)    }
-  .rel.bss       : { *(.rel.bss)               }
-  .rela.bss      : { *(.rela.bss)              }
-  .rel.plt       : { *(.rel.plt)               }
-  .rela.plt      : { *(.rela.plt)              }
-  .init          : { *(.init)  } =0
-  .plt : { *(.plt) }
-  .text      :
-  {
-    *(.text)
-    *(.fixup)
-    *(.got1)
-  }
-  _etext = .;
-  PROVIDE (etext = .);
-  .rodata    :
-  {
-    *(.rodata)
-    *(.rodata1)
-  }
-  .fini      : { *(.fini)    } =0
-  .ctors     : { *(.ctors)   }
-  .dtors     : { *(.dtors)   }
-  /* Read-write section, merged into data segment: */
-  . = (. + 0x0FFF) & 0xFFFFF000;
-  .data    :
-  {
-    *(.data)
-    *(.data1)
-    *(.sdata)
-    *(.sdata2)
-    *(.got.plt) *(.got)
-    *(.dynamic)
-    CONSTRUCTORS
-  }
-  _edata  =  .;
-/*
-  . = ALIGN(4096);
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-*/
-  __bss_start = .;             /* BSS */
-  PROVIDE (edata = .);
-  __bss_start = .;
-  .bss       :
-  {
-   *(.sbss) *(.scommon)
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-}
-
index 68b33f047a745652ce4b0b0fbb94a5153d3e4f35..8b84ce2aeef2245fb7c5b59ec2d8750e3dc2b193 100644 (file)
@@ -1,38 +1,11 @@
-.c.s:
-       $(CC) $(CFLAGS) -S $<
-.s.o:
-       $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
-       $(CC) $(CFLAGS) -c $<
-.S.s:
-       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-.S.o:
-       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-       $(AS) $(ASFLAGS) -o $*.o $*.s
-       rm $*.s
-
-HOST_CC = gcc
-
-L_TARGET = lib.o
-L_OBJS  = checksum.o cksum_support.o string.o
-
-${L_TARGET}: $(L_OBJS)
-       $(LD) -r -o ${L_TARGET} $(L_OBJS)
-
-
-fastdep:
-       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
-       $(CPP) -M *.S *.c > .depend
+#
+# Makefile for ppc-specific library files..
+#
 
-modules: 
+.S.o:
+       $(CC) -D__ASSEMBLY__ -c $< -o $*.o
 
-dummy:
+O_TARGET = lib.o
+O_OBJS  = checksum.o string.o strcase.o
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S
new file mode 100644 (file)
index 0000000..6c53d50
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+_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)
+       addi    r4,r4,-2
+       addc    r0,r0,r5
+       mtctr   r4
+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:     cmpi    0,r4,2
+       blt+    4f
+       lhz     r5,4(r3)
+       addi    r3,r3,2
+       subi    r4,r4,2
+       adde    r0,r0,r5
+4:     cmpi    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:     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:     cmpi    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:     cmpi    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
+
+.section .fixup,"ax"
+
+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
+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:
+       cmpi    0,r7,0
+       beq     1f
+       li      r6,-EFAULT
+       stw     r6,0(r7)
+1:     addze   r3,r0
+       blr
+
+dst_error:
+       cmpi    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   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/ppc/lib/checksum.c b/arch/ppc/lib/checksum.c
deleted file mode 100644 (file)
index 973916f..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * INET                An implementation of the TCP/IP protocol suite for the LINUX
- *             operating system.  INET is implemented using the  BSD Socket
- *             interface as the means of communication with the user level.
- *
- *             IP/TCP/UDP checksumming routines
- *
- * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
- *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *             Tom May, <ftom@netcom.com>
- *             Lots of code moved from tcp.c and ip.c; see those files
- *             for more names.
- *
- * Adapted for PowerPC by Gary Thomas <gdt@mc.com>
- *
- *             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 <net/checksum.h>
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
-{
-       unsigned long result = ~_csum_partial(buff, len, sum);
-#if 0  
-printk("Csum partial(%x, %d, %x) = %x\n", buff, len, sum, result);
-dump_buf(buff, len);
-#endif
-       return result;
-}
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit boundary
- */
-
-unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum)
-{
-       /*
-        * The whole idea is to do the copy and the checksum at
-        * the same time, but we do it the easy way now.
-        *
-        * At least csum on the source, not destination, for cache
-        * reasons..
-        */
-       sum = csum_partial(src, len, sum);
-       memcpy(dst, src, len);
-       return sum;
-}
-
-extern unsigned short _ip_fast_csum(unsigned char *buf);
-
-unsigned short
-ip_fast_csum(unsigned char *buf, unsigned int len)
-{
-       unsigned short _val;
-       _val = _ip_fast_csum(buf);
-#if 0
-       printk("IP CKSUM(%x, %d) = %x\n", buf, len, _val);
-       dump_buf(buf, len*4);
-#endif 
-       return (_val);
-}
-
-extern unsigned short _ip_compute_csum(unsigned char *buf, int len);
-
-unsigned short
-ip_compute_csum(unsigned char *buf, int len)
-{
-       unsigned short _val;
-       _val = _ip_compute_csum(buf, len);
-#if 0
-       printk("Compute IP CKSUM(%x, %d) = %x\n", buf, len, _val);
-       dump_buf(buf, len);
-#endif 
-       return (_val);
-}
-
-unsigned short
-_udp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-udp_check(unsigned char *buf, int len, int saddr, int daddr)
-{
-       unsigned short _val;
-       int hdr;
-       hdr = (len << 16) + IPPROTO_UDP;
-       _val = _udp_check(buf, len, saddr, daddr, hdr);
-#if 0
-       printk("UDP CSUM(%x,%d,%x,%x) = %x\n", buf, len, saddr, daddr, _val);
-       dump_buf(buf, len);
-#endif 
-       return (_val);
-}
-
-unsigned short
-_tcp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, unsigned int sum)
-{
-       unsigned short _val;
-       _val = _csum_tcpudp_magic(saddr, daddr, sum, (len<<16)+proto);
-#if 0
-       printk("TCP Magic(%x, %x, %x, %x) = %x\n", saddr, daddr, (len<<16)+proto, sum, _val);
-#endif
-       return (_val);
-}
-
-/*
- *     Fold a partial checksum without adding pseudo headers
- */
-
-unsigned int csum_fold(unsigned int sum)
-{
-       sum = (sum & 0xffff) + (sum >> 16);
-       sum = (sum & 0xffff) + (sum >> 16);
-       return ~sum;
-}
-
diff --git a/arch/ppc/lib/cksum_support.S b/arch/ppc/lib/cksum_support.S
deleted file mode 100644 (file)
index 264d5a6..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
- */
-
-#include <linux/sys.h>
-#include "../kernel/ppc_asm.tmpl"
-
-_TEXT()
-
-/*
- * Compute IP checksums
- *   _ip_fast_csum(buf, len) -- Optimized for IP header
- *   _ip_compute_csum(buf, len)
- */
-
-_GLOBAL(_ip_fast_csum)
-       li      r0,0
-       addic   r0,r0,0         /* Clear initial carry */
-       lwz     r4,0(r3)
-       lwz     r5,4(r3)
-       adde    r0,r0,r4
-       lwz     r4,8(r3)
-       adde    r0,r0,r5
-       lwz     r5,12(r3)
-       adde    r0,r0,r4
-       lwz     r4,16(r3)
-       adde    r0,r0,r5
-       adde    r0,r0,r4
-       mr      r3,r0
-       andi.   r3,r3,0xFFFF
-       srwi    r0,r0,16
-       adde    r3,r3,r0
-       andis.  r0,r3,1
-       beq     10f
-       addi    r3,r3,1
-10:    not     r3,r3
-       andi.   r3,r3,0xFFFF
-       blr
-
-_GLOBAL(_ip_compute_csum)
-       li      r0,0
-       addic   r0,r0,0
-finish_ip_csum:        
-       subi    r3,r3,4
-       andi.   r5,r3,2         /* Align buffer to longword boundary */
-       beq     10f
-       lhz     r5,4(r3)
-       adde    r0,r0,r5
-       addi    r3,r3,2
-       subi    r4,r4,2
-10:    cmpi    0,r4,16         /* unrolled loop - 16 bytes at a time */
-       blt     20f
-       lwz     r5,4(r3)
-       lwz     r6,8(r3)
-       adde    r0,r0,r5
-       lwz     r5,12(r3)
-       adde    r0,r0,r6
-       lwzu    r6,16(r3)
-       adde    r0,r0,r5
-       adde    r0,r0,r6
-       subi    r4,r4,16
-       b       10b
-20:    cmpi    0,r4,4
-       blt     30f
-       lwzu    r5,4(r3)
-       adde    r0,r0,r5
-       subi    r4,r4,4
-       b       20b
-30:    cmpi    0,r4,2
-       blt     40f
-       lhz     r5,4(r3)
-       addi    r3,r3,2
-       adde    r0,r0,r5
-       subi    r4,r4,2
-40:    cmpi    0,r4,1
-       bne     50f
-       lbz     r5,4(r3)
-       slwi    r5,r5,8         /* Upper byte of word */
-       adde    r0,r0,r5
-50:    mr      r3,r0
-       andi.   r3,r3,0xFFFF
-       srwi    r0,r0,16
-       adde    r3,r3,r0
-       andis.  r0,r3,1
-       beq     60f
-       addi    r3,r3,1
-60:    not     r3,r3
-       andi.   r3,r3,0xFFFF
-       blr
-
-_GLOBAL(_udp_check)
-       addc    r0,r5,r6        /* Add in header fields */
-       adde    r0,r0,r7
-       b       finish_ip_csum  
-
-_GLOBAL(_tcp_check)
-       addc    r0,r5,r6        /* Add in header fields */
-       adde    r0,r0,r7
-       b       finish_ip_csum  
-
-_GLOBAL(_csum_partial)
-       li      r0,0
-       addc    r0,r5,r0
-       b       finish_ip_csum  
-
-/*
- * Compute 16 bit sum:
- *   _csum_tcpudp_magic(int saddr, int daddr, int sum, int proto)
- */    
-_GLOBAL(_csum_tcpudp_magic)
-       addc    r0,r3,r4
-       adde    r0,r0,r5
-       adde    r0,r0,r6
-       mr      r3,r0
-       andi.   r3,r3,0xFFFF
-       srwi    r0,r0,16
-       adde    r3,r3,r0
-       andis.  r0,r3,1                 /* Carry out of 16 bits? */
-       beq     10f
-       addi    r3,r3,1
-10:    not     r3,r3
-       andi.   r3,r3,0xFFFF
-       blr
-
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
new file mode 100644 (file)
index 0000000..a9e40bc
--- /dev/null
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+       int c1, c2;
+
+       do {
+               c1 = tolower(*s1++);
+               c2 = tolower(*s2++);
+       } while (c1 == c2 && c1 != 0);
+       return c1 - c2;
+}
index 9ff7a054df07a1fd077cc3506c7fc2ef6571a33e..96378dec14a38d0484e497384208175d9a33468d 100644 (file)
@@ -94,6 +94,7 @@ memset:
 8:     stbu    r4,1(r6)
        bdnz    8b
        blr
+
        .globl  bcopy
 bcopy:
        mr      r6,r3
@@ -189,7 +190,7 @@ backwards_memcpy:
        .globl  memcmp
 memcmp:
        cmpwi   0,r5,0
-       blelr
+       ble-    2f
        mtctr   r5
        addi    r6,r3,-1
        addi    r4,r4,-1
@@ -198,6 +199,22 @@ memcmp:
        subf.   r3,r0,r3
        bdnzt   2,1b
        blr
+2:     li      r3,0
+       blr
+
+       .global memchr
+memchr:
+       cmpwi   0,r5,0
+       ble-    2f
+       mtctr   r5
+       addi    r3,r3,-1
+1:     lbzu    r0,1(r3)
+       cmpw    0,r0,r4
+       bdnzf   2,1b
+       beqlr
+2:     li      r3,0
+       blr
+
        .globl  __copy_tofrom_user
 __copy_tofrom_user:
        rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
index f91571954cbf9eafd381bc6c8f76f4f7f10f6efb..80408b7417e305247a8bdaf4c59b1e5113b6da8b 100644 (file)
@@ -1,9 +1,13 @@
 #!/bin/bash
 
-N=`basename $PWD`
-V=`echo $N | sed 's/linux-//'`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
 date=`date +'%y%m%d'`
-mkdir -p ../dist
-mv zImage ../dist/zImage-$V-$date
-mv System.map ../dist/System.map-$V-$date
+
+echo zImage-$V.$P.$S-$date
+echo System.map-$V.$P.$S-$date
+
+rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date
+rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date
 
index 965eefbbad4509f84aed6eea7bd89b4f270d667f..a50112ff6ea6c2803ab85f49ad6228c887f3f827 100644 (file)
@@ -1,7 +1,9 @@
 #!/bin/bash
 
-N=`basename $PWD`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
 date=`date +'%y%m%d'`
 cd ../
 mkdir -p dist
-tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
+tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux
index 13aeab6cabe6ceda3ed5be95bc1b803e2a709634..2b07c722764b5c8858f7b12d59241304e054ee08 100644 (file)
@@ -7,28 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-       $(CC) $(CFLAGS) -c $<
-.s.o:
-       $(AS) -o $*.o $<
-.c.s:
-       $(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS = fault.o init.o extable.o
 
-OBJS   = fault.o init.o extable.o
-
-mm.o: $(OBJS)
-       $(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-
-fastdep:
-       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
index fea722780310f22fc623861f3a418ed889570b93..3b7c763e65e227a0e2283a413952cf9110cf7edf 100644 (file)
@@ -1,8 +1,12 @@
 /*
  *  arch/ppc/mm/fault.c
  *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *  Ported to PPC by Gary Thomas
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
  *  Modified by Cort Dougan and Paul Mackerras.
  *
  *  This program is free software; you can redistribute it and/or
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mmu.h>
 #include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
 extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
-   make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC 
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
 #endif
 
 extern void die_if_kernel(char *, struct pt_regs *, long);
 void bad_page_fault(struct pt_regs *, unsigned long);
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
 
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)     
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+                  unsigned long error_code)
 {
-       struct task_struct *tsk = current;
-       extern unsigned _end[];
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
-       pgd_t *dir;
-       pmd_t *pmd;
-       pte_t *pte;
-       
-       /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
-              current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
        if (xmon_fault_handler && regs->trap == 0x300) {
                xmon_fault_handler();
                return;
        }
+       if (error_code & 0x00400000) {
+               /* DABR match */
+               if (xmon_dabr_match(regs))
+                       return;
+       }
 #endif
        if (in_interrupt()) {
                static int complained;
@@ -68,14 +74,18 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long er
                        printk("page fault in interrupt handler, addr=%lx\n",
                               address);
                        show_regs(regs);
+#ifdef CONFIG_XMON
+                       if (xmon_kernel_faults)
+                               xmon(regs);
+#endif
                }
        }
-       if (current == NULL)
-               goto bad_area;
-       
-do_page:
+       if (current == NULL) {
+               bad_page_fault(regs, address);
+               return;
+       }
        down(&mm->mmap_sem);
-       vma = find_vma(tsk->mm, address);
+       vma = find_vma(mm, address);
        if (!vma)
                goto bad_area;
        if (vma->vm_start <= address)
@@ -84,7 +94,7 @@ do_page:
                goto bad_area;
        if (expand_stack(vma, address))
                goto bad_area;
-  
+
 good_area:
        if (error_code & 0xb5700000)
                /* an error such as lwarx to I/O controller space,
@@ -98,67 +108,45 @@ good_area:
        /* a read */
        } else {
                /* protection fault */
-               if ( error_code & 0x08000000 )
+               if (error_code & 0x08000000)
                        goto bad_area;
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
        handle_mm_fault(current, vma, address, error_code & 0x02000000);
-        up(&mm->mmap_sem);
-       /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
-             current->comm,current->pid,address,regs->msr);*/
-       /* not needed since flush_page_to_ram() works */
-#if 0
-       flush_page(address);
-#endif
+       up(&mm->mmap_sem);
        return;
-  
+
 bad_area:
-       up(&current->mm->mmap_sem);
+       up(&mm->mmap_sem);
        bad_page_fault(regs, address);
 }
 
-
 void
 bad_page_fault(struct pt_regs *regs, unsigned long address)
 {
-       extern unsigned int probingmem;
-       struct task_struct *tsk = current;
        unsigned long fixup;
-       
+
+       if (user_mode(regs)) {
+               force_sig(SIGSEGV, current);
+               return;
+       }
        
        /* Are we prepared to handle this fault?  */
        if ((fixup = search_exception_table(regs->nip)) != 0) {
-               if ( user_mode(regs) )
-                       printk("Exception from user mode\n");
-#if 0    
-               printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif    
                regs->nip = fixup;
                return;
        }
 
-       if ( user_mode(regs) )
-       {
-               force_sig(SIGSEGV, tsk);
-               return;
-       }
-  
-bad_kernel_access:
-       /* make sure it's not a bootup probe test */
-       if ( probingmem )
-       {
-               probingmem = 0;
-               return;
-       }
        /* kernel has accessed a bad area */
        show_regs(regs);
-       print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
-       xmon(regs);
+       print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+       if (xmon_kernel_faults)
+               xmon(regs);
 #endif
-       panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
-             regs->nip,address,tsk->comm,tsk->pid);
+       panic("kernel access of bad area\n pc %lx address %lX tsk %s/%d",
+             regs->nip,address,current->comm,current->pid);
 }
 
 unsigned long va_to_phys(unsigned long address)
@@ -189,6 +177,10 @@ unsigned long va_to_phys(unsigned long address)
        return (0);
 }
 
+#if 0
+/*
+ * Misc debugging functions.  Please leave them here. -- Cort
+ */
 void print_pte(struct _PTE p)
 {
        printk(
@@ -210,7 +202,8 @@ unsigned long htab_phys_to_va(unsigned long address)
        for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
        {
                if ( ptr->rpn == (address>>12) )
-                       printk("phys %08X -> va ???\n",
+                       printk("phys %08lX -> va ???\n",
                               address);
        }
 }
+#endif
index d469759963373e181432a47828411852c1cba8c6..701136bbd00520865c70ae4fe3b41749c08238c4 100644 (file)
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/stddef.h>
-#ifdef CONFIG_PMAC
 #include <asm/prom.h>
-#endif
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
-#ifdef CONFIG_PREP
 #include <asm/residual.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>         /* for initrd_* */
 #endif
 
+int prom_trashed;
 int next_mmu_context;
+unsigned long _SDR1;
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int mem_init_done;
 extern pgd_t swapper_pg_dir[];
 extern char _start[], _end[];
 extern char etext[], _stext[];
-/* References to section boundaries */
 extern char __init_begin, __init_end;
+extern RESIDUAL res;
 
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-extern unsigned long *find_end_of_memory(void);
 
-#undef MAP_RAM_WITH_SEGREGS 1
-
-#ifdef CONFIG_PMAC
 void *find_mem_piece(unsigned, unsigned);
 static void mapin_ram(void);
 static void inherit_prom_translations(void);
-#endif
-#ifdef CONFIG_PREP
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
-int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);     
-#endif
-
 static void hash_init(void);
 static void *MMU_get_page(void);
-void map_page(struct thread_struct *, unsigned long va,
+void map_page(struct task_struct *, unsigned long va,
                     unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long *find_end_of_memory(void);
 
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int mem_init_done;
+/*
+ * this tells the prep system to map all of ram with the segregs
+ * instead of the bats.  I'd like to get this to apply to the
+ * pmac as well then have everything use the bats -- Cort
+ */
+#undef MAP_RAM_WITH_SEGREGS 1 
 
-#ifdef CONFIG_PREP
-#ifdef HASHSTATS
-extern unsigned long evicts;
-#endif /* HASHSTATS */
 /*
  * these are used to setup the initial page tables
  * They can waste up to an entire page since the
@@ -88,8 +82,6 @@ extern unsigned long evicts;
 unsigned int probingmem = 0;
 unsigned int mmu_pages_count = 0;
 char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
-unsigned long _TotalMemory;
-#endif /* CONFIG_PREP */
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -120,7 +112,6 @@ pte_t __bad_page(void)
        return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
 }
 
-#ifdef CONFIG_PMAC
 #define MAX_MEM_REGIONS        32
 phandle memory_pkg;
 
@@ -128,7 +119,6 @@ struct mem_pieces {
        int n_regions;
        struct reg_property regions[MAX_MEM_REGIONS];
 };
-
 struct mem_pieces phys_mem;
 struct mem_pieces phys_avail;
 struct mem_pieces prom_mem;
@@ -138,7 +128,6 @@ static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
 static void print_mem_pieces(struct mem_pieces *);
 
 unsigned long avail_start;
-int prom_trashed;
 
 /*
  * Read in a property describing some pieces of memory.
@@ -272,7 +261,7 @@ find_mem_piece(unsigned size, unsigned align)
  * Our text, data, bss use something over 1MB, starting at 0.
  * Open Firmware may be using 1MB at the 4MB point.
  */
-unsigned long *find_end_of_memory(void)
+unsigned long *pmac_find_end_of_memory(void)
 {
        unsigned long a, total;
        unsigned long h, kstart, ksize;
@@ -353,6 +342,9 @@ unsigned long find_available_memory(void)
        int i;
        unsigned long a, free;
        unsigned long start, end;
+       
+       if ( _machine != _MACH_Pmac )
+               return 0;
 
        free = 0;
        for (i = 0; i < phys_avail.n_regions - 1; ++i) {
@@ -366,7 +358,6 @@ unsigned long find_available_memory(void)
        avail_start = (unsigned long) __va(a);
        return avail_start;
 }
-#endif /* CONFIG_PMAC */
 
 void show_mem(void)
 {
@@ -399,14 +390,21 @@ void show_mem(void)
               "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
        for_each_task(p)
        {       
-               printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+               printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
                       p->comm,p->pid,
                       p->mm->count,p->mm->context,
                       p->mm->context<<4, p->tss.last_syscall,
                       user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
-                      p);
+                      (ulong)p);
                if ( p == current )
-                       printk(" current");
+                       printk("current");
+               if ( p == last_task_used_math )
+               {
+                       if ( p == current )
+                               printk(",");
+                       printk("last math");
+               }
+
                printk("\n");
        }
 }
@@ -434,76 +432,68 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
        unsigned long addr;
-#ifdef CONFIG_PMAC
        int i;
-       unsigned long lim;
-#endif
+       unsigned long a, lim;
        int codepages = 0;
        int datapages = 0;
        int initpages = 0;
 
        end_mem &= PAGE_MASK;
        high_memory = (void *) end_mem;
-       num_physpages = max_mapnr = MAP_NR(high_memory);
-       
-       /* clear the zero-page */
-       memset(empty_zero_page, 0, PAGE_SIZE);
-       
+       max_mapnr = MAP_NR(high_memory);
+       num_physpages = max_mapnr;      /* RAM is assumed contiguous */
+
        /* mark usable pages in the mem_map[] */
        start_mem = PAGE_ALIGN(start_mem);
-       
-#ifdef CONFIG_PMAC
-       remove_mem_piece(&phys_avail, __pa(avail_start),
-                        start_mem - avail_start, 1);
-
-       for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
-               set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-
-       for (i = 0; i < phys_avail.n_regions; ++i) {
-               a = (unsigned long) __va(phys_avail.regions[i].address);
-               lim = a + phys_avail.regions[i].size;
-               a = PAGE_ALIGN(a);
-               for (; a < lim; a += PAGE_SIZE) {
-                       clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-                       mem_map[MAP_NR(a)].count = 1;
-                       free_page(a);
+
+       if ( _machine == _MACH_Pmac )
+       {
+               remove_mem_piece(&phys_avail, __pa(avail_start),
+                                start_mem - avail_start, 1);
+               
+               for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
+                       set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+               
+               for (i = 0; i < phys_avail.n_regions; ++i) {
+                       a = (unsigned long) __va(phys_avail.regions[i].address);
+                       lim = a + phys_avail.regions[i].size;
+                       a = PAGE_ALIGN(a);
+                       for (; a < lim; a += PAGE_SIZE)
+                               clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
                }
-       }
-       phys_avail.n_regions = 0;
-
-       /* free the prom's memory */
-       for (i = 0; i < prom_mem.n_regions; ++i) {
-               a = (unsigned long) __va(prom_mem.regions[i].address);
-               lim = a + prom_mem.regions[i].size;
-               a = PAGE_ALIGN(a);
-               for (; a < lim; a += PAGE_SIZE) {
-                       clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-                       mem_map[MAP_NR(a)].count = 1;
-                       free_page(a);
+               phys_avail.n_regions = 0;
+               
+               /* free the prom's memory */
+               for (i = 0; i < prom_mem.n_regions; ++i) {
+                       a = (unsigned long) __va(prom_mem.regions[i].address);
+                       lim = a + prom_mem.regions[i].size;
+                       a = PAGE_ALIGN(a);
+                       for (; a < lim; a += PAGE_SIZE)
+                               clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
                }
+               prom_trashed = 1;
        }
-       prom_trashed = 1;
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_PREP
-       /* mark mem used by kernel as reserved, mark other unreserved */
-       for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+       else /* prep */
        {
-               /* skip hash table gap */
-               if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
-                       continue;
-               if ( addr < (ulong) /*Hash_end*/ start_mem )
-                       set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
-               else
-                       clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+               /* mark mem used by kernel as reserved, mark other unreserved */
+               for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+               {
+                       /* skip hash table gap */
+                       if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+                               continue;
+                       if ( addr < (ulong) /*Hash_end*/ start_mem )
+                               set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+                       else
+                               clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+               }
        }
 
        for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-               if(PageReserved(mem_map + MAP_NR(addr))) {
+               if (PageReserved(mem_map + MAP_NR(addr))) {
                        if (addr < (ulong) etext)
                                codepages++;
-                       /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
-                                initpages++;*/
+                       else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                                initpages++;
                         else if (addr < (ulong) start_mem)
                                datapages++;
                        continue;
@@ -515,9 +505,8 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
 #endif /* CONFIG_BLK_DEV_INITRD */
                        free_page(addr);
        }
-       
-#endif /* CONFIG_PREP */
-        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+
+        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
               (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
               codepages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10), 
@@ -534,7 +523,6 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
  */
 void free_initmem(void)
 {
-       unsigned long addr;
        unsigned long a;
        unsigned long num_freed_pages = 0;
 
@@ -548,16 +536,14 @@ void free_initmem(void)
                num_freed_pages++;
        }
 
-#if 0
-       addr = (unsigned long)(&__init_begin);
-       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-               num_freed_pages++;
-               mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-               mem_map[MAP_NR(addr)].count = 1;
-               free_page(addr);
+       a = (unsigned long)(&__init_begin);
+       for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
+               mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+               atomic_set(&mem_map[MAP_NR(a)].count, 1);
+               free_page(a);
        }
-#endif 
-       printk ("Freeing unused kernel memory: %dk freed\n",
+
+       printk ("Freeing unused kernel memory: %ldk freed\n",
                (num_freed_pages * PAGE_SIZE) >> 10);
 }
 
@@ -576,19 +562,13 @@ void si_meminfo(struct sysinfo *val)
                val->totalram++;
                if (!atomic_read(&mem_map[i].count))
                        continue;
-               val->sharedram += atomic_read(&mem_map[i].count)-1;
+               val->sharedram += atomic_read(&mem_map[i].count) - 1;
        }
        val->totalram <<= PAGE_SHIFT;
        val->sharedram <<= PAGE_SHIFT;
        return;
 }
 
-/* Kernel MMU setup & lowest level hardware support */
-
-unsigned long _SDR1;           /* Hardware SDR1 image */
-
-#ifdef CONFIG_PREP
-
 BAT BAT0 =
 {
   {
@@ -635,7 +615,11 @@ BAT BAT2 =
     0x00000000>>17,            /* brpn */
     0,                 /* w */
     0,                 /* i */
+#ifdef __SMP__    
     1,                 /* m */
+#else    
+    0,                 /* m */
+#endif    
     0,                 /* g */
     BPP_RW                     /* pp */
   }
@@ -724,61 +708,41 @@ P601_BAT BAT3_601 =
  * this will likely stay seperate from the pmac.
  * -- Cort
  */
-unsigned long *find_end_of_memory(void)
+unsigned long *prep_find_end_of_memory(void)
 {
-       extern RESIDUAL res;
-       extern unsigned long resptr;
-       int i, p;
+       int i;
        unsigned long h;
-
-       /* copy residual data */
-       if ( resptr )
-               memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
-       else
-               /* clearing bss probably clears this but... */
-               memset( &res, sizeof(RESIDUAL), 0 );
-       _TotalMemory = res.TotalMemory;
-       
-       /* this really has nothing to do with the mmu_init() but is
-          necessary for early setup -- Cort */
-       if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
-       {
-               _machine = _MACH_IBM;
-       }
-       else
-               _machine = _MACH_Motorola;
-  
        /* setup the hash table */
-       if (_TotalMemory == 0 )
+       if (res.TotalMemory == 0 )
        {
                /*
                 * I need a way to probe the amount of memory if the residual
                 * data doesn't contain it. -- Cort
                 */
                printk("Ramsize from residual data was 0 -- Probing for value\n");
-               _TotalMemory = 0x03000000;
-               printk("Ramsize default to be %dM\n", _TotalMemory>>20);
+               res.TotalMemory = 0x03000000;
+               printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
        }
        
 #if 0
        /* linux has trouble with > 64M ram -- Cort */
-       if ( _TotalMemory > 0x04000000 /* 64M */ )
+       if ( res.TotalMemory > 0x04000000 /* 64M */ )
        {
                printk("Only using first 64M of ram.\n");
-               _TotalMemory = 0x04000000;
+               res.TotalMemory = 0x04000000;
        }
 #endif 
        
        /* setup the bat2 mapping to cover physical ram */
        BAT2.batu.bl = 0x1; /* 256k mapping */
-       for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+       for ( h = 256*1024 /* 256k */ ; (h <= res.TotalMemory) && (h <= 256*1024*1024);
              h *= 2 )
                BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
        /*
         * Allow 64k of hash table for every 16MB of memory,
         * up to a maximum of 2MB.
         */
-       for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+       for (h = 64<<10; h < res.TotalMemory / 256 && h < 2<<20; h *= 2)
                ;
        Hash_size = h;
        Hash_mask = (h >> 6) - 1;
@@ -799,11 +763,11 @@ unsigned long *find_end_of_memory(void)
        if ( _get_PVR() == 1 )
        {
                /* map in rest of ram with seg regs */
-               if ( _TotalMemory > 0x01000000 /* 16M */)
+               if ( res.TotalMemory > 0x01000000 /* 16M */)
                {
                        for (i = KERNELBASE+0x01000000;
-                            i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
-                               map_page(&init_task.tss, i, __pa(i),
+                            i < KERNELBASE+res.TotalMemory;  i += PAGE_SIZE)
+                               map_page(&init_task, i, __pa(i),
                                         _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
                }
        }
@@ -815,25 +779,23 @@ unsigned long *find_end_of_memory(void)
        memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
        memset(&BAT3_601, sizeof(BAT2), 0);
        /* map all of ram for kernel with segregs */
-       for (i = KERNELBASE;  i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
+       for (i = KERNELBASE;  i < KERNELBASE+res.TotalMemory;  i += PAGE_SIZE)
        {
                if ( i < (unsigned long)etext )
-                       map_page(&init_task.tss, i, __pa(i),
+                       map_page(&init_task, i, __pa(i),
                                 _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
                else
-                       map_page(&init_task.tss, i, __pa(i),
+                       map_page(&init_task, i, __pa(i),
                                 _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
        }
 #endif /* MAP_RAM_WITH_SEGREGS */
        
        printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
-              _TotalMemory >> 20, Hash_size >> 10, Hash);
-       return ((unsigned long *)_TotalMemory);
+              res.TotalMemory >> 20, Hash_size >> 10, Hash);
+       return ((unsigned long *)res.TotalMemory);
 }
-#endif /* CONFIG_PREP */
 
 
-#ifdef CONFIG_PMAC
 /*
  * Map in all of physical memory starting at KERNELBASE.
  */
@@ -854,7 +816,10 @@ static void mapin_ram()
            f = _PAGE_PRESENT | _PAGE_ACCESSED;
            if ((char *) v < _stext || (char *) v >= etext)
                f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-           map_page(&init_task.tss, v, p, f);
+           else
+               /* On the powerpc, no user access forces R/W kernel access */
+               f |= _PAGE_USER;
+           map_page(&init_task, v, p, f);
            v += PAGE_SIZE;
            p += PAGE_SIZE;
        }
@@ -889,7 +854,7 @@ static void inherit_prom_translations()
 
        for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
                /* ignore stuff mapped down low */
-               if (tp->virt < 0x10000000)
+               if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
                        continue;
                /* map PPC mmu flags to linux mm flags */
                f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
@@ -900,13 +865,12 @@ static void inherit_prom_translations()
                p = tp->phys;
                n = tp->size;
                for (; n != 0; n -= PAGE_SIZE) {
-                       map_page(&init_task.tss, v, p, f);
+                       map_page(&init_task, v, p, f);
                        v += PAGE_SIZE;
                        p += PAGE_SIZE;
                }
        }
 }
-#endif
 
 /*
  * Initialize the hash table and patch the instructions in head.S.
@@ -943,8 +907,8 @@ static void hash_init(void)
         * out from the data cache and invalidated in the instruction
         * cache, on those machines with split caches.
         */
-       store_cache_range((unsigned long) hash_page_patch_A,
-                         (unsigned long) (hash_page_patch_C + 1));
+       flush_icache_range((unsigned long) hash_page_patch_A,
+                          (unsigned long) (hash_page_patch_C + 1));
 }
 
 
@@ -958,71 +922,74 @@ static void hash_init(void)
 void
 MMU_init(void)
 {
-        end_of_DRAM = find_end_of_memory();
+       if ( _machine == _MACH_Pmac )
+               end_of_DRAM = pmac_find_end_of_memory();
+       else /* prep */
+               end_of_DRAM = prep_find_end_of_memory();
+               
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#ifdef CONFIG_PMAC
-        /* Force initial page tables */
-       /* this done by INIT_TSS in processor.h on prep -- Cort */
-        init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
-
-       /* Map in all of RAM starting at KERNELBASE */
-       mapin_ram();
-       /* Copy mappings from the prom */
-       inherit_prom_translations();
-#endif /* CONFIG_PMAC */
+
+       if ( _machine == _MACH_Pmac )
+       {
+               /* Map in all of RAM starting at KERNELBASE */
+               mapin_ram();
+               /* Copy mappings from the prom */
+               inherit_prom_translations();
+       }
 }
 
 static void *
 MMU_get_page()
 {
-  void *p;
-  
-  if (mem_init_done) {
-    p = (void *) __get_free_page(GFP_KERNEL);
-    if (p == 0)
-      panic("couldn't get a page in MMU_get_page");
-  } else {
-#ifdef CONFIG_PREP
-    mmu_pages_count++;
-    if ( mmu_pages_count > MAX_MMU_PAGES )
-      printk("out of mmu pages!\n");
-    p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
-               (mmu_pages_count+PAGE_SIZE));
-#endif
-#ifdef CONFIG_PMAC
-    p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
-#endif
-  }
-  memset(p, 0, PAGE_SIZE);
-  return p;
+       void *p;
+
+       if (mem_init_done) {
+               p = (void *) __get_free_page(GFP_KERNEL);
+               if (p == 0)
+                       panic("couldn't get a page in MMU_get_page");
+       } else {
+               if ( is_prep )
+               {
+                       mmu_pages_count++;
+                       if ( mmu_pages_count > MAX_MMU_PAGES )
+                               printk("out of mmu pages!\n");
+                       p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+                                   (mmu_pages_count+PAGE_SIZE));
+               }
+               else /* pmac */
+               {
+                       p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+               }
+       }
+       memset(p, 0, PAGE_SIZE);
+       return p;
 }
 
-#ifdef CONFIG_PMAC
 void *
 ioremap(unsigned long addr, unsigned long size)
 {
        unsigned long p, end = addr + size;
 
        for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
-               map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+               map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
        return (void *) addr;
 }
-#endif
 
 void
-map_page(struct thread_struct *tss, unsigned long va,
+map_page(struct task_struct *tsk, unsigned long va,
         unsigned long pa, int flags)
 {
        pmd_t *pd;
        pte_t *pg;
+       
 
-       if (tss->pg_tables == NULL) {
+       if (tsk->mm->pgd == NULL) {
                /* Allocate upper level page map */
-               tss->pg_tables = (unsigned long *) MMU_get_page();
+               tsk->mm->pgd = (pgd_t *) MMU_get_page();
        }
        /* Use upper 10 bits of VA to index the first level map */
-       pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+       pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
        if (pmd_none(*pd)) {
                /* Need to allocate second-level table */
                pg = (pte_t *) MMU_get_page();
@@ -1084,26 +1051,6 @@ flush_tlb_mm(struct mm_struct *mm)
        }
 }
 
-
-void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-       unsigned vsid;
-       
-       if ( vmaddr < TASK_SIZE) {
-               /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
-               flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
-               /* this is needed on prep at the moment -- don't know why
-                  -- Cort*/
-               MMU_invalidate_page(vma->vm_mm,vmaddr);
-       }
-       else
-       {
-               /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
-       }
-}
-
-
 /* for each page addr in the range, call MMU_invalidate_page()
    if the range is very large and the hash table is small it might be faster to
    do a search of the hash table and just invalidate pages that are in the range
@@ -1113,15 +1060,10 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 void
 flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-        start &= PAGE_MASK;
+       start &= PAGE_MASK;
        for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
        {
-               /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
-                               start );*/
                flush_hash_page(mm->context, start);
-               /* this is needed on prep at the moment -- don't know why
-                  -- Cort*/
-               MMU_invalidate_page(mm,start);
        }
 }
 
@@ -1135,78 +1077,17 @@ void
 mmu_context_overflow(void)
 {
        struct task_struct *tsk;
-       int nr;
 
-       printk(KERN_INFO "mmu_context_overflow\n");
-       for (nr = 0; nr < NR_TASKS; ++nr) {
-               tsk = task[nr];
-               if (tsk && tsk->mm)
+       printk(KERN_DEBUG "mmu_context_overflow\n");
+       read_lock(&tasklist_lock);
+       for_each_task(tsk) {
+               if (tsk->mm)
                        tsk->mm->context = NO_CONTEXT;
        }
+       read_unlock(&tasklist_lock);
        flush_hash_segments(0x10, 0xffffff);
-       _tlbia();
        next_mmu_context = 0;
-}
-
-#ifdef CONFIG_PREP
-/*
- * it's not a simple matter to get rid of these and switch to the
- * ones paul is using. it will take some time and thought  -- Cort
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
-{
-       int hash, page_index, segment, i, h, _h, api, vsid, perms;
-       PTE *_pte, *slot;
-       int flags = 0;
-       page_index = ((int)va & 0x0FFFF000) >> 12;
-       segment = (unsigned int)va >> 28;
-       api = page_index >> 10;
-       vsid = VSID_FROM_CONTEXT(segment,mm->context);
-       for (_h = 0;  _h < 2;  _h++)
-       {
-               hash = page_index ^ vsid;               
-               if (_h)
-               {
-                       hash = ~hash;  /* Secondary hash uses ones-complement */
-               }
-               hash &= 0x3FF | (Hash_mask /*<< 10*/);
-               hash *= 8;  /* Eight entries / hash bucket */
-               _pte = &Hash[hash];
-               for (i = 0;  i < 8;  i++, _pte++)
-               {
-                       if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-                       { /* Found it! */
-                               _tlbie(va); /* Clear TLB */
-                               if (_pte->r) flags |= _PAGE_ACCESSED;
-                               if (_pte->c) flags |= _PAGE_DIRTY;
-                               _pte->v = 0;
-                               return /*(flags)*/;
-                       }
-               }
-       }
-       _tlbie(va);
-       return /*(flags)*/;
-}
-#endif
-
-#include <asm/mmu.h>
-void print_mm_info(void)
-{
-       struct _SEGREG s;
-       long a;
-       struct _BATU bu;
-       struct _BATL bl;
-       unsigned long i;
-
-       for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
-       {
-               a = get_SR(i);
-               memcpy(&s,&a,4);
-               printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x  %x\n",
-                      i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
-       }
-
-       asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
-       printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
-                      bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
+       /* make sure current always has a context */
+       current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+       set_context(current->mm->context);
 }
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
new file mode 100644 (file)
index 0000000..5f34efc
--- /dev/null
@@ -0,0 +1,274 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_NATIVE=y
+CONFIG_PMAC=y
+# CONFIG_PREP is not set
+CONFIG_MCOMMON=y
+# CONFIG_M601 is not set
+# CONFIG_M603 is not set
+# CONFIG_M604 is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_XMON=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_QLOGIC_PMAC=m
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+CONFIG_NET_IPIP=m
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+CONFIG_INET_RARP=y
+CONFIG_PATH_MTU_DISCOVERY=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACE=y
+CONFIG_DEC_ELCP=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+# CONFIG_CS4232 is not set
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CONFIG_LOWLEVEL_SOUND=y
+# CONFIG_ACI_MIXER is not set
+# CONFIG_AWE32_SYNTH is not set
+# CONFIG_AEDSP16 is not set
+CONFIG_AWACS=y
index bd955c7515cb4cd426be8dc7eec37609be963ba0..a0b37564de45ad45c560e6ada5482a668b62726c 100644 (file)
@@ -1,30 +1,31 @@
 #
 # Automatically generated by make menuconfig: don't edit
 #
+
+#
+# Platform support
+#
 CONFIG_NATIVE=y
 # CONFIG_PMAC is not set
 CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
 CONFIG_MCOMMON=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
 
 #
 # Plug and Play support
@@ -46,10 +47,10 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -100,7 +101,6 @@ CONFIG_SCSI_NCR53C7xx=y
 # CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
 
 #
 # Network device support
@@ -117,6 +117,7 @@ CONFIG_INET=y
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 CONFIG_PATH_MTU_DISCOVERY=y
@@ -155,6 +156,7 @@ CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
 # CONFIG_ES3210 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
@@ -183,16 +185,13 @@ CONFIG_PPP=y
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -205,7 +204,6 @@ CONFIG_ISO9660_FS=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
 
 #
 # Character devices
@@ -213,12 +211,7 @@ CONFIG_HFS_FS=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
@@ -227,13 +220,39 @@ CONFIG_MOUSE=y
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds
new file mode 100644 (file)
index 0000000..f584839
--- /dev/null
@@ -0,0 +1,80 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .rel.text      : { *(.rel.text)              }
+  .rela.text     : { *(.rela.text)     }
+  .rel.data      : { *(.rel.data)              }
+  .rela.data     : { *(.rela.data)     }
+  .rel.rodata    : { *(.rel.rodata)    }
+  .rela.rodata   : { *(.rela.rodata)   }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+/*  .init          : { *(.init)        } =0*/
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+
index 55a778ed792adbbf6fb5377f97a71f73aad09b06..8bd67e530ead6ed424774467d3bfa0d37afe5b0f 100644 (file)
@@ -455,7 +455,8 @@ static inline int aplib_poll(unsigned counter)
 
        while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
                tnet_check_completion();
-               if (need_resched) break;
+               if (resched_needed())
+                       break;
                if (current->signal & ~current->blocked) break;
        }
        return 0;
index 84ef7f28e2888b32880f99781614c72d497b1224..3465e311b5049dda604c2e690ac0ebc4028a0080 100644 (file)
@@ -28,7 +28,7 @@ static int last_task = 0;
 void mpp_schedule(struct cap_request *req)
 {
        mpp_current_task = req->data[0];
-       need_resched = 1;
+       resched_force();
        mark_bh(TQUEUE_BH);
 }
 
index 242df954c5e22616f11c45eac58c2e50d7ab2505..fc8aaf6e5ac9720ce5ef9dcad960ea146d339d34 100644 (file)
@@ -338,7 +338,7 @@ static inline void qbmful_interrupt(void)
 #endif
                MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
                intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
-               need_resched = 1;
+               resched_force();
                block_parallel_tasks = 1;
                mark_bh(TQUEUE_BH);
        }
index 14a29ae7a0c16862edcf342d9a50f55e1c36430f..293be0d5b02de6fc7e3c4aff703fbf23354ec1de 100644 (file)
@@ -613,7 +613,7 @@ void tnet_send_ip(int cid,struct sk_buff *skb)
 
 static void reschedule(void)
 {
-       need_resched = 1;  
+       resched_force();
        mark_bh(TQUEUE_BH);
 }
 
index 80e1145854f38b7801fc76dcb24f48515fd7e470..434d95d2bf44567bf5d75b098d76b3446277c245 100644 (file)
@@ -49,6 +49,7 @@ SUN_FB_CREATOR=y
 #
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 
@@ -105,6 +106,7 @@ CONFIG_IP_MASQUERADE=y
 CONFIG_IP_ALIAS=m
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -184,7 +186,7 @@ CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
@@ -207,6 +209,7 @@ CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Kernel hacking
index 95eed628720b3dbf6ea031ab27be00f85e286120..c86c3b575fe4a19fbc5d1152193fe4e9487d0232 100644 (file)
@@ -105,6 +105,8 @@ out:
 /* This is being executed in task 0 'user space'. */
 int cpu_idle(void *unused)
 {
+       extern volatile int smp_commenced;
+
        current->priority = -100;
        while(1) {
                /*
@@ -118,7 +120,8 @@ int cpu_idle(void *unused)
                }
                /* endless idle loop with no priority at all */
                current->counter = -100;
-               schedule();
+               if(!smp_commenced || resched_needed())
+                       schedule();
        }
 }
 
index 732b3006dd67b96fd578be3edc7a44c1bceb2614..933a5acfa74acf95abf82307fa3487fda2629289 100644 (file)
@@ -886,7 +886,7 @@ asmlinkage void syscall_trace(void)
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
        current->tss.flags ^= MAGIC_CONSTANT;
-       notify_parent(current);
+       notify_parent(current, SIGCHLD);
        schedule();
        /*
         * this isn't the same as continuing with a signal, but it will do
index d8d1601141df7d0be43f2f00da840848005056ed..8d46d487edd3b4017656ca7c7423b9869a41b355 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $
+/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -65,12 +65,14 @@ C_LABEL(ret_trap_lockless_ipi):
 
        wr      %t_psr, 0x0, %psr
        b       ret_trap_kernel
-        nop
+        mov    1, %o0
 
 1:
+       ld      [%curptr + AOFF_task_processor], %o1
        ld      [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
+       sll     %o0, %o1, %o0
 
-       cmp     %g2, 0
+       andcc   %g2, %o0, %g0
        be      signal_p
         nop
 
index fd5fa634e35d4e2f3bb4ce580f980527b227fe25..fbb5578fa98a8e419654693861f97baedf8c89aa 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
+/*  $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -722,7 +722,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
                        /* This happens to be SMP safe so no need to
                         * grab master kernel lock even in this case.
                         */
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -773,7 +773,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
                                /* notify_parent() is SMP safe */
                                if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
                                     SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
index beef2df14037891d7b6572199a8bd20659bb2ead..17931fd558fd32bc68fa4353987a0614644df1e5 100644 (file)
@@ -87,7 +87,7 @@ volatile int smp_process_available=0;
 #define SMP_PRINTK(x)
 #endif
 
-static volatile int smp_commenced = 0;
+volatile int smp_commenced = 0;
 
 static char smp_buf[512];
 
@@ -558,7 +558,7 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
-       need_resched=1;
+       resched_force();
 }
 
 /* Running cross calls. */
@@ -623,7 +623,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
 
                        if(--current->counter < 0) {
                                current->counter = 0;
-                               need_resched = 1;
+                               resched_force();
                        }
 
                        spin_lock(&ticker_lock);
index f60ecbe9ca3f8d5598b1abd192d65b19b23ee624..2d067c458388bf6d7a10c626aa178580b6ad4845 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
+/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index ad9aa8953d248cf9019765d4cdbdbc93b5d98581..4cbf17f21fbfb68787bd64254b72e4e45cf3b9e9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
+/* $Id: srmmu.c,v 1.150 1997/07/25 23:06:17 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2601,7 +2601,7 @@ __initfunc(static void init_swift(void))
 }
 
 /* turbosparc.S */
-extern void turbosparc_flush_cache_all();
+extern void turbosparc_flush_cache_all(void);
 extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 
 static void poke_turbosparc(void)
index fcbac5c1aff084f03cc032b2c636d9f068ae0594..a3495ffe5667ce14fbb9b37cf8ce2a694acc442a 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
+# $Id: config.in,v 1.10 1997/08/11 14:35:45 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -43,6 +43,7 @@ else
        define_bool CONFIG_SUN_CONSOLE y
        define_bool CONFIG_SUN_AUXIO y
        define_bool CONFIG_SUN_IO y
+       define_bool CONFIG_PCI y
        source drivers/sbus/char/Config.in
 fi
 
index c9c92b9877b8589534ca6022ac97f6ed4e4b3d75..f2f4b1fc17154ee9c6944c6571d43915a050f0a3 100644 (file)
@@ -29,6 +29,7 @@ CONFIG_SUN_KEYBOARD=y
 CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
+CONFIG_PCI=y
 
 #
 # SBUS Frame Buffer support
@@ -49,6 +50,7 @@ SUN_FB_CREATOR=y
 #
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 CONFIG_SUN_OPENPROMFS=m
@@ -85,6 +87,7 @@ CONFIG_INET=y
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -187,6 +190,7 @@ CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Kernel hacking
index aecb9fd471b3c4cc06f4d79e85f4df2ce3d7e2f5..2b07a0e159fb3509a99e02ef99a2036718e0cb0d 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
+# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -29,9 +29,10 @@ all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 O_OBJS   := process.o setup.o cpu.o idprom.o \
-           systbls.o traps.o devices.o auxio.o ioport.o \
+           traps.o devices.o auxio.o ioport.o \
            irq.o ptrace.o time.o sys_sparc.o signal.o \
-           unaligned.o sys_sunos32.o sunos_ioctl32.o
+           unaligned.o sys_sunos32.o sunos_ioctl32.o \
+           central.o psycho.o ebus.o
 OX_OBJS  := sparc64_ksyms.o
 
 ifdef SMP
index 00e5f272295f95a3508dacf653ecc3f03723c51a..6c993825d7ba681d39d7538445b71d7c8fd4fef0 100644 (file)
@@ -3,15 +3,20 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/delay.h>
+
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
 #include <asm/sbus.h>
+#include <asm/ebus.h>
+#include <asm/fhc.h>
 
 /* Probe and map in the Auxiliary I/O register */
 unsigned char *auxio_register;
@@ -31,9 +36,32 @@ __initfunc(void auxio_probe(void))
         }
 
        if (!sdev) {
+#ifdef CONFIG_PCI
+               struct linux_ebus *ebus;
+               struct linux_ebus_device *edev = 0;
+
+               for_all_ebusdev(edev, ebus)
+                       if (!strcmp(edev->prom_name, "auxio"))
+                               break;
+
+               if (edev) {
+                       auxio_register = (unsigned char *)
+                               sparc_alloc_io(edev->regs[0].phys_addr, 0,
+                                              edev->regs[0].reg_size,
+                                              "auxiliaryIO",
+                                              edev->regs[0].which_io, 0x0);
+                       *(auxio_register) = 0x01;
+                       return;
+               }
+#endif
+               if(central_bus) {
+                       auxio_register = NULL;
+                       return;
+               }
                prom_printf("Cannot find auxio node, cannot continue...\n");
                prom_halt();
        }
+
        prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
        prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
        /* Map the register both read and write */
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
new file mode 100644 (file)
index 0000000..8973681
--- /dev/null
@@ -0,0 +1,131 @@
+/* $Id: central.c,v 1.3 1997/08/12 14:51:55 davem Exp $
+ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/fhc.h>
+
+struct linux_central *central_bus = NULL;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+       return ((addr + (sizeof(unsigned long) - 1)) &
+               ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_central_ranges_init(int cnode, struct linux_central *central);
+extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+
+unsigned long central_probe(unsigned long memory_start)
+{
+       struct linux_prom_registers fpregs[6];
+       struct linux_fhc *fhc;
+       char namebuf[128];
+       int cnode, fnode, err;
+
+       prom_printf("CENTRAL: ");
+       printk("CENTRAL: ");
+       cnode = prom_finddevice("/central");
+       if(cnode == 0 || cnode == -1) {
+               prom_printf("no central found.\n");
+               printk("no central found.\n");
+               return memory_start;
+       }
+       prom_printf("found central PROM node.\n");
+       printk("found central PROM node.\n");
+
+       /* Ok we got one, grab some memory for software state. */
+       memory_start = long_align(memory_start);
+       central_bus = (struct linux_central *) (memory_start);
+
+       prom_printf("CENTRAL: central_bus[%p] ", central_bus);
+       memory_start += sizeof(struct linux_central);
+       memory_start = long_align(memory_start);
+       fhc = (struct linux_fhc *)(memory_start);
+       memory_start += sizeof(struct linux_fhc);
+       memory_start = long_align(memory_start);
+
+       prom_printf("fhc[%p] ", fhc);
+
+       /* First init central. */
+       central_bus->child = fhc;
+       central_bus->prom_node = cnode;
+
+       prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
+       strcpy(central_bus->prom_name, namebuf);
+
+       prom_printf("init_central_ranges ");
+       prom_central_ranges_init(cnode, central_bus);
+
+       /* And then central's FHC. */
+       fhc->next = NULL;
+       fhc->parent = central_bus;
+       fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
+       if(fnode == 0 || fnode == -1) {
+               prom_printf("Critical error, central board lacks fhc.\n");
+               prom_halt();
+       }
+       fhc->prom_node = fnode;
+       prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
+       strcpy(fhc->prom_name, namebuf);
+
+       prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
+       prom_fhc_ranges_init(fnode, fhc);
+
+       /* Finally, map in FHC register set.  (From the prtconf dumps
+        * I have seen on Ex000 boxes only the central ranges need to
+        * be applied to the fhc internal register set) -DaveM
+        */
+       err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
+       if(err == -1) {
+               prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+               prom_halt();
+       }
+       prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+       prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
+                   "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
+                   fpregs[0].which_io, fpregs[0].phys_addr,
+                   fpregs[1].which_io, fpregs[1].phys_addr,
+                   fpregs[2].which_io, fpregs[2].phys_addr,
+                   fpregs[3].which_io, fpregs[3].phys_addr,
+                   fpregs[4].which_io, fpregs[4].phys_addr,
+                   fpregs[5].which_io, fpregs[5].phys_addr);
+       fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+               __va((((unsigned long)fpregs[0].which_io)<<32) |
+                    (((unsigned long)fpregs[0].phys_addr)));
+       fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+               __va((((unsigned long)fpregs[1].which_io)<<32) |
+                    (((unsigned long)fpregs[1].phys_addr)));
+       fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+               __va((((unsigned long)fpregs[2].which_io)<<32) |
+                    (((unsigned long)fpregs[2].phys_addr)));
+       fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+               __va((((unsigned long)fpregs[3].which_io)<<32) |
+                    (((unsigned long)fpregs[3].phys_addr)));
+       fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+               __va((((unsigned long)fpregs[4].which_io)<<32) |
+                    (((unsigned long)fpregs[4].phys_addr)));
+       fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+               __va((((unsigned long)fpregs[5].which_io)<<32) |
+                    (((unsigned long)fpregs[5].phys_addr)));
+       prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
+                   fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
+                   fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
+                   fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
+
+       prom_printf("CENTRAL: reading FHC_ID register... ");
+       err = fhc->fhc_regs.pregs->fhc_id;
+       prom_printf("VALUE[%x]\n", err);
+       printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+              ((err & FHC_ID_VERS) >> 28),
+              ((err & FHC_ID_PARTID) >> 12),
+              ((err & FHC_ID_MANUF) >> 1));
+
+       return memory_start;
+}
index 2c96a83e94d08a876aa6c78eebd3f6227db2c5e7..d009f39d8051554452a493535a8745edcc48e532 100644 (file)
@@ -46,8 +46,13 @@ struct cpu_iu_info linux_sparc_chips[] = {
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#ifdef __SMP__
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#else
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+#endif
 
 unsigned int fsr_storage;
 
index 9327058a80b9695ec5959b051e9d6076e3bfd550..24ca3ff100ac65021fc64e57a92c3ddbb73ae157 100644 (file)
@@ -17,13 +17,14 @@ struct prom_cpuinfo linux_cpus[NR_CPUS];
 int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
+extern unsigned long central_probe(unsigned long);
 
 __initfunc(unsigned long
 device_scan(unsigned long mem_start))
 {
        char node_str[128];
        int nd, prom_node_cpu, thismid;
-       int cpu_nds[NCPUS];  /* One node for each cpu */
+       int cpu_nds[NR_CPUS];  /* One node for each cpu */
        int cpu_ctr = 0;
 
        prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
@@ -43,11 +44,14 @@ device_scan(unsigned long mem_start))
                        if(strcmp(node_str, "cpu") == 0) {
                                cpu_nds[cpu_ctr] = scan;
                                linux_cpus[cpu_ctr].prom_node = scan;
-                               prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+                               prom_getproperty(scan, "upa-portid",
+                                                (char *) &thismid, sizeof(thismid));
                                linux_cpus[cpu_ctr].mid = thismid;
                                prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
                                            cpu_ctr, (unsigned) scan,
                                            thismid);
+                               printk("Found CPU %d <node=%08x,mid=%d>\n",
+                                      cpu_ctr, (unsigned) scan, thismid);
                                cpu_ctr++;
                        }
                };
@@ -62,5 +66,5 @@ device_scan(unsigned long mem_start))
        linux_num_cpus = cpu_ctr;
 
        cpu_probe();
-       return mem_start;
+       return central_probe(mem_start);
 }
index b034ef407e5ac51fc61b6c95c4b8a50fc9e5b72a..04efb1cec33d8485726b71a31bb9a49e81ba69cc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
+/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
  * dtlb_miss.S:        Data TLB miss code, this is included directly
  *              into the trap table.
  *
@@ -62,7 +62,7 @@
   /*0x40*/     sllx            %g1, 22, %g5                    ! This is now physical page + PAGE_OFFSET
   /*0x44*/     brgez,pn        %g5, 4f                         ! If >= 0, then walk down page tables
   /*0x48*/      sethi          %uhi(KERN_HIGHBITS), %g1        ! Construct PTE ^ PAGE_OFFSET
-  /*0x4c*/     andcc           %g3, 0x80, %g0                  ! Slick trick...
+  /*0x4c*/     andcc           %g3, 0x400, %g0                 ! Slick trick...
   /*0x50*/     sllx            %g1, 32, %g1                    ! Move high bits up
   /*0x54*/     or              %g1, (KERN_LOWBITS), %g1        ! Assume not IO
   /*0x58*/     bne,a,pn        %icc, 5f                        ! Is it an IO page?
index 2cf372ca916e136dfe89c3fa631febcb91697446..55e86c887a677c00008af7bb9e15fb29305e701b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
+/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
  * dtlb_prot.S:        Data TLB protection code, this is included directly
  *              into the trap table.
  *
                                /* ICACHE line 3 */
   /*0x40*/     add             %g2, 7, %g5                             ! Compute mask
   /*0x44*/     andn            %g4, %g5, %g4                           ! Mask page
-  /*0x48*/     or              %g4, 0x10, %g4                          ! 2ndary Context
-  /*0x4c*/     stxa            %g0, [%g4] ASI_DMMU_DEMAP               ! TLB flush page
-  /*0x50*/     membar          #Sync                                   ! Synchronize
-  /*0x54*/     stxa            %g3, [%g1] ASI_PHYS_USE_EC              ! Update sw PTE
-  /*0x58*/     stxa            %g3, [%g0] ASI_DTLB_DATA_IN             ! TLB load
-  /*0x5c*/     retry                                                   ! Trap return
+  /*0x48*/     mov             TLB_SFSR, %g5                           ! read SFSR
+  /*0x4c*/     ldxa            [%g5] ASI_DMMU, %g5                     ! from DMMU for
+  /*0x50*/     and             %g5, 0x10, %g5                          ! context bit
+  /*0x54*/     or              %g4, %g5, %g4                           ! for prot trap
+1:/*0x58*/     stxa            %g0, [%g4] ASI_DMMU_DEMAP               ! TLB flush page
+  /*0x5c*/     membar          #Sync                                   ! Synchronize
 
                                /* ICACHE line 4 */
-  /*0x60*/     nop
-  /*0x64*/     nop
-  /*0x68*/     nop
+  /*0x60*/     stxa            %g3, [%g1] ASI_PHYS_USE_EC              ! Update sw PTE
+  /*0x64*/     stxa            %g3, [%g0] ASI_DTLB_DATA_IN             ! TLB load
+  /*0x68*/     retry                                                   ! Trap return
   /*0x6c*/     nop
   /*0x70*/     nop
   /*0x74*/     nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
new file mode 100644 (file)
index 0000000..2fd384d
--- /dev/null
@@ -0,0 +1,169 @@
+/* $Id: ebus.c,v 1.2 1997/08/15 06:44:13 davem Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+struct linux_ebus *ebus_chain = 0;
+
+static char lbuf[128];
+
+extern void prom_ebus_ranges_init(struct linux_ebus *);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+{
+       int irqs[PROMINTR_MAX];
+       int i, len;
+
+       dev->prom_node = node;
+       prom_getstring(node, "name", lbuf, sizeof(lbuf));
+       strcpy(dev->prom_name, lbuf);
+
+       len = prom_getproperty(node, "reg", (void *)dev->regs,
+                              sizeof(dev->regs));
+       if (len % sizeof(struct linux_prom_registers)) {
+               prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+                           dev->prom_name, len,
+                           (int)sizeof(struct linux_prom_registers));
+               panic(__FUNCTION__);
+       }
+       dev->num_registers = len / sizeof(struct linux_prom_registers);
+
+       prom_apply_ebus_ranges(dev->parent, dev->regs, dev->num_registers);
+#if 0 /* XXX No longer exists/needed in new framework... */
+       prom_apply_pbm_ranges(dev->parent->parent, dev->regs,
+                             dev->num_registers);
+#endif
+
+       len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+       if ((len == -1) || (len == 0)) {
+               dev->irqs[0].pri = 0;
+               dev->num_irqs = 0;
+       } else {
+               dev->num_irqs = len / sizeof(irqs[0]);
+               for (i = 0; i < dev->num_irqs; i++)
+                       dev->irqs[i].pri = irqs[i];
+       }
+
+       printk("Found '%s' at %x.%08x", dev->prom_name,
+              dev->regs[0].which_io, dev->regs[0].phys_addr);
+       if (dev->num_irqs) {
+               printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+               for (i = 0; i < dev->num_irqs; i++)
+                       printk(" %03x", dev->irqs[i].pri);
+       }
+       printk("\n");
+}
+
+__initfunc(unsigned long ebus_init(unsigned long memory_start,
+                                  unsigned long memory_end))
+{
+       struct linux_ebus_device *dev;
+       struct linux_ebus *ebus;
+       int nd, ebusnd, topnd;
+       int num_ebus = 0;
+
+#ifndef CONFIG_PCI
+       return memory_start;
+#endif
+
+       memory_start = ((memory_start + 7) & (~7));
+
+       topnd = psycho_root->pbm_B.prom_node;
+       if (!topnd)
+               return memory_start;
+
+       ebusnd = prom_searchsiblings(prom_getchild(topnd), "ebus");
+       if (ebusnd == 0) {
+               printk("EBUS: No EBUS's found.\n");
+               return memory_start;
+       }
+
+       ebus_chain = ebus = (struct linux_ebus *)memory_start;
+       memory_start += sizeof(struct linux_ebus);
+       ebus->next = 0;
+
+       while (ebusnd) {
+               printk("ebus%d: ", num_ebus);
+
+               prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+               ebus->prom_node = ebusnd;
+               strcpy(ebus->prom_name, lbuf);
+               ebus->parent = &psycho_root->pbm_B;
+
+               prom_ebus_ranges_init(ebus);
+
+               nd = prom_getchild(ebusnd);
+               ebus->devices = (struct linux_ebus_device *)memory_start;
+               memory_start += sizeof(struct linux_ebus_device);
+
+               dev = ebus->devices;
+               dev->next = 0;
+               dev->parent = ebus;
+               fill_ebus_device(nd, dev);
+
+               while ((nd = prom_getsibling(nd))) {
+                       dev->next = (struct linux_ebus_device *)memory_start;
+                       memory_start += sizeof(struct linux_ebus_device);
+
+                       dev = dev->next;
+                       dev->next = 0;
+                       dev->parent = ebus;
+                       fill_ebus_device(nd, dev);
+               }
+
+               ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
+               ++num_ebus;
+       }
+
+#ifdef CONFIG_SUN_OPENPROMIO
+       openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+       rtc_init();
+#endif
+#ifdef CONFIG_SPARCAUDIO
+       sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+       bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+       if (sparc_cpu_model == sun4u)
+               auxio_probe();
+#endif
+#ifdef __sparc_v9__
+       if (sparc_cpu_model == sun4u) {
+               extern void sun4u_start_timers(void);
+               extern void clock_probe(void);
+
+               sun4u_start_timers();
+               clock_probe();
+       }
+#endif
+       return memory_start;
+}
index 425c2d873c85914a3945da2982a3607a201b059e..23b4b20f2aebbff89569f8e7ddbbc6b75fce65e3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
+/* $Id: entry.S,v 1.61 1997/08/15 06:44:16 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -50,41 +50,39 @@ sparc64_dtlb_prot_catch:
 
        bgu,a,pn        %icc, winfix_trampoline
         rdpr           %tpc, %g3
+       sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
        b,pt            %xcc, 1f
         mov            1, %o2
+       .align          32
 sparc64_dtlb_refbit_catch:
        srlx            %g5, 9, %g4
        and             %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-
        cmp             %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
        be,a,pt         %xcc, 2f
         mov            1, %g4
        wr              %g0, ASI_DMMU, %asi
        rdpr            %pstate, %g1
        wrpr            %g1, PSTATE_AG|PSTATE_MG, %pstate
+
        rdpr            %tl, %g3
        ldxa            [%g0 + TLB_TAG_ACCESS] %asi, %g5
-
        cmp             %g3, 1
        bgu,pn          %icc, winfix_trampoline
         rdpr           %tpc, %g3
+       sethi           %hi(109f), %g7
        b,pt            %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
+
        clr             %o2
 1:     srlx            %l5, PAGE_SHIFT, %o1
        add             %sp, STACK_BIAS + REGWIN_SZ, %o0
-
        call            do_sparc64_fault
         sllx           %o1, PAGE_SHIFT, %o1
        b,pt            %xcc, rtrap
         clr            %l6
-       nop
-       nop
-       nop
-       nop
-
+       .align          32
 sparc64_itlb_refbit_catch:
        srlx            %g5, 9, %g4
        and             %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
@@ -95,17 +93,21 @@ sparc64_itlb_refbit_catch:
        wrpr            %g1, PSTATE_AG|PSTATE_MG, %pstate
        rdpr            %tpc, %g5
 
+       sethi           %hi(109f), %g7
        b,pt            %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
        b,pt            %xcc, 1b
         clr            %o2
+
+       .align          32
 2:     sllx            %g4, 63, %g4                            ! _PAGE_VALID
        or              %g5, _PAGE_ACCESSED, %g5
        or              %g5, %g4, %g5
        stxa            %g5, [%g3 + %g1] ASI_PHYS_USE_EC        ! store new PTE
-
        stxa            %g5, [%g0] ASI_DTLB_DATA_IN             ! TLB load
        retry
+
+       .align          32
 3:     sllx            %g4, 63, %g4                            ! _PAGE_VALID
        or              %g5, _PAGE_ACCESSED, %g5
        or              %g5, %g4, %g5
@@ -172,6 +174,7 @@ fpload_fromkstk:
        or              %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
        add             %g6, %g2, %g2
        mov             SECONDARY_CONTEXT, %g3
+       ldxa            [%g3] ASI_DMMU, %g7
        stxa            %g0, [%g3] ASI_DMMU
        flush           %g2
        wr              %g0, ASI_BLK_S, %asi    ! grrr, where is ASI_BLK_NUCLEUS 8-(
@@ -182,9 +185,12 @@ fpload_fromkstk:
        ldda            [%g2 + 0x080] %asi, %f32
        ldda            [%g2 + 0x0c0] %asi, %f48
        ldx             [%g2 + 0x100], %fsr
-       ldx             [%g2 + 0x108], %g2
+       ldx             [%g2 + 0x108], %g4
        membar          #Sync
-       wr              %g2, 0, %gsr
+       wr              %g4, 0, %gsr
+
+       stxa            %g7, [%g3] ASI_DMMU
+       flush           %g2
 fpdis_exit:
        rdpr            %tstate, %g3
        sethi           %hi(TSTATE_PEF), %g4
@@ -192,10 +198,7 @@ fpdis_exit:
        wrpr            %g3, %tstate
        retry
 
-#ifdef __SMP__
-       /* Note check out head.h, this code isn't even used for UP,
-        * for SMP things will be different.  In particular the data
-        * registers for cross calls will be:
+       /* The registers for cross calls will be:
         *
         * DATA 0: [low 32-bits]  Address of function to call, jmp to this
         *         [high 32-bits] MMU Context Argument 0, place in %g5
@@ -205,11 +208,17 @@ fpdis_exit:
         * With this method we can do most of the cross-call tlb/cache
         * flushing very quickly.
         */
+       .data
+       .align  8
+       .globl  ivec_spurious_cookie
+ivec_spurious_cookie:  .xword  0
+
+       .text
        .align  32
-       .globl  do_ivec, do_ivec_return
+       .globl  do_ivec
 do_ivec:
-       ldxa            [%g0] ASI_INTR_RECEIVE, %g1
-       andcc           %g1, 0x20, %g0
+       ldxa            [%g0] ASI_INTR_RECEIVE, %g5
+       andcc           %g5, 0x20, %g0
        be,pn           %xcc, do_ivec_return
         mov            0x40, %g2
 
@@ -230,32 +239,35 @@ do_ivec:
         * which is completely harmless.
         */
        wr              %g2, 0x0, %set_softint
-
 do_ivec_return:
-       /* Acknowledge the UPA */
        stxa            %g0, [%g0] ASI_INTR_RECEIVE
        membar          #Sync
        retry
 do_ivec_xcall:
        srlx            %g3, 32, %g5
        add             %g2, 0x10, %g2
-       sra             %g3, 0, %g3
+       srl             %g3, 0, %g3
        ldxa            [%g2] ASI_UDB_INTR_R, %g6
        add             %g2, 0x10, %g2
+       ldxa            [%g2] ASI_UDB_INTR_R, %g7
+       stxa            %g0, [%g0] ASI_INTR_RECEIVE
        jmpl            %g3, %g0
-        ldxa           [%g2] ASI_UDB_INTR_R, %g7
+        membar         #Sync
 do_ivec_spurious:
+       srl             %g3, 3, %g3
+       sethi           %hi(ivec_spurious_cookie), %g2
+       stx             %g3, [%g2 + %lo(ivec_spurious_cookie)]
        stxa            %g0, [%g0] ASI_INTR_RECEIVE
        membar          #Sync
-       rdpr            %pstate, %g1
-       wrpr            %g1, PSTATE_IG | PSTATE_AG, %pstate
+       rdpr            %pstate, %g5
+       wrpr            %g5, PSTATE_IG | PSTATE_AG, %pstate
+       sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
        call            report_spurious_ivec
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
-#endif /* __SMP__ */
 
        .globl          getcc, setcc
 getcc:
@@ -359,8 +371,9 @@ floppy_overrun:
 floppy_dosoftint:
        rdpr            %pil, %g2
        wrpr            %g0, 15, %pil
+       sethi           %hi(109f), %g7
        b,pt            %xcc, etrap_irq
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
 
        mov             11, %o0
        mov             0, %o1
@@ -386,8 +399,9 @@ do_mna:
        cmp             %g3, 1
        bgu,a,pn        %icc, winfix_mna
         rdpr           %tpc, %g3
+       sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
        call            mem_address_unaligned
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
        ba,pt           %xcc, rtrap
@@ -573,14 +587,8 @@ sys_fork:
 sys_vfork:     mov             SIGCHLD, %o0
                clr             %o1
 sys_clone:     mov             %o7, %l5
-/*???*/                save            %sp, -REGWIN_SZ, %sp
-               flushw
-/*???*/                restore         %g0, %g0, %g0
-               rdpr            %cwp, %o4
                add             %sp, STACK_BIAS + REGWIN_SZ, %o2
-
                movrz           %o1, %fp, %o1
-               stx             %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
                call            do_fork
                 mov            %l5, %o7
 #ifdef __SMP__
@@ -611,9 +619,9 @@ linux_sparc_syscall:
        cmp             %g1, NR_SYSCALLS                        ! IEU1  Group
        bgeu,pn         %xcc, linux_sparc_ni_syscall            ! CTI
         mov            %i0, %o0                                ! IEU0
-       sll             %g1, 3, %l4                             ! IEU0  Group
+       sll             %g1, 2, %l4                             ! IEU0  Group
        mov             %i1, %o1                                ! IEU1
-       ld            [%l7 + %l4], %l7                        ! Load
+       lduw            [%l7 + %l4], %l7                        ! Load
 syscall_is_too_hard:
        mov             %i2, %o2                                ! IEU0  Group
        ldx             [%curptr + AOFF_task_flags], %l5        ! Load
index 4daf30e21babc0e500121e3112ea910ab46552bd..1cde7d9e9844c6c29976455eaa8536456709184b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
+/* $Id: etrap.S,v 1.34 1997/08/08 08:33:40 jj Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
 #define                TASK_REGOFF             ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
                                         TRACEREG_SZ-REGWIN_SZ)
 
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
+
                .text
                .align                  32
                .globl                  etrap, etrap_irq, etraptl1
@@ -111,18 +116,23 @@ etrap_save_fpu:   and                     %g3, FPRS_FEF, %g3
                membar                  #Sync
 
                sub                     %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
-2:             b,pt                    %xcc, etrap_after_fpu
+2:             bne,pn                  %xcc, etrap_after_fpu
                 wr                     %g0, 0, %fprs
-3:             /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */
-               mov                     SECONDARY_CONTEXT, %g3
+               ld                      [%g6 + AOFF_task_tss + AOFF_thread_ctx], %g3
+               wr                      %g0, ASI_DMMU, %asi
+               nop
+               stxa                    %g3, [%g0 + SECONDARY_CONTEXT] %asi
+               flush                   %g2
+
+               b,pt                    %xcc, etrap_after_fpu
+                nop
+3:             mov                     SECONDARY_CONTEXT, %g3
                stxa                    %g0, [%g3] ASI_DMMU
                flush                   %g2
                wr                      %g0, ASI_BLK_S, %asi
-               nop
-
                b,pt                    %xcc, 1b
                 mov                    FPRS_FEF, %g3
-               nop
+
 etraptl1:      rdpr                    %tstate, %g1
                sub                     %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
                ba,pt                   %xcc, etrap_maybe_fpu
index 0ed975aff584624370cecc559a61ed5fd625c649..43f950b2523119b34f3943d838cb9412d3fd1d64 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
+/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
 #include <asm/processor.h>
 #include <asm/lsu.h>
 #include <asm/head.h>
+#include <asm/ttable.h>
        
 /* This section from from _start to sparc64_boot_end should fit into
  * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
@@ -89,6 +90,28 @@ sparc64_boot:
          */
        wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
 
+#ifdef __SMP__
+       /* Ugly but necessary... */
+       sethi   %hi(KERNBASE), %g7
+       sethi   %hi(sparc64_cpu_startup), %g5
+       or      %g5, %lo(sparc64_cpu_startup), %g5
+       sub     %g5, %g7, %g5
+       sethi   %hi(sparc64_cpu_startup_end), %g6
+       or      %g6, %lo(sparc64_cpu_startup_end), %g6
+       sub     %g6, %g7, %g6
+       sethi   %hi(smp_trampoline), %g3
+       or      %g3, %lo(smp_trampoline), %g3
+       sub     %g3, %g7, %g3
+1:     ldx     [%g5], %g1
+       stx     %g1, [%g3]
+       membar  #StoreStore
+       flush   %g3
+       add     %g5, 8, %g5
+       cmp     %g5, %g6
+       blu,pt  %xcc, 1b
+        add    %g3, 8, %g3
+#endif
+
 create_mappings:
        /* %g5 holds the tlb data */
         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -340,7 +363,7 @@ setup_tba:
        mov     0x40, %g2                       /* INTR data 0 register */
 
        /* Ok, we're done setting up all the state our trap mechanims needs,
-        * now get back into normal globals and let the PROM know what it up.
+        * now get back into normal globals and let the PROM know what is up.
         */
        wrpr    %g0, %g0, %wstate
        wrpr    %o1, PSTATE_IE, %pstate
@@ -374,6 +397,7 @@ bootup_kernel_stack:
 ! 0x0000000000408000
 
 #include "ttable.S"
+#include "systbls.S"
 #include "etrap.S"
 #include "rtrap.S"
 #include "winfixup.S"
index 81eb45e4258943453f8be8a809e1d23a45e1c684..1ad3dc2ed500f6ae9b2ee6fdfc3725a464392630 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
+/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index 7d1580b397a2be95e50fad21c317c10bbff03fd4..b7bd7d4c682129b37d3e328909616f17f2dec446 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
+/* $Id: ioport.c,v 1.12 1997/08/08 05:07:02 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,7 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
                      u32 bus_type, int rdonly)
 {
        unsigned long vaddr, base_address;
-       unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+       unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
        unsigned long offset = (addr & (~PAGE_MASK));
 
        if (virtual) {
@@ -64,7 +64,12 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
                /* Tell Linux resource manager about the mapping */
                request_region ((vaddr | offset), len, name);
        } else {
-               return __va(addr);
+               unsigned long vaddr = (unsigned long) __va(addr);
+
+               if(!check_region(vaddr, len))
+                       request_region(vaddr, len, name);
+
+               return (void *) vaddr;
        }
 
        base_address = vaddr;
index f76c27c57ac6fbe850a08fbaba1c68e90ce41098..c6247eb22baf9ccb338ce9d96c766ffca7b9cf4c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
+/* $Id: irq.c,v 1.34 1997/08/15 06:44:18 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <asm/pbm.h>
+#endif
+
 /* Internal flag, should not be visible elsewhere at all. */
-#define SA_SYSIO_MASKED                0x100
+#define SA_IMAP_MASKED         0x100
+
+#ifdef __SMP__
+void distribute_irqs(void);
+static int irqs_have_been_distributed = 0;
+#endif
 
 /* UPA nodes send interrupt packet to UltraSparc with first data reg value
  * low 5 bits holding the IRQ identifier being delivered.  We must translate
  * make things even more swift we store the complete mask here.
  */
 
-#define NUM_IVECS      2048    /* XXX may need more on sunfire/wildfire */
+#define NUM_HARD_IVECS 2048
+#define NUM_IVECS      (NUM_HARD_IVECS + 64)   /* For SMP IRQ distribution alg. */
 
 unsigned long ivector_to_mask[NUM_IVECS];
 
+struct ino_bucket {
+       struct ino_bucket *next;
+       unsigned int ino;
+       unsigned int *imap;
+       unsigned int *iclr;
+};
+
+#define INO_HASHSZ     (NUM_HARD_IVECS >> 2)
+#define NUM_INO_STATIC 4
+static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
+static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
+static int static_ino_bucket_count = 0;
+
+static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
+{
+       struct ino_bucket *ret = ino_hash[hash];
+
+       for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
+               ;
+
+       return ret;
+}
+
+static inline struct ino_bucket *ino_lookup(unsigned int ino)
+{
+       return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
+}
+
 /* This is based upon code in the 32-bit Sparc kernel written mostly by
  * David Redman (djhr@tadpole.co.uk).
  */
@@ -76,12 +115,12 @@ int get_irq_list(char *buf)
        return len;
 }
 
-/* INO number to Sparc PIL level. */
-unsigned char ino_to_pil[] = {
-       0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 0 */
-       0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 1 */
-       0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 2 */
-       0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 3 */
+/* SBUS SYSIO INO number to Sparc PIL level. */
+unsigned char sysio_ino_to_pil[] = {
+       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 0 */
+       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 1 */
+       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 2 */
+       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 3 */
        3, /* Onboard SCSI */
        5, /* Onboard Ethernet */
 /*XXX*/        8, /* Onboard BPP */
@@ -112,7 +151,7 @@ unsigned char ino_to_pil[] = {
  */
 #define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
 #define bogon     ((unsigned long) -1)
-static unsigned long irq_offsets[] = {
+static unsigned long sysio_irq_offsets[] = {
 /* SBUS Slot 0 --> 3, level 1 --> 7 */
 offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
 offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
@@ -134,29 +173,29 @@ offset(imap_pmgmt),
 
 #undef bogon
 
-#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
 
-/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
- * Interrupt Mapping register pointer, or NULL if none exists.
+/* XXX Old compatability cruft, get rid of me when all drivers have been
+ * XXX converted to dcookie registry calls... -DaveM
  */
-static unsigned int *irq_to_imap(unsigned int irq)
+static unsigned int *sysio_irq_to_imap(unsigned int irq)
 {
        unsigned long offset;
        struct sysio_regs *sregs;
 
        if((irq == 14) ||
-          (irq >= NUM_IRQ_ENTRIES) ||
-          ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+          (irq >= NUM_SYSIO_OFFSETS) ||
+          ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
                return NULL;
        sregs = SBus_chain->iommu->sysio_regs;
        offset += ((unsigned long) sregs);
-       return ((unsigned int *)offset) + 1;
+       return ((unsigned int *)offset);
 }
 
 /* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer.
+ * Interrupt Clear register pointer, SYSIO specific version.
  */
-static unsigned int *imap_to_iclr(unsigned int *imap)
+static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
 {
        unsigned long diff;
 
@@ -166,32 +205,63 @@ static unsigned int *imap_to_iclr(unsigned int *imap)
 
 #undef offset
 
-/* For non-SBUS IRQ's we do nothing, else we must enable them in the
- * appropriate SYSIO interrupt map registers.
+#ifdef CONFIG_PCI
+/* PCI PSYCHO INO number to Sparc PIL level. */
+unsigned char psycho_ino_to_pil[] = {
+       7, 5, 5, 2,                     /* PCI A slot 0  Int A, B, C, D */
+       7, 5, 5, 2,                     /* PCI A slot 1  Int A, B, C, D */
+       0, 0, 0, 0,
+       0, 0, 0, 0,
+       6, 4, 3, 1,                     /* PCI B slot 0  Int A, B, C, D */
+       6, 4, 3, 1,                     /* PCI B slot 1  Int A, B, C, D */
+       6, 4, 3, 1,                     /* PCI B slot 2  Int A, B, C, D */
+       6, 4, 3, 1,                     /* PCI B slot 3  Int A, B, C, D */
+       3, /* SCSI */
+       3, /* Ethernet */
+       2, /* Parallel Port */
+       8, /* Audio Record */
+       7, /* Audio Playback */
+       8, /* PowerFail */
+       7, /* Keyboard/Mouse/Serial */
+       8, /* Floppy */
+       2, /* Spare Hardware */
+       4, /* Keyboard */
+       4, /* Mouse */
+       7, /* Serial */
+       6, /* Timer 0 */
+       6, /* Timer 1 */
+       8, /* Uncorrectable ECC */
+       8, /* Correctable ECC */
+       8, /* PCI Bus A Error */
+       7, /* PCI Bus B Error */
+       1, /* Power Management */
+};
+
+/* INO number to IMAP register offset for PSYCHO external IRQ's.
  */
-void enable_irq(unsigned int irq)
+#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
+
+#define psycho_imap_offset(ino)                                                        \
+       ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) :    \
+                       (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
+
+#define psycho_iclr_offset(ino)                                                        \
+       ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) :    \
+                       (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+
+#endif
+
+/* Now these are always passed a true fully specified sun4u INO. */
+void enable_irq(unsigned int ino)
 {
+       struct ino_bucket *bucket = ino_lookup(ino);
        unsigned long tid;
        unsigned int *imap;
 
-       /* If this is for the tick interrupt, just ignore, note
-        * that this is the one and only locally generated interrupt
-        * source, all others come from external sources (essentially
-        * any UPA device which is an interruptor).  (actually, on
-        * second thought Ultra can generate local interrupts for
-        * async memory errors and we may setup handlers for those
-        * at some point as well)
-        *
-        * XXX See commentary below in request_irq() this assumption
-        * XXX is broken and needs to be fixed.
-        */
-       if(irq == 14)
+       if(!bucket)
                return;
 
-       /* Check for bogons. */
-       imap = irq_to_imap(irq);
-       if(imap == NULL)
-               goto do_the_stb_watoosi;
+       imap = bucket->imap;
 
        /* We send it to our UPA MID, for SMP this will be different. */
        __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -202,28 +272,22 @@ void enable_irq(unsigned int irq)
         * Register, the hardware just mirrors that value here.
         * However for Graphics and UPA Slave devices the full
         * SYSIO_IMAP_INR field can be set by the programmer here.
-        * (XXX we will have to handle those for FFB etc. XXX)
+        *
+        * Things like FFB can now be handled via the dcookie mechanism.
         */
        *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
-       return;
-
-do_the_stb_watoosi:
-       printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
-       panic("Trying to enable bogon IRQ");
 }
 
-void disable_irq(unsigned int irq)
+/* This now gets passed true ino's as well. */
+void disable_irq(unsigned int ino)
 {
+       struct ino_bucket *bucket = ino_lookup(ino);
        unsigned int *imap;
 
-       /* XXX Grrr, I know this is broken... */
-       if(irq == 14)
+       if(!bucket)
                return;
 
-       /* Check for bogons. */
-       imap = irq_to_imap(irq);
-       if(imap == NULL)
-               goto do_the_stb_watoosi;
+       imap = bucket->imap;
 
        /* NOTE: We do not want to futz with the IRQ clear registers
         *       and move the state to IDLE, the SCSI code does call
@@ -231,34 +295,218 @@ void disable_irq(unsigned int irq)
         *       SCSI adapter driver code.  Thus we'd lose interrupts.
         */
        *imap &= ~(SYSIO_IMAP_VALID);
-       return;
+}
+
+static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
+                                unsigned int **imap, unsigned int **iclr,
+                                void *busp, unsigned long flags,
+                                unsigned int irq)
+{
+       if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
+               return;
 
-do_the_stb_watoosi:
-       printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
-       panic("Trying to enable bogon IRQ");
+       if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
+               printk("get_irq_translations: Partial specification, this is bad.\n");
+               printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
+                      *cpu_irq, *imap, *iclr, busp);
+               panic("Bad IRQ translations...");
+       }
+
+       if(SA_BUS(flags) == SA_SBUS) {
+               struct linux_sbus *sbusp = busp;
+               struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
+               unsigned long offset;
+
+               *cpu_irq = sysio_ino_to_pil[irq];
+               if(*cpu_irq == 0) {
+                       printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
+                       panic("Bad SYSIO IRQ translations...");
+               }
+               offset = sysio_irq_offsets[irq];
+               if(offset == ((unsigned long)-1)) {
+                       printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+                              irq, *cpu_irq);
+                       panic("BAD SYSIO IRQ offset...");
+               }
+               offset += ((unsigned long)sregs);
+               *imap = ((unsigned int *)offset);
+
+               /* SYSIO inconsistancy.  For external SLOTS, we have to select
+                * the right ICLR register based upon the lower SBUS irq level
+                * bits.
+                */
+               if(irq >= 0x20) {
+                       *iclr = sysio_imap_to_iclr(*imap);
+               } else {
+                       unsigned long iclraddr;
+                       int sbus_slot = (irq & 0x18)>>3;
+                       int sbus_level = irq & 0x7;
+
+                       switch(sbus_slot) {
+                       case 0:
+                               *iclr = &sregs->iclr_slot0;
+                               break;
+                       case 1:
+                               *iclr = &sregs->iclr_slot1;
+                               break;
+                       case 2:
+                               *iclr = &sregs->iclr_slot2;
+                               break;
+                       case 3:
+                               *iclr = &sregs->iclr_slot3;
+                               break;
+                       };
+
+                       iclraddr = (unsigned long) *iclr;
+                       iclraddr += ((sbus_level - 1) * 8);
+                       *iclr = (unsigned int *) iclraddr;
+
+#if 0 /* DEBUGGING */
+                       printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
+                              sbus_slot, sbus_level, *iclr);
+#endif
+
+                       /* Also, make sure this is accounted for in ivindex
+                        * computations done by the caller.
+                        */
+                       *ivindex_fixup = sbus_level;
+               }
+               return;
+       }
+#ifdef CONFIG_PCI
+       if(SA_BUS(flags) == SA_PCI) {
+               struct pci_bus *pbusp = busp;
+               struct linux_pbm_info *pbm = pbusp->sysdata;
+               struct psycho_regs *pregs = pbm->parent->psycho_regs;
+               unsigned long offset;
+
+               *cpu_irq = psycho_ino_to_pil[irq & 0x3f];
+               if(*cpu_irq == 0) {
+                       printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
+                       panic("Bad PSYCHO IRQ translations...");
+               }
+               offset = psycho_imap_offset(irq);
+               if(offset == ((unsigned long)-1)) {
+                       printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
+                              irq, *cpu_irq);
+                       panic("Bad PSYCHO IRQ offset...");
+               }
+               offset += ((unsigned long)pregs);
+               *imap = ((unsigned int *)offset) + 1;
+               *iclr = (unsigned int *)
+                       (((unsigned long)pregs) + psycho_imap_offset(irq));
+               return;
+       }
+#endif
+#if 0  /* XXX More to do before we can use this. -DaveM */
+       if(SA_BUS(flags) == SA_FHC) {
+               struct fhc_bus *fbusp = busp;
+               struct fhc_regs *fregs = fbusp->regs;
+               unsigned long offset;
+
+               *cpu_irq = fhc_ino_to_pil[irq];
+               if(*cpu_irq == 0) {
+                       printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
+                       panic("Bad FHC IRQ translations...");
+               }
+               offset = fhc_irq_offset[*cpu_irq];
+               if(offset == ((unsigned long)-1)) {
+                       printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
+                              irq, *cpu_irq);
+                       panic("Bad FHC IRQ offset...");
+               }
+               offset += ((unsigned long)pregs);
+               *imap = (((unsigned int *)offset)+1);
+               *iclr = fhc_imap_to_iclr(*imap);
+               return;
+       }
+#endif
+       printk("get_irq_translations: IRQ register for unknown bus type.\n");
+       printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
+              SA_BUS(flags), irq);
+       panic("Bad IRQ bus type...");
+}
+
+/* Once added, they are never removed. */
+static struct ino_bucket *add_ino_hash(unsigned int ivindex,
+                                      unsigned int *imap, unsigned int *iclr,
+                                      unsigned long flags)
+{
+       struct ino_bucket *new = NULL, **hashp;
+       unsigned int hash = (ivindex & (INO_HASHSZ - 1));
+
+       new = __ino_lookup(hash, ivindex);
+       if(new)
+               return new;
+       if(flags & SA_STATIC_ALLOC) {
+               if(static_ino_bucket_count < NUM_INO_STATIC)
+                       new = &static_ino_buckets[static_ino_bucket_count++];
+               else
+                       printk("Request for ino bucket SA_STATIC_ALLOC failed "
+                              "using kmalloc\n");
+       }
+       if(new == NULL)
+               new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
+       if(new) {
+               hashp = &ino_hash[hash];
+               new->imap = imap;
+               new->iclr = iclr;
+               new->ino  = ivindex;
+               new->next = *hashp;
+               *hashp = new;
+       }
+       return new;
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, const char *name, void *dev_cookie)
+               unsigned long irqflags, const char *name, void *dev_id)
 {
        struct irqaction *action, *tmp = NULL;
+       struct devid_cookie *dcookie = NULL;
+       struct ino_bucket *bucket = NULL;
        unsigned long flags;
-       unsigned int cpu_irq, *imap, *iclr;
+       unsigned int *imap, *iclr;
+       void *bus_id = NULL;
+       int ivindex, ivindex_fixup, cpu_irq = -1;
        
-       /* XXX This really is not the way to do it, the "right way"
-        * XXX is to have drivers set SA_SBUS or something like that
-        * XXX in irqflags and we base our decision here on whether
-        * XXX that flag bit is set or not.
-        */
-       if(irq == 14)
-               cpu_irq = irq;
-       else
-               cpu_irq = ino_to_pil[irq];
-
        if(!handler)
            return -EINVAL;
 
-       imap = irq_to_imap(irq);
+       imap = iclr = NULL;
+
+       ivindex_fixup = 0;
+       if(irqflags & SA_DCOOKIE) {
+               if(!dev_id) {
+                       printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+                       panic("Bogus irq registry.");
+               }
+               dcookie         = dev_id;
+               dev_id          = dcookie->real_dev_id;
+               cpu_irq         = dcookie->pil;
+               imap            = dcookie->imap;
+               iclr            = dcookie->iclr;
+               bus_id          = dcookie->bus_cookie;
+               get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+                                    &iclr, bus_id, irqflags, irq);
+       } else {
+               /* XXX NOTE: This code is maintained for compatability until I can
+                * XXX       verify that all drivers sparc64 will use are updated
+                * XXX       to use the new IRQ registry dcookie interface.  -DaveM
+                */
+               if(irq == 14)
+                       cpu_irq = irq;
+               else
+                       cpu_irq = sysio_ino_to_pil[irq];
+               imap = sysio_irq_to_imap(irq);
+               if(!imap) {
+                       printk("request_irq: BAD, null imap for old style "
+                              "irq registry IRQ[%x].\n", irq);
+                       panic("Bad IRQ registery...");
+               }
+               iclr = sysio_imap_to_iclr(imap);
+       }
+       ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+       ivindex += ivindex_fixup;
 
        action = *(cpu_irq + irq_action);
        if(action) {
@@ -297,52 +545,61 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
                return -ENOMEM;
        }
 
-       if(imap) {
-               int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+       bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+       if(!bucket) {
+               kfree(action);
+               restore_flags(flags);
+               return -ENOMEM;
+       }
 
-               ivector_to_mask[ivindex] = (1<<cpu_irq);
-               iclr = imap_to_iclr(imap);
-               action->mask = (unsigned long) iclr;
-               irqflags |= SA_SYSIO_MASKED;
-       } else {
-               action->mask = 0;
+       ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+       if(dcookie) {
+               dcookie->ret_ino = ivindex;
+               dcookie->ret_pil = cpu_irq;
        }
 
+       action->mask = (unsigned long) bucket;
        action->handler = handler;
-       action->flags = irqflags;
+       action->flags = irqflags | SA_IMAP_MASKED;
        action->name = name;
        action->next = NULL;
-       action->dev_id = dev_cookie;
+       action->dev_id = dev_id;
 
        if(tmp)
                tmp->next = action;
        else
                *(cpu_irq + irq_action) = action;
 
-       enable_irq(irq);
+       enable_irq(ivindex);
        restore_flags(flags);
+#ifdef __SMP__
+       if(irqs_have_been_distributed)
+               distribute_irqs();
+#endif
        return 0;
 }
 
-void free_irq(unsigned int irq, void *dev_cookie)
+void free_irq(unsigned int irq, void *dev_id)
 {
        struct irqaction *action;
        struct irqaction *tmp = NULL;
        unsigned long flags;
        unsigned int cpu_irq;
+       int ivindex = -1;
 
        if(irq == 14)
                cpu_irq = irq;
        else
-               cpu_irq = ino_to_pil[irq];
+               cpu_irq = sysio_ino_to_pil[irq];
        action = *(cpu_irq + irq_action);
        if(!action->handler) {
                printk("Freeing free IRQ %d\n", irq);
                return;
        }
-       if(dev_cookie) {
+       if(dev_id) {
                for( ; action; action = action->next) {
-                       if(action->dev_id == dev_cookie)
+                       if(action->dev_id == dev_id)
                                break;
                        tmp = action;
                }
@@ -351,7 +608,7 @@ void free_irq(unsigned int irq, void *dev_cookie)
                        return;
                }
        } else if(action->flags & SA_SHIRQ) {
-               printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+               printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
                return;
        }
 
@@ -367,29 +624,37 @@ void free_irq(unsigned int irq, void *dev_cookie)
        else
                *(cpu_irq + irq_action) = action->next;
 
-       if(action->flags & SA_SYSIO_MASKED) {
-               unsigned int *imap = irq_to_imap(irq);
-               if(imap != NULL)
-                       ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+       if(action->flags & SA_IMAP_MASKED) {
+               struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+               unsigned int *imap = bucket->imap;
+
+               if(imap != NULL) {
+                       ivindex = bucket->ino;
+                       ivector_to_mask[ivindex] = 0;
+               }
                else
                        printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
        }
 
        kfree(action);
-       if(!*(cpu_irq + irq_action))
-               disable_irq(irq);
+       if(ivindex != -1)
+               disable_irq(ivindex);
 
        restore_flags(flags);
 }
 
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
-unsigned int local_irq_count[NR_CPUS];
+/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
+ * structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned int local_irq_count;
+#endif
 
 #ifndef __SMP__
 int __sparc64_bh_counter = 0;
 
-#define irq_enter(cpu, irq)    (local_irq_count[cpu]++)
-#define irq_exit(cpu, irq)     (local_irq_count[cpu]--)
+#define irq_enter(cpu, irq)    (local_irq_count++)
+#define irq_exit(cpu, irq)     (local_irq_count--)
 
 #else
 
@@ -407,18 +672,31 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
 /* Global IRQ locking depth. */
 atomic_t global_irq_count = ATOMIC_INIT(0);
 
-static inline void wait_on_irq(int cpu)
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
 {
-       int local_count = local_irq_count[cpu];
+       int stuck = INIT_STUCK;
+       int local_count = local_irq_count;
 
        while(local_count != atomic_read(&global_irq_count)) {
                atomic_sub(local_count, &global_irq_count);
                spin_unlock(&global_irq_lock);
                for(;;) {
+                       STUCK;
+                       membar("#StoreLoad | #LoadLoad");
                        if (atomic_read(&global_irq_count))
                                continue;
-                       if (*((unsigned char *)&global_irq_lock))
+                       if (*((volatile unsigned char *)&global_irq_lock))
                                continue;
+                       membar("#LoadLoad | #LoadStore");
                        if (spin_trylock(&global_irq_lock))
                                break;
                }
@@ -426,25 +704,41 @@ static inline void wait_on_irq(int cpu)
        }
 }
 
-static inline void get_irqlock(int cpu)
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
 {
+       int stuck = INIT_STUCK;
+
        if (!spin_trylock(&global_irq_lock)) {
+               membar("#StoreLoad | #LoadLoad");
                if ((unsigned char) cpu == global_irq_holder)
                        return;
                do {
-                       barrier();
+                       do {
+                               STUCK;
+                               membar("#LoadLoad");
+                       } while(*((volatile unsigned char *)&global_irq_lock));
                } while (!spin_trylock(&global_irq_lock));
        }
-       wait_on_irq(cpu);
+       wait_on_irq(cpu, where);
        global_irq_holder = cpu;
+       previous_irqholder = where;
 }
 
 void __global_cli(void)
 {
        int cpu = smp_processor_id();
+       unsigned long where;
 
+       __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
        __cli();
-       get_irqlock(cpu);
+       get_irqlock(cpu, where);
 }
 
 void __global_sti(void)
@@ -453,11 +747,6 @@ void __global_sti(void)
        __sti();
 }
 
-unsigned long __global_save_flags(void)
-{
-       return global_irq_holder == (unsigned char) smp_processor_id();
-}
-
 void __global_restore_flags(unsigned long flags)
 {
        if (flags & 1) {
@@ -472,15 +761,24 @@ void __global_restore_flags(unsigned long flags)
        }
 }
 
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
 void irq_enter(int cpu, int irq)
 {
+       int stuck = INIT_STUCK;
+
        hardirq_enter(cpu);
-       barrier();
-       while (*((unsigned char *)&global_irq_lock)) {
+       while (*((volatile unsigned char *)&global_irq_lock)) {
                if ((unsigned char) cpu == global_irq_holder)
                        printk("irq_enter: Frosted Lucky Charms, "
                               "they're magically delicious!\n");
-               barrier();
+               STUCK;
+               membar("#LoadLoad");
        }
 }
 
@@ -492,8 +790,7 @@ void irq_exit(int cpu, int irq)
 
 void synchronize_irq(void)
 {
-       int cpu = smp_processor_id();
-       int local_count = local_irq_count[cpu];
+       int local_count = local_irq_count;
        unsigned long flags;
 
        if (local_count != atomic_read(&global_irq_count)) {
@@ -506,8 +803,10 @@ void synchronize_irq(void)
 
 void report_spurious_ivec(struct pt_regs *regs)
 {
-       printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
-              regs->tpc);
+       extern unsigned long ivec_spurious_cookie;
+
+       printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
+              ivec_spurious_cookie, regs->tpc);
        return;
 }
 
@@ -547,13 +846,20 @@ void handler_irq(int irq, struct pt_regs *regs)
        irq_enter(cpu, irq);
        action = *(irq + irq_action);
        kstat.interrupts[irq]++;
-       do {
-               if(!action || !action->handler)
-                       unexpected_irq(irq, 0, regs);
-               action->handler(irq, action->dev_id, regs);
-               if(action->flags & SA_SYSIO_MASKED)
-                       *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
-       } while((action = action->next) != NULL);
+       if(!action) {
+               unexpected_irq(irq, 0, regs);
+       } else {
+               do {
+                       action->handler(irq, action->dev_id, regs);
+                       if(action->flags & SA_IMAP_MASKED) {
+                               struct ino_bucket *bucket =
+                                       (struct ino_bucket *)action->mask;
+
+                               *(bucket->iclr) = SYSIO_ICLR_IDLE;
+                               membar("#MemIssue");
+                       }
+               } while((action = action->next) != NULL);
+       }
        irq_exit(cpu, irq);
 }
 
@@ -567,7 +873,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
 
        irq_enter(cpu, irq);
        floppy_interrupt(irq, dev_cookie, regs);
-       if(action->flags & SA_SYSIO_MASKED)
+       if(action->flags & SA_IMAP_MASKED)
                *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
        irq_exit(cpu, irq);
 }
@@ -595,7 +901,7 @@ static void install_fast_irq(unsigned int cpu_irq,
        insns[0] = SPARC_BRANCH(((unsigned long) handler),
                                ((unsigned long)&insns[0]));
        insns[1] = SPARC_NOP;
-       __asm__ __volatile__("flush %0" : : "r" (ttent));
+       __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
 }
 
 int request_fast_irq(unsigned int irq,
@@ -605,6 +911,7 @@ int request_fast_irq(unsigned int irq,
        struct irqaction *action;
        unsigned long flags;
        unsigned int cpu_irq, *imap, *iclr;
+       int ivindex = -1;
 
        /* XXX This really is not the way to do it, the "right way"
         * XXX is to have drivers set SA_SBUS or something like that
@@ -616,11 +923,11 @@ int request_fast_irq(unsigned int irq,
         */
        if(irq == 14)
                return -EINVAL;
-       cpu_irq = ino_to_pil[irq];
+       cpu_irq = sysio_ino_to_pil[irq];
 
        if(!handler)
                return -EINVAL;
-       imap = irq_to_imap(irq);
+       imap = sysio_irq_to_imap(irq);
        action = *(cpu_irq + irq_action);
        if(action) {
                if(action->flags & SA_SHIRQ)
@@ -648,12 +955,12 @@ int request_fast_irq(unsigned int irq,
        install_fast_irq(cpu_irq, handler);
 
        if(imap) {
-               int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-
+               ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
                ivector_to_mask[ivindex] = (1 << cpu_irq);
-               iclr = imap_to_iclr(imap);
+               iclr = sysio_imap_to_iclr(imap);
                action->mask = (unsigned long) iclr;
-               irqflags |= SA_SYSIO_MASKED;
+               irqflags |= SA_IMAP_MASKED;
+               add_ino_hash(ivindex, imap, iclr, irqflags);
        } else
                action->mask = 0;
 
@@ -665,7 +972,9 @@ int request_fast_irq(unsigned int irq,
 
        *(cpu_irq + irq_action) = action;
 
-       enable_irq(irq);
+       if(ivindex != -1)
+               enable_irq(ivindex);
+
        restore_flags(flags);
        return 0;
 }
@@ -675,31 +984,27 @@ int request_fast_irq(unsigned int irq,
  */
 unsigned long probe_irq_on(void)
 {
-  return 0;
+       return 0;
 }
 
 int probe_irq_off(unsigned long mask)
 {
-  return 0;
+       return 0;
 }
 
 struct sun5_timer *linux_timers = NULL;
 
-/* This is called from sbus_init() to get the jiffies timer going.
- * We need to call this after there exists a valid SBus_chain so
- * that the IMAP/ICLR registers can be accessed.
- *
- * XXX That is because the whole startup sequence is broken.  I will
- * XXX fix it all up very soon.  -DaveM
- */
+/* This is gets the master level10 timer going. */
 void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 {
        struct linux_prom64_registers pregs[3];
+       struct devid_cookie dcookie;
+       unsigned int *imap, *iclr;
        u32 pirqs[2];
        int node, err;
 
        node = prom_finddevice("/counter-timer");
-       if(node == 0) {
+       if(node == 0 || node == -1) {
                prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
                prom_halt();
        }
@@ -715,13 +1020,22 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
                prom_halt();
        }
        linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
+       iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
+       imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
 
        /* Shut it up first. */
        linux_timers->limit0 = 0;
 
        /* Register IRQ handler. */
-       err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
-                         cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+       dcookie.real_dev_id = NULL;
+       dcookie.imap = imap;
+       dcookie.iclr = iclr;
+       dcookie.pil = 10;
+       dcookie.bus_cookie = NULL;
+
+       err = request_irq(pirqs[0], cfunc,
+                         (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
+                         "timer", &dcookie);
 
        if(err) {
                prom_printf("Serious problem, cannot register timer interrupt\n");
@@ -825,6 +1139,52 @@ void enable_prom_timer(void)
        prom_timers->count0 = 0;
 }
 
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+       unsigned long flags;
+       int cpu, level;
+
+       printk("SMP: redistributing interrupts...\n");
+       save_and_cli(flags);
+       cpu = 0;
+       for(level = 0; level < NR_IRQS; level++) {
+               struct irqaction *p = irq_action[level];
+
+               while(p) {
+                       if(p->flags & SA_IMAP_MASKED) {
+                               struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+                               unsigned int *imap = bucket->imap;
+                               unsigned int val;
+                               unsigned long tid = linux_cpus[cpu].mid << 9;
+
+                               val = *imap;
+                               *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+                               printk("SMP: Redirecting IGN[%x] INO[%x] "
+                                      "to cpu %d [%s]\n",
+                                      (val & SYSIO_IMAP_IGN) >> 6,
+                                      (val & SYSIO_IMAP_INO), cpu,
+                                      p->name);
+
+                               cpu += 1;
+                               while(!(cpu_present_map & (1UL << cpu))) {
+                                       cpu += 1;
+                                       if(cpu >= smp_num_cpus)
+                                               cpu = 0;
+                               }
+                       }
+                       p = p->next;
+               }
+       }
+       restore_flags(flags);
+       irqs_have_been_distributed = 1;
+}
+#endif
+
 __initfunc(void init_IRQ(void))
 {
        int i;
index afd5af8d0330babce1ece9b6672b0d750b6806e4..3b9e37640c03ee47632cb542dc509d688c565adb 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
+/*  $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
 #include <linux/a.out.h>
 #include <linux/config.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
 
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/pstate.h>
 #include <asm/elf.h>
 #include <asm/fpumacro.h>
 
+#define PGTCACHE_HIGH_WATER            50
+#define PGTCACHE_LOW_WATER             25
+
 #ifndef __SMP__
 
 /*
@@ -53,6 +56,16 @@ asmlinkage int sys_idle(void)
        current->priority = -100;
        current->counter = -100;
        for (;;) {
+               if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+                       do {
+                               if(pgd_quicklist)
+                                       free_page((unsigned long) get_pgd_fast());
+                               if(pmd_quicklist)
+                                       free_page((unsigned long) get_pmd_fast());
+                               if(pte_quicklist)
+                                       free_page((unsigned long) get_pte_fast());
+                       } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+               }
                run_task_queue(&tq_scheduler);
                schedule();
        }
@@ -68,13 +81,26 @@ asmlinkage int cpu_idle(void)
 {
        current->priority = -100;
        while(1) {
+               if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+                       do {
+                               if(pgd_quicklist)
+                                       free_page((unsigned long) get_pgd_fast());
+                               if(pmd_quicklist)
+                                       free_page((unsigned long) get_pmd_fast());
+                               if(pte_quicklist)
+                                       free_page((unsigned long) get_pte_fast());
+                       } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+               }
                if(tq_scheduler) {
                        lock_kernel();
                        run_task_queue(&tq_scheduler);
                        unlock_kernel();
                }
+               barrier();
                current->counter = -100;
-               schedule();
+               if(resched_needed())
+                       schedule();
+               barrier();
        }
 }
 
@@ -251,8 +277,20 @@ void show_stackframe32(struct sparc_stackf32 *sf)
        } while ((size -= sizeof(unsigned)));
 }
 
-void show_regs(struct pt_regs * regs)
+#ifdef __SMP__
+static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+void __show_regs(struct pt_regs * regs)
 {
+#ifdef __SMP__
+       unsigned long flags;
+
+       spin_lock_irqsave(&regdump_lock, flags);
+       printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+              smp_processor_id(), local_irq_count,
+              atomic_read(&global_irq_count));
+#endif
         printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
               regs->tpc, regs->tnpc, regs->y);
        printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
@@ -268,6 +306,21 @@ void show_regs(struct pt_regs * regs)
               regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
               regs->u_regs[15]);
        show_regwindow(regs);
+#ifdef __SMP__
+       spin_unlock_irqrestore(&regdump_lock, flags);
+#endif
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       __show_regs(regs);
+#ifdef __SMP__
+       {
+               extern void smp_report_regs(void);
+
+               smp_report_regs();
+       }
+#endif
 }
 
 void show_regs32(struct pt_regs32 *regs)
@@ -337,12 +390,16 @@ void flush_thread(void)
        /* Now, this task is no longer a kernel thread. */
        current->tss.current_ds = USER_DS;
        if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+               extern spinlock_t scheduler_lock;
+
                current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
                /* exec_mmap() set context to NO_CONTEXT, here is
                 * where we grab a new one.
                 */
+               spin_lock(&scheduler_lock);
                get_mmu_context(current);
+               spin_unlock(&scheduler_lock);
        }
        current->tss.ctx = current->mm->context & 0x1fff;
        spitfire_set_secondary_context (current->tss.ctx);
@@ -437,10 +494,14 @@ void fault_in_user_windows(struct pt_regs *regs)
                        struct reg_window *rwin = &tp->reg_window[window];
 
                        if(copy_to_user((char *)sp, rwin, winsize))
-                               do_exit(SIGILL);
+                               goto barf;
                } while(window--);
        }
        current->tss.w_saved = 0;
+       return;
+barf:
+       lock_kernel();
+       do_exit(SIGILL);
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
@@ -483,7 +544,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
 #endif
        p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
-       p->tss.cwp = regs->u_regs[UREG_G0];
+       p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
        if(regs->tstate & TSTATE_PRIV) {
                p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
                p->tss.flags |= SPARC_FLAG_KTHREAD;
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
new file mode 100644 (file)
index 0000000..e00f9d4
--- /dev/null
@@ -0,0 +1,668 @@
+/* $Id: psycho.c,v 1.5 1997/08/15 06:44:18 davem Exp $
+ * psycho.c: Ultra/AX U2P PCI controller support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+       return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+                                 unsigned long dfn,
+                                 unsigned long off,
+                                 unsigned long len,
+                                 unsigned char *buf)
+{
+       return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+                                  unsigned long dfn,
+                                  unsigned long off,
+                                  unsigned long len,
+                                  unsigned char *buf)
+{
+       return 0;
+}
+
+#else
+
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#include <asm/uaccess.h>
+
+struct linux_psycho *psycho_root = NULL;
+
+/* This is used to make the scan_bus in the generic PCI code be
+ * a nop, as we need to control the actual bus probing sequence.
+ * After that we leave it on of course.
+ */
+static int pci_probe_enable = 0;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+       return ((addr + (sizeof(unsigned long) - 1)) &
+               ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+
+unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+{
+       struct linux_prom64_registers pr_regs[3];
+       char namebuf[128];
+       u32 portid;
+       int node;
+
+       /* prom_printf("PSYCHO: Probing for controllers.\n"); */
+       printk("PSYCHO: Probing for controllers.\n");
+
+       memory_start = long_align(memory_start);
+       node = prom_getchild(prom_root_node);
+       while((node = prom_searchsiblings(node, "pci")) != 0) {
+               struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
+               struct linux_psycho *search;
+               struct linux_pbm_info *pbm = NULL;
+               u32 busrange[2];
+               int err, is_pbm_a;
+
+               portid = prom_getintdefault(node, "upa-portid", 0xff);
+               for(search = psycho_root; search; search = search->next) {
+                       if(search->upa_portid == portid) {
+                               psycho = search;
+
+                               /* This represents _this_ instance, so it's
+                                * which ever one does _not_ have the prom node
+                                * info filled in yet.
+                                */
+                               is_pbm_a = (psycho->pbm_A.prom_node == 0);
+                               goto other_pbm;
+                       }
+               }
+
+               memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+               memset(psycho, 0, sizeof(*psycho));
+
+               psycho->next = psycho_root;
+               psycho_root = psycho;
+
+               psycho->upa_portid = portid;
+
+               /* Map in PSYCHO register set and report the presence of this PSYCHO. */
+               err = prom_getproperty(node, "reg",
+                                      (char *)&pr_regs[0], sizeof(pr_regs));
+               if(err == 0 || err == -1) {
+                       prom_printf("PSYCHO: Error, cannot get U2P registers "
+                                   "from PROM.\n");
+                       prom_halt();
+               }
+
+               /* Third REG in property is base of entire PSYCHO register space. */
+               psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+                                                    NULL, sizeof(struct psycho_regs),
+                                                    "PSYCHO Registers",
+                                                    (pr_regs[2].phys_addr >> 32), 0);
+               if(psycho->psycho_regs == NULL) {
+                       prom_printf("PSYCHO: Error, cannot map PSYCHO "
+                                   "main registers.\n");
+                       prom_halt();
+               }
+
+               prom_printf("PSYCHO: Found controller, main regs at %p\n",
+                           psycho->psycho_regs);
+               printk("PSYCHO: Found controller, main regs at %p\n",
+                      psycho->psycho_regs);
+
+               /* Now map in PCI config space for entire PSYCHO. */
+               psycho->pci_config_space =
+                       sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+                                      NULL, 0x01000000,
+                                      "PCI Config Space",
+                                      (pr_regs[2].phys_addr >> 32), 0);
+               if(psycho->pci_config_space == NULL) {
+                       prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
+                       prom_halt();
+               }
+
+               /* Finally map in I/O space for both PBM's.  This is essentially
+                * backwards compatability for non-conformant PCI cards which
+                * do not map themselves into the PCI memory space.
+                */
+               psycho->pbm_B.pbm_IO = __va(pr_regs[2].phys_addr + 0x02000000UL);
+               psycho->pbm_A.pbm_IO = __va(pr_regs[2].phys_addr + 0x02010000UL);
+
+               /* Now record MEM space for both PBM's.
+                *
+                * XXX Eddie, these can be reversed if BOOT_BUS pin is clear, is
+                * XXX there some way to find out what value of BOOT_BUS pin is?
+                */
+               psycho->pbm_B.pbm_mem = __va(pr_regs[2].phys_addr + 0x180000000UL);
+               psycho->pbm_A.pbm_mem = __va(pr_regs[2].phys_addr + 0x100000000UL);
+
+               /* Report some more info. */
+               prom_printf("PSYCHO: PCI config space at %p\n",
+                           psycho->pci_config_space);
+               prom_printf("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+                           psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+               prom_printf("PSYCHO: PBM A MEM at %p, PBM B MEM at %p\n");
+
+               printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+               printk("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+                      psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+
+               is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+       other_pbm:
+               if(is_pbm_a)
+                       pbm = &psycho->pbm_A;
+               else
+                       pbm = &psycho->pbm_B;
+
+               pbm->parent = psycho;
+               pbm->prom_node = node;
+
+               prom_getstring(node, "name", namebuf, sizeof(namebuf));
+               strcpy(pbm->prom_name, namebuf);
+
+               /* Now the ranges. */
+               prom_pbm_ranges_init(node, pbm);
+
+               /* Finally grab the pci bus root array for this pbm after
+                * having found the bus range existing under it.
+                */
+               err = prom_getproperty(node, "bus-range",
+                                      (char *)&busrange[0], sizeof(busrange));
+               if(err == 0 || err == -1) {
+                       prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
+                       prom_halt();
+               }
+               pbm->pci_first_busno = busrange[0];
+               pbm->pci_last_busno = busrange[1];
+               memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+               node = prom_getsibling(node);
+               if(!node)
+                       break;
+       }
+
+       /* Last minute sanity check. */
+       if(psycho_root == NULL && SBus_chain == NULL) {
+               prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
+               prom_halt();
+       }
+
+       return memory_start;
+}
+
+int pcibios_present(void)
+{
+       return psycho_root != NULL;
+}
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+                        unsigned short index, unsigned char *bus,
+                        unsigned char *devfn)
+{
+       unsigned int curr = 0;
+       struct pci_dev *dev;
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               if (dev->vendor == vendor && dev->device == device_id) {
+                       if (curr == index) {
+                               *devfn = dev->devfn;
+                               *bus = dev->bus->number;
+                               return PCIBIOS_SUCCESSFUL;
+                       }
+                       ++curr;
+               }
+       }
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+                       unsigned char *bus, unsigned char *devfn)
+{
+       unsigned int curr = 0;
+       struct pci_dev *dev;
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               if (dev->class == class_code) {
+                       if (curr == index) {
+                               *devfn = dev->devfn;
+                               *bus = dev->bus->number;
+                               return PCIBIOS_SUCCESSFUL;
+                       }
+                       ++curr;
+               }
+       }
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+{
+       struct pci_bus *pbus = &pbm->pci_bus;
+
+       /* PSYCHO PBM's include child PCI bridges in bus-range property,
+        * but we don't scan each of those ourselves, Linux generic PCI
+        * probing code will find child bridges and link them into this
+        * pbm's root PCI device hierarchy.
+        */
+       pbus->number = pbm->pci_first_busno;
+       pbus->sysdata = pbm;
+       pbus->subordinate = pci_scan_bus(pbus, mstart);
+}
+
+static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+{
+       struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
+       struct pci_dev *pdev;
+
+       for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
+               pbtmp->sysdata = pbm;
+
+       for( ; pbus; pbus = pbus->children)
+               for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+                       pdev->sysdata = pbm;
+}
+
+static void fixup_pci_dev(struct pci_dev *pdev,
+                         struct pci_bus *pbus,
+                         struct linux_pbm_info *pbm)
+{
+       struct linux_prom_pci_registers pregs[PROMREG_MAX];
+       int node;
+#if 0
+       int nregs, busno = pbus->number;
+#endif
+
+       node = prom_getchild(pbm->prom_node);
+       while(node) {
+               u32 devfn;
+               int err, nregs;
+
+               err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+               if(err == 0 || err == -1) {
+                       prom_printf("fixup_pci_dev: No PCI device reg property?!?!\n");
+                       prom_halt();
+               }
+               nregs = (err / sizeof(struct linux_prom_pci_registers));
+
+               devfn = (pregs[0].phys_hi >> 8) & 0xff;
+               if(devfn == pdev->devfn) {
+
+                       return;
+               }
+
+               node = prom_getsibling(node);
+       }
+
+       prom_printf("fixup_pci_dev: Cannot find prom node for PCI device\n");
+       prom_halt();
+}
+
+static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+{
+       struct pci_dev *pdev;
+
+       for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+               fixup_pci_dev(pdev, pbus, pbm);
+
+       for(pbus = pbus->children; pbus; pbus = pbus->children)
+               fixup_pci_bus(pbus, pbm);
+}
+
+static void fixup_addr_irq(struct linux_pbm_info *pbm)
+{
+       struct pci_bus *pbus = &pbm->pci_bus;
+
+       /* Work through top level devices (not bridges, those and their
+        * devices are handled specially in the next loop).
+        */
+       fixup_pci_bus(pbus, pbm);
+}
+
+/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
+ * We use OBP for most of this work.
+ */
+static void psycho_final_fixup(struct linux_psycho *psycho)
+{
+       /* First, walk all PCI devices found.  For each device, and
+        * PCI bridge which is not one of the PSYCHO PBM's, fill in the
+        * sysdata with a pointer to the PBM.
+        */
+       fill_in_pbm_cookies(&psycho->pbm_A);
+       fill_in_pbm_cookies(&psycho->pbm_B);
+
+       /* Second, fixup base address registers and IRQ lines... */
+       fixup_addr_irq(&psycho->pbm_A);
+       fixup_addr_irq(&psycho->pbm_B);
+}
+
+unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+{
+       struct linux_psycho *psycho = psycho_root;
+
+       pci_probe_enable = 1;
+
+       /* XXX Really this should be per-PSYCHO, but the config space
+        * XXX reads and writes give us no way to know which PSYCHO
+        * XXX in which the config space reads should occur.
+        * XXX
+        * XXX Further thought says that we cannot change this generic
+        * XXX interface, else we'd break xfree86 and other parts of the
+        * XXX kernel (but whats more important is breaking userland for
+        * XXX the ix86/Alpha/etc. people).  So we should define our own
+        * XXX internal extension initially, we can compile our own user
+        * XXX apps that need to get at PCI configuration space.
+        */
+
+       /* Probe busses under PBM A. */
+       pbm_probe(&psycho->pbm_A, &memory_start);
+
+       /* Probe busses under PBM B. */
+       pbm_probe(&psycho->pbm_B, &memory_start);
+
+
+       psycho_final_fixup(psycho);
+
+       return ebus_init(memory_start, memory_end);
+}
+
+/* "PCI: The emerging standard..." 8-( */
+volatile int pci_poke_in_progress = 0;
+volatile int pci_poke_faulted = 0;
+
+/* XXX Current PCI support code is broken, it assumes one master PCI config
+ * XXX space exists, on Ultra we can have many of them, especially with
+ * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
+ */
+static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
+                       unsigned char where)
+{
+       unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+
+       ret |= (1 << 24);
+       ret |= ((bus & 0xff) << 16);
+       ret |= ((device_fn & 0xff) << 8);
+       ret |= (where & 0xfc);
+       return (unsigned char *)ret;
+}
+
+static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+{
+       return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
+               (bus == 1 && PCI_SLOT(device_fn) > 6) ||
+               (pci_probe_enable == 0));
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned char *value)
+{
+       unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+       unsigned int word, trapped;
+
+       *value = 0xff;
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       pci_poke_in_progress = 1;
+       pci_poke_faulted = 0;
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "lduwa [%1] %2, %0\n\t"
+                            "membar #Sync"
+                            : "=r" (word)
+                            : "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+       trapped = pci_poke_faulted;
+       pci_poke_faulted = 0;
+       if(!trapped) {
+               switch(where & 3) {
+               case 0:
+                       *value = word & 0xff;
+                       break;
+               case 1:
+                       *value = (word >> 8) & 0xff;
+                       break;
+               case 2:
+                       *value = (word >> 16) & 0xff;
+                       break;
+               case 3:
+                       *value = (word >> 24) & 0xff;
+                       break;
+               };
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned short *value)
+{
+       unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+       unsigned int word, trapped;
+
+       *value = 0xffff;
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       /* XXX Check no-probe-list conflicts here. XXX */
+
+       pci_poke_in_progress = 1;
+       pci_poke_faulted = 0;
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "lduwa [%1] %2, %0\n\t"
+                            "membar #Sync"
+                            : "=r" (word)
+                            : "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+       trapped = pci_poke_faulted;
+       pci_poke_faulted = 0;
+       if(!trapped) {
+               switch(where & 3) {
+               case 0:
+                       *value = word & 0xffff;
+                       break;
+               case 2:
+                       *value = (word >> 16) & 0xffff;
+                       break;
+               default:
+                       prom_printf("pcibios_read_config_word: misaligned "
+                                   "reg [%x]\n", where);
+                       prom_halt();
+               };
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned int *value)
+{
+       unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+       unsigned int word, trapped;
+
+       *value = 0xffffffff;
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       /* XXX Check no-probe-list conflicts here. XXX */
+
+       pci_poke_in_progress = 1;
+       pci_poke_faulted = 0;
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "lduwa [%1] %2, %0\n\t"
+                            "membar #Sync"
+                            : "=r" (word)
+                            : "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+       trapped = pci_poke_faulted;
+       pci_poke_faulted = 0;
+       if(!trapped)
+               *value = word;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned char value)
+{
+       unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       /* XXX Check no-probe-list conflicts here. XXX */
+
+       pci_poke_in_progress = 1;
+
+       /* Endianness doesn't matter but we have to get the memory
+        * barriers in there so...
+        */
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "stba %0, [%1] %2\n\t"
+                            "membar #Sync\n\t"
+                            : /* no outputs */
+                            : "r" (value), "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned short value)
+{
+       unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       /* XXX Check no-probe-list conflicts here. XXX */
+
+       pci_poke_in_progress = 1;
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "stha %0, [%1] %2\n\t"
+                            "membar #Sync\n\t"
+                            : /* no outputs */
+                            : "r" (value), "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+                               unsigned char where, unsigned int value)
+{
+       unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+
+       if(out_of_range(bus, device_fn))
+               return PCIBIOS_SUCCESSFUL;
+
+       /* XXX Check no-probe-list conflicts here. XXX */
+
+       pci_poke_in_progress = 1;
+       __asm__ __volatile__("membar #Sync\n\t"
+                            "stwa %0, [%1] %2\n\t"
+                            "membar #Sync"
+                            : /* no outputs */
+                            : "r" (value), "r" (addr), "i" (ASI_PL));
+       pci_poke_in_progress = 0;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+                                 unsigned long dfn,
+                                 unsigned long off,
+                                 unsigned long len,
+                                 unsigned char *buf)
+{
+       unsigned char ubyte;
+       unsigned short ushort;
+       unsigned int uint;
+       int err = 0;
+
+       lock_kernel();
+       switch(len) {
+       case 1:
+               pcibios_read_config_byte(bus, dfn, off, &ubyte);
+               put_user(ubyte, buf);
+               break;
+       case 2:
+               pcibios_read_config_word(bus, dfn, off, &ushort);
+               put_user(ushort, buf);
+               break;
+       case 4:
+               pcibios_read_config_dword(bus, dfn, off, &uint);
+               put_user(uint, buf);
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+       };
+       unlock_kernel();
+
+       return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+                                  unsigned long dfn,
+                                  unsigned long off,
+                                  unsigned long len,
+                                  unsigned char *buf)
+{
+       unsigned char ubyte;
+       unsigned short ushort;
+       unsigned int uint;
+       int err = 0;
+
+       lock_kernel();
+       switch(len) {
+       case 1:
+               err = get_user(ubyte, (unsigned char *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, ubyte);
+               break;
+
+       case 2:
+               err = get_user(ushort, (unsigned short *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, ushort);
+               break;
+
+       case 4:
+               err = get_user(uint, (unsigned int *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, uint);
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+
+       };
+       unlock_kernel();
+
+       return err;
+}
+
+#endif
index ac91df8940a6c21fd170682622ce305435e5425c..3df35ef143c73241d25feb61a5105237e7448290 100644 (file)
@@ -609,10 +609,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                unsigned long tmp;
                int res;
 
-#if 0
-               /* XXX Find out what is really going on. */
-               flush_cache_all();
-#endif
                /* Non-word alignment _not_ allowed on Sparc. */
                if (current->tss.flags & SPARC_FLAG_32BIT) {
                        unsigned int x;
@@ -1055,7 +1051,7 @@ asmlinkage void syscall_trace(void)
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
        current->tss.flags ^= MAGIC_CONSTANT;
-       notify_parent(current);
+       notify_parent(current, SIGCHLD);
        schedule();
        /*
         * this isn't the same as continuing with a signal, but it will do
@@ -1067,9 +1063,9 @@ asmlinkage void syscall_trace(void)
                current->pid, current->exit_code);
 #endif
        if (current->exit_code) {
-               /* spin_lock_irq(&current->sigmask_lock); */
+               spin_lock_irq(&current->sigmask_lock);
                current->signal |= (1 << (current->exit_code - 1));
-               /* spin_unlock_irq(&current->sigmask_lock); */
+               spin_unlock_irq(&current->sigmask_lock);
        }
 
        current->exit_code = 0;
index 9f087a969a3fb7771a3a50f2cc4aa9ee0512560b..d7f58d9625f16860de8eead0c5f575ef6655330a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
+/* $Id: rtrap.S,v 1.30 1997/08/10 04:49:33 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -21,58 +21,60 @@ rtrap:              sethi                   %hi(bh_active), %l2
                sethi                   %hi(bh_mask), %l1
                ldx                     [%l2 + %lo(bh_active)], %l4
                ldx                     [%l1 + %lo(bh_mask)], %l7
-
                andcc                   %l4, %l7, %g0
                be,pt                   %xcc, 2f
+
                 nop
                call                    do_bottom_half
                 nop
 2:             ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
                sethi                   %hi(0xf << 20), %l4
                andcc                   %l1, TSTATE_PRIV, %l3
-
                and                     %l1, %l4, %l4
                rdpr                    %pstate, %l7
+
                andn                    %l1, %l4, %l1
                be,pt                   %icc, to_user
                 andn                   %l7, PSTATE_IE, %l7
 rt_continue:   ld                      [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
                ld                      [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
                ldx                     [%sp + PTREGS_OFF + PT_V9_G1], %g1
-
                brnz,pn                 %l2, rt_fpu_restore
                 ldx                    [%sp + PTREGS_OFF + PT_V9_G2], %g2
+
 rt_after_fpu:  ldx                     [%sp + PTREGS_OFF + PT_V9_G3], %g3
                mov                     %g6, %l6
                ldx                     [%sp + PTREGS_OFF + PT_V9_G4], %g4
                ldx                     [%sp + PTREGS_OFF + PT_V9_G5], %g5
                ldx                     [%sp + PTREGS_OFF + PT_V9_G6], %g6
                ldx                     [%sp + PTREGS_OFF + PT_V9_G7], %g7
-
                wrpr                    %l7, PSTATE_AG, %pstate
                ldx                     [%sp + PTREGS_OFF + PT_V9_I0], %i0
+
                ldx                     [%sp + PTREGS_OFF + PT_V9_I1], %i1
                ldx                     [%sp + PTREGS_OFF + PT_V9_I2], %i2
                ldx                     [%sp + PTREGS_OFF + PT_V9_I3], %i3
                ldx                     [%sp + PTREGS_OFF + PT_V9_I4], %i4
                ldx                     [%sp + PTREGS_OFF + PT_V9_I5], %i5
                ldx                     [%sp + PTREGS_OFF + PT_V9_I6], %i6
-
                ldx                     [%sp + PTREGS_OFF + PT_V9_I7], %i7
                ld                      [%sp + PTREGS_OFF + PT_V9_Y], %o3
+
                ldx                     [%sp + PTREGS_OFF + PT_V9_TPC], %l2
                ldx                     [%sp + PTREGS_OFF + PT_V9_TNPC], %o2
                wr                      %o3, %g0, %y
                srl                     %l4, 20, %l4
                wrpr                    %l4, 0x0, %pil
                wrpr                    %g0, 0x1, %tl
-
                wrpr                    %l1, %g0, %tstate
                wrpr                    %l2, %g0, %tpc
-               mov                     PRIMARY_CONTEXT, %l7
+
+               wr                      %g0, ASI_DMMU, %asi
                brnz,pn                 %l3, kern_rtt
                 wrpr                   %o2, %g0, %tnpc
-               stxa                    %l0, [%l7] ASI_DMMU
+               stxa                    %l0, [%g0 + SECONDARY_CONTEXT] %asi
+               flush                   %l6
+               stxa                    %l0, [%g0 + PRIMARY_CONTEXT] %asi
                flush                   %l6
                rdpr                    %wstate, %l1
 
@@ -88,47 +90,54 @@ rt_after_fpu:       ldx                     [%sp + PTREGS_OFF + PT_V9_G3], %g3
                retry
 kern_rtt:      restore
                retry
-to_user:       sethi                   %hi(need_resched), %l0
-               ld                      [%l0 + %lo(need_resched)], %l0
+to_user:       lduw                    [%g6 + AOFF_task_processor], %o0
+               mov                     1, %o1
+               sethi                   %hi(need_resched), %l0
+               ldx                     [%l0 + %lo(need_resched)], %l0
+               sllx                    %o1, %o0, %o1
+
                wrpr                    %l7, PSTATE_IE, %pstate
-               brz,pt                  %l0, check_signal
+               andcc                   %o1, %l0, %g0
+               be,pt                   %xcc, check_signal
                 ldx                    [%g6 + AOFF_task_signal], %l0
-
                call                    schedule
                 nop
                ldx                     [%g6 + AOFF_task_signal], %l0
                nop
+
 check_signal:  ldx                     [%g6 + AOFF_task_blocked], %o0
                andncc                  %l0, %o0, %g0
                be,pt                   %xcc, check_user_wins
                 ldx                    [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
                mov                     %l5, %o2  
                mov                     %l6, %o3
                call                    do_signal
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o1
+
                ldx                     [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
                clr                     %l6
-check_user_wins:
-               brz,pt                  %o2, rt_continue
+check_user_wins:brz,pt                 %o2, rt_continue
                 nop
-
                call                    fault_in_user_windows
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o0
                ba,a,pt                 %xcc, rt_continue
 rt_fpu_restore:        wr                      %g0, FPRS_FEF, %fprs
+
                add                     %sp, PTREGS_OFF + TRACEREG_SZ, %g4
                wr                      %g0, ASI_BLK_P, %asi
-
                membar                  #StoreLoad | #LoadLoad
                ldda                    [%g4 + 0x000] %asi, %f0
                ldda                    [%g4 + 0x040] %asi, %f16
                ldda                    [%g4 + 0x080] %asi, %f32
                ldda                    [%g4 + 0x0c0] %asi, %f48
                ldx                     [%g4 + 0x100], %fsr
+
                ldx                     [%g4 + 0x108], %g3
                membar                  #Sync
-
                b,pt                    %xcc, rt_after_fpu
                 wr                     %g3, 0, %gsr
+               nop
+               nop
+               nop
+               nop
 #undef PTREGS_OFF
index cfc55fc2efa36216630f95099eacfc92276a465d..477ebd5b3717f685dba22e5e0df9aec373d63f82 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/*  $Id: signal.c,v 1.22 1997/08/05 19:19:36 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -54,12 +54,12 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        if(tp->w_saved                                          ||
           (((unsigned long)ucp) & (sizeof(unsigned long)-1))   ||
           (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
-               do_exit(SIGSEGV);
+               goto do_sigsegv;
        grp = &ucp->uc_mcontext.mc_gregs;
        __get_user(pc, &((*grp)[MC_PC]));
        __get_user(npc, &((*grp)[MC_NPC]));
        if((pc | npc) & 3)
-               do_exit(SIGSEGV);
+               goto do_sigsegv;
        if(regs->u_regs[UREG_I1]) {
                __get_user(current->blocked, &ucp->uc_sigmask);
                current->blocked &= _BLOCKABLE;
@@ -100,6 +100,10 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
                __get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
                regs->fprs = FPRS_FEF;
        }
+       return;
+do_sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -113,7 +117,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
 
        synchronize_user_stack();
        if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
-               do_exit(SIGSEGV);
+               goto do_sigsegv;
        mcp = &ucp->uc_mcontext;
        grp = &mcp->mc_gregs;
 
@@ -156,6 +160,10 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
                __put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
                __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
        }
+       return;
+do_sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 /* 
@@ -452,7 +460,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -498,7 +506,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
                                current->exit_code = signr;
                                if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
                                     SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
index 5135c2ae51376bd2972ab2089e49bd6e14316c8e..f874e270ca852753dd0eb8d90a217f64f42f177d 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
+/*  $Id: signal32.c,v 1.28 1997/08/05 19:19:40 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -555,6 +555,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
        synchronize_user_stack();
        if (current->tss.w_saved){
                printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+               lock_kernel();
                do_exit (SIGSEGV);
        }
        if(clear_user(uc, sizeof (*uc)))
@@ -718,7 +719,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
-                       notify_parent(current);
+                       notify_parent(current, SIGCHLD);
                        schedule();
                        if (!(signr = current->exit_code))
                                continue;
@@ -764,7 +765,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
                                current->exit_code = signr;
                                if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
                                     SA_NOCLDSTOP))
-                                       notify_parent(current);
+                                       notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
 
index 77ccf40a0ad55f9b0c2fb2e6de7df0919b5f5025..165511a92dc847e86e9dc6f91c472479078814b9 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/delay.h>
 
+#include <asm/head.h>
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -33,9 +34,9 @@ volatile int smp_processors_ready = 0;
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
-struct cpuinfo_sparc cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+
 static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
 
@@ -44,8 +45,6 @@ volatile int cpu_logical_map[NR_CPUS];
 
 struct klock_info klock_info = { KLOCK_CLEAR, 0 };
 
-static volatile int smp_commenced = 0;
-
 void smp_setup(char *str, int *ints)
 {
        /* XXX implement me XXX */
@@ -68,45 +67,64 @@ char *smp_info(void)
 
 void smp_store_cpu_info(int id)
 {
-       cpu_data[id].udelay_val = loops_per_sec;
+       cpu_data[id].udelay_val                 = loops_per_sec;
+       cpu_data[id].irq_count                  = 0;
+       cpu_data[id].last_tlbversion_seen       = tlb_context_cache & CTX_VERSION_MASK;
+       cpu_data[id].pgcache_size               = 0;
+       cpu_data[id].pgd_cache                  = NULL;
+       cpu_data[id].pmd_cache                  = NULL;
+       cpu_data[id].pte_cache                  = NULL;
 }
 
+extern void distribute_irqs(void);
+
 void smp_commence(void)
 {
-       flush_cache_all();
-       flush_tlb_all();
-       smp_commenced = 1;
-       flush_cache_all();
-       flush_tlb_all();
+       distribute_irqs();
 }
 
 static void smp_setup_percpu_timer(void);
 
 static volatile unsigned long callin_flag = 0;
 
+extern void inherit_locked_prom_mappings(int save_p);
+extern void cpu_probe(void);
+
 void smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
 
-       flush_cache_all();
-       flush_tlb_all();
+       inherit_locked_prom_mappings(0);
+
+       __flush_cache_all();
+       __flush_tlb_all();
+
+       cpu_probe();
+
+       /* Master did this already, now is the time for us to do it. */
+       __asm__ __volatile__("
+       sethi   %%hi(0x80000000), %%g1
+       sllx    %%g1, 32, %%g1
+       rd      %%tick, %%g2
+       add     %%g2, 6, %%g2
+       andn    %%g2, %%g1, %%g2
+       wrpr    %%g2, 0, %%tick
+"      : /* no outputs */
+       : /* no inputs */
+       : "g1", "g2");
 
        smp_setup_percpu_timer();
 
+       __sti();
+
        calibrate_delay();
        smp_store_cpu_info(cpuid);
        callin_flag = 1;
        __asm__ __volatile__("membar #Sync\n\t"
                             "flush  %%g6" : : : "memory");
 
-       while(!task[cpuid])
-               barrier();
-       current = task[cpuid];
-
-       while(!smp_commenced)
-               barrier();
-
-       __sti();
+       while(!smp_processors_ready)
+               membar("#LoadLoad");
 }
 
 extern int cpu_idle(void *unused);
@@ -130,18 +148,22 @@ void cpu_panic(void)
        panic("SMP bolixed\n");
 }
 
+static void smp_tickoffset_init(void);
+
 extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-extern unsigned long sparc64_cpu_startup;
+
+extern unsigned long smp_trampoline;
 
 void smp_boot_cpus(void)
 {
        int cpucount = 0, i;
 
        printk("Entering UltraSMPenguin Mode...\n");
+       smp_tickoffset_init();
        __sti();
        cpu_present_map = 0;
        for(i = 0; i < linux_num_cpus; i++)
-               cpu_present_map |= (1 << i);
+               cpu_present_map |= (1UL << i);
        for(i = 0; i < NR_CPUS; i++) {
                cpu_number_map[i] = -1;
                cpu_logical_map[i] = -1;
@@ -160,23 +182,24 @@ void smp_boot_cpus(void)
                if(i == boot_cpu_id)
                        continue;
 
-               if(cpu_present_map & (1 << i)) {
+               if(cpu_present_map & (1UL << i)) {
+                       unsigned long entry = (unsigned long)(&smp_trampoline);
                        struct task_struct *p;
                        int timeout;
 
+                       entry -= KERNBASE;
                        kernel_thread(start_secondary, NULL, CLONE_PID);
                        p = task[++cpucount];
                        p->processor = i;
+                       callin_flag = 0;
                        prom_startcpu(linux_cpus[i].prom_node,
-                                     ((unsigned long)&sparc64_cpu_startup),
-                                     ((unsigned long)p));
+                                     entry, ((unsigned long)p));
                        for(timeout = 0; timeout < 5000000; timeout++) {
-                               if(cpu_callin_map[i])
+                               if(callin_flag)
                                        break;
                                udelay(100);
                        }
-                       if(cpu_callin_map[i]) {
-                               /* XXX fix this */
+                       if(callin_flag) {
                                cpu_number_map[i] = i;
                                cpu_logical_map[i] = i;
                        } else {
@@ -184,19 +207,19 @@ void smp_boot_cpus(void)
                                printk("Processor %d is stuck.\n", i);
                        }
                }
-               if(!(cpu_callin_map[i])) {
-                       cpu_present_map &= ~(1 << i);
+               if(!callin_flag) {
+                       cpu_present_map &= ~(1UL << i);
                        cpu_number_map[i] = -1;
                }
        }
        if(cpucount == 0) {
                printk("Error: only one processor found.\n");
-               cpu_present_map = (1 << smp_processor_id());
+               cpu_present_map = (1UL << smp_processor_id());
        } else {
                unsigned long bogosum = 0;
 
                for(i = 0; i < NR_CPUS; i++) {
-                       if(cpu_present_map & (1 << i))
+                       if(cpu_present_map & (1UL << i))
                                bogosum += cpu_data[i].udelay_val;
                }
                printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -207,27 +230,39 @@ void smp_boot_cpus(void)
                smp_num_cpus = cpucount + 1;
        }
        smp_processors_ready = 1;
+       membar("#StoreStore | #StoreLoad");
 }
 
-/* XXX deprecated interface... */
+/* We don't even need to do anything, the only generic message pass done
+ * anymore is to stop all cpus during a panic().  When the user drops to
+ * the PROM prompt, the firmware will send the other cpu's it's MONDO
+ * vector anyways, so doing anything special here is pointless.
+ *
+ * This whole thing should go away anyways...
+ */
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-       printk("smp_message_pass() called, this is bad, spinning.\n");
-       __sti();
-       while(1)
-               barrier();
 }
 
+/* #define XCALL_DEBUG */
+
 static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
 {
-       u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
-
+       u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+       int stuck;
+
+#ifdef XCALL_DEBUG
+       printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
+              smp_processor_id(), data0, data1, data2, target);
+#endif
+again:
        __asm__ __volatile__("
        wrpr    %0, %1, %%pstate
        wr      %%g0, %2, %%asi
        stxa    %3, [0x40] %%asi
        stxa    %4, [0x50] %%asi
        stxa    %5, [0x60] %%asi
+       membar  #Sync
        stxa    %%g0, [%6] %%asi
        membar  #Sync"
        : /* No outputs */
@@ -235,27 +270,46 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, in
          "r" (data0), "r" (data1), "r" (data2), "r" (target));
 
        /* NOTE: PSTATE_IE is still clear. */
+       stuck = 100000;
        do {
                __asm__ __volatile__("ldxa [%%g0] %1, %0"
                        : "=r" (result)
                        : "i" (ASI_INTR_DISPATCH_STAT));
+               if(result == 0) {
+                       __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+                                            : : "r" (pstate));
+                       return;
+               }
+               stuck -= 1;
+               if(stuck == 0)
+                       break;
        } while(result & 0x1);
        __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
                             : : "r" (pstate));
-       if(result & 0x2)
-               panic("Penguin NACK's master!");
+       if(stuck == 0) {
+#ifdef XCALL_DEBUG
+               printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+                      smp_processor_id(), result);
+#endif
+       } else {
+#ifdef XCALL_DEBUG
+               printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
+#endif
+               udelay(2);
+               goto again;
+       }
 }
 
 void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
 {
        if(smp_processors_ready) {
-               unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+               unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
                u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
                int i, ncpus = smp_num_cpus;
 
                __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
                for(i = 0; i < ncpus; i++) {
-                       if(mask & (1 << i))
+                       if(mask & (1UL << i))
                                xcall_deliver(data0, data1, data2, pstate, i);
                }
                /* NOTE: Caller runs local copy on master. */
@@ -266,7 +320,14 @@ extern unsigned long xcall_flush_tlb_page;
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
 extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_tlbcachesync;
 extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_report_regs;
+
+void smp_report_regs(void)
+{
+       smp_cross_call(&xcall_report_regs, 0, 0, 0);
+}
 
 void smp_flush_cache_all(void)
 {
@@ -280,11 +341,33 @@ void smp_flush_tlb_all(void)
        __flush_tlb_all();
 }
 
+static void smp_cross_call_avoidance(struct mm_struct *mm)
+{
+       spin_lock(&scheduler_lock);
+       get_new_mmu_context(mm, &tlb_context_cache);
+       mm->cpu_vm_mask = (1UL << smp_processor_id());
+       if(current->tss.current_ds) {
+               u32 ctx = mm->context & 0x1fff;
+
+               current->tss.ctx = ctx;
+               spitfire_set_secondary_context(ctx);
+               __asm__ __volatile__("flush %g6");
+       }
+       spin_unlock(&scheduler_lock);
+}
+
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        u32 ctx = mm->context & 0x1fff;
-       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-               smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+       if(mm == current->mm && mm->count == 1) {
+               if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+                       goto local_flush_and_out;
+               return smp_cross_call_avoidance(mm);
+       }
+       smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+local_flush_and_out:
        __flush_tlb_mm(ctx);
 }
 
@@ -292,22 +375,98 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                         unsigned long end)
 {
        u32 ctx = mm->context & 0x1fff;
-       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-               smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+       if(mm == current->mm && mm->count == 1) {
+               if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+                       goto local_flush_and_out;
+               return smp_cross_call_avoidance(mm);
+       }
+       smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+local_flush_and_out:
        __flush_tlb_range(ctx, start, end);
 }
 
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
-       struct mm_struct *mm = vma->vm_mm;
        u32 ctx = mm->context & 0x1fff;
 
-       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-               smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+       if(mm == current->mm && mm->count == 1) {
+               if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+                       goto local_flush_and_out;
+               return smp_cross_call_avoidance(mm);
+       } else if(mm != current->mm && mm->count == 1) {
+               /* Try to handle two special cases to avoid cross calls
+                * in common scenerios where we are swapping process
+                * pages out.
+                */
+               if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+                       return; /* It's dead, nothing to do. */
+               if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+                       goto local_flush_and_out;
+       }
+       smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+
+local_flush_and_out:
        __flush_tlb_page(ctx, page);
 }
 
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+/* CPU capture. */
+#define CAPTURE_DEBUG
+extern unsigned long xcall_capture;
+
+static atomic_t smp_capture_depth = ATOMIC_INIT(0);
+static atomic_t smp_capture_registry = ATOMIC_INIT(0);
+static unsigned long penguins_are_doing_time = 0;
+
+void smp_capture(void)
+{
+       int result = atomic_add_return(1, &smp_capture_depth);
+
+       membar("#StoreStore | #LoadStore");
+       if(result == 1) {
+               int ncpus = smp_num_cpus;
+
+#ifdef CAPTURE_DEBUG
+               printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+#endif
+               penguins_are_doing_time = 1;
+               membar("#StoreStore | #LoadStore");
+               atomic_inc(&smp_capture_registry);
+               smp_cross_call(&xcall_capture, 0, 0, 0);
+               while(atomic_read(&smp_capture_registry) != ncpus)
+                       membar("#LoadLoad");
+#ifdef CAPTURE_DEBUG
+               printk("done\n");
+#endif
+       }
+}
+
+void smp_release(void)
+{
+       if(atomic_dec_and_test(&smp_capture_depth)) {
+#ifdef CAPTURE_DEBUG
+               printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+                      smp_processor_id());
+#endif
+               penguins_are_doing_time = 0;
+               membar("#StoreStore | #StoreLoad");
+               atomic_dec(&smp_capture_registry);
+       }
+}
+
+/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
+ * can service tlb flush xcalls...
+ */
+void smp_penguin_jailcell(void)
+{
+       flushw_user();
+       atomic_inc(&smp_capture_registry);
+       membar("#StoreLoad | #StoreStore");
+       while(penguins_are_doing_time)
+               membar("#LoadLoad");
+       atomic_dec(&smp_capture_registry);
+}
 
 static inline void sparc64_do_profile(unsigned long pc)
 {
@@ -317,59 +476,100 @@ static inline void sparc64_do_profile(unsigned long pc)
                pc -= (unsigned long) &_stext;
                pc >>= prof_shift;
 
-               spin_lock(&ticker_lock);
-               if(pc < prof_len)
-                       prof_buffer[pc]++;
-               else
-                       prof_buffer[prof_len - 1]++;
-               spin_unlock(&ticker_lock);
+               if(pc >= prof_len)
+                       pc = prof_len - 1;
+               atomic_inc((atomic_t *)&prof_buffer[pc]);
        }
 }
 
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+static unsigned long real_tick_offset, current_tick_offset;
+
+#define prof_multiplier(__cpu)         cpu_data[(__cpu)].multiplier
+#define prof_counter(__cpu)            cpu_data[(__cpu)].counter
 
 extern void update_one_process(struct task_struct *p, unsigned long ticks,
                               unsigned long user, unsigned long system);
 
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
+       unsigned long compare, tick;
        int cpu = smp_processor_id();
        int user = user_mode(regs);
 
-       /* XXX clear_profile_irq(cpu); */
-       if(!user)
-               sparc64_do_profile(regs->tpc);
-       if(!--prof_counter[cpu]) {
-               if(current->pid) {
-                       update_one_process(current, 1, user, !user);
-                       if(--current->counter < 0) {
-                               current->counter = 0;
-                               need_resched = 1;
-                       }
-
-                       spin_lock(&ticker_lock);
-                       if(user) {
-                               if(current->priority < DEF_PRIORITY)
-                                       kstat.cpu_nice++;
-                               else
-                                       kstat.cpu_user++;
-                       } else {
-                               kstat.cpu_system++;
+       clear_softint((1UL << 0));
+       do {
+               if(!user)
+                       sparc64_do_profile(regs->tpc);
+               if(!--prof_counter(cpu)) {
+                       if(current->pid) {
+                               unsigned int *inc_me;
+
+                               update_one_process(current, 1, user, !user);
+                               if(--current->counter < 0) {
+                                       current->counter = 0;
+                                       resched_force();
+                               }
+
+                               if(user) {
+                                       if(current->priority < DEF_PRIORITY)
+                                               inc_me = &kstat.cpu_nice;
+                                       else
+                                               inc_me = &kstat.cpu_user;
+                               } else {
+                                       inc_me = &kstat.cpu_system;
+                               }
+                               atomic_inc((atomic_t *)inc_me);
                        }
-                       spin_unlock(&ticker_lock);
+                       prof_counter(cpu) = prof_multiplier(cpu);
                }
-               prof_counter[cpu] = prof_multiplier[cpu];
-       }
+               __asm__ __volatile__("rd        %%tick_cmpr, %0\n\t"
+                                    "add       %0, %2, %0\n\t"
+                                    "wr        %0, 0x0, %%tick_cmpr\n\t"
+                                    "rd        %%tick, %1"
+                                    : "=&r" (compare), "=r" (tick)
+                                    : "r" (current_tick_offset));
+       } while (tick >= compare);
 }
 
 static void smp_setup_percpu_timer(void)
 {
-       /* XXX implement me */
+       int cpu = smp_processor_id();
+
+       prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+       __asm__ __volatile__("rd        %%tick, %%g1\n\t"
+                            "add       %%g1, %0, %%g1\n\t"
+                            "wr        %%g1, 0x0, %%tick_cmpr"
+                            : /* no outputs */
+                            : "r" (current_tick_offset)
+                            : "g1");
+}
+
+static void smp_tickoffset_init(void)
+{
+       int node;
+
+       node = linux_cpus[0].prom_node;
+       real_tick_offset = prom_getint(node, "clock-frequency");
+       real_tick_offset = real_tick_offset / HZ;
+       current_tick_offset = real_tick_offset;
 }
 
 int setup_profiling_timer(unsigned int multiplier)
 {
-       /* XXX implement me */
+       unsigned long flags;
+       int i;
+
+       if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+               return -EINVAL;
+
+       save_and_cli(flags);
+       for(i = 0; i < NR_CPUS; i++) {
+               if(cpu_present_map & (1UL << i))
+                       prof_multiplier(i) = multiplier;
+       }
+       current_tick_offset = (real_tick_offset / multiplier);
+       restore_flags(flags);
+
        return 0;
 }
index 990202bacfc97ebd2a42c64ec932ff52079f333f..fd2ddc08daf32c2de84b85087f086d516b504ac3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.17 1997/08/10 01:51:01 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,8 @@ extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst,
+                                             int len, unsigned int sum);
 extern char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
@@ -57,6 +58,10 @@ extern int __ashrdi3(int, int);
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
+#ifdef __SMP__
+extern spinlock_t scheduler_lock;
+#endif
+
 /* One thing to note is that the way the symbols of the mul/div
  * support routines are named is a mess, they all start with
  * a '.' which makes it a bitch to export, here is the trick:
@@ -70,7 +75,17 @@ __attribute__((section("__ksymtab"))) =                              \
 
 /* used by various drivers */
 #ifdef __SMP__
+EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(global_bh_lock);
 EXPORT_SYMBOL(klock_info);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL_PRIVATE(global_cli);
+EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+#else
+EXPORT_SYMBOL(local_irq_count);
 #endif
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
@@ -81,12 +96,13 @@ EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(__sparc64_bh_counter);
 EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
 EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
 #if CONFIG_SBUS
 EXPORT_SYMBOL(SBus_chain);
 EXPORT_SYMBOL(dma_chain);
@@ -150,7 +166,7 @@ EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__strncmp);
 EXPORT_SYMBOL(__memmove);
 
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial_copy_sparc64);
 
 /* Moving data to/from userspace. */
 EXPORT_SYMBOL(__copy_to_user);
index c827df7a1aba3bc70bde1d1e1e6364423909a1ba..0517a93578a7737d31fe21d22ffd083b4ea87962 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.3 1997/07/29 09:35:10 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -220,46 +220,36 @@ asmlinkage int
 sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
 {
        struct sigaction new_sa, *p;
-       int err = -EINVAL;
 
-       lock_kernel();
        if(signum < 0) {
                current->tss.new_signal = 1;
                signum = -signum;
        }
-
        if (signum<1 || signum>32)
-               goto out;
+               return -EINVAL;
        p = signum - 1 + current->sig->action;
        if (action) {
-               err = -EINVAL;
                if (signum==SIGKILL || signum==SIGSTOP)
-                       goto out;
-               err = -EFAULT;
+                       return -EINVAL;
                if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
-                       goto out;       
+                       return -EFAULT;
                if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
-                       err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+                       int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
                        if (err)
-                               goto out;
+                               return err;
                }
        }
-
        if (oldaction) {
-               err = -EFAULT;
                if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
-                       goto out;       
+                       return -EFAULT;
        }
-
        if (action) {
+               spin_lock_irq(&current->sig->siglock);
                *p = new_sa;
                check_pending(signum);
+               spin_unlock_irq(&current->sig->siglock);
        }
-
-       err = 0;
-out:
-       unlock_kernel();
-       return err;
+       return 0;
 }
 
 /* only AP+ systems have sys_aplib */
index b6ca9448c28e6858b47f1c2d9a21794ae8869001..31fc29019523dd7b6a213e2aa7fdcb214da1b1d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.44 1997/07/20 09:18:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -87,10 +87,11 @@ static unsigned long name_page_cache32 = 0;
 
 void putname32(char * name)
 {
-       if (name_page_cache32 == 0)
-               name_page_cache32 = (unsigned long) name;
-       else
-               free_page((unsigned long) name);
+       unsigned long page;
+
+       page = xchg(&name_page_cache32, ((unsigned long)name));
+       if(page)
+               free_page(page);
 }
 
 int getname32(u32 filename, char **result)
@@ -98,8 +99,7 @@ int getname32(u32 filename, char **result)
        unsigned long page;
        int retval;
 
-       page = name_page_cache32;
-       name_page_cache32 = 0;
+       page = xchg(&name_page_cache32, NULL);
        if (!page) {
                page = __get_free_page(GFP_KERNEL);
                if (!page)
@@ -1010,7 +1010,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
        lock_kernel ();
        p = (char *)__get_free_page (GFP_KERNEL);
        if (!p)
-               goto out;
+               goto out_nofree;
 
        q = (u32 *)p;
        Inp = (u32 *)A(inp);
@@ -1079,6 +1079,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
        }
 out:
        free_page ((unsigned long)p);
+out_nofree:
        unlock_kernel();
        return ret;
 }
@@ -2110,54 +2111,45 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
 {
        struct sigaction32 new_sa, old_sa;
        struct sigaction *p;
-       int err = -EINVAL;
 
-       lock_kernel();
        if(signum < 0) {
                current->tss.new_signal = 1;
                signum = -signum;
        }
-
        if (signum<1 || signum>32)
-               goto out;
+               return -EINVAL;
        p = signum - 1 + current->sig->action;
        if (action) {
-               err = -EINVAL;
                if (signum==SIGKILL || signum==SIGSTOP)
-                       goto out;
-               err = -EFAULT;
+                       return -EINVAL;
                if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
-                       goto out;
+                       return -EFAULT;
                if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && 
                    ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
-                       err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+                       int err = verify_area(VERIFY_READ,
+                                             (__sighandler_t)A(new_sa.sa_handler), 1);
                        if (err)
-                               goto out;
+                               return err;
                }
        }
-
        if (oldaction) {
-               err = -EFAULT;
                old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
                old_sa.sa_mask = (sigset_t32)(p->sa_mask);
                old_sa.sa_flags = (unsigned)(p->sa_flags);
                old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
                if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
-                       goto out;       
+                       return -EFAULT;
        }
-
        if (action) {
+               spin_lock_irq(&current->sig->siglock);
                p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
                p->sa_mask = (sigset_t)(new_sa.sa_mask);
                p->sa_flags = new_sa.sa_flags;
                p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
                check_pending(signum);
+               spin_unlock_irq(&current->sig->siglock);
        }
-
-       err = 0;
-out:
-       unlock_kernel();
-       return err;
+       return 0;
 }
 
 /*
@@ -2298,7 +2290,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
                 base = 1;
 
        lock_kernel();
-        filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+        filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
        error = PTR_ERR(filename);
         if(IS_ERR(filename))
                 goto out;
@@ -2720,9 +2712,7 @@ static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res
        return 0;
 }
 
-extern asmlinkage int sys_nfsservctl(int cmd,
-                                    struct nfsctl_arg *arg,
-                                    union nfsctl_res *resp);
+extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
 
 int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
 {
index eda0ff32632ff92c711aeea916f6e03eaa3b6126..0b4caf42a6637b073bcfd1e08589005fe9f85e5a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
+/* $Id: systbls.S,v 1.23 1997/08/09 18:33:17 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  */
 
-       .data
-       .align  8
+       .text
+       .align  1024
 
        /* First, the 32-bit Linux native syscall table. */
 
        .globl sys_call_table32
 sys_call_table32:
-/*0*/  .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/  .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/  .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
-       .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
-       .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
-       .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
-       .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
-       .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
-       .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
-       .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/        .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/        .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
-       .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/        .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
-       .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
-       .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
-/*170*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-       .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-       .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/        .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
-       .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/        .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
-       .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/        .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
-       .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/        .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
-       .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/        .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-       .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/        .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/        .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-       .xword sys_aplib, sys_nis_syscall
+/*0*/  .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/  .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/  .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+       .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+       .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+       .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
+/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+       .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+       .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+       .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+       .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/        .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/        .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+       .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/        .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+       .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+       .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+       .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
+       .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/        .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
+       .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/        .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+       .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/        .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+       .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/        .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
+       .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/        .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+       .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/        .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*250*/        .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+       .word sys_aplib
 
        /* Now the 64-bit native Linux syscall table. */
 
+       .align  1024
        .globl sys_call_table64, sys_call_table
 sys_call_table64:
 sys_call_table:
-/*0*/  .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/  .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
-       .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
-       .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
-       .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
-       .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-       .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
-       .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
-       .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/        .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
-       .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
-       .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
-/*120*/        .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
-       .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/        .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
-       .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/        .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
-       .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/        .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
-       .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-       .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-       .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/        .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
-       .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/        .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
-       .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/        .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
-       .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/        .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
-       .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/        .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-       .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/        .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
-       .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/        .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-       .xword sys_aplib, sys_nis_syscall
+/*0*/  .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/  .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+       .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+       .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+       .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+       .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+       .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+       .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+       .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/        .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
+       .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+       .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+/*120*/        .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+       .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/        .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
+       .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/        .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+       .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/        .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+       .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+       .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+       .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/        .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+       .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/        .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+       .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/        .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+       .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/        .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+       .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/        .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+       .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/        .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/        .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+       .word sys_aplib
 
        /* Now the 32-bit SunOS syscall table. */
 
-       .align 8
+       .align 1024
        .globl sunos_sys_table
 sunos_sys_table:
-/*0*/  .xword sunos_indir, sys_exit, sys_fork
-       .xword sunos_read, sunos_write, sunos_open
-       .xword sys_close, sunos_wait4, sys32_creat
-       .xword sys32_link, sys32_unlink, sunos_execv
-       .xword sys32_chdir, sunos_nosys, sys32_mknod
-       .xword sys32_chmod, sys32_chown, sunos_brk
-       .xword sunos_nosys, sys32_lseek, sunos_getpid
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_getuid, sunos_nosys, sys_ptrace
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sys32_access, sunos_nosys, sunos_nosys
-       .xword sys_sync, sys_kill, sys32_newstat
-       .xword sunos_nosys, sys32_newlstat, sys_dup
-       .xword sys_pipe, sunos_nosys, sys_profil
-       .xword sunos_nosys, sunos_nosys, sunos_getgid
-       .xword sunos_nosys, sunos_nosys
-/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys
-       .xword sunos_mctl, sunos_ioctl, sys32_reboot
-       .xword sunos_nosys, sys32_symlink, sys32_readlink
-       .xword sys32_execve, sys_umask, sys32_chroot
-       .xword sys32_newfstat, sunos_nosys, sys_getpagesize
-       .xword sys32_msync, sys_vfork, sunos_nosys
-       .xword sunos_nosys, sunos_sbrk, sunos_sstk
-       .xword sunos_mmap, sunos_vadvise, sys32_munmap
-       .xword sys32_mprotect, sunos_madvise, sys_vhangup
-       .xword sunos_nosys, sunos_mincore, sys32_getgroups
-       .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp
-       .xword sys32_setitimer, sunos_nosys, sys32_swapon
-       .xword sys32_getitimer, sys32_gethostname, sys32_sethostname
-       .xword sunos_getdtablesize, sys_dup2, sunos_nop
-       .xword sys32_fcntl, sunos_select, sunos_nop
-       .xword sys_fsync, sys_setpriority, sys_socket
-       .xword sys32_connect, sunos_accept
-/*100*/        .xword sys_getpriority, sunos_send, sunos_recv
-       .xword sunos_nosys, sys32_bind, sunos_setsockopt
-       .xword sys_listen, sunos_nosys, sunos_sigaction
-       .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
-       .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg
-       .xword sunos_nosys, sys_gettimeofday, sys32_getrusage
-       .xword sunos_getsockopt, sunos_nosys, sunos_readv
-       .xword sunos_writev, sys_settimeofday, sys_fchown
-       .xword sys_fchmod, sys32_recvfrom, sys32_setreuid
-       .xword sys_setregid, sys32_rename, sys32_truncate
-       .xword sys32_ftruncate, sys_flock, sunos_nosys
-       .xword sys32_sendto, sys_shutdown, sys_socketpair
-       .xword sys32_mkdir, sys32_rmdir, sys32_utimes
-       .xword sys_sigreturn, sunos_nosys, sys32_getpeername
-       .xword sunos_gethostid, sunos_nosys, sys32_getrlimit
-       .xword sys32_setrlimit, sunos_killpg, sunos_nosys
-       .xword sunos_nosys, sunos_nosys
-/*150*/        .xword sys32_getsockname, sunos_nosys, sunos_nosys
-       .xword sys32_poll, sunos_nosys, sunos_nosys
-       .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs
-       .xword sys32_umount, sunos_nosys, sunos_nosys
-       .xword sunos_getdomainname, sys32_setdomainname
-       .xword sunos_nosys, sys32_quotactl, sunos_nosys
-       .xword sunos_mount, sys32_ustat, sunos_semsys
-       .xword sunos_nosys, sunos_shmsys, sunos_audit
-       .xword sunos_nosys, sunos_getdents, sys_setsid
-       .xword sys_fchdir, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sys32_sigpending, sunos_nosys
-       .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
-       .xword sunos_sysconf, sunos_uname, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-/*200*/        .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys
-/*250*/        .xword sunos_nosys, sunos_nosys, sunos_nosys
-       .xword sunos_nosys, sunos_nosys, sys_aplib
+/*0*/  .word sunos_indir, sys_exit, sys_fork
+       .word sunos_read, sunos_write, sunos_open
+       .word sys_close, sunos_wait4, sys32_creat
+       .word sys32_link, sys32_unlink, sunos_execv
+       .word sys32_chdir, sunos_nosys, sys32_mknod
+       .word sys32_chmod, sys32_chown, sunos_brk
+       .word sunos_nosys, sys32_lseek, sunos_getpid
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_getuid, sunos_nosys, sys_ptrace
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sys32_access, sunos_nosys, sunos_nosys
+       .word sys_sync, sys_kill, sys32_newstat
+       .word sunos_nosys, sys32_newlstat, sys_dup
+       .word sys_pipe, sunos_nosys, sys_profil
+       .word sunos_nosys, sunos_nosys, sunos_getgid
+       .word sunos_nosys, sunos_nosys
+/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys
+       .word sunos_mctl, sunos_ioctl, sys32_reboot
+       .word sunos_nosys, sys32_symlink, sys32_readlink
+       .word sys32_execve, sys_umask, sys32_chroot
+       .word sys32_newfstat, sunos_nosys, sys_getpagesize
+       .word sys32_msync, sys_vfork, sunos_nosys
+       .word sunos_nosys, sunos_sbrk, sunos_sstk
+       .word sunos_mmap, sunos_vadvise, sys32_munmap
+       .word sys32_mprotect, sunos_madvise, sys_vhangup
+       .word sunos_nosys, sunos_mincore, sys32_getgroups
+       .word sys32_setgroups, sys_getpgrp, sunos_setpgrp
+       .word sys32_setitimer, sunos_nosys, sys32_swapon
+       .word sys32_getitimer, sys32_gethostname, sys32_sethostname
+       .word sunos_getdtablesize, sys_dup2, sunos_nop
+       .word sys32_fcntl, sunos_select, sunos_nop
+       .word sys_fsync, sys_setpriority, sys_socket
+       .word sys32_connect, sunos_accept
+/*100*/        .word sys_getpriority, sunos_send, sunos_recv
+       .word sunos_nosys, sys32_bind, sunos_setsockopt
+       .word sys_listen, sunos_nosys, sunos_sigaction
+       .word sunos_sigblock, sunos_sigsetmask, sys_sigpause
+       .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
+       .word sunos_nosys, sys_gettimeofday, sys32_getrusage
+       .word sunos_getsockopt, sunos_nosys, sunos_readv
+       .word sunos_writev, sys_settimeofday, sys_fchown
+       .word sys_fchmod, sys32_recvfrom, sys32_setreuid
+       .word sys_setregid, sys32_rename, sys32_truncate
+       .word sys32_ftruncate, sys_flock, sunos_nosys
+       .word sys32_sendto, sys_shutdown, sys_socketpair
+       .word sys32_mkdir, sys32_rmdir, sys32_utimes
+       .word sys_sigreturn, sunos_nosys, sys32_getpeername
+       .word sunos_gethostid, sunos_nosys, sys32_getrlimit
+       .word sys32_setrlimit, sunos_killpg, sunos_nosys
+       .word sunos_nosys, sunos_nosys
+/*150*/        .word sys32_getsockname, sunos_nosys, sunos_nosys
+       .word sys32_poll, sunos_nosys, sunos_nosys
+       .word sunos_getdirentries, sys32_statfs, sys32_fstatfs
+       .word sys32_umount, sunos_nosys, sunos_nosys
+       .word sunos_getdomainname, sys32_setdomainname
+       .word sunos_nosys, sys32_quotactl, sunos_nosys
+       .word sunos_mount, sys32_ustat, sunos_semsys
+       .word sunos_nosys, sunos_shmsys, sunos_audit
+       .word sunos_nosys, sunos_getdents, sys_setsid
+       .word sys_fchdir, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sys32_sigpending, sunos_nosys
+       .word sys_setpgid, sunos_pathconf, sunos_fpathconf
+       .word sunos_sysconf, sunos_uname, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/        .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys
+/*250*/        .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sys_aplib
index df6a1c05e93456e9f837fa05c122b18f2e5e698c..b83aebd88dfa6d3e2bde7737cc403030ae56f328 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
+/* $Id: time.c,v 1.9 1997/08/12 04:12:40 ecd Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/fhc.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
 
 struct mostek48t02 *mstk48t02_regs = 0;
 struct mostek48t08 *mstk48t08_regs = 0;
@@ -155,33 +160,55 @@ static int has_low_battery(void)
 
 
 /* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+__initfunc(static void set_system_time(void))
 {
-       struct linux_prom_registers clk_reg[2];
-       char model[128];
-       int node, sbusnd, err;
-
-       /* XXX HACK HACK HACK, delete me soon */
-       struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
-       int XXX_sbus_nranges;
+       unsigned int year, mon, day, hour, min, sec;
+       struct mostek48t02 *mregs;
 
-       node = prom_getchild(prom_root_node);
-       sbusnd = prom_searchsiblings(node, "sbus");
-       node = prom_getchild(sbusnd);
+       do_get_fast_time = do_gettimeofday;
 
-       if(node == 0 || node == -1) {
-               prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+       mregs = mstk48t02_regs;
+       if(!mregs) {
+               prom_printf("Something wrong, clock regs not mapped yet.\n");
                prom_halt();
+       }               
+
+       mregs->creg |= MSTK_CREG_READ;
+       sec = MSTK_REG_SEC(mregs);
+       min = MSTK_REG_MIN(mregs);
+       hour = MSTK_REG_HOUR(mregs);
+       day = MSTK_REG_DOM(mregs);
+       mon = MSTK_REG_MONTH(mregs);
+       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+       xtime.tv_usec = 0;
+       mregs->creg &= ~MSTK_CREG_READ;
+}
+
+__initfunc(void clock_probe(void))
+{
+       struct linux_prom_registers clk_reg[2];
+       char model[128];
+       int node, busnd = -1, err;
+
+       if(central_bus != NULL) {
+               busnd = central_bus->child->prom_node;
+       }
+#ifdef CONFIG_PCI
+       else if (ebus_chain != NULL) {
+               busnd = ebus_chain->prom_node;
+       }
+#endif
+       else {
+               busnd = SBus_chain->prom_node;
        }
 
-       /* XXX FIX ME */
-       err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
-                              sizeof(XXX_sbus_ranges));
-       if(err == -1) {
-               prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+       if(busnd == -1) {
+               prom_printf("clock_probe: problem, cannot find bus to search.\n");
                prom_halt();
        }
-       XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+       node = prom_getchild(busnd);
 
        while(1) {
                prom_getstring(node, "model", model, sizeof(model));
@@ -199,12 +226,34 @@ __initfunc(static void clock_probe(void))
                err = prom_getproperty(node, "reg", (char *)clk_reg,
                                       sizeof(clk_reg));
                if(err == -1) {
-                       prom_printf("clock_probe: Cannot make Mostek\n");
+                       prom_printf("clock_probe: Cannot get Mostek reg property\n");
                        prom_halt();
                }
 
-               /* XXX fix me badly */
-               prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+               if(central_bus) {
+                       prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
+                       prom_apply_central_ranges(central_bus, clk_reg, 1);
+               }
+#ifdef CONFIG_PCI
+               else if (ebus_chain) {
+                       struct linux_ebus_device *edev;
+
+                       for_each_ebusdev(edev, ebus_chain)
+                               if (edev->prom_node == node)
+                                       break;
+                       if (!edev) {
+                               prom_printf("%s: Mostek not probed by EBUS\n");
+                               prom_halt();
+                       }
+
+                       clk_reg[0] = edev->regs[0];
+               }
+#endif
+               else {
+                       prom_adjust_regs(clk_reg, 1,
+                                        SBus_chain->sbus_ranges,
+                                        SBus_chain->num_sbus_ranges);
+               }
 
                if(model[5] == '0' && model[6] == '2') {
                        mstk48t02_regs = (struct mostek48t02 *)
@@ -234,6 +283,8 @@ __initfunc(static void clock_probe(void))
        /* Kick start the clock if it is completely stopped. */
        if (mstk48t02_regs->sec & MSTK_STOP)
                kick_start_clock();
+
+       set_system_time();
 }
 
 #ifndef BCD_TO_BIN
@@ -246,29 +297,10 @@ __initfunc(static void clock_probe(void))
 
 __initfunc(void time_init(void))
 {
-       unsigned int year, mon, day, hour, min, sec;
-       struct mostek48t02 *mregs;
-
-       do_get_fast_time = do_gettimeofday;
-
-       clock_probe();
-
-       mregs = mstk48t02_regs;
-       if(!mregs) {
-               prom_printf("Something wrong, clock regs not mapped yet.\n");
-               prom_halt();
-       }               
-
-       mregs->creg |= MSTK_CREG_READ;
-       sec = MSTK_REG_SEC(mregs);
-       min = MSTK_REG_MIN(mregs);
-       hour = MSTK_REG_HOUR(mregs);
-       day = MSTK_REG_DOM(mregs);
-       mon = MSTK_REG_MONTH(mregs);
-       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_usec = 0;
-       mregs->creg &= ~MSTK_CREG_READ;
+       /* clock_probe() is now done at end of sbus_init on sparc64
+        * so that both sbus and fhc bus information is probed and
+        * available.
+        */
 }
 
 extern void init_timers(void (*func)(int, void *, struct pt_regs *));
@@ -307,8 +339,11 @@ void do_gettimeofday(struct timeval *tv)
        sethi   %hi(xtime), %g2
        ldx     [%o1 + %lo(linux_timers)], %g3
 1:     ldd     [%g2 + %lo(xtime)], %o4
+       membar  #LoadLoad | #MemIssue
        ldx     [%g3], %o1
+       membar  #LoadLoad | #MemIssue
        ldd     [%g2 + %lo(xtime)], %o2
+       membar  #LoadLoad
        xor     %o4, %o2, %o2
        xor     %o5, %o3, %o3
        orcc    %o2, %o3, %g0
index fe0df3200b551246e80519071d71342f0af8e536..b5ca851ac091509144f4e4eb8848fc50399e204a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+/* $Id: trampoline.S,v 1.2 1997/07/28 02:57:32 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/spitfire.h>
 #include <asm/asm_offsets.h>
 
+       .data
+       .align          8
+       .globl          smp_trampoline
+smp_trampoline:                .skip   0x300
+
        .text
-       .globl          sparc64_cpu_startup
+       .align          8
+       .globl          sparc64_cpu_startup, sparc64_cpu_startup_end
 sparc64_cpu_startup:
        flushw
        mov     (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
        stxa    %g1, [%g0] ASI_LSU_CONTROL
+       membar  #Sync
        wrpr    %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
        wrpr    %g0, 15, %pil
 
-       mov     %o0, %g6
+       sethi   %uhi(PAGE_OFFSET), %g4
+       sllx    %g4, 32, %g4
+
+       /* XXX Buggy PROM... */
+       srl     %o0, 0, %g6
+       add     %g6, %g4, %g6
 
        sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
        sllx    %g5, 32, %g5
@@ -33,9 +45,8 @@ sparc64_cpu_startup:
        sllx    %g3, 32, %g3
        sethi   %hi(_PAGE_PADDR), %g7
        or      %g7, %lo(_PAGE_PADDR), %g7
-       or      %g3, %g7, %g7
+       or      %g3, %g7, %g3
 
-       /* Find TLB entry we are executing out of. */
        clr     %l0
        set     0x1fff, %l2
        rd      %pc, %l3
@@ -69,7 +80,7 @@ sparc64_cpu_startup:
        andn    %g1, %l2, %g1
        cmp     %g1, %g3
        blu,pn  %xcc, 2f
-       cmp     %g1, %g7
+        cmp    %g1, %g7
        bgeu,pn %xcc, 2f
         nop
        stxa    %g0, [%l7] ASI_IMMU
@@ -109,7 +120,7 @@ sparc64_cpu_startup:
        stxa    %g3, [%l7] ASI_IMMU
        stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS
        membar  #Sync
-       flush   %g6
+       flush   %g3
        membar  #Sync
        b,pt    %xcc, 1f
         nop
@@ -125,9 +136,6 @@ bounce:
        stxa    %g0, [%g7] ASI_DMMU
        membar  #Sync
 
-       sethi   %uhi(PAGE_OFFSET), %g4
-       sllx    %g4, 32, %g4
-
        mov     TLB_TAG_ACCESS, %g2
        stxa    %g3, [%g2] ASI_IMMU
        stxa    %g3, [%g2] ASI_DMMU
@@ -143,7 +151,7 @@ bounce:
        stxa    %g1, [%g7] ASI_DTLB_DATA_ACCESS
        membar  #Sync
 
-       flush   %g6
+       flush   %g3
        membar  #Sync
 
        mov     1, %g5
@@ -184,7 +192,6 @@ bounce:
        stxa    %o5, [%o4] ASI_IMMU
        membar  #Sync
 
-       wrpr    %g0, 0, %pil
        or      %o1, PSTATE_IE, %o1
        wrpr    %o1, 0, %pstate
 
@@ -195,3 +202,6 @@ bounce:
        call    cpu_panic
         nop
 1:     b,a,pt  %xcc, 1b
+
+       .align          8
+sparc64_cpu_startup_end:
index ac3e79958b5df52b18d825da981318e32f31d7a6..1ffd43730ee1739c0e13ab5302fa4b05f5e482ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
 #include <asm/unistd.h>
 #include <asm/uaccess.h>
 #include <asm/fpumacro.h>
+#include <asm/lsu.h>
 
 /* #define SYSCALL_TRACING */
 /* #define VERBOSE_SYSCALL_TRACING */
@@ -194,8 +195,55 @@ void data_access_exception (struct pt_regs *regs)
        send_sig(SIGSEGV, current, 1);
 }
 
+#ifdef CONFIG_PCI
+/* This is really pathetic... */
+/* #define DEBUG_PCI_POKES */
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+#endif
+
 void do_dae(struct pt_regs *regs)
 {
+#ifdef CONFIG_PCI
+#ifdef DEBUG_PCI_POKES
+       prom_printf(" (POKE ");
+#endif
+       if(pci_poke_in_progress) {
+               unsigned long va;
+#ifdef DEBUG_PCI_POKES
+               prom_printf("tpc[%016lx] tnpc[%016lx] ",
+                           regs->tpc, regs->tnpc);
+#endif
+               pci_poke_faulted = 1;
+               regs->tnpc = regs->tpc + 4;
+
+
+#ifdef DEBUG_PCI_POKES
+               prom_printf("PCI) ");
+               /* prom_halt(); */
+#endif
+               /* Re-enable I/D caches, Ultra turned them off. */
+               for(va =  0; va < (PAGE_SIZE << 1); va += 32) {
+                       spitfire_put_icache_tag(va, 0x0);
+                       spitfire_put_dcache_tag(va, 0x0);
+               }
+               __asm__ __volatile__("flush %%g6\n\t"
+                                    "membar #Sync\n\t"
+                                    "stxa %0, [%%g0] %1\n\t"
+                                    "membar #Sync"
+                                    : /* no outputs */
+                                    : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+                                           LSU_CONTROL_IM | LSU_CONTROL_DM),
+                                      "i" (ASI_LSU_CONTROL)
+                                    : "memory");
+               return;
+       }
+#ifdef DEBUG_PCI_POKES
+       prom_printf("USER) ");
+       prom_printf("tpc[%016lx] tnpc[%016lx]\n");
+       prom_halt();
+#endif
+#endif
        send_sig(SIGSEGV, current, 1);
 }
 
@@ -215,11 +263,9 @@ void do_fpe_common(struct pt_regs *regs)
                regs->tpc = regs->tnpc;
                regs->tnpc += 4;
        } else {
-               lock_kernel();
                current->tss.sig_address = regs->tpc;
                current->tss.sig_desc = SUBSIG_FPERROR;
                send_sig(SIGFPE, current, 1);
-               unlock_kernel();
        }
 }
 
@@ -288,6 +334,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
        }
        printk("Instruction DUMP:");
        instruction_dump ((unsigned int *) regs->tpc);
+       lock_kernel(); /* Or else! */
        if(regs->tstate & TSTATE_PRIV)
                do_exit(SIGKILL);
        do_exit(SIGSEGV);
@@ -298,13 +345,11 @@ void do_illegal_instruction(struct pt_regs *regs)
        unsigned long pc = regs->tpc;
        unsigned long tstate = regs->tstate;
 
-       lock_kernel();
        if(tstate & TSTATE_PRIV)
                die_if_kernel("Kernel illegal instruction", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_ILLINST;
        send_sig(SIGILL, current, 1);
-       unlock_kernel();
 }
 
 void mem_address_unaligned(struct pt_regs *regs)
@@ -333,19 +378,16 @@ void do_privact(struct pt_regs *regs)
        current->tss.sig_address = regs->tpc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
        send_sig(SIGILL, current, 1);
-       unlock_kernel();
 }
 
 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                         unsigned long tstate)
 {
-       lock_kernel();
        if(tstate & TSTATE_PRIV)
                die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
        send_sig(SIGILL, current, 1);
-       unlock_kernel();
 }
 
 /* XXX User may want to be allowed to do this. XXX */
@@ -353,7 +395,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
 void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                            unsigned long tstate)
 {
-       lock_kernel();
        if(regs->tstate & TSTATE_PRIV) {
                printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
                       regs->u_regs[UREG_RETPC]);
@@ -363,15 +404,12 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
        send_sig(SIGBUS, current, 1);
-       unlock_kernel();
 }
 
 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                       unsigned long psr)
 {
-       lock_kernel();
        send_sig(SIGILL, current, 1);
-       unlock_kernel();
 }
 
 /* Trap level 1 stuff or other traps we should never see... */
index 73bda96d9ea80f4bab339e19bab4b5a0be797d5f..a02dbed8654cc17b8c6b2d8c45c1c0d03ecdd07c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
+/* $Id: ttable.S,v 1.19 1997/07/26 18:38:56 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,8 @@ tl0_irq5:     TRAP_IRQ(handler_irq, 5)  TRAP_IRQ(handler_irq, 6)
 tl0_irq7:      TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
 tl0_irq9:      TRAP_IRQ(handler_irq, 9)  TRAP_IRQ(handler_irq, 10)
 tl0_irq11:     TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13:     TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq13:     TRAP_IRQ(handler_irq, 13)
+tl0_itick:     TRAP_TICK
 tl0_irq15:     TRAP_IRQ(handler_irq, 15)
 tl0_resv050:   BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:   BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
index f2c714eae022ac41078e7f50a5033fb1cfa3f54f..0ebf92767bd516894a2109b3343812ec92638c6c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
+/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -143,8 +143,9 @@ spill_fixup:
        retry
 window_scheisse_from_user_common:
        wrpr            %g1, %cwp
+       sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
 window_scheisse_merge:
        srlx            %l5, PAGE_SHIFT, %o1
 
@@ -244,8 +245,9 @@ spill_fixup_mna:
        retry
 window_mna_from_user_common:
        wrpr            %g1, %cwp
+       sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
-        rd             %pc, %g7
+109:    or             %g7, %lo(109b), %g7
 window_mna_merge:
        call            mem_address_unaligned
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
index 3da21c6060e740e0a35687d30e7263278ff69c80..1c32b3e46c18fc6f40d3ff599f7a7cd7f202abeb 100644 (file)
@@ -6,7 +6,7 @@ CFLAGS := $(CFLAGS) -ansi
 
 OBJS  = blockops.o locks.o strlen.o strncmp.o \
        memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-       VIScopy.o VISbzero.o VISmemset.o VIScsum.o
+       VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
 
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
index 1afaf35300c7c25de55b2ed91da600a118b1f30b..303d20a191448e190cbd4fd16f789d73bded750b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: VISbzero.S,v 1.4 1997/06/28 17:21:21 jj Exp $
+/* $Id: VISbzero.S,v 1.6 1997/08/08 08:34:00 jj Exp $
  * VISbzero.S: High speed clear operations utilizing the UltraSparc
  *        Visual Instruction Set.
  *
@@ -147,7 +147,7 @@ bzero:
 #else
         wr             %g0, ASI_BLK_P, %asi
 #endif
-       membar          #StoreStore | #LoadStore
+       membar          #StoreLoad | #StoreStore | #LoadStore
        fzero           %f0
        andcc           %o3, 0xc0, %o2
        and             %o1, 0x3f, %o1
@@ -181,15 +181,23 @@ bzero:
        wr              %g0, 0, %fprs
        wr              %g7, 0x0, %asi
 #endif
-       membar          #Sync
+       membar          #StoreLoad | #StoreStore
 9:     andcc           %o1, 0xf8, %o2
        be,pn           %xcc, 13f
         andcc          %o1, 7, %o1
+#ifdef __KERNEL__
+14:    sethi           %hi(13f), %o4
+       srl             %o2, 1, %o3
+       sub             %o4, %o3, %o4
+       jmpl            %o4 + %lo(13f), %g0
+        add            %o0, %o2, %o0
+#else
 14:    rd              %pc, %o4
        srl             %o2, 1, %o3
        sub             %o4, %o3, %o4
        jmpl            %o4 + (13f - 14b), %g0
         add            %o0, %o2, %o0
+#endif
 12:    ZERO_BLOCKS(%o0, 0xc8, %g0)
        ZERO_BLOCKS(%o0, 0x88, %g0)
        ZERO_BLOCKS(%o0, 0x48, %g0)
index 97b9b519dd176dde7f4c2ec1acc13cfb62ccff63..819546492efda55decbe8f0be93409d8895c3e5a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.9 1997/07/13 18:23:39 davem Exp $
+/* $Id: VIScopy.S,v 1.11 1997/08/08 08:34:02 jj Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -303,7 +303,7 @@ copy_page:  wr              %g0, FPRS_FEF, %fprs            ! FPU   Group
                sethi           %hi(8192), %o2                  ! IEU0  Group
                mov             ASI_BLK_P, asi_src              ! IEU1
                b,pt            %xcc, dest_is_64byte_aligned    ! CTI
-                mov            ASI_BLK_COMMIT_P, asi_dest      ! IEU0  Group
+                mov            ASI_BLK_P, asi_dest             ! IEU0  Group
 
                .align                  32
                .globl                  __copy_from_user
@@ -446,6 +446,13 @@ dest_is_64byte_aligned:
        EXVIS1(LDBLK            [%o1 + 0x40] ASIBLK, %f16)      ! LSU   Group
        sub                     %g7, 0x80, %g7                  ! IEU0
        EXVIS(LDBLK             [%o1 + 0x80] ASIBLK, %f32)      ! LSU   Group
+#ifdef __KERNEL__
+vispc: sll                     %g2, 9, %g2                     ! IEU0  Group
+       sethi                   %hi(vis00), %g5                 ! IEU1
+       or                      %g5, %lo(vis00), %g5            ! IEU0  Group
+       jmpl                    %g5 + %g2, %g0                  ! CTI   Group brk forced
+        addcc                  %o1, 0xc0, %o1                  ! IEU1  Group
+#else
                                                                ! Clk1  Group 8-(
                                                                ! Clk2  Group 8-(
                                                                ! Clk3  Group 8-(
@@ -455,6 +462,7 @@ vispc:      rd                      %pc, %g5                        ! PDU   Group 8-(
        sll                     %g2, 9, %g2                     ! IEU0
        jmpl                    %g5 + %g2, %g0                  ! CTI   Group brk forced
         addcc                  %o1, 0xc0, %o1                  ! IEU1  Group
+#endif
        .align                  512             /* OK, here comes the fun part... */
 vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01)
       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02)
@@ -721,20 +729,21 @@ __memcpy_16plus:
 3:     andcc           %o2, 0x70, %g7                          ! IEU1  Group
 41:    be,pn           %xcc, 80f                               ! CTI
         andcc          %o2, 8, %g0                             ! IEU1  Group
-                                                               ! Clk1 8-(
-                                                               ! Clk2 8-(
-                                                               ! Clk3 8-(
-                                                               ! Clk4 8-(
-79:    rd              %pc, %o5                                ! PDU   Group
 #ifdef __KERNEL__
+79:    sethi           %hi(80f), %o5                           ! IEU0
        sll             %g7, 1, %g5                             ! IEU0  Group
        add             %o1, %g7, %o1                           ! IEU1
        srl             %g7, 1, %g2                             ! IEU0  Group
        sub             %o5, %g5, %o5                           ! IEU1
        sub             %o5, %g2, %o5                           ! IEU0  Group
-       jmpl            %o5 + %lo(80f - 79b), %g0               ! CTI   Group brk forced
+       jmpl            %o5 + %lo(80f), %g0                     ! CTI   Group brk forced
         add            %o0, %g7, %o0                           ! IEU0  Group
 #else
+                                                               ! Clk1 8-(
+                                                               ! Clk2 8-(
+                                                               ! Clk3 8-(
+                                                               ! Clk4 8-(
+79:    rd              %pc, %o5                                ! PDU   Group
        sll             %g7, 1, %g5                             ! IEU0  Group
        add             %o1, %g7, %o1                           ! IEU1
        sub             %o5, %g5, %o5                           ! IEU0  Group
@@ -814,19 +823,20 @@ normal_retl:
        andcc           %o2, 0x70, %g7                          ! IEU1
        be,pn           %xcc, 84f                               ! CTI
         andcc          %o2, 8, %g0                             ! IEU1  Group
+#ifdef __KERNEL__
+83:    srl             %g7, 1, %g5                             ! IEU0
+       sethi           %hi(84f), %o5                           ! IEU0  Group
+       add             %g7, %g5, %g5                           ! IEU1
+       add             %o1, %g7, %o1                           ! IEU0  Group
+       sub             %o5, %g5, %o5                           ! IEU1
+       jmpl            %o5 + %lo(84f), %g0                     ! CTI   Group brk forced
+        add            %o0, %g7, %o0                           ! IEU0  Group
+#else
                                                                ! Clk1 8-(
                                                                ! Clk2 8-(
                                                                ! Clk3 8-(
                                                                ! Clk4 8-(
 83:    rd              %pc, %o5                                ! PDU   Group
-#ifdef __KERNEL__
-       srl             %g7, 1, %g5                             ! IEU0  Group
-       add             %g7, %g5, %g5                           ! IEU0  Group
-       add             %o1, %g7, %o1                           ! IEU1
-       sub             %o5, %g5, %o5                           ! IEU0  Group
-       jmpl            %o5 + %lo(84f - 83b), %g0               ! CTI   Group brk forced
-        add            %o0, %g7, %o0                           ! IEU0  Group
-#else
        add             %o1, %g7, %o1                           ! IEU0  Group
        sub             %o5, %g7, %o5                           ! IEU1
        jmpl            %o5 + %lo(84f - 83b), %g0               ! CTI   Group brk forced
index b3c510a073828fcb2ce480639883bcff1d120c5a..d99ad11e88c113fb69a53ac39ea536b646894911 100644 (file)
@@ -434,3 +434,447 @@ csum_partial:
         add            %o2, 1, %o2             /*  IEU0                                */
 1:     ba,pt           %xcc, 25b               /*  CTI         Group                   */
         sllx           %o2, 32, %g1            /*  IEU0                                */
+/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
+ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
+ *            Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ *      Copyright(C) 1995 Linus Torvalds
+ *      Copyright(C) 1995 Miguel de Icaza
+ *      Copyright(C) 1996,1997 David S. Miller
+ *    derived from:
+ *       Linux/Alpha checksum c-code
+ *        Linux/ix86 inline checksum assembly
+ *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *       David Mosberger-Tang for optimized reference c-code
+ *       BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF       2175
+#else
+#define STACKOFF       64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#else
+#define ASI_BLK_P      0xf0
+#define FRPS_FEF       0x04
+#endif
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ */
+
+#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10)                                                 \
+       fcmpgt32        %fz, %f0, %g1           /*  FPM         Group                   */;     \
+       fcmpgt32        %fz, %f2, %g2           /*  FPM         Group                   */;     \
+       fcmpgt32        %fz, %f4, %g3           /*  FPM         Group                   */;     \
+       fcmpgt32        %fz, %f6, %g5           /*  FPM         Group                   */;     \
+       inc             %g1                     /*  IEU0                                */;     \
+       fcmpgt32        %fz, %f8, %g7           /*  FPM         Group                   */;     \
+       srl             %g1, 1, %g1             /*  IEU0                                */;     \
+       inc             %g2                     /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f10, %o3          /*  FPM         Group                   */;     \
+       srl             %g2, 1, %g2             /*  IEU0                                */;     \
+       add             %o2, %g1, %o2           /*  IEU1                                */;     \
+       add             %g3, 1, %g3             /*  IEU0        Group                   */;     \
+       srl             %g3, 1, %g3             /*  IEU0        Group                   */;     \
+       add             %o2, %g2, %o2           /*  IEU1                                */;     \
+       inc             %g5                     /*  IEU0        Group                   */;     \
+       add             %o2, %g3, %o2           /*  IEU1                                */;
+
+#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14)            \
+       fcmpgt32        %O12, %f12, %o4         /*  FPM         Group                   */;     \
+       srl             %g5, 1, %g5             /*  IEU0                                */;     \
+       inc             %g7                     /*  IEU1                                */;     \
+       fpadd32         %F0, %f0, %F0           /*  FPA                                 */;     \
+       fcmpgt32        %O14, %f14, %o5         /*  FPM         Group                   */;     \
+       srl             %g7, 1, %g7             /*  IEU0                                */;     \
+       add             %o2, %g5, %o2           /*  IEU1                                */;     \
+       fpadd32         %F2, %f2, %F2           /*  FPA                                 */;     \
+       inc             %o3                     /*  IEU0        Group                   */;     \
+       add             %o2, %g7, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %f0, %F0, %g1           /*  FPM         Group                   */;     \
+       srl             %o3, 1, %o3             /*  IEU0                                */;     \
+       inc             %o4                     /*  IEU1                                */;     \
+       fpadd32         %F4, %f4, %F4           /*  FPA                                 */;     \
+       fcmpgt32        %f2, %F2, %g2           /*  FPM         Group                   */;     \
+       srl             %o4, 1, %o4             /*  IEU0                                */;     \
+       add             %o2, %o3, %o2           /*  IEU1                                */;     \
+       fpadd32         %F6, %f6, %F6           /*  FPA                                 */;     \
+       inc             %o5                     /*  IEU0        Group                   */;     \
+       add             %o2, %o4, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %f4, %F4, %g3           /*  FPM         Group                   */;     \
+       srl             %o5, 1, %o5             /*  IEU0                                */;     \
+       inc             %g1                     /*  IEU1                                */;     \
+       fpadd32         %F8, %f8, %F8           /*  FPA                                 */;     \
+       fcmpgt32        %f6, %F6, %g5           /*  FPM         Group                   */;     \
+       srl             %g1, 1, %g1             /*  IEU0                                */;     \
+       add             %o2, %o5, %o2           /*  IEU1                                */;     \
+       fpadd32         %F10, %f10, %F10        /*  FPA                                 */;     \
+       inc             %g2                     /*  IEU0        Group                   */;     \
+       add             %o2, %g1, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %f8, %F8, %g7           /*  FPM         Group                   */;     \
+       srl             %g2, 1, %g2             /*  IEU0                                */;     \
+       inc             %g3                     /*  IEU1                                */;     \
+       fpadd32         %F12, %f12, %F12        /*  FPA                                 */;     \
+       fcmpgt32        %f10, %F10, %o3         /*  FPM         Group                   */;     \
+       srl             %g3, 1, %g3             /*  IEU0                                */;     \
+       add             %o2, %g2, %o2           /*  IEU1                                */;     \
+       fpadd32         %F14, %f14, %F14        /*  FPA                                 */;     \
+       inc             %g5                     /*  IEU0        Group                   */;     \
+       add             %o2, %g3, %o2           /*  IEU1                                */;
+
+#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz)              \
+       fcmpgt32        %O12, %f12, %o4         /*  FPM         Group                   */;     \
+       srl             %g5, 1, %g5             /*  IEU0                                */;     \
+       inc             %g7                     /*  IEU1                                */;     \
+       fpadd32         %f2, %f0, %S0           /*  FPA                                 */;     \
+       fcmpgt32        %O14, %f14, %o5         /*  FPM         Group                   */;     \
+       srl             %g7, 1, %g7             /*  IEU0                                */;     \
+       add             %o2, %g5, %o2           /*  IEU1                                */;     \
+       fpadd32         %f6, %f4, %S1           /*  FPA                                 */;     \
+       inc             %o3                     /*  IEU0        Group                   */;     \
+       add             %o2, %g7, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %f0, %S0, %g1           /*  FPM         Group                   */;     \
+       srl             %o3, 1, %o3             /*  IEU0                                */;     \
+       inc             %o4                     /*  IEU1                                */;     \
+       fpadd32         %f10, %f8, %S2          /*  FPA                                 */;     \
+       fcmpgt32        %f4, %S1, %g2           /*  FPM         Group                   */;     \
+       srl             %o4, 1, %o4             /*  IEU0                                */;     \
+       add             %o2, %o3, %o2           /*  IEU1                                */;     \
+       fpadd32         %f14, %f12, %S3         /*  FPA                                 */;     \
+       inc             %o5                     /*  IEU0        Group                   */;     \
+       add             %o2, %o4, %o2           /*  IEU1                                */;     \
+       fzero           %fz                     /*  FPA                                 */;     \
+       fcmpgt32        %f8, %S2, %g3           /*  FPM         Group                   */;     \
+       srl             %o5, 1, %o5             /*  IEU0                                */;     \
+       inc             %g1                     /*  IEU1                                */;     \
+       fpadd32         %S0, %S1, %T0           /*  FPA                                 */;     \
+       fcmpgt32        %f12, %S3, %g5          /*  FPM         Group                   */;     \
+       srl             %g1, 1, %g1             /*  IEU0                                */;     \
+       add             %o2, %o5, %o2           /*  IEU1                                */;     \
+       fpadd32         %S2, %S3, %T1           /*  FPA                                 */;     \
+       inc             %g2                     /*  IEU0        Group                   */;     \
+       add             %o2, %g1, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %S0, %T0, %g7           /*  FPM         Group                   */;     \
+       srl             %g2, 1, %g2             /*  IEU0                                */;     \
+       inc             %g3                     /*  IEU1                                */;     \
+       fcmpgt32        %S2, %T1, %o3           /*  FPM         Group                   */;     \
+       srl             %g3, 1, %g3             /*  IEU0                                */;     \
+       add             %o2, %g2, %o2           /*  IEU1                                */;     \
+       inc             %g5                     /*  IEU0        Group                   */;     \
+       add             %o2, %g3, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f2, %o4           /*  FPM         Group                   */;     \
+       srl             %g5, 1, %g5             /*  IEU0                                */;     \
+       inc             %g7                     /*  IEU1                                */;     \
+       fpadd32         %T0, %T1, %U0           /*  FPA                                 */;     \
+       fcmpgt32        %fz, %f6, %o5           /*  FPM         Group                   */;     \
+       srl             %g7, 1, %g7             /*  IEU0                                */;     \
+       add             %o2, %g5, %o2           /*  IEU1                                */;     \
+       inc             %o3                     /*  IEU0        Group                   */;     \
+       add             %o2, %g7, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f10, %g1          /*  FPM         Group                   */;     \
+       srl             %o3, 1, %o3             /*  IEU0                                */;     \
+       inc             %o4                     /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f14, %g2          /*  FPM         Group                   */;     \
+       srl             %o4, 1, %o4             /*  IEU0                                */;     \
+       add             %o2, %o3, %o2           /*  IEU1                                */;     \
+       std             %U0, [%sp + STACKOFF]   /*  Store       Group                   */;     \
+       inc             %o5                     /*  IEU0                                */;     \
+       sub             %o2, %o4, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %fz, %S1, %g3           /*  FPM         Group                   */;     \
+       srl             %o5, 1, %o5             /*  IEU0                                */;     \
+       inc             %g1                     /*  IEU1                                */;     \
+       fcmpgt32        %fz, %S3, %g5           /*  FPM         Group                   */;     \
+       srl             %g1, 1, %g1             /*  IEU0                                */;     \
+       sub             %o2, %o5, %o2           /*  IEU1                                */;     \
+       ldx             [%sp + STACKOFF], %o5   /*  Load        Group                   */;     \
+       inc             %g2                     /*  IEU0                                */;     \
+       sub             %o2, %g1, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %fz, %T1, %g7           /*  FPM         Group                   */;     \
+       srl             %g2, 1, %g2             /*  IEU0                                */;     \
+       inc             %g3                     /*  IEU1                                */;     \
+       fcmpgt32        %T0, %U0, %o3           /*  FPM         Group                   */;     \
+       srl             %g3, 1, %g3             /*  IEU0                                */;     \
+       sub             %o2, %g2, %o2           /*  IEU1                                */;     \
+       inc             %g5                     /*  IEU0        Group                   */;     \
+       sub             %o2, %g3, %o2           /*  IEU1                                */;     \
+       fcmpgt32        %fz, %U0, %o4           /*  FPM         Group                   */;     \
+       srl             %g5, 1, %g5             /*  IEU0                                */;     \
+       inc             %g7                     /*  IEU1                                */;     \
+       srl             %g7, 1, %g7             /*  IEU0        Group                   */;     \
+       sub             %o2, %g5, %o2           /*  IEU1                                */;     \
+       inc             %o3                     /*  IEU0        Group                   */;     \
+       sub             %o2, %g7, %o2           /*  IEU1                                */;     \
+       srl             %o3, 1, %o3             /*  IEU0        Group                   */;     \
+       inc             %o4                     /*  IEU1                                */;     \
+       srl             %o4, 1, %o4             /*  IEU0        Group                   */;     \
+       add             %o2, %o3, %o2           /*  IEU1                                */;     \
+       sub             %o2, %o4, %o2           /*  IEU0        Group                   */;     \
+       addcc           %o2, %o5, %o2           /*  IEU1        Group                   */;     \
+       bcs,a,pn        %xcc, 33f               /*  CTI                                 */;     \
+        add            %o2, 1, %o2             /*  IEU0                                */;     \
+33:                                            /*  That's it                           */;
+
+#define CSUM_LASTCHUNK(offset)                                                                 \
+        ldx             [%o0 - offset - 0x10], %g2;                                            \
+        ldx             [%o0 - offset - 0x08], %g3;                                            \
+        addcc           %g2, %o2, %o2;                                                         \
+        bcs,a,pn        %xcc, 31f;                                                             \
+         add            %o2, 1, %o2;                                                           \
+31:     addcc           %g3, %o2, %o2;                                                         \
+        bcs,a,pn        %xcc, 32f;                                                             \
+         add            %o2, 1, %o2;                                                           \
+32:
+
+       .text
+       .globl          csum_partial
+       .align          32
+csum_partial:
+       andcc           %o0, 7, %g0             /*  IEU1        Group                   */
+       be,pt           %icc, 4f                /*  CTI                                 */
+        andcc          %o0, 0x38, %g3          /*  IEU1                                */
+       mov             1, %g5                  /*  IEU0        Group                   */
+       cmp             %o1, 6                  /*  IEU1                                */
+       bl,pn           %icc, 21f               /*  CTI                                 */
+        andcc          %o0, 2, %g0             /*  IEU1        Group                   */
+       be,pt           %icc, 1f                /*  CTI                                 */
+        and            %o0, 4, %g7             /*  IEU0                                */
+       lduh            [%o0], %g2              /*  Load                                */
+       sub             %o1, 2, %o1             /*  IEU0        Group                   */
+       add             %o0, 2, %o0             /*  IEU1                                */
+       andcc           %o0, 4, %g7             /*  IEU1        Group                   */
+       sll             %g5, 16, %g5            /*  IEU0                                */
+       sll             %g2, 16, %g2            /*  IEU0        Group                   */
+       addcc           %g2, %o2, %o2           /*  IEU1        Group (regdep)          */
+       bcs,a,pn        %icc, 1f                /*  CTI                                 */
+        add            %o2, %g5, %o2           /*  IEU0                                */
+1:     ld              [%o0], %g2              /*  Load                                */
+       brz,a,pn        %g7, 4f                 /*  CTI+IEU1    Group                   */
+        and            %o0, 0x38, %g3          /*  IEU0                                */
+       add             %o0, 4, %o0             /*  IEU0        Group                   */
+       sub             %o1, 4, %o1             /*  IEU1                                */
+       addcc           %g2, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %icc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     and             %o0, 0x38, %g3          /*  IEU1        Group                   */
+4:     srl             %o2, 0, %o2             /*  IEU0        Group                   */
+       mov             0x40, %g1               /*  IEU1                                */
+       brz,pn          %g3, 3f                 /*  CTI+IEU1    Group                   */
+        sub            %g1, %g3, %g1           /*  IEU0                                */
+       cmp             %o1, 56                 /*  IEU1        Group                   */
+       blu,pn          %icc, 20f               /*  CTI                                 */
+        andcc          %o0, 8, %g0             /*  IEU1        Group                   */
+       be,pn           %icc, 1f                /*  CTI                                 */
+        ldx            [%o0], %g2              /*  Load                                */
+       add             %o0, 8, %o0             /*  IEU0        Group                   */
+       sub             %o1, 8, %o1             /*  IEU1                                */
+       addcc           %g2, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     andcc           %g1, 0x10, %g0          /*  IEU1        Group                   */
+       be,pn           %icc, 2f                /*  CTI                                 */
+        and            %g1, 0x20, %g1          /*  IEU0                                */
+       ldx             [%o0], %g2              /*  Load                                */
+       ldx             [%o0+8], %g3            /*  Load        Group                   */
+       add             %o0, 16, %o0            /*  IEU0                                */
+       sub             %o1, 16, %o1            /*  IEU1                                */
+       addcc           %g2, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     addcc           %g3, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 2f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+2:     brz,pn          %g1, 3f                 /*  CTI+IEU1    Group                   */
+        ldx            [%o0], %g2              /*  Load                                */
+       ldx             [%o0+8], %g3            /*  Load        Group                   */
+       ldx             [%o0+16], %g5           /*  Load        Group                   */
+       ldx             [%o0+24], %g7           /*  Load        Group                   */
+       add             %o0, 32, %o0            /*  IEU0                                */
+       sub             %o1, 32, %o1            /*  IEU1                                */
+       addcc           %g2, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     addcc           %g3, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     addcc           %g5, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     addcc           %g7, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 3f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+3:     cmp             %o1, 0xc0               /*  IEU1        Group                   */
+       blu,pn          %icc, 20f               /*  CTI                                 */
+        sllx           %o2, 32, %g1            /*  IEU0                                */
+       addcc           %o2, %g1, %o2           /*  IEU1        Group                   */
+       sub             %o1, 0xc0, %o1          /*  IEU0                                */
+       wr              %g0, ASI_BLK_P, %asi    /*  LSU         Group                   */
+#ifdef __KERNEL__
+       wr              %g0, FPRS_FEF, %fprs    /*  LSU         Group                   */
+#endif
+       membar          #StoreLoad              /*  LSU         Group                   */
+       srlx            %o2, 32, %o2            /*  IEU0        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU1                                */
+1:     andcc           %o1, 0x80, %g0          /*  IEU1        Group                   */
+       bne,pn          %icc, 7f                /*  CTI                                 */
+        andcc          %o1, 0x40, %g0          /*  IEU1        Group                   */
+       be,pn           %icc, 6f                /*  CTI                                 */
+        fzero          %f12                    /*  FPA                                 */
+       fzero           %f14                    /*  FPA         Group                   */
+       ldda            [%o0 + 0x000] %asi, %f16
+       ldda            [%o0 + 0x040] %asi, %f32
+       ldda            [%o0 + 0x080] %asi, %f48
+       START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
+       ba,a,pt         %xcc, 3f
+6:     sub             %o0, 0x40, %o0          /*  IEU0        Group                   */
+       fzero           %f28                    /*  FPA                                 */
+       fzero           %f30                    /*  FPA         Group                   */
+       ldda            [%o0 + 0x040] %asi, %f32
+       ldda            [%o0 + 0x080] %asi, %f48
+       ldda            [%o0 + 0x0c0] %asi, %f0
+       START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
+       ba,a,pt         %xcc, 4f
+7:     bne,pt          %icc, 8f                /*  CTI                                 */
+        fzero          %f44                    /*  FPA                                 */
+       add             %o0, 0x40, %o0          /*  IEU0        Group                   */
+       fzero           %f60                    /*  FPA                                 */
+       fzero           %f62                    /*  FPA         Group                   */
+       ldda            [%o0 - 0x040] %asi, %f0
+       ldda            [%o0 + 0x000] %asi, %f16
+       ldda            [%o0 + 0x040] %asi, %f32
+       START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
+       ba,a,pt         %xcc, 2f
+8:     add             %o0, 0x80, %o0          /*  IEU0        Group                   */
+       fzero           %f46                    /*  FPA                                 */
+       ldda            [%o0 - 0x080] %asi, %f48
+       ldda            [%o0 - 0x040] %asi, %f0
+       ldda            [%o0 + 0x000] %asi, %f16
+       START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58)
+1:     DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+       ldda            [%o0 + 0x040] %asi, %f32
+2:     DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+       ldda            [%o0 + 0x080] %asi, %f48
+3:     DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
+       ldda            [%o0 + 0x0c0] %asi, %f0
+4:     DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
+       add             %o0, 0x100, %o0         /*  IEU0        Group                   */
+       subcc           %o1, 0x100, %o1         /*  IEU1                                */
+       bgeu,a,pt       %icc, 1b                /*  CTI                                 */
+        ldda           [%o0 + 0x000] %asi, %f16
+       membar          #Sync                   /*  LSU         Group                   */
+       DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+       END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+       and             %o1, 0x3f, %o1          /*  IEU0        Group                   */
+#ifdef __KERNEL__
+       wr              %g0, 0, %fprs           /*  LSU         Group                   */
+#endif
+20:    andcc           %o1, 0xf0, %g1          /*  IEU1        Group                   */
+       be,pn           %icc, 23f               /*  CTI                                 */
+        and            %o1, 0xf, %o3           /*  IEU0                                */
+#ifdef __KERNEL__
+22:    sll             %g1, 1, %o4             /*  IEU0        Group                   */
+       sethi           %hi(23f), %g7           /*  IEU1                                */
+       sub             %g7, %o4, %g7           /*  IEU0        Group                   */
+       jmpl            %g7 + %lo(23f), %g0     /*  CTI         Group brk forced        */
+        add            %o0, %g1, %o0           /*  IEU0                                */
+#else
+22:    rd              %pc, %g7                /*  LSU         Group+4bubbles          */
+       sll             %g1, 1, %o4             /*  IEU0        Group                   */
+       sub             %g7, %o4, %g7           /*  IEU0        Group (regdep)          */
+       jmpl            %g7 + (23f - 22b), %g0  /*  CTI         Group brk forced        */
+        add            %o0, %g1, %o0           /*  IEU0                                */
+#endif
+       CSUM_LASTCHUNK(0xe0)
+       CSUM_LASTCHUNK(0xd0)
+       CSUM_LASTCHUNK(0xc0)
+       CSUM_LASTCHUNK(0xb0)
+       CSUM_LASTCHUNK(0xa0)
+       CSUM_LASTCHUNK(0x90)
+       CSUM_LASTCHUNK(0x80)
+       CSUM_LASTCHUNK(0x70)
+       CSUM_LASTCHUNK(0x60)
+       CSUM_LASTCHUNK(0x50)
+       CSUM_LASTCHUNK(0x40)
+       CSUM_LASTCHUNK(0x30)
+       CSUM_LASTCHUNK(0x20)
+       CSUM_LASTCHUNK(0x10)
+       CSUM_LASTCHUNK(0x00)
+23:    brnz,pn         %o3, 26f                /*  CTI+IEU1    Group                   */
+24:     sllx           %o2, 32, %g1            /*  IEU0                                */
+25:    addcc           %o2, %g1, %o0           /*  IEU1        Group                   */
+       srlx            %o0, 32, %o0            /*  IEU0        Group (regdep)          */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o0, 1, %o0             /*  IEU1                                */
+1:     retl                                    /*  CTI         Group brk forced        */
+        srl            %o0, 0, %o0             /*  IEU0                                */
+26:    andcc           %o1, 8, %g0             /*  IEU1        Group                   */
+       be,pn           %icc, 1f                /*  CTI                                 */
+        ldx            [%o0], %g3              /*  Load                                */
+       add             %o0, 8, %o0             /*  IEU0        Group                   */
+       addcc           %g3, %o2, %o2           /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     andcc           %o1, 4, %g0             /*  IEU1        Group                   */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %g2                     /*  IEU0                                */
+       ld              [%o0], %g2              /*  Load                                */
+       add             %o0, 4, %o0             /*  IEU0        Group                   */
+       sllx            %g2, 32, %g2            /*  IEU0        Group                   */
+1:     andcc           %o1, 2, %g0             /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o4                     /*  IEU0        Group                   */
+       lduh            [%o0], %o4              /*  Load                                */
+       add             %o0, 2, %o0             /*  IEU1                                */
+       sll             %o4, 16, %o4            /*  IEU0        Group                   */
+1:     andcc           %o1, 1, %g0             /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o5                     /*  IEU0        Group                   */
+       ldub            [%o0], %o5              /*  Load                                */
+       sll             %o5, 8, %o5             /*  IEU0        Group                   */
+1:     or              %g2, %o4, %o4           /*  IEU1                                */
+       or              %o5, %o4, %o4           /*  IEU0        Group (regdep)          */
+       addcc           %o4, %o2, %o2           /*  IEU1        Group (regdep)          */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     ba,pt           %xcc, 25b               /*  CTI         Group                   */
+        sllx           %o2, 32, %g1            /*  IEU0                                */
+21:    srl             %o2, 0, %o2             /*  IEU0        Group                   */
+       cmp             %o1, 0                  /*  IEU1                                */
+       be,pn           %icc, 24b               /*  CTI                                 */
+        andcc          %o1, 4, %g0             /*  IEU1        Group                   */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %g2                     /*  IEU0                                */
+       lduh            [%o0], %g3              /*  Load                                */
+       lduh            [%o0+2], %g2            /*  Load        Group                   */
+       add             %o0, 4, %o0             /*  IEU0        Group                   */
+       sllx            %g3, 48, %g3            /*  IEU0        Group                   */
+       sllx            %g2, 32, %g2            /*  IEU0        Group                   */
+       or              %g3, %g2, %g2           /*  IEU0        Group                   */
+1:     andcc           %o1, 2, %g0             /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o4                     /*  IEU0        Group                   */
+       lduh            [%o0], %o4              /*  Load                                */
+       add             %o0, 2, %o0             /*  IEU1                                */
+       sll             %o4, 16, %o4            /*  IEU0        Group                   */
+1:     andcc           %o1, 1, %g0             /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o5                     /*  IEU0        Group                   */
+       ldub            [%o0], %o5              /*  Load                                */
+       sll             %o5, 8, %o5             /*  IEU0        Group                   */
+1:     or              %g2, %o4, %o4           /*  IEU1                                */
+       or              %o5, %o4, %o4           /*  IEU0        Group (regdep)          */
+       addcc           %o4, %o2, %o2           /*  IEU1        Group (regdep)          */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %o2, 1, %o2             /*  IEU0                                */
+1:     ba,pt           %xcc, 25b               /*  CTI         Group                   */
+        sllx           %o2, 32, %g1            /*  IEU0                                */
diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
new file mode 100644 (file)
index 0000000..7a62c48
--- /dev/null
@@ -0,0 +1,880 @@
+/* $Id: VIScsumcopy.S,v 1.1 1997/08/09 18:14:29 jj Exp $
+ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
+ *            copying utilizing the UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ *      Copyright(C) 1995 Linus Torvalds
+ *      Copyright(C) 1995 Miguel de Icaza
+ *      Copyright(C) 1996,1997 David S. Miller
+ *    derived from:
+ *       Linux/Alpha checksum c-code
+ *        Linux/ix86 inline checksum assembly
+ *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *       David Mosberger-Tang for optimized reference c-code
+ *       BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF       0x7ff+128
+#else
+#define STACKOFF       64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#else
+#define ASI_P          0x80
+#define ASI_BLK_P      0xf0
+#define FRPS_FEF       0x04
+#define FPRS_DU                0x02
+#define FPRS_DL                0x01
+#endif
+#define ASI_BLK_XOR    (ASI_BLK_P ^ ASI_P)
+
+#define src            o0
+#define dst            o1
+#define        len             o2
+#define sum            o3
+#define x1             g1
+#define x2             g2
+#define x3             g3
+#define x4             g4
+#define x5             g5
+#define x6             g7
+#define x7             o4
+#define x8             o5
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ * Once AGAIN, the SunSoft engineers are caught
+ * asleep at the keyboard :)).
+ * The main loop does about 20 superscalar cycles
+ * per 64bytes checksummed/copied.
+ */
+
+#define LDBLK(O0)                                                                              \
+       ldda            [%src] %asi, %O0        /*  Load        Group                   */
+
+#define STBLK                                                                                  \
+       stda            %f48, [%dst] ASI_BLK_P  /*  Store                               */
+
+#define ST(fx,off)                                                                             \
+       std             %fx, [%dst + off]       /*  Store                               */
+
+#define SYNC                                                                                   \
+       membar          #Sync
+
+
+#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
+       LOAD                                    /*  Load        Group                   */;     \
+       faligndata      %A14, %F0, %A14         /*  FPA         Group                   */;     \
+       inc             %x5                     /*  IEU0                                */;     \
+       STORE1                                  /*  Store (optional)                    */;     \
+       faligndata      %F0, %F2, %A0           /*  FPA         Group                   */;     \
+       srl             %x5, 1, %x5             /*  IEU0                                */;     \
+       add             %sum, %x4, %sum         /*  IEU1                                */;     \
+       fpadd32         %F0, %f0, %F0           /*  FPA         Group                   */;     \
+       inc             %x6                     /*  IEU0                                */;     \
+       STORE2                                  /*  Store (optional)                    */;     \
+       faligndata      %F2, %F4, %A2           /*  FPA         Group                   */;     \
+       srl             %x6, 1, %x6             /*  IEU0                                */;     \
+       add             %sum, %x5, %sum         /*  IEU1                                */;     \
+       fpadd32         %F2, %f2, %F2           /*  FPA         Group                   */;     \
+       add             %src, 64, %src          /*  IEU0                                */;     \
+       add             %dst, 64, %dst          /*  IEU1                                */;     \
+       fcmpgt32        %f0, %F0, %x1           /*  FPM         Group                   */;     \
+       inc             %x7                     /*  IEU0                                */;     \
+       STORE3                                  /*  Store (optional)                    */;     \
+       faligndata      %F4, %F6, %A4           /*  FPA                                 */;     \
+       srl             %x7, 1, %x7             /*  IEU0        Group                   */;     \
+       add             %sum, %x6, %sum         /*  IEU1                                */;     \
+       fpadd32         %F4, %f4, %F4           /*  FPA                                 */;     \
+       fcmpgt32        %f2, %F2, %x2           /*  FPM         Group                   */;     \
+       inc             %x8                     /*  IEU0                                */;     \
+       STORE4                                  /*  Store (optional)                    */;     \
+       faligndata      %F6, %F8, %A6           /*  FPA                                 */;     \
+       srl             %x8, 1, %x8             /*  IEU0        Group                   */;     \
+       add             %sum, %x7, %sum         /*  IEU1                                */;     \
+       fpadd32         %F6, %f6, %F6           /*  FPA                                 */;     \
+       fcmpgt32        %f4, %F4, %x3           /*  FPM         Group                   */;     \
+       inc             %x1                     /*  IEU0                                */;     \
+       STORE5                                  /*  Store (optional)                    */;     \
+       faligndata      %F8, %F10, %A8          /*  FPA                                 */;     \
+       srl             %x1, 1, %x1             /*  IEU0        Group                   */;     \
+       add             %sum, %x8, %sum         /*  IEU1                                */;     \
+       fpadd32         %F8, %f8, %F8           /*  FPA                                 */;     \
+       fcmpgt32        %f6, %F6, %x4           /*  FPM         Group                   */;     \
+       inc             %x2                     /*  IEU0                                */;     \
+       STORE6                                  /*  Store (optional)                    */;     \
+       faligndata      %F10, %F12, %A10        /*  FPA                                 */;     \
+       srl             %x2, 1, %x2             /*  IEU0        Group                   */;     \
+       add             %sum, %x1, %sum         /*  IEU1                                */;     \
+       fpadd32         %F10, %f10, %F10        /*  FPA                                 */;     \
+       fcmpgt32        %f8, %F8, %x5           /*  FPM         Group                   */;     \
+       inc             %x3                     /*  IEU0                                */;     \
+       STORE7                                  /*  Store (optional)                    */;     \
+       faligndata      %F12, %F14, %A12        /*  FPA                                 */;     \
+       srl             %x3, 1, %x3             /*  IEU0        Group                   */;     \
+       add             %sum, %x2, %sum         /*  IEU1                                */;     \
+       fpadd32         %F12, %f12, %F12        /*  FPA                                 */;     \
+       fcmpgt32        %f10, %F10, %x6         /*  FPM         Group                   */;     \
+       inc             %x4                     /*  IEU0                                */;     \
+       STORE8                                  /*  Store (optional)                    */;     \
+       fmovd           %F14, %B14              /*  FPA                                 */;     \
+       srl             %x4, 1, %x4             /*  IEU0        Group                   */;     \
+       add             %sum, %x3, %sum         /*  IEU1                                */;     \
+       fpadd32         %F14, %f14, %F14        /*  FPA                                 */;     \
+       fcmpgt32        %f12, %F12, %x7         /*  FPM         Group                   */;     \
+       subcc           %len, 64, %len          /*  IEU1                                */;     \
+       BRANCH                                  /*  CTI                                 */;     \
+       fcmpgt32        %f14, %F14, %x8         /*  FPM         Group                   */;     \
+
+#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
+       inc             %x5                     /*  IEU0        Group                   */;     \
+       fpadd32         %f2, %f0, %S0           /*  FPA                                 */;     \
+       srl             %x5, 1, %x5             /*  IEU0        Group                   */;     \
+       add             %sum, %x4, %sum         /*  IEU1                                */;     \
+       fpadd32         %f6, %f4, %S1           /*  FPA                                 */;     \
+       inc             %x6                     /*  IEU0        Group                   */;     \
+       add             %sum, %x5, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %f0, %S0, %x1           /*  FPM         Group                   */;     \
+       srl             %x6, 1, %x6             /*  IEU0                                */;     \
+       inc             %x7                     /*  IEU1                                */;     \
+       fpadd32         %f10, %f8, %S2          /*  FPA                                 */;     \
+       fcmpgt32        %f4, %S1, %x2           /*  FPM         Group                   */;     \
+       srl             %x7, 1, %x7             /*  IEU0                                */;     \
+       add             %sum, %x6, %sum         /*  IEU1                                */;     \
+       fpadd32         %f14, %f12, %S3         /*  FPA                                 */;     \
+       inc             %x8                     /*  IEU0        Group                   */;     \
+       add             %sum, %x7, %sum         /*  IEU1                                */;     \
+       fzero           %fz                     /*  FPA                                 */;     \
+       fcmpgt32        %f8, %S2, %x3           /*  FPM         Group                   */;     \
+       srl             %x8, 1, %x8             /*  IEU0                                */;     \
+       inc             %x1                     /*  IEU1                                */;     \
+       fpadd32         %S0, %S1, %T0           /*  FPA                                 */;     \
+       fcmpgt32        %f12, %S3, %x4          /*  FPM         Group                   */;     \
+       srl             %x1, 1, %x1             /*  IEU0                                */;     \
+       add             %sum, %x8, %sum         /*  IEU1                                */;     \
+       fpadd32         %S2, %S3, %T1           /*  FPA                                 */;     \
+       inc             %x2                     /*  IEU0        Group                   */;     \
+       add             %sum, %x1, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %S0, %T0, %x5           /*  FPM         Group                   */;     \
+       srl             %x2, 1, %x2             /*  IEU0                                */;     \
+       inc             %x3                     /*  IEU1                                */;     \
+       fcmpgt32        %S2, %T1, %x6           /*  FPM         Group                   */;     \
+       srl             %x3, 1, %x3             /*  IEU0                                */;     \
+       add             %sum, %x2, %sum         /*  IEU1                                */;     \
+       inc             %x4                     /*  IEU0        Group                   */;     \
+       add             %sum, %x3, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f2, %x7           /*  FPM         Group                   */;     \
+       srl             %x4, 1, %x4             /*  IEU0                                */;     \
+       inc             %x5                     /*  IEU1                                */;     \
+       fpadd32         %T0, %T1, %U0           /*  FPA                                 */;     \
+       fcmpgt32        %fz, %f6, %x8           /*  FPM         Group                   */;     \
+       srl             %x5, 1, %x5             /*  IEU0                                */;     \
+       add             %sum, %x4, %sum         /*  IEU1                                */;     \
+       inc             %x6                     /*  IEU0        Group                   */;     \
+       add             %sum, %x5, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f10, %x1          /*  FPM         Group                   */;     \
+       srl             %x6, 1, %x6             /*  IEU0                                */;     \
+       inc             %x7                     /*  IEU1                                */;     \
+       fcmpgt32        %fz, %f14, %x2          /*  FPM         Group                   */;     \
+       ba,pt           %xcc, ett               /*  CTI                                 */;     \
+        fmovd          %FA, %FB                /*  FPA                                 */;     \
+
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB)                                       \
+       END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
+
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz)                                          \
+       fpadd32         %U0, %U1, %V0           /*  FPA         Group                   */;     \
+       srl             %x7, 1, %x7             /*  IEU0                                */;     \
+       add             %sum, %x6, %sum         /*  IEU1                                */;     \
+       std             %V0, [%sp + STACKOFF]   /*  Store       Group                   */;     \
+       inc             %x8                     /*  IEU0                                */;     \
+       sub             %sum, %x7, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %S1, %x3           /*  FPM         Group                   */;     \
+       srl             %x8, 1, %x8             /*  IEU0                                */;     \
+       inc             %x1                     /*  IEU1                                */;     \
+       fcmpgt32        %fz, %S3, %x4           /*  FPM         Group                   */;     \
+       srl             %x1, 1, %x1             /*  IEU0                                */;     \
+       sub             %sum, %x8, %sum         /*  IEU1                                */;     \
+       ldx             [%sp + STACKOFF], %x8   /*  Load        Group                   */;     \
+       inc             %x2                     /*  IEU0                                */;     \
+       sub             %sum, %x1, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %T1, %x5           /*  FPM         Group                   */;     \
+       srl             %x2, 1, %x2             /*  IEU0                                */;     \
+       inc             %x3                     /*  IEU1                                */;     \
+       fcmpgt32        %T0, %U0, %x6           /*  FPM         Group                   */;     \
+       srl             %x3, 1, %x3             /*  IEU0                                */;     \
+       sub             %sum, %x2, %sum         /*  IEU1                                */;     \
+       inc             %x4                     /*  IEU0        Group                   */;     \
+       sub             %sum, %x3, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %U1, %x7           /*  FPM         Group                   */;     \
+       srl             %x4, 1, %x4             /*  IEU0                                */;     \
+       inc             %x5                     /*  IEU1                                */;     \
+       fcmpgt32        %U0, %V0, %x1           /*  FPM         Group                   */;     \
+       srl             %x5, 1, %x5             /*  IEU0                                */;     \
+       sub             %sum, %x4, %sum         /*  IEU1                                */;     \
+       fcmpgt32        %fz, %V0, %x2           /*  FPM         Group                   */;     \
+       inc             %x6                     /*  IEU0                                */;     \
+       sub             %sum, %x5, %sum         /*  IEU1                                */;     \
+       srl             %x6, 1, %x6             /*  IEU0        Group                   */;     \
+       inc             %x7                     /*  IEU1                                */;     \
+       srl             %x7, 1, %x7             /*  IEU0        Group                   */;     \
+       add             %sum, %x6, %sum         /*  IEU1                                */;     \
+       inc             %x1                     /*  IEU0        Group                   */;     \
+       sub             %sum, %x7, %sum         /*  IEU1                                */;     \
+       srl             %x1, 1, %x1             /*  IEU0        Group                   */;     \
+       inc             %x2                     /*  IEU1                                */;     \
+       srl             %x2, 1, %x2             /*  IEU0        Group                   */;     \
+       add             %sum, %x1, %sum         /*  IEU1                                */;     \
+       sub             %sum, %x2, %sum         /*  IEU0        Group                   */;     \
+       addcc           %sum, %x8, %sum         /*  IEU         Group                   */;     \
+       bcs,a,pn        %xcc, 33f               /*  CTI                                 */;     \
+        add            %sum, 1, %sum           /*  IEU0                                */;     \
+33:                                            /*  That's it                           */;
+
+       .text
+       .globl          csum_partial_copy_vis
+       .align          32
+/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */
+/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+csum_partial_copy_vis:
+       andcc           %dst, 7, %g0            /*  IEU1        Group                   */
+       be,pt           %icc, 4f                /*  CTI                                 */
+        and            %dst, 0x38, %g3         /*  IEU0                                */
+       mov             1, %g5                  /*  IEU0        Group                   */
+       andcc           %dst, 2, %g0            /*  IEU1                                */
+       be,pt           %icc, 1f                /*  CTI                                 */
+        and            %dst, 4, %g7            /*  IEU0        Group                   */
+       lduha           [%src] %asi, %g2        /*  Load                                */
+       sub             %len, 2, %len           /*  IEU0        Group                   */
+       add             %dst, 2, %dst           /*  IEU1                                */
+       andcc           %dst, 4, %g7            /*  IEU1        Group                   */
+       sll             %g5, 16, %g5            /*  IEU0                                */
+       sth             %g2, [%dst - 2]         /*  Store       Group                   */
+       sll             %g2, 16, %g2            /*  IEU0                                */
+       add             %src, 2, %src           /*  IEU1                                */
+       addcc           %g2, %sum, %sum         /*  IEU1        Group                   */
+       bcs,a,pn        %icc, 1f                /*  CTI                                 */
+        add            %sum, %g5, %sum         /*  IEU0                                */
+1:     lduwa           [%src] %asi, %g2        /*  Load                                */
+       brz,a,pn        %g7, 4f                 /*  CTI+IEU1    Group                   */
+        and            %dst, 0x38, %g3         /*  IEU0                                */
+       add             %dst, 4, %dst           /*  IEU0        Group                   */
+       sub             %len, 4, %len           /*  IEU1                                */
+       addcc           %g2, %sum, %sum         /*  IEU1        Group                   */
+       bcs,a,pn        %icc, 1f                /*  CTI                                 */
+        add            %sum, 1, %sum           /*  IEU0                                */
+1:     and             %dst, 0x38, %g3         /*  IEU0        Group                   */
+       stw             %g2, [%dst - 4]         /*  Store                               */
+       add             %src, 4, %src           /*  IEU1                                */
+4:
+#ifdef __KERNEL__
+       wr              %g0, FPRS_FEF, %fprs    /*  LSU         Group                   */
+#endif
+       mov             %src, %g7               /*  IEU1        Group                   */
+       fzero           %f48                    /*  FPA                                 */
+       alignaddr       %src, %g0, %src         /*  Single      Group                   */
+       subcc           %g7, %src, %g7          /*  IEU1        Group                   */
+       be,pt           %xcc, 1f                /*  CTI                                 */
+        mov            0x40, %g1               /*  IEU0                                */
+       lduwa           [%src] %asi, %g2        /*  Load        Group                   */
+       subcc           %sum, %g2, %sum         /*  IEU1        Group+load stall        */
+       bcs,a,pn        %icc, 1f                /*  CTI                                 */
+        sub            %sum, 1, %sum           /*  IEU0                                */
+1:     srl             %sum, 0, %sum           /*  IEU0        Group                   */
+       clr             %g5                     /*  IEU1                                */
+       brz,pn          %g3, 3f                 /*  CTI+IEU1    Group                   */
+        sub            %g1, %g3, %g1           /*  IEU0                                */
+       ldda            [%src] %asi, %f0        /*  Load                                */
+       clr             %g3                     /*  IEU0        Group                   */
+       andcc           %dst, 8, %g0            /*  IEU1                                */
+       be,pn           %icc, 1f                /*  CTI                                 */
+        ldda           [%src + 8] %asi, %f2    /*  Load        Group                   */
+       add             %src, 8, %src           /*  IEU0                                */
+       sub             %len, 8, %len           /*  IEU1                                */
+       fpadd32         %f0, %f48, %f50         /*  FPA                                 */
+       addcc           %dst, 8, %dst           /*  IEU1        Group                   */
+       faligndata      %f0, %f2, %f16          /*  FPA                                 */
+       fcmpgt32        %f48, %f50, %g3         /*  FPM         Group                   */
+       fmovd           %f2, %f0                /*  FPA         Group                   */
+       ldda            [%src + 8] %asi, %f2    /*  Load                                */
+       std             %f16, [%dst - 8]        /*  Store                               */
+       fmovd           %f50, %f48              /*  FPA                                 */
+1:     andcc           %g1, 0x10, %g0          /*  IEU1        Group                   */
+       be,pn           %icc, 1f                /*  CTI                                 */
+        and            %g1, 0x20, %g1          /*  IEU0                                */
+       fpadd32         %f0, %f48, %f50         /*  FPA                                 */
+       ldda            [%src + 16] %asi, %f4   /*  Load        Group                   */
+       add             %src, 16, %src          /*  IEU0                                */
+       add             %dst, 16, %dst          /*  IEU1                                */
+       faligndata      %f0, %f2, %f16          /*  FPA                                 */
+       fcmpgt32        %f48, %f50, %g5         /*  FPM         Group                   */
+       sub             %len, 16, %len          /*  IEU0                                */
+       inc             %g3                     /*  IEU1                                */
+       std             %f16, [%dst - 16]       /*  Store       Group                   */
+       fpadd32         %f2, %f50, %f48         /*  FPA                                 */
+       srl             %g3, 1, %o5             /*  IEU0                                */
+       faligndata      %f2, %f4, %f18          /*  FPA         Group                   */
+       std             %f18, [%dst - 8]        /*  Store                               */
+       fcmpgt32        %f50, %f48, %g3         /*  FPM         Group                   */
+       add             %o5, %sum, %sum         /*  IEU0                                */
+       ldda            [%src + 8] %asi, %f2    /*  Load                                */
+       fmovd           %f4, %f0                /*  FPA                                 */
+1:     brz,a,pn        %g1, 4f                 /*  CTI+IEU1    Group                   */
+        rd             %asi, %g2               /*  LSU         Group + 4 bubbles       */
+       inc             %g5                     /*  IEU0                                */
+       fpadd32         %f0, %f48, %f50         /*  FPA                                 */
+       ldda            [%src + 16] %asi, %f4   /*  Load        Group                   */
+       srl             %g5, 1, %g5             /*  IEU0                                */
+       add             %dst, 32, %dst          /*  IEU1                                */
+       faligndata      %f0, %f2, %f16          /*  FPA                                 */
+       fcmpgt32        %f48, %f50, %o5         /*  FPM         Group                   */
+       inc             %g3                     /*  IEU0                                */
+       ldda            [%src + 24] %asi, %f6   /*  Load                                */
+       srl             %g3, 1, %g3             /*  IEU0        Group                   */
+       add             %g5, %sum, %sum         /*  IEU1                                */
+       ldda            [%src + 32] %asi, %f8   /*  Load                                */
+       fpadd32         %f2, %f50, %f48         /*  FPA                                 */
+       faligndata      %f2, %f4, %f18          /*  FPA         Group                   */
+       sub             %len, 32, %len          /*  IEU0                                */
+       std             %f16, [%dst - 32]       /*  Store                               */
+       fcmpgt32        %f50, %f48, %o4         /*  FPM         Group                   */
+       inc             %o5                     /*  IEU0                                */
+       add             %g3, %sum, %sum         /*  IEU1                                */
+       fpadd32         %f4, %f48, %f50         /*  FPA                                 */
+       faligndata      %f4, %f6, %f20          /*  FPA         Group                   */
+       srl             %o5, 1, %o5             /*  IEU0                                */
+       fcmpgt32        %f48, %f50, %g5         /*  FPM         Group                   */
+       add             %o5, %sum, %sum         /*  IEU0                                */
+       std             %f18, [%dst - 24]       /*  Store                               */
+       fpadd32         %f6, %f50, %f48         /*  FPA                                 */
+       inc             %o4                     /*  IEU0        Group                   */
+       std             %f20, [%dst - 16]       /*  Store                               */
+       add             %src, 32, %src          /*  IEU1                                */
+       faligndata      %f6, %f8, %f22          /*  FPA                                 */
+       fcmpgt32        %f50, %f48, %g3         /*  FPM         Group                   */
+       srl             %o4, 1, %o4             /*  IEU0                                */
+       std             %f22, [%dst - 8]        /*  Store                               */      
+       add             %o4, %sum, %sum         /*  IEU0        Group                   */
+3:     rd              %asi, %g2               /*  LSU         Group + 4 bubbles       */
+#ifdef __KERNEL__
+4:     sethi           %hi(vis0s), %g7         /*  IEU0        Group                   */
+#else
+4:     rd              %pc, %g7                /*  LSU         Group + 4 bubbles       */
+#endif
+       inc             %g5                     /*  IEU0        Group                   */
+       and             %src, 0x38, %o4         /*  IEU1                                */      
+       membar          #StoreLoad              /*  LSU         Group                   */
+       srl             %g5, 1, %g5             /*  IEU0                                */
+       inc             %g3                     /*  IEU1                                */
+       sll             %o4, 8, %o4             /*  IEU0        Group                   */
+       sub             %len, 0xc0, %len        /*  IEU1                                */
+       addcc           %g5, %sum, %sum         /*  IEU1        Group                   */
+       srl             %g3, 1, %g3             /*  IEU0                                */
+       add             %g7, %o4, %g7           /*  IEU0        Group                   */
+       add             %g3, %sum, %sum         /*  IEU1                                */
+#ifdef __KERNEL__
+       jmpl            %g7 + %lo(vis0s), %g0   /*  CTI+IEU1    Group                   */
+#else
+       jmpl            %g7 + (vis0s - 4b), %g0 /*  CTI+IEU1    Group                   */
+#endif
+        fzero          %f32                    /*  FPA                                 */
+
+       .align          2048
+vis0s: wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       add             %src, 128, %src         /*  IEU0        Group                   */
+       ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f62              /*  FPA         Group                   */
+       faligndata      %f0, %f2, %f48          /*  FPA         Group                   */
+       fcmpgt32        %f32, %f2, %x1          /*  FPM         Group                   */
+       fpadd32         %f0, %f62, %f0          /*  FPA                                 */
+       fcmpgt32        %f32, %f4, %x2          /*  FPM         Group                   */
+       faligndata      %f2, %f4, %f50          /*  FPA                                 */
+       fcmpgt32        %f62, %f0, %x3          /*  FPM         Group                   */
+       faligndata      %f4, %f6, %f52          /*  FPA                                 */
+       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
+       inc             %x1                     /*  IEU0                                */
+       faligndata      %f6, %f8, %f54          /*  FPA                                 */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       srl             %x1, 1, %x1             /*  IEU0                                */
+       inc             %x2                     /*  IEU1                                */
+       faligndata      %f8, %f10, %f56         /*  FPA                                 */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       srl             %x2, 1, %x2             /*  IEU0                                */
+       add             %sum, %x1, %sum         /*  IEU1                                */
+       faligndata      %f10, %f12, %f58        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       inc             %x3                     /*  IEU0                                */
+       add             %sum, %x2, %sum         /*  IEU1                                */
+       faligndata      %f12, %f14, %f60        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       srl             %x3, 1, %x3             /*  IEU0                                */
+       inc             %x4                     /*  IEU1                                */
+       fmovd           %f14, %f62              /*  FPA                                 */
+       srl             %x4, 1, %x4             /*  IEU0        Group                   */
+       add             %sum, %x3, %sum         /*  IEU1                                */
+vis0:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f62,                                                           
+                       ,LDBLK(f32),    STBLK,,,,,,,,                                                                   
+                       ,bcs,pn %icc, vis0e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f62,                                                           
+                       ,LDBLK(f0),     STBLK,,,,,,,,                                                                   
+                       ,bcs,pn %icc, vis0e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+                       ,LDBLK(f16),    STBLK,,,,,,,,
+                       ,bcc,pt %icc, vis0)
+vis0e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f32,
+                       ,SYNC,          STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+                       ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
+vis0e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f0,
+                       ,SYNC,          STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+                       ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
+vis0e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f48,f50,f52,f54,f56,f58,f60,f62,f16,
+                       ,SYNC,          STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+                       ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis1s: wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       add             %src, 128 - 8, %src     /*  IEU0        Group                   */
+       ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       fcmpgt32        %f32, %f2, %x2          /*  FPM         Group                   */
+       faligndata      %f2, %f4, %f48          /*  FPA                                 */
+       fcmpgt32        %f32, %f4, %x3          /*  FPM         Group                   */
+       faligndata      %f4, %f6, %f50          /*  FPA                                 */
+       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
+       faligndata      %f6, %f8, %f52          /*  FPA                                 */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       inc             %x2                     /*  IEU1                                */
+       faligndata      %f8, %f10, %f54         /*  FPA                                 */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       srl             %x2, 1, %x2             /*  IEU0                                */
+       faligndata      %f10, %f12, %f56        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       inc             %x3                     /*  IEU0                                */
+       add             %sum, %x2, %sum         /*  IEU1                                */
+       faligndata      %f12, %f14, %f58        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       srl             %x3, 1, %x3             /*  IEU0                                */
+       inc             %x4                     /*  IEU1                                */
+       fmovd           %f14, %f60              /*  FPA                                 */
+       srl             %x4, 1, %x4             /*  IEU0        Group                   */
+       add             %sum, %x3, %sum         /*  IEU1                                */
+vis1:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+                       ,LDBLK(f32),    ,STBLK,,,,,,,
+                       ,bcs,pn %icc, vis1e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+                       ,LDBLK(f0),     ,STBLK,,,,,,,
+                       ,bcs,pn %icc, vis1e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+                       ,LDBLK(f16),    ,STBLK,,,,,,,
+                       ,bcc,pt %icc, vis1)
+vis1e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f32,
+                       ,SYNC,          ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+                       ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
+vis1e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f0,
+                       ,SYNC,          ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+                       ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
+vis1e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f62,f48,f50,f52,f54,f56,f58,f60,f16,
+                       ,SYNC,          ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+                       ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis2s: wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       add             %src, 128 - 16, %src    /*  IEU0        Group                   */
+       ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */      
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       fzero           %f2                     /*  FPA         Group                   */
+       fcmpgt32        %f32, %f4, %x3          /*  FPM         Group                   */
+       faligndata      %f4, %f6, %f48          /*  FPA                                 */
+       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
+       faligndata      %f6, %f8, %f50          /*  FPA                                 */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       faligndata      %f8, %f10, %f52         /*  FPA                                 */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       faligndata      %f10, %f12, %f54        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       inc             %x3                     /*  IEU0                                */
+       faligndata      %f12, %f14, %f56        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       srl             %x3, 1, %x3             /*  IEU0                                */
+       inc             %x4                     /*  IEU1                                */
+       fmovd           %f14, %f58              /*  FPA                                 */
+       srl             %x4, 1, %x4             /*  IEU0        Group                   */
+       add             %sum, %x3, %sum         /*  IEU1                                */
+vis2:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+                       ,LDBLK(f32),    ,,STBLK,,,,,,
+                       ,bcs,pn %icc, vis2e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+                       ,LDBLK(f0),     ,,STBLK,,,,,,
+                       ,bcs,pn %icc, vis2e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+                       ,LDBLK(f16),    ,,STBLK,,,,,,
+                       ,bcc,pt %icc, vis2)
+vis2e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f32,
+                       ,SYNC,          ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+                       ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
+vis2e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f0,
+                       ,SYNC,          ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+                       ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
+vis2e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f60,f62,f48,f50,f52,f54,f56,f58,f16,
+                       ,SYNC,          ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+                       ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis3s: wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       add             %src, 128 - 24, %src    /*  IEU0        Group                   */
+       ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       fzero           %f2                     /*  FPA         Group                   */
+       fzero           %f4                     /*  FPA         Group                   */
+       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
+       faligndata      %f6, %f8, %f48          /*  FPA                                 */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       faligndata      %f8, %f10, %f50         /*  FPA                                 */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       faligndata      %f10, %f12, %f52        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       faligndata      %f12, %f14, %f54        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       fmovd           %f14, %f56              /*  FPA                                 */
+       inc             %x4                     /*  IEU0                                */
+       srl             %x4, 1, %x4             /*  IEU0        Group                   */
+vis3:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+                       ,LDBLK(f32),    ,,,STBLK,,,,,
+                       ,bcs,pn %icc, vis3e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+                       ,LDBLK(f0),     ,,,STBLK,,,,,
+                       ,bcs,pn %icc, vis3e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+                       ,LDBLK(f16),    ,,,STBLK,,,,,
+                       ,bcc,pt %icc, vis3)
+vis3e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f32,
+                       ,SYNC,          ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+                       ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
+vis3e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f0,
+                       ,SYNC,          ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+                       ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
+vis3e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f58,f60,f62,f48,f50,f52,f54,f56,f16,
+                       ,SYNC,          ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+                       ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis4s: wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       add             %src, 128 - 32, %src    /*  IEU0        Group                   */
+       ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       fzero           %f2                     /*  FPA         Group                   */
+       fzero           %f4                     /*  FPA         Group                   */
+       fzero           %f6                     /*  FPA         Group                   */
+       clr             %x4                     /*  IEU0                                */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       faligndata      %f8, %f10, %f48         /*  FPA                                 */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       faligndata      %f10, %f12, %f50        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       faligndata      %f12, %f14, %f52        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       fmovd           %f14, %f54              /*  FPA                                 */
+vis4:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+                       ,LDBLK(f32),    ,,,,STBLK,,,,
+                       ,bcs,pn %icc, vis4e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+                       ,LDBLK(f0),     ,,,,STBLK,,,,
+                       ,bcs,pn %icc, vis4e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+                       ,LDBLK(f16),    ,,,,STBLK,,,,
+                       ,bcc,pt %icc, vis4)
+vis4e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f32,
+                       ,SYNC,          ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+                       ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
+vis4e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f0,
+                       ,SYNC,          ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+                       ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
+vis4e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f56,f58,f60,f62,f48,f50,f52,f54,f16,
+                       ,SYNC,          ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+                       ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis5s: add             %src, 128 - 40, %src    /*  IEU0        Group                   */
+       ldda            [%src-88] %asi, %f10    /*  Load        Group                   */
+       ldda            [%src-80] %asi, %f12    /*  Load        Group                   */
+       ldda            [%src-72] %asi, %f14    /*  Load        Group                   */
+       wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f2         /*  FPM                                 */
+       clr             %x4                     /*  IEU0                                */
+       faddd           %f32, %f32, %f4         /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f6         /*  FPM                                 */
+       clr             %x5                     /*  IEU0                                */
+       faddd           %f32, %f32, %f8         /*  FPA         Group                   */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       faligndata      %f10, %f12, %f48        /*  FPA                                 */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       faligndata      %f12, %f14, %f50        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       fmovd           %f14, %f52              /*  FPA                                 */
+vis5:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+                       ,LDBLK(f32),    ,,,,,STBLK,,,
+                       ,bcs,pn %icc, vis5e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+                       ,LDBLK(f0),     ,,,,,STBLK,,,
+                       ,bcs,pn %icc, vis5e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+                       ,LDBLK(f16),    ,,,,,STBLK,,,
+                       ,bcc,pt %icc, vis5)
+vis5e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f32,
+                       ,SYNC,          ,,,,,STBLK,ST(f48,64),ST(f50,72),
+                       ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
+vis5e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f0,
+                       ,SYNC,          ,,,,,STBLK,ST(f48,64),ST(f50,72),
+                       ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
+vis5e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f54,f56,f58,f60,f62,f48,f50,f52,f16,
+                       ,SYNC,          ,,,,,STBLK,ST(f48,64),ST(f50,72),
+                       ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis6s: add             %src, 128 - 48, %src    /*  IEU0        Group                   */
+       ldda            [%src-80] %asi, %f12    /*  Load        Group                   */
+       ldda            [%src-72] %asi, %f14    /*  Load        Group                   */
+       wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f2         /*  FPM                                 */
+       clr             %x4                     /*  IEU0                                */
+       faddd           %f32, %f32, %f4         /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f6         /*  FPM                                 */
+       clr             %x5                     /*  IEU0                                */
+       faddd           %f32, %f32, %f8         /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f10        /*  FPM                                 */
+       clr             %x6                     /*  IEU0                                */
+       fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       faligndata      %f12, %f14, %f48        /*  FPA                                 */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       fmovd           %f14, %f50              /*  FPA                                 */
+vis6:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+                       ,LDBLK(f32),    ,,,,,,STBLK,,
+                       ,bcs,pn %icc, vis6e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+                       ,LDBLK(f0),     ,,,,,,STBLK,,
+                       ,bcs,pn %icc, vis6e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+                       ,LDBLK(f16),    ,,,,,,STBLK,,
+                       ,bcc,pt %icc, vis6)
+vis6e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f32,
+                       ,SYNC,          ,,,,,,STBLK,ST(f48,64),
+                       ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
+vis6e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f0,
+                       ,SYNC,          ,,,,,,STBLK,ST(f48,64),
+                       ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
+vis6e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f52,f54,f56,f58,f60,f62,f48,f50,f16,
+                       ,SYNC,          ,,,,,,STBLK,ST(f48,64),
+                       ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
+       .align          2048
+vis7s: add             %src, 128 - 56, %src    /*  IEU0        Group                   */
+       ldda            [%src-72] %asi, %f14    /*  Load        Group                   */
+       wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
+       ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f48, %f0               /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f2         /*  FPM                                 */
+       clr             %x4                     /*  IEU0                                */
+       faddd           %f32, %f32, %f4         /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f6         /*  FPM                                 */
+       clr             %x5                     /*  IEU0                                */
+       faddd           %f32, %f32, %f8         /*  FPA         Group                   */
+       fmuld           %f32, %f32, %f10        /*  FPM                                 */
+       clr             %x6                     /*  IEU0                                */
+       faddd           %f32, %f32, %f12        /*  FPA         Group                   */
+       clr             %x7                     /*  IEU0                                */
+       fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
+       sub             %dst, 64, %dst          /*  IEU0                                */
+       fmovd           %f14, %f48              /*  FPA                                 */
+vis7:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+                       ,LDBLK(f32),    ,,,,,,,STBLK,
+                       ,bcs,pn %icc, vis7e1)
+       DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+                       ,LDBLK(f0),     ,,,,,,,STBLK,
+                       ,bcs,pn %icc, vis7e2)
+       DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+                       ,LDBLK(f16),    ,,,,,,,STBLK,
+                       ,bcc,pt %icc, vis7)
+vis7e3:        DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f32,
+                       ,SYNC,          ,,,,,,,STBLK,
+                       ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
+vis7e1:        DO_THE_TRICK(   f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f0,
+                       ,SYNC,          ,,,,,,,STBLK,
+                       ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
+vis7e2:        DO_THE_TRICK(   f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,     
+                       ,f50,f52,f54,f56,f58,f60,f62,f48,f16,
+                       ,SYNC,          ,,,,,,,STBLK,
+                       ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
+e1:    END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
+e2:    END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
+e3:    END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
+ett:   rd              %gsr, %x3               /*  LSU         Group+4bubbles          */
+       andcc           %x3, 7, %x3             /*  IEU1        Group                   */
+       add             %dst, 8, %dst           /*  IEU0        Group                   */
+       bne,pn          %icc, 1f                /*  CTI                                 */
+        fzero          %f10                    /*  FPA                                 */
+       brz,a,pn        %len, 2f                /*  CTI+IEU1    Group                   */
+        std            %f6, [%dst - 8]         /*  Store                               */
+1:     rd              %asi, %x4               /*  LSU         Group+4bubbles          */
+       sub             %src, 64, %src          /*  IEU0        Group                   */
+       cmp             %len, 8                 /*  IEU1                                */
+       blu,pn          %icc, 3f                /*  CTI                                 */
+        wr             %x4, ASI_BLK_XOR, %asi  /*  LSU         Group+4bubbles          */
+1:     ldda            [%src] %asi, %f2        /*  Load        Group                   */
+       fpadd32         %f10, %f2, %f12         /*  FPA         Group+load stall        */
+       add             %src, 8, %src           /*  IEU0                                */
+       add             %dst, 8, %dst           /*  IEU1                                */
+       faligndata      %f6, %f2, %f14          /*  FPA         Group                   */
+       fcmpgt32        %f10, %f12, %x5         /*  FPM         Group                   */
+       std             %f14, [%dst - 16]       /*  Store                               */
+       fmovd           %f2, %f6                /*  FPA                                 */
+       fmovd           %f12, %f10              /*  FPA         Group                   */
+       sub             %len, 8, %len           /*  IEU1                                */
+       fzero           %f16                    /*  FPA         Group - FPU nop         */
+       fzero           %f18                    /*  FPA         Group - FPU nop         */
+       inc             %x5                     /*  IEU0                                */
+       srl             %x5, 1, %x5             /*  IEU0        Group (regdep)          */
+       cmp             %len, 8                 /*  IEU1                                */
+       bgeu,pt         %icc, 1b                /*  CTI                                 */
+        add            %x5, %sum, %sum         /*  IEU0        Group                   */
+3:     brz,a,pt        %x3, 2f                 /*  CTI+IEU1                            */
+        std            %f6, [%dst - 8]         /*  Store       Group                   */
+       st              %f7, [%dst - 8]         /*  Store       Group                   */
+       sub             %dst, 4, %dst           /*  IEU0                                */
+       add             %len, 4, %len           /*  IEU1                                */
+2:
+#ifdef __KERNEL__
+       sub             %sp, 8, %sp             /*  IEU0        Group                   */
+#endif
+       END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
+       membar          #Sync                   /*  LSU         Group                   */
+#ifdef __KERNEL__
+       wr              %g0, 0, %fprs           /*  LSU         Group                   */
+       add             %sp, 8, %sp             /*  IEU0        Group                   */
+#endif
+23:    brnz,pn         %len, 26f               /*  CTI+IEU1    Group                   */
+24:     sllx           %sum, 32, %g1           /*  IEU0                                */
+25:    addcc           %sum, %g1, %src         /*  IEU1        Group                   */
+       srlx            %src, 32, %src          /*  IEU0        Group (regdep)          */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %src, 1, %src           /*  IEU1                                */
+#ifndef __KERNEL__
+1:     retl                                    /*  CTI         Group brk forced        */
+        srl            %src, 0, %src           /*  IEU0                                */
+#else
+1:     sethi           %uhi(PAGE_OFFSET), %g4  /*  IEU0        Group                   */
+       retl                                    /*  CTI         Group brk forced        */
+        sllx           %g4, 32, %g4            /*  IEU0                                */
+#endif
+26:    andcc           %len, 8, %g0            /*  IEU1        Group                   */
+       be,pn           %icc, 1f                /*  CTI                                 */
+        lduwa          [%src] %asi, %g3        /*  Load                                */
+       lduwa           [%src+4] %asi, %g2      /*  Load        Group                   */
+       add             %src, 8, %src           /*  IEU0                                */
+       add             %dst, 8, %dst           /*  IEU1                                */
+       sllx            %g3, 32, %g5            /*  IEU0        Group                   */
+       stw             %g3, [%dst - 8]         /*  Store                               */
+       or              %g5, %g2, %g5           /*  IEU0        Group                   */
+       stw             %g2, [%dst - 4]         /*  Store                               */
+       addcc           %g5, %sum, %sum         /*  IEU1        Group                   */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %sum, 1, %sum           /*  IEU0                                */
+1:     andcc           %len, 4, %g0            /*  IEU1        Group                   */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %g2                     /*  IEU0                                */
+       lduwa           [%src] %asi, %g7        /*  Load                                */
+       add             %src, 4, %src           /*  IEU0        Group                   */
+       add             %dst, 4, %dst           /*  IEU1                                */
+       sllx            %g7, 32, %g2            /*  IEU0        Group                   */
+       stw             %g7, [%dst - 4]         /*  Store                               */
+1:     andcc           %len, 2, %g0            /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o4                     /*  IEU0        Group                   */
+       lduha           [%src] %asi, %g7        /*  Load                                */
+       add             %src, 2, %src           /*  IEU1                                */
+       add             %dst, 2, %dst           /*  IEU0        Group                   */
+       sll             %g7, 16, %o4            /*  IEU0        Group                   */
+       sth             %g7, [%dst - 2]         /*  Store                               */
+1:     andcc           %len, 1, %g0            /*  IEU1                                */
+       be,a,pn         %icc, 1f                /*  CTI                                 */
+        clr            %o5                     /*  IEU0        Group                   */
+       lduba           [%src] %asi, %g7        /*  Load                                */
+       sll             %g7, 8, %o5             /*  IEU0        Group                   */
+       stb             %g7, [%dst]             /*  Store                               */
+1:     or              %g2, %o4, %o4           /*  IEU1                                */
+       or              %o5, %o4, %o4           /*  IEU0        Group (regdep)          */
+       addcc           %o4, %sum, %sum         /*  IEU1        Group (regdep)          */
+       bcs,a,pn        %xcc, 1f                /*  CTI                                 */
+        add            %sum, 1, %sum           /*  IEU0                                */
+1:     ba,pt           %xcc, 25b               /*  CTI         Group                   */
+        sllx           %sum, 32, %g1           /*  IEU0                                */
+
+#ifdef __KERNEL__
+end:
+
+       .section        __ex_table
+       .align          8
+       .xword          csum_partial_copy_vis, 0, end, cpc_handler
+#endif
index bdcba34fc76c672e5922357dbcb93ef9a08acf9c..57fc47a0ae093879168ad71adde6bbf28114aaf2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: VISmemset.S,v 1.4 1997/07/02 19:00:39 jj Exp $
+/* $Id: VISmemset.S,v 1.6 1997/08/08 08:34:13 jj Exp $
  * VISmemset.S: High speed memset operations utilizing the UltraSparc
  *        Visual Instruction Set.
  *
@@ -172,10 +172,17 @@ memset:
 #ifdef __KERNEL__
        wr              %g0, 0, %fprs
 #endif
-       membar          #Sync
+       membar          #StoreLoad | #StoreStore
 9:     andcc           %o2, 0x78, %g5
        be,pn           %xcc, 13f
         andcc          %o2, 7, %o2
+#ifdef __KERNEL__
+14:    srl             %g5, 1, %o3
+       sethi           %hi(13f), %o4
+       sub             %o4, %o3, %o4
+       jmpl            %o4 + %lo(13f), %g0
+        add            %o0, %g5, %o0
+#else
 14:    rd              %pc, %o4
 #ifdef REGS_64BIT
        srl             %g5, 1, %o3
@@ -185,6 +192,7 @@ memset:
 #endif
        jmpl            %o4 + (13f - 14b), %g0
         add            %o0, %g5, %o0
+#endif
 12:    SET_BLOCKS(%o0, 0x68, %o1)
        SET_BLOCKS(%o0, 0x48, %o1)
        SET_BLOCKS(%o0, 0x28, %o1)
index 59083aa028b6c08590b954bb8e6873fd6bf99da1..7d5b240ad96a1a4fafd2dd3b66a33e9ec0b65ff1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
+/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
  * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,7 +15,7 @@ __bfill64:            /* %o0 = buf, %o1= ptr to pattern */
        wr              %g0, FPRS_FEF, %fprs            ! FPU   Group
        ldd             [%o1], %f48                     ! Load  Group
        wr              %g0, ASI_BLK_P, %asi            ! LSU   Group
-       membar          #StoreStore | #LoadStore        ! LSU   Group
+       membar          #StoreLoad | #StoreStore | #LoadStore   ! LSU   Group
        mov             32, %g2                         ! IEU0  Group
 
        /* Cannot perform real arithmatic on the pattern, that can
@@ -36,7 +36,7 @@ __bfill64:            /* %o0 = buf, %o1= ptr to pattern */
        subcc           %g2, 1, %g2                     ! IEU1  Group
        bne,pt          %icc, 1b                        ! CTI
         add            %o0, 0x100, %o0                 ! IEU0
-       membar          #Sync                           ! LSU   Group
+       membar          #StoreLoad | #StoreStore        ! LSU   Group
 
        jmpl            %o7 + 0x8, %g0                  ! CTI   Group brk forced
         wr             %g0, 0, %fprs                   ! FPU   Group
@@ -56,7 +56,7 @@ __bzero_1page:
        faddd           %f0, %f2, %f12                  ! FPA   Group
        fmuld           %f0, %f2, %f14                  ! FPM
        wr              %g0, ASI_BLK_P, %asi            ! LSU   Group
-       membar          #StoreStore | #LoadStore        ! LSU   Group
+       membar          #StoreLoad | #StoreStore | #LoadStore   ! LSU   Group
 1:     stda            %f0, [%o0 + 0x00] %asi          ! Store Group
        stda            %f0, [%o0 + 0x40] %asi          ! Store Group
        stda            %f0, [%o0 + 0x80] %asi          ! Store Group
@@ -65,6 +65,6 @@ __bzero_1page:
        subcc           %g1, 1, %g1                     ! IEU1
        bne,pt          %icc, 1b                        ! CTI
         add            %o0, 0x100, %o0                 ! IEU0  Group
-       membar          #Sync                           ! LSU   Group
+       membar          #StoreLoad | #StoreStore        ! LSU   Group
        jmpl            %o7 + 0x8, %g0                  ! CTI   Group brk forced
         wr             %g0, 0, %fprs                   ! FPU   Group
index 703370fc64d4932a33d37d9f6fafde28ab77401b..79f6dedea42a804d6c01bd48651cceb09a3dff2d 100644 (file)
         * are two fold.  Firstly, they cannot pair with jack shit,
         * and also they only add in the 32-bit carry condition bit
         * into the accumulated sum.  The following is much better.
-        *
-        * This should run at max bandwidth for ecache hits, a better
-        * technique is to use VIS and fpu operations. This is already
-        * done for csum_partial, needs to be written for the copy stuff
-        * still.
+        * For larger chunks we use VIS code, which is faster ;)
         */
 
-       .text
-       .globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
 
+       .text
        /* I think I have an erection...  Once _AGAIN_ the SunSoft
         * engineers are caught asleep at the keyboard, tsk tsk...
         */
-#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7)                 \
-       ldxa            [src + off + 0x00] %asi, t0;                                    \
-       ldxa            [src + off + 0x08] %asi, t1;                                    \
-       ldxa            [src + off + 0x10] %asi, t2;                                    \
-       ldxa            [src + off + 0x18] %asi, t3;                                    \
-       ldxa            [src + off + 0x20] %asi, t4;                                    \
-       ldxa            [src + off + 0x28] %asi, t5;                                    \
-       ldxa            [src + off + 0x30] %asi, t6;                                    \
-       ldxa            [src + off + 0x38] %asi, t7;                                    \
+#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7)                      \
+       ldxa            [%src + off + 0x00] %asi, t0;                                   \
+       ldxa            [%src + off + 0x08] %asi, t1;                                   \
+       ldxa            [%src + off + 0x10] %asi, t2;                                   \
+       ldxa            [%src + off + 0x18] %asi, t3;                                   \
+       ldxa            [%src + off + 0x20] %asi, t4;                                   \
+       ldxa            [%src + off + 0x28] %asi, t5;                                   \
+       ldxa            [%src + off + 0x30] %asi, t6;                                   \
+       ldxa            [%src + off + 0x38] %asi, t7;                                   \
        nop; nop; /* DO NOT TOUCH THIS!!!!! */
 
-#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
-       stx             t0, [dest + off - 0x40];                                        \
-       addcc           sum, t0, sum;                                                   \
+#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7)               \
+       stx             t0, [%dst + off - 0x40];                                        \
+       addcc           %sum, t0, %sum;                                                 \
        bcc,pt          %xcc, 11f;                                                      \
-        ldxa           [src + off + 0x00] %asi, t0;                                    \
-       add             sum, 1, sum;                                                    \
-11:    stx             t1, [dest + off - 0x38];                                        \
-       addcc           sum, t1, sum;                                                   \
+        ldxa           [%src + off + 0x00] %asi, t0;                                   \
+       add             %sum, 1, %sum;                                                  \
+11:    stx             t1, [%dst + off - 0x38];                                        \
+       addcc           %sum, t1, %sum;                                                 \
        bcc,pt          %xcc, 12f;                                                      \
-        ldxa           [src + off + 0x08] %asi, t1;                                    \
-       add             sum, 1, sum;                                                    \
-12:    stx             t2, [dest + off - 0x30];                                        \
-       addcc           sum, t2, sum;                                                   \
+        ldxa           [%src + off + 0x08] %asi, t1;                                   \
+       add             %sum, 1, %sum;                                                  \
+12:    stx             t2, [%dst + off - 0x30];                                        \
+       addcc           %sum, t2, %sum;                                                 \
        bcc,pt          %xcc, 13f;                                                      \
-        ldxa           [src + off + 0x10] %asi, t2;                                    \
-       add             sum, 1, sum;                                                    \
-13:    stx             t3, [dest + off - 0x28];                                        \
-       addcc           sum, t3, sum;                                                   \
+        ldxa           [%src + off + 0x10] %asi, t2;                                   \
+       add             %sum, 1, %sum;                                                  \
+13:    stx             t3, [%dst + off - 0x28];                                        \
+       addcc           %sum, t3, %sum;                                                 \
        bcc,pt          %xcc, 14f;                                                      \
-        ldxa           [src + off + 0x18] %asi, t3;                                    \
-       add             sum, 1, sum;                                                    \
-14:    stx             t4, [dest + off - 0x20];                                        \
-       addcc           sum, t4, sum;                                                   \
+        ldxa           [%src + off + 0x18] %asi, t3;                                   \
+       add             %sum, 1, %sum;                                                  \
+14:    stx             t4, [%dst + off - 0x20];                                        \
+       addcc           %sum, t4, %sum;                                                 \
        bcc,pt          %xcc, 15f;                                                      \
-        ldxa           [src + off + 0x20] %asi, t4;                                    \
-       add             sum, 1, sum;                                                    \
-15:    stx             t5, [dest + off - 0x18];                                        \
-       addcc           sum, t5, sum;                                                   \
+        ldxa           [%src + off + 0x20] %asi, t4;                                   \
+       add             %sum, 1, %sum;                                                  \
+15:    stx             t5, [%dst + off - 0x18];                                        \
+       addcc           %sum, t5, %sum;                                                 \
        bcc,pt          %xcc, 16f;                                                      \
-        ldxa           [src + off + 0x28] %asi, t5;                                    \
-       add             sum, 1, sum;                                                    \
-16:    stx             t6, [dest + off - 0x10];                                        \
-       addcc           sum, t6, sum;                                                   \
+        ldxa           [%src + off + 0x28] %asi, t5;                                   \
+       add             %sum, 1, %sum;                                                  \
+16:    stx             t6, [%dst + off - 0x10];                                        \
+       addcc           %sum, t6, %sum;                                                 \
        bcc,pt          %xcc, 17f;                                                      \
-        ldxa           [src + off + 0x30] %asi, t6;                                    \
-       add             sum, 1, sum;                                                    \
-17:    stx             t7, [dest + off - 0x08];                                        \
-       addcc           sum, t7, sum;                                                   \
+        ldxa           [%src + off + 0x30] %asi, t6;                                   \
+       add             %sum, 1, %sum;                                                  \
+17:    stx             t7, [%dst + off - 0x08];                                        \
+       addcc           %sum, t7, %sum;                                                 \
        bcc,pt          %xcc, 18f;                                                      \
-        ldxa           [src + off + 0x38] %asi, t7;                                    \
-       add             sum, 1, sum;                                                    \
+        ldxa           [%src + off + 0x38] %asi, t7;                                   \
+       add             %sum, 1, %sum;                                                  \
 18:
 
-#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
-       stw             t0, [dest + off - 0x3c];                                        \
-       addcc           sum, t0, sum;                                                   \
+#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7)               \
+       stw             t0, [%dst + off - 0x3c];                                        \
+       addcc           %sum, t0, %sum;                                                 \
        srlx            t0, 32, t0;                                                     \
-       stw             t0, [dest + off - 0x40];                                        \
+       stw             t0, [%dst + off - 0x40];                                        \
        bcc,pt          %xcc, 21f;                                                      \
-        ldxa           [src + off + 0x00] %asi, t0;                                    \
-       add             sum, 1, sum;                                                    \
-21:    stw             t1, [dest + off - 0x34];                                        \
-       addcc           sum, t1, sum;                                                   \
+        ldxa           [%src + off + 0x00] %asi, t0;                                   \
+       add             %sum, 1, %sum;                                                  \
+21:    stw             t1, [%dst + off - 0x34];                                        \
+       addcc           %sum, t1, %sum;                                                 \
        srlx            t1, 32, t1;                                                     \
-       stw             t1, [dest + off - 0x38];                                        \
+       stw             t1, [%dst + off - 0x38];                                        \
        bcc,pt          %xcc, 22f;                                                      \
-        ldxa           [src + off + 0x08] %asi, t1;                                    \
-       add             sum, 1, sum;                                                    \
-22:    stw             t2, [dest + off - 0x2c];                                        \
-       addcc           sum, t2, sum;                                                   \
+        ldxa           [%src + off + 0x08] %asi, t1;                                   \
+       add             %sum, 1, %sum;                                                  \
+22:    stw             t2, [%dst + off - 0x2c];                                        \
+       addcc           %sum, t2, %sum;                                                 \
        srlx            t2, 32, t2;                                                     \
-       stw             t2, [dest + off - 0x30];                                        \
+       stw             t2, [%dst + off - 0x30];                                        \
        bcc,pt          %xcc, 23f;                                                      \
-        ldxa           [src + off + 0x10] %asi, t2;                                    \
-       add             sum, 1, sum;                                                    \
-23:    stw             t3, [dest + off - 0x24];                                        \
-       addcc           sum, t3, sum;                                                   \
+        ldxa           [%src + off + 0x10] %asi, t2;                                   \
+       add             %sum, 1, %sum;                                                  \
+23:    stw             t3, [%dst + off - 0x24];                                        \
+       addcc           %sum, t3, %sum;                                                 \
        srlx            t3, 32, t3;                                                     \
-       stw             t3, [dest + off - 0x28];                                        \
+       stw             t3, [%dst + off - 0x28];                                        \
        bcc,pt          %xcc, 24f;                                                      \
-        ldxa           [src + off + 0x18] %asi, t3;                                    \
-       add             sum, 1, sum;                                                    \
-24:    stw             t4, [dest + off - 0x1c];                                        \
-       addcc           sum, t4, sum;                                                   \
+        ldxa           [%src + off + 0x18] %asi, t3;                                   \
+       add             %sum, 1, %sum;                                                  \
+24:    stw             t4, [%dst + off - 0x1c];                                        \
+       addcc           %sum, t4, %sum;                                                 \
        srlx            t4, 32, t4;                                                     \
-       stw             t4, [dest + off - 0x20];                                        \
+       stw             t4, [%dst + off - 0x20];                                        \
        bcc,pt          %xcc, 25f;                                                      \
-        ldxa           [src + off + 0x20] %asi, t4;                                    \
-       add             sum, 1, sum;                                                    \
-25:    stw             t5, [dest + off - 0x14];                                        \
-       addcc           sum, t5, sum;                                                   \
+        ldxa           [%src + off + 0x20] %asi, t4;                                   \
+       add             %sum, 1, %sum;                                                  \
+25:    stw             t5, [%dst + off - 0x14];                                        \
+       addcc           %sum, t5, %sum;                                                 \
        srlx            t5, 32, t5;                                                     \
-       stw             t5, [dest + off - 0x18];                                        \
+       stw             t5, [%dst + off - 0x18];                                        \
        bcc,pt          %xcc, 26f;                                                      \
-        ldxa           [src + off + 0x28] %asi, t5;                                    \
-       add             sum, 1, sum;                                                    \
-26:    stw             t6, [dest + off - 0x0c];                                        \
-       addcc           sum, t6, sum;                                                   \
+        ldxa           [%src + off + 0x28] %asi, t5;                                   \
+       add             %sum, 1, %sum;                                                  \
+26:    stw             t6, [%dst + off - 0x0c];                                        \
+       addcc           %sum, t6, %sum;                                                 \
        srlx            t6, 32, t6;                                                     \
-       stw             t6, [dest + off - 0x10];                                        \
+       stw             t6, [%dst + off - 0x10];                                        \
        bcc,pt          %xcc, 27f;                                                      \
-        ldxa           [src + off + 0x30] %asi, t6;                                    \
-       add             sum, 1, sum;                                                    \
-27:    stw             t7, [dest + off - 0x04];                                        \
-       addcc           sum, t7, sum;                                                   \
+        ldxa           [%src + off + 0x30] %asi, t6;                                   \
+       add             %sum, 1, %sum;                                                  \
+27:    stw             t7, [%dst + off - 0x04];                                        \
+       addcc           %sum, t7, %sum;                                                 \
        srlx            t7, 32, t7;                                                     \
-       stw             t7, [dest + off - 0x08];                                        \
+       stw             t7, [%dst + off - 0x08];                                        \
        bcc,pt          %xcc, 28f;                                                      \
-        ldxa           [src + off + 0x38] %asi, t7;                                    \
-       add             sum, 1, sum;                                                    \
+        ldxa           [%src + off + 0x38] %asi, t7;                                   \
+       add             %sum, 1, %sum;                                                  \
 28:
 
-#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)          \
-       addcc           sum, t0, sum;                                                   \
+#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7)                     \
+       addcc           %sum, t0, %sum;                                                 \
        bcc,pt          %xcc, 31f;                                                      \
-        stx            t0, [dest + off + 0x00];                                        \
-       add             sum, 1, sum;                                                    \
-31:    addcc           sum, t1, sum;                                                   \
+        stx            t0, [%dst + off + 0x00];                                        \
+       add             %sum, 1, %sum;                                                  \
+31:    addcc           %sum, t1, %sum;                                                 \
        bcc,pt          %xcc, 32f;                                                      \
-        stx            t1, [dest + off + 0x08];                                        \
-       add             sum, 1, sum;                                                    \
-32:    addcc           sum, t2, sum;                                                   \
+        stx            t1, [%dst + off + 0x08];                                        \
+       add             %sum, 1, %sum;                                                  \
+32:    addcc           %sum, t2, %sum;                                                 \
        bcc,pt          %xcc, 33f;                                                      \
-        stx            t2, [dest + off + 0x10];                                        \
-       add             sum, 1, sum;                                                    \
-33:    addcc           sum, t3, sum;                                                   \
+        stx            t2, [%dst + off + 0x10];                                        \
+       add             %sum, 1, %sum;                                                  \
+33:    addcc           %sum, t3, %sum;                                                 \
        bcc,pt          %xcc, 34f;                                                      \
-        stx            t3, [dest + off + 0x18];                                        \
-       add             sum, 1, sum;                                                    \
-34:    addcc           sum, t4, sum;                                                   \
+        stx            t3, [%dst + off + 0x18];                                        \
+       add             %sum, 1, %sum;                                                  \
+34:    addcc           %sum, t4, %sum;                                                 \
        bcc,pt          %xcc, 35f;                                                      \
-        stx            t4, [dest + off + 0x20];                                        \
-       add             sum, 1, sum;                                                    \
-35:    addcc           sum, t5, sum;                                                   \
+        stx            t4, [%dst + off + 0x20];                                        \
+       add             %sum, 1, %sum;                                                  \
+35:    addcc           %sum, t5, %sum;                                                 \
        bcc,pt          %xcc, 36f;                                                      \
-        stx            t5, [dest + off + 0x28];                                        \
-       add             sum, 1, sum;                                                    \
-36:    addcc           sum, t6, sum;                                                   \
+        stx            t5, [%dst + off + 0x28];                                        \
+       add             %sum, 1, %sum;                                                  \
+36:    addcc           %sum, t6, %sum;                                                 \
        bcc,pt          %xcc, 37f;                                                      \
-        stx            t6, [dest + off + 0x30];                                        \
-       add             sum, 1, sum;                                                    \
-37:    addcc           sum, t7, sum;                                                   \
+        stx            t6, [%dst + off + 0x30];                                        \
+       add             %sum, 1, %sum;                                                  \
+37:    addcc           %sum, t7, %sum;                                                 \
        bcc,pt          %xcc, 38f;                                                      \
-        stx            t7, [dest + off + 0x38];                                        \
-       add             sum, 1, sum;                                                    \
+        stx            t7, [%dst + off + 0x38];                                        \
+       add             %sum, 1, %sum;                                                  \
 38:
 
-#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)          \
-       stw             t0, [dest + off + 0x04];                                        \
-       addcc           sum, t0, sum;                                                   \
+#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7)                     \
+       stw             t0, [%dst + off + 0x04];                                        \
+       addcc           %sum, t0, %sum;                                                 \
        srlx            t0, 32, t0;                                                     \
        bcc,pt          %xcc, 41f;                                                      \
-        stw            t0, [dest + off + 0x00];                                        \
-       add             sum, 1, sum;                                                    \
-41:    stw             t1, [dest + off + 0x0c];                                        \
-       addcc           sum, t1, sum;                                                   \
+        stw            t0, [%dst + off + 0x00];                                        \
+       add             %sum, 1, %sum;                                                  \
+41:    stw             t1, [%dst + off + 0x0c];                                        \
+       addcc           %sum, t1, %sum;                                                 \
        srlx            t1, 32, t1;                                                     \
        bcc,pt          %xcc, 42f;                                                      \
-        stw            t1, [dest + off + 0x08];                                        \
-       add             sum, 1, sum;                                                    \
-42:    stw             t2, [dest + off + 0x14];                                        \
-       addcc           sum, t2, sum;                                                   \
+        stw            t1, [%dst + off + 0x08];                                        \
+       add             %sum, 1, %sum;                                                  \
+42:    stw             t2, [%dst + off + 0x14];                                        \
+       addcc           %sum, t2, %sum;                                                 \
        srlx            t2, 32, t2;                                                     \
        bcc,pt          %xcc, 43f;                                                      \
-        stw            t2, [dest + off + 0x10];                                        \
-       add             sum, 1, sum;                                                    \
-43:    stw             t3, [dest + off + 0x1c];                                        \
-       addcc           sum, t3, sum;                                                   \
+        stw            t2, [%dst + off + 0x10];                                        \
+       add             %sum, 1, %sum;                                                  \
+43:    stw             t3, [%dst + off + 0x1c];                                        \
+       addcc           %sum, t3, %sum;                                                 \
        srlx            t3, 32, t3;                                                     \
        bcc,pt          %xcc, 44f;                                                      \
-        stw            t3, [dest + off + 0x18];                                        \
-       add             sum, 1, sum;                                                    \
-44:    stw             t4, [dest + off + 0x24];                                        \
-       addcc           sum, t4, sum;                                                   \
+        stw            t3, [%dst + off + 0x18];                                        \
+       add             %sum, 1, %sum;                                                  \
+44:    stw             t4, [%dst + off + 0x24];                                        \
+       addcc           %sum, t4, %sum;                                                 \
        srlx            t4, 32, t4;                                                     \
        bcc,pt          %xcc, 45f;                                                      \
-        stw            t4, [dest + off + 0x20];                                        \
-       add             sum, 1, sum;                                                    \
-45:    stw             t5, [dest + off + 0x2c];                                        \
-       addcc           sum, t5, sum;                                                   \
+        stw            t4, [%dst + off + 0x20];                                        \
+       add             %sum, 1, %sum;                                                  \
+45:    stw             t5, [%dst + off + 0x2c];                                        \
+       addcc           %sum, t5, %sum;                                                 \
        srlx            t5, 32, t5;                                                     \
        bcc,pt          %xcc, 46f;                                                      \
-        stw            t5, [dest + off + 0x28];                                        \
-       add             sum, 1, sum;                                                    \
-46:    stw             t6, [dest + off + 0x34];                                        \
-       addcc           sum, t6, sum;                                                   \
+        stw            t5, [%dst + off + 0x28];                                        \
+       add             %sum, 1, %sum;                                                  \
+46:    stw             t6, [%dst + off + 0x34];                                        \
+       addcc           %sum, t6, %sum;                                                 \
        srlx            t6, 32, t6;                                                     \
        bcc,pt          %xcc, 47f;                                                      \
-        stw            t6, [dest + off + 0x30];                                        \
-       add             sum, 1, sum;                                                    \
-47:    stw             t7, [dest + off + 0x3c];                                        \
-       addcc           sum, t7, sum;                                                   \
+        stw            t6, [%dst + off + 0x30];                                        \
+       add             %sum, 1, %sum;                                                  \
+47:    stw             t7, [%dst + off + 0x3c];                                        \
+       addcc           %sum, t7, %sum;                                                 \
        srlx            t7, 32, t7;                                                     \
        bcc,pt          %xcc, 48f;                                                      \
-        stw            t7, [dest + off + 0x38];                                        \
-       add             sum, 1, sum;                                                    \
+        stw            t7, [%dst + off + 0x38];                                        \
+       add             %sum, 1, %sum;                                                  \
 48:
 
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1)                                 \
-       ldxa            [src - off - 0x08] %asi, t0;                                    \
-       ldxa            [src - off - 0x00] %asi, t1;                                    \
+#define CSUMCOPY_LASTCHUNK(off, t0, t1)                                                        \
+       ldxa            [%src - off - 0x08] %asi, t0;                                   \
+       ldxa            [%src - off - 0x00] %asi, t1;                                   \
        nop; nop;                                                                       \
-       addcc           t0, sum, sum;                                                   \
-       stw             t0, [dst - off - 0x04];                                         \
+       addcc           t0, %sum, %sum;                                                 \
+       stw             t0, [%dst - off - 0x04];                                        \
        srlx            t0, 32, t0;                                                     \
        bcc,pt          %xcc, 51f;                                                      \
-        stw            t0, [dst - off - 0x08];                                         \
-       add             sum, 1, sum;                                                    \
-51:    addcc           t1, sum, sum;                                                   \
-       stw             t1, [dst - off + 0x04];                                         \
+        stw            t0, [%dst - off - 0x08];                                        \
+       add             %sum, 1, %sum;                                                  \
+51:    addcc           t1, %sum, %sum;                                                 \
+       stw             t1, [%dst - off + 0x04];                                        \
        srlx            t1, 32, t1;                                                     \
        bcc,pt          %xcc, 52f;                                                      \
-        stw            t1, [dst - off - 0x00];                                         \
-       add             sum, 1, sum;                                                    \
+        stw            t1, [%dst - off - 0x00];                                        \
+       add             %sum, 1, %sum;                                                  \
 52:
 
+cpc_start:
 cc_end_cruft:
-       andcc           %o3, 8, %g0             ! IEU1  Group
+       andcc           %g7, 8, %g0             ! IEU1  Group
        be,pn           %icc, 1f                ! CTI
-        and            %o3, 4, %g5             ! IEU0
-       ldxa            [%o0 + 0x00] %asi, %g2  ! Load  Group
-       add             %o1, 8, %o1             ! IEU0
-       add             %o0, 8, %o0             ! IEU1
-       addcc           %g2, %g7, %g7           ! IEU1  Group + 2 bubbles
-       stw             %g2, [%o1 - 0x04]       ! Store
+        and            %g7, 4, %g5             ! IEU0
+       ldxa            [%src + 0x00] %asi, %g2 ! Load  Group
+       add             %dst, 8, %dst           ! IEU0
+       add             %src, 8, %src           ! IEU1
+       addcc           %g2, %sum, %sum         ! IEU1  Group + 2 bubbles
+       stw             %g2, [%dst - 0x04]      ! Store
        srlx            %g2, 32, %g2            ! IEU0
        bcc,pt          %xcc, 1f                ! CTI   Group
-        stw            %g2, [%o1 - 0x08]       ! Store
-       add             %g7, 1, %g7             ! IEU0
+        stw            %g2, [%dst - 0x08]      ! Store
+       add             %sum, 1, %sum           ! IEU0
 1:     brz,pt          %g5, 1f                 ! CTI   Group
         clr            %g2                     ! IEU0
-       lduwa           [%o0 + 0x00] %asi, %g2  ! Load
-       add             %o1, 4, %o1             ! IEU0  Group
-       add             %o0, 4, %o0             ! IEU1
-       stw             %g2, [%o1 - 0x04]       ! Store Group + 2 bubbles
+       lduwa           [%src + 0x00] %asi, %g2 ! Load
+       add             %dst, 4, %dst           ! IEU0  Group
+       add             %src, 4, %src           ! IEU1
+       stw             %g2, [%dst - 0x04]      ! Store Group + 2 bubbles
        sllx            %g2, 32, %g2            ! IEU0
-1:     andcc           %o3, 2, %g0             ! IEU1
+1:     andcc           %g7, 2, %g0             ! IEU1
        be,pn           %icc, 1f                ! CTI   Group
         clr            %o4                     ! IEU1
-       lduha           [%o0 + 0x00] %asi, %o4  ! Load
-       add             %o0, 2, %o0             ! IEU0  Group
-       add             %o1, 2, %o1             ! IEU1
-       sth             %o4, [%o1 - 0x2]        ! Store Group + 2 bubbles
+       lduha           [%src + 0x00] %asi, %o4 ! Load
+       add             %src, 2, %src           ! IEU0  Group
+       add             %dst, 2, %dst           ! IEU1
+       sth             %o4, [%dst - 0x2]       ! Store Group + 2 bubbles
        sll             %o4, 16, %o4            ! IEU0
-1:     andcc           %o3, 1, %g0             ! IEU1
+1:     andcc           %g7, 1, %g0             ! IEU1
        be,pn           %icc, 1f                ! CTI   Group
         clr            %o5                     ! IEU0
-       lduba           [%o0 + 0x00] %asi, %o5  ! Load
-       stb             %o5, [%o1 + 0x00]       ! Store Group + 2 bubbles
+       lduba           [%src + 0x00] %asi, %o5 ! Load
+       stb             %o5, [%dst + 0x00]      ! Store Group + 2 bubbles
        sll             %o5, 8, %o5             ! IEU0
 1:     or              %g2, %o4, %o4           ! IEU1
        or              %o5, %o4, %o4           ! IEU0  Group
-       addcc           %o4, %g7, %g7           ! IEU1
+       addcc           %o4, %sum, %sum         ! IEU1
        bcc,pt          %xcc, ccfold            ! CTI
         sethi          %uhi(PAGE_OFFSET), %g4  ! IEU0  Group
        b,pt            %xcc, ccfold            ! CTI
-        add            %g7, 1, %g7             ! IEU1
+        add            %sum, 1, %sum           ! IEU1
 
 cc_fixit:
        bl,a,pn         %icc, ccte              ! CTI
-        andcc          %g1, 0xf, %o3           ! IEU1  Group
-       andcc           %o0, 1, %g0             ! IEU1  Group
-       bne,pn          %icc, ccslow            ! CTI
-        andcc          %o0, 2, %g0             ! IEU1  Group
+        andcc          %len, 0xf, %g7          ! IEU1  Group
+       andcc           %src, 2, %g0            ! IEU1  Group
        be,pn           %icc, 1f                ! CTI
-        andcc          %o0, 0x4, %g0           ! IEU1  Group
-       lduha           [%o0 + 0x00] %asi, %g4  ! Load
-       sub             %g1, 2, %g1             ! IEU0
-       add             %o0, 2, %o0             ! IEU0  Group
-       add             %o1, 2, %o1             ! IEU1
+        andcc          %src, 0x4, %g0          ! IEU1  Group
+       lduha           [%src + 0x00] %asi, %g4 ! Load
+       sub             %len, 2, %len           ! IEU0
+       add             %src, 2, %src           ! IEU0  Group
+       add             %dst, 2, %dst           ! IEU1
        sll             %g4, 16, %g3            ! IEU0  Group + 1 bubble
-       addcc           %g3, %g7, %g7           ! IEU1
+       addcc           %g3, %sum, %sum         ! IEU1
        bcc,pt          %xcc, 0f                ! CTI
-        srl            %g7, 16, %g3            ! IEU0  Group
+        srl            %sum, 16, %g3           ! IEU0  Group
        add             %g3, 1, %g3             ! IEU0  4 clocks (mispredict)
-0:     andcc           %o0, 0x4, %g0           ! IEU1  Group
-       sth             %g4, [%o1 - 0x2]        ! Store
-       sll             %g7, 16, %g7            ! IEU0
+0:     andcc           %src, 0x4, %g0          ! IEU1  Group
+       sth             %g4, [%dst - 0x2]       ! Store
+       sll             %sum, 16, %sum          ! IEU0
        sll             %g3, 16, %g3            ! IEU0  Group
-       srl             %g7, 16, %g7            ! IEU0  Group
-       or              %g3, %g7, %g7           ! IEU0  Group (regdep)
+       srl             %sum, 16, %sum          ! IEU0  Group
+       or              %g3, %sum, %sum         ! IEU0  Group (regdep)
 1:     be,pt           %icc, cc_dword_aligned  ! CTI
-        andn           %g1, 0xff, %g2          ! IEU1
-       lduwa           [%o0 + 0x00] %asi, %g4  ! Load  Group
-       sub             %g1, 4, %g1             ! IEU0
-       add             %o0, 4, %o0             ! IEU1
-       add             %o1, 4, %o1             ! IEU0  Group
-       addcc           %g4, %g7, %g7           ! IEU1  Group + 1 bubble
-       stw             %g4, [%o1 - 0x4]        ! Store
+        andn           %len, 0xff, %g2         ! IEU1
+       lduwa           [%src + 0x00] %asi, %g4 ! Load  Group
+       sub             %len, 4, %len           ! IEU0
+       add             %src, 4, %src           ! IEU1
+       add             %dst, 4, %dst           ! IEU0  Group
+       addcc           %g4, %sum, %sum         ! IEU1  Group + 1 bubble
+       stw             %g4, [%dst - 0x4]       ! Store
        bcc,pt          %xcc, cc_dword_aligned  ! CTI
-        andn           %g1, 0xff, %g2          ! IEU0  Group
+        andn           %len, 0xff, %g2         ! IEU0  Group
        b,pt            %xcc, cc_dword_aligned  ! CTI   4 clocks (mispredict)
-        add            %g7, 1, %g7             ! IEU0
+        add            %sum, 1, %sum           ! IEU0
 
        .align          32
-       .globl          __csum_partial_copy_sparc_generic, csum_partial_copy
-csum_partial_copy:
-__csum_partial_copy_sparc_generic:             /* %o0=src, %o1=dest, %g1=len, %g7=sum */
-       xorcc           %o0, %o1, %o4           ! IEU1  Group
-       srl             %g7, 0, %g7             ! IEU0
+       .globl          csum_partial_copy_sparc64
+csum_partial_copy_sparc64:                     /* %o0=src, %o1=dest, %o2=len, %o3=sum */
+       xorcc           %src, %dst, %o4         ! IEU1  Group
+       srl             %sum, 0, %sum           ! IEU0
        andcc           %o4, 3, %g0             ! IEU1  Group
-       srl             %g1, 0, %g1             ! IEU0
+       srl             %len, 0, %len           ! IEU0
+       bne,pn          %icc, ccslow            ! CTI
+        andcc          %src, 1, %g0            ! IEU1  Group
        bne,pn          %icc, ccslow            ! CTI
-        andcc          %o0, 7, %g0             ! IEU1  Group
+        cmp            %len, 256               ! IEU1  Group
+       bgeu,pt         %icc, csum_partial_copy_vis ! CTI
+        andcc          %src, 7, %g0            ! IEU1  Group
        be,pt           %icc, cc_dword_aligned  ! CTI
-        andn           %g1, 0xff, %g2          ! IEU0
+        andn           %len, 0xff, %g2         ! IEU0
        b,pt            %xcc, cc_fixit          ! CTI   Group
-        cmp            %g1, 6                  ! IEU1
+        cmp            %len, 6                 ! IEU1
 cc_dword_aligned:
        brz,pn          %g2, 3f                 ! CTI   Group
-        andcc          %o1, 4, %g0             ! IEU1  Group (brz uses IEU1)
+        andcc          %dst, 4, %g0            ! IEU1  Group (brz uses IEU1)
        be,pn           %icc, ccdbl + 4         ! CTI
-5:     CSUMCOPY_ECACHE_LOAD(       %o0,    0x00,    %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STUNALIGN(          %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+5:     CSUMCOPY_ECACHE_LOAD(       0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STUNALIGN(      0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
 10:
-       sub             %g1, 256, %g1           ! IEU0  Group
-       add             %o0, 256, %o0           ! IEU1
-       andncc          %g1, 0xff, %g0          ! IEU1  Group
+       sub             %len, 256, %len         ! IEU0  Group
+       add             %src, 256, %src         ! IEU1
+       andncc          %len, 0xff, %g0         ! IEU1  Group
        bne,pt          %icc, 5b                ! CTI
-        add            %o1, 256, %o1           ! IEU0
-3:     andcc           %g1, 0xf0, %o2          ! IEU1  Group
+        add            %dst, 256, %dst         ! IEU0
+3:     andcc           %len, 0xf0, %g1         ! IEU1  Group
 ccmerge:be,pn          %icc, ccte              ! CTI
-        andcc          %g1, 0xf, %o3           ! IEU1  Group
-       sll             %o2, 2, %o4             ! IEU0
-13:    rd              %pc, %o5                ! LSU   Group + 4 clocks
-       add             %o0, %o2, %o0           ! IEU0  Group
-       sub             %o5, %o4, %o5           ! IEU1  Group
-       jmpl            %o5 + (12f - 13b), %g0  ! CTI   Group brk forced
-        add            %o1, %o2, %o1           ! IEU0  Group
-cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3)
+        andcc          %len, 0xf, %g7          ! IEU1  Group
+       sll             %g1, 2, %o4             ! IEU0
+13:    sethi           %hi(12f), %o5           ! IEU0  Group
+       add             %src, %g1, %src         ! IEU1  
+       sub             %o5, %o4, %o5           ! IEU0  Group
+       jmpl            %o5 + %lo(12f), %g0     ! CTI   Group brk forced
+        add            %dst, %g1, %dst         ! IEU0  Group
+cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+       CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
 12:
-       andcc           %g1, 0xf, %o3           ! IEU1  Group
+       andcc           %len, 0xf, %g7          ! IEU1  Group
 ccte:  bne,pn          %icc, cc_end_cruft      ! CTI
         sethi          %uhi(PAGE_OFFSET), %g4  ! IEU0
-ccfold:        sllx            %g7, 32, %o0            ! IEU0  Group
-       addcc           %g7, %o0, %o0           ! IEU1  Group (regdep)
+ccfold:        sllx            %sum, 32, %o0           ! IEU0  Group
+       addcc           %sum, %o0, %o0          ! IEU1  Group (regdep)
        srlx            %o0, 32, %o0            ! IEU0  Group (regdep)
        bcs,a,pn        %xcc, 1f                ! CTI
         add            %o0, 1, %o0             ! IEU1  4 clocks (mispredict)
 1:     retl                                    ! CTI   Group brk forced
         sllx           %g4, 32,%g4             ! IEU0  Group
-ccdbl: CSUMCOPY_ECACHE_LOAD(       %o0,    0x00,    %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_EC_STALIGNED(          %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ccdbl: CSUMCOPY_ECACHE_LOAD(       0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+       CSUMCOPY_EC_STALIGNED(      0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
 11:
-       sub             %g1, 256, %g1           ! IEU0  Group
-       add             %o0, 256, %o0           ! IEU1
-       andncc          %g1, 0xff, %g0          ! IEU1  Group   
+       sub             %len, 256, %len         ! IEU0  Group
+       add             %src, 256, %src         ! IEU1
+       andncc          %len, 0xff, %g0         ! IEU1  Group   
        bne,pt          %icc, ccdbl             ! CTI
-        add            %o1, 256, %o1           ! IEU0
+        add            %dst, 256, %dst         ! IEU0
        b,pt            %xcc, ccmerge           ! CTI   Group
-        andcc          %g1, 0xf0, %o2          ! IEU1
+        andcc          %len, 0xf0, %g1         ! IEU1
 
 ccslow:        mov     0, %g5
-       brlez,pn %g1, 4f
-        andcc  %o0, 1, %o5             
+       brlez,pn %len, 4f
+        andcc  %src, 1, %o5            
        be,a,pt %icc, 1f
-        srl    %g1, 1, %o3             
-       sub     %g1, 1, %g1     
-       lduba [%o0] %asi, %g5
-       add     %o0, 1, %o0     
-       stb     %g5, [%o1]
-       srl     %g1, 1, %o3
-       add     %o1, 1, %o1
-1:     brz,a,pn %o3, 3f
-        andcc  %g1, 1, %g0
-       andcc   %o0, 2, %g0     
+        srl    %len, 1, %g7            
+       sub     %len, 1, %len   
+       lduba [%src] %asi, %g5
+       add     %src, 1, %src   
+       stb     %g5, [%dst]
+       srl     %len, 1, %g7
+       add     %dst, 1, %dst
+1:     brz,a,pn %g7, 3f
+        andcc  %len, 1, %g0
+       andcc   %src, 2, %g0    
        be,a,pt %icc, 1f
-        srl    %o3, 1, %o3
-       lduha [%o0] %asi, %o4
-       sub     %g1, 2, %g1     
+        srl    %g7, 1, %g7
+       lduha [%src] %asi, %o4
+       sub     %len, 2, %len   
        srl     %o4, 8, %g2
-       sub     %o3, 1, %o3     
-       stb     %g2, [%o1]
+       sub     %g7, 1, %g7     
+       stb     %g2, [%dst]
        add     %o4, %g5, %g5
-       stb     %o4, [%o1 + 1]
-       add     %o0, 2, %o0     
-       srl     %o3, 1, %o3
-       add     %o1, 2, %o1
-1:     brz,a,pn %o3, 2f                
-        andcc  %g1, 2, %g0
-       lda     [%o0] %asi, %o4
+       stb     %o4, [%dst + 1]
+       add     %src, 2, %src   
+       srl     %g7, 1, %g7
+       add     %dst, 2, %dst
+1:     brz,a,pn %g7, 2f                
+        andcc  %len, 2, %g0
+       lduwa   [%src] %asi, %o4
 5:     srl     %o4, 24, %g2
        srl     %o4, 16, %g3
-       stb     %g2, [%o1]
+       stb     %g2, [%dst]
        srl     %o4, 8, %g2
-       stb     %g3, [%o1 + 1]
-       add     %o0, 4, %o0
-       stb     %g2, [%o1 + 2]
+       stb     %g3, [%dst + 1]
+       add     %src, 4, %src
+       stb     %g2, [%dst + 2]
        addcc   %o4, %g5, %g5
-       stb     %o4, [%o1 + 3]
-       addc    %g5, %g0, %g5   ! I am now to lazy to optimize this (question is if it
-       add     %o1, 4, %o1     ! is worthy). Maybe some day - with the sll/srl
-       subcc   %o3, 1, %o3     ! tricks
+       stb     %o4, [%dst + 3]
+       addc    %g5, %g0, %g5
+       add     %dst, 4, %dst
+       subcc   %g7, 1, %g7
        bne,a,pt %icc, 5b
-        lda [%o0] %asi, %o4
+        lduwa [%src] %asi, %o4
        sll     %g5, 16, %g2
        srl     %g5, 16, %g5
        srl     %g2, 16, %g2
-       andcc   %g1, 2, %g0
+       andcc   %len, 2, %g0
        add     %g2, %g5, %g5 
 2:     be,a,pt %icc, 3f                
-        andcc  %g1, 1, %g0
-       lduha [%o0] %asi, %o4
-       andcc   %g1, 1, %g0
+        andcc  %len, 1, %g0
+       lduha [%src] %asi, %o4
+       andcc   %len, 1, %g0
        srl     %o4, 8, %g2
-       add     %o0, 2, %o0     
-       stb     %g2, [%o1]
+       add     %src, 2, %src   
+       stb     %g2, [%dst]
        add     %g5, %o4, %g5
-       stb     %o4, [%o1 + 1]
-       add     %o1, 2, %o1
+       stb     %o4, [%dst + 1]
+       add     %dst, 2, %dst
 3:     be,a,pt %icc, 1f                
         sll    %g5, 16, %o4
-       lduba [%o0] %asi, %g2
+       lduba [%src] %asi, %g2
        sll     %g2, 8, %o4     
-       stb     %g2, [%o1]
+       stb     %g2, [%dst]
        add     %g5, %o4, %g5
        sll     %g5, 16, %o4
 1:     addcc   %o4, %g5, %g5
@@ -484,8 +484,22 @@ ccslow:    mov     0, %g5
        and     %o4, 0xff, %o4
        sll     %g2, 8, %g2
        or      %g2, %o4, %g5
-4:     addcc   %g7, %g5, %g7
-       addc    %g0, %g7, %o0
+4:     addcc   %sum, %g5, %sum
+       addc    %g0, %sum, %o0
        retl    
         srl    %o0, 0, %o0
-__csum_partial_copy_end:
+cpc_end:
+
+       .globl  cpc_handler
+cpc_handler:
+       ldx     [%sp + 0x7ff + 128], %g1
+       sub     %g0, EFAULT, %g2
+       brnz,a,pt %g1, 1f
+        st     %g2, [%g1]
+1:     retl
+        nop
+
+       .section __ex_table
+       .align  8
+       .xword  cpc_start, 0, cpc_end, cpc_handler
+
index 74054f63a920fe52aa8508c8e800a559fb024f1e..7b2bdba62086a62251310dc92678c1748b6aacab 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
+/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
  * locks.S: SMP low-level lock primitives on Sparc64.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -12,9 +12,9 @@
        .align          32
 
 ___lk_busy_spin:
-       orcc            %g2, 0, %g0
-       bne,pt          %icc, ___lk_busy_spin
-        ldub           [%g1 + 0], %g2
+       ldub            [%g1 + 0], %g2
+       brnz,pt         %g2, ___lk_busy_spin
+        membar         #LoadLoad
        b,pt            %xcc, 1f
         ldstub         [%g1 + 0], %g2
 
@@ -23,16 +23,15 @@ ___lock_kernel:
        addcc           %g2, -1, %g2
        rdpr            %pil, %g3
        bcs,a,pn        %icc, 9f
-        st             %g2, [%g6 + AOFF_task_lock_depth]
+        stw            %g2, [%g6 + AOFF_task_lock_depth]
        wrpr            %g0, 15, %pil
        ldstub          [%g1 + 0], %g2
-1:     brnz,a,pn       %g2, ___lk_busy_spin
-        ldub           [%g1 + 0], %g2
+1:     brnz,pn         %g2, ___lk_busy_spin
+        membar         #StoreLoad | #StoreStore
        lduw            [%g6 + AOFF_task_processor], %g2
-       membar          #LoadLoad | #LoadStore
        stb             %g2, [%g1 + 1]
 2:     mov             -1, %g2
-       st              %g2, [%g6 + AOFF_task_lock_depth]
+       stw             %g2, [%g6 + AOFF_task_lock_depth]
        wrpr            %g3, 0, %pil
 9:     jmpl            %o7 + 0x8, %g0
         mov            %g5, %o7
@@ -41,16 +40,16 @@ ___lock_kernel:
 ___lock_reacquire_kernel:
        rdpr            %pil, %g3
        wrpr            %g0, 15, %pil
-       st              %g2, [%g6 + AOFF_task_lock_depth]
+       stw             %g2, [%g6 + AOFF_task_lock_depth]
        ldstub          [%g1 + 0], %g2
 1:     brz,pt          %g2, 3f
-        ldub           [%g1 + 0], %g2
-2:     brnz,a,pt       %g2, 2b
-        ldub           [%g1 + 0], %g2
+        membar         #StoreLoad | #StoreStore
+2:     ldub            [%g1 + 0], %g2
+       brnz,pt         %g2, 2b
+        membar         #LoadLoad
        b,pt            %xcc, 1b
         ldstub         [%g1 + 0], %g2
 3:     lduw            [%g6 + AOFF_task_processor], %g2
-       membar          #LoadLoad | #LoadStore
        stb             %g2, [%g1 + 1]
        wrpr            %g3, 0, %pil
        jmpl            %o7 + 0x8, %g0
index 5e16e12189ed72e46e65de8489eaf7caa04ce0c5..97b9a256b764e97384f277730d520f62242bad24 100644 (file)
@@ -217,56 +217,3 @@ bad_area:
 out:
        unlock_kernel();
 }
-
-void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-       struct vm_area_struct *vmaring;
-       struct inode *inode;
-       unsigned long vaddr, offset, start;
-       pgd_t *pgdp;
-       pmd_t *pmdp;
-       pte_t *ptep;
-       int alias_found = 0;
-
-       inode = vma->vm_dentry->d_inode;
-       if(!inode)
-               return;
-
-       offset = (address & PAGE_MASK) - vma->vm_start;
-       vmaring = inode->i_mmap;
-       do {
-               vaddr = vmaring->vm_start + offset;
-
-               /* This conditional is misleading... */
-               if((vaddr ^ address) & PAGE_SIZE) {
-                       alias_found++;
-                       start = vmaring->vm_start;
-                       while(start < vmaring->vm_end) {
-                               pgdp = pgd_offset(vmaring->vm_mm, start);
-                               if(!pgdp) goto next;
-                               pmdp = pmd_offset(pgdp, start);
-                               if(!pmdp) goto next;
-                               ptep = pte_offset(pmdp, start);
-                               if(!ptep) goto next;
-
-                               if(pte_val(*ptep) & _PAGE_PRESENT) {
-                                       flush_cache_page(vmaring, start);
-                                       *ptep = __pte(pte_val(*ptep) &
-                                                     ~(_PAGE_CV));
-                                       flush_tlb_page(vmaring, start);
-                               }
-                       next:
-                               start += PAGE_SIZE;
-                       }
-               }
-       } while((vmaring = vmaring->vm_next_share) != NULL);
-
-       if(alias_found && (pte_val(pte) & _PAGE_CV)) {
-               pgdp = pgd_offset(vma->vm_mm, address);
-               pmdp = pmd_offset(pgdp, address);
-               ptep = pte_offset(pmdp, address);
-               flush_cache_page(vma, address);
-               *ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV));
-               flush_tlb_page(vma, address);
-       }
-}
index 386c8540f79e083369dffb5722653bf017560448..fd071e5731b92dc13619ba4b204f771ea79908d3 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
+/*  $Id: init.c,v 1.54 1997/08/15 06:44:23 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,18 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION;
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
 
+extern void __bfill64(void *, unsigned long *);
+
+static __inline__ void __init_pmd(pmd_t *pmdp)
+{
+       __bfill64((void *)pmdp, &null_pte_table);
+}
+
+static __inline__ void __init_pgd(pgd_t *pgdp)
+{
+       __bfill64((void *)pgdp, &null_pmd_table);
+}
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -103,47 +115,71 @@ void show_mem(void)
 
 /* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
 
-/* XXX Also, play with the streaming buffers at some point, both
- * XXX Fusion and Sunfire both have them aparently... -DaveM
- */
-
 /* This keeps track of pages used in sparc_alloc_dvma() invocations. */
 static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
 static unsigned long dvma_pages_current_offset = 0;
 static int dvma_pages_current_index = 0;
 
+/* #define E3000_DEBUG */
+
 __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
                                    unsigned long memory_end, struct linux_sbus *sbus))
 {
        struct iommu_struct *iommu;
        struct sysio_regs *sregs;
-       struct linux_prom_registers rprop[2];
+       struct linux_prom64_registers rprop;
        unsigned long impl, vers;
        unsigned long control, tsbbase;
        unsigned long *iopte;
+       u32 rlow, rhigh;
        int err, i;
 
-       err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+#ifdef E3000_DEBUG
+       prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
+                   iommu_node, memory_start, memory_end, sbus);
+#endif
+       err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
                               sizeof(rprop));
        if(err == -1) {
                prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
                prom_halt();
        }
-       sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
-                                                    (void *)0,
+       rlow  = (rprop.phys_addr & 0xffffffff);
+       rhigh = (rprop.phys_addr >> 32);
+#ifdef E3000_DEBUG
+       prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
+#endif
+       sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
                                                     sizeof(struct sysio_regs),
-                                                    "SYSIO Regs",
-                                                    rprop[0].which_io, 0x0);
+                                                    "SYSIO Regs", rhigh, 0x0);
+#ifdef E3000_DEBUG
+       prom_printf("sregs[%p]\n");
+#endif
+       if(!sregs) {
+               prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
+               prom_halt();
+       }
 
        memory_start = (memory_start + 7) & ~7;
        iommu = (struct iommu_struct *) memory_start;
        memory_start += sizeof(struct iommu_struct);
+
+#ifdef E3000_DEBUG
+       prom_printf("iommu_init: iommu[%p] ", iommu);
+#endif
+
+       spin_lock_init(&iommu->iommu_lock);
        iommu->sysio_regs = sregs;
        sbus->iommu = iommu;
 
        control = sregs->iommu_control;
        impl = (control & IOMMU_CTRL_IMPL) >> 60;
        vers = (control & IOMMU_CTRL_VERS) >> 56;
+#ifdef E3000_DEBUG
+       prom_printf("sreg_control[%08x]\n", control);
+       prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+                   (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+#endif
        printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
               (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
        
@@ -168,7 +204,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
 
        /* Setup aliased mappings... */
        for(i = 0; i < (65536 - 4096); i++) {
-               *iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+               *iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
+                          IOPTE_CACHE | IOPTE_WRITE);
                *iopte |= (i << 16);
                iopte++;
        }
@@ -177,15 +214,47 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
        for( ; i < 65536; i++)
                *iopte++ = 0;
 
+#ifdef E3000_DEBUG
+       prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
+#endif
        sregs->iommu_tsbbase = __pa(tsbbase);
        sregs->iommu_control = control;
 
+#ifdef E3000_DEBUG
+       prom_printf("done\n");
+#endif
+       /* Get the streaming buffer going. */
+       control = sregs->sbuf_control;
+       impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
+       vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
+#ifdef E3000_DEBUG
+       prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
+                   control);
+#endif
+       printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+              (unsigned int)impl, (unsigned int)vers);
+       printk("FlushFLAG[%p,%016lx] ... ",
+              (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
+              (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+       *(iommu->sbuf_flushflag_va) = 0;
+       memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
+
+       sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+
+#ifdef E3000_DEBUG
+       prom_printf("done, returning %016lx\n", memory_start);
+#endif
+       printk("ENABLED\n");
+
+       /* Finally enable DVMA arbitration for all devices, just in case. */
+       sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
        return memory_start;
 }
 
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
+                     struct linux_sbus *sbus)
 {
-       struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
        pgd_t *pgdp;
        pmd_t *pmdp;
        pte_t *ptep;
@@ -193,6 +262,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
        /* Find out if we need to grab some pages. */
        if(!dvma_map_pages[dvma_pages_current_index] ||
           ((dvma_pages_current_offset + len) > (1 << 16))) {
+               struct linux_sbus *sbus;
                unsigned long *iopte;
                unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
                int i;
@@ -212,9 +282,16 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
 
                /* Stick it in the IOMMU. */
                i = (65536 - 4096) + i;
-               iopte = (unsigned long *)(iommu->page_table + i);
-               *iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
-               *iopte |= __pa(newpages);
+               for_each_sbus(sbus) {
+                       struct iommu_struct *iommu = sbus->iommu;
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&iommu->iommu_lock, flags);
+                       iopte = (unsigned long *)(iommu->page_table + i);
+                       *iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+                       *iopte |= __pa(newpages);
+                       spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+               }
        }
 
        /* Get this out of the way. */
@@ -258,6 +335,33 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
         return (__u32)0;
 }
 
+void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+       struct iommu_struct *iommu = sbus->iommu;
+       struct sysio_regs *sregs = iommu->sysio_regs;
+       unsigned long start = (unsigned long) vaddr;
+       unsigned long end = PAGE_ALIGN(start + len);
+       unsigned long flags;
+       unsigned int *sync_word;
+
+       start &= PAGE_MASK;
+
+       spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+       while(start < end) {
+               sregs->sbuf_pflush = start;
+               start += PAGE_SIZE;
+       }
+       sync_word = iommu->sbuf_flushflag_va;
+       sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+       membar("#StoreLoad | #MemIssue");
+       while((*sync_word & 0x1) == 0)
+               membar("#LoadLoad");
+       *sync_word = 0;
+
+       spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
 void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
        while(sz >= 0) {
@@ -273,6 +377,36 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
        }
 }
 
+void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+       struct iommu_struct *iommu = sbus->iommu;
+       struct sysio_regs *sregs = iommu->sysio_regs;
+       unsigned long flags;
+       unsigned int *sync_word;
+
+       spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+       while(sz >= 0) {
+               unsigned long start = sg[sz].dvma_addr;
+               unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+               start &= PAGE_MASK;
+               while(start < end) {
+                       sregs->sbuf_pflush = start;
+                       start += PAGE_SIZE;
+               }
+               sz--;
+       }
+       sync_word = iommu->sbuf_flushflag_va;
+       sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+       membar("#StoreLoad | #MemIssue");
+       while((*sync_word & 0x1) == 0)
+               membar("#LoadLoad");
+       *sync_word = 0;
+
+       spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
 static char sfmmuinfo[512];
 
 char *mmu_info(void)
@@ -340,7 +474,7 @@ int prom_itlb_ent, prom_dtlb_ent;
 unsigned long prom_itlb_tag, prom_itlb_data;
 unsigned long prom_dtlb_tag, prom_dtlb_data;
 
-static inline void inherit_locked_prom_mappings(void)
+void inherit_locked_prom_mappings(int save_p)
 {
        int i;
        int dtlb_seen = 0;
@@ -367,9 +501,12 @@ static inline void inherit_locked_prom_mappings(void)
                data = spitfire_get_dtlb_data(i);
                if(!dtlb_seen && (data & _PAGE_L)) {
                        unsigned long tag = spitfire_get_dtlb_tag(i);
-                       prom_dtlb_ent = i;
-                       prom_dtlb_tag = tag;
-                       prom_dtlb_data = data;
+
+                       if(save_p) {
+                               prom_dtlb_ent = i;
+                               prom_dtlb_tag = tag;
+                               prom_dtlb_data = data;
+                       }
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
                        membar("#Sync");
@@ -390,9 +527,12 @@ static inline void inherit_locked_prom_mappings(void)
                data = spitfire_get_itlb_data(i);
                if(!itlb_seen && (data & _PAGE_L)) {
                        unsigned long tag = spitfire_get_itlb_tag(i);
-                       prom_itlb_ent = i;
-                       prom_itlb_tag = tag;
-                       prom_itlb_data = data;
+
+                       if(save_p) {
+                               prom_itlb_ent = i;
+                               prom_itlb_tag = tag;
+                               prom_itlb_data = data;
+                       }
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
                        membar("#Sync");
@@ -443,10 +583,14 @@ void __flush_cache_all(void)
 /* If not locked, zap it. */
 void __flush_tlb_all(void)
 {
-       unsigned long flags;
+       unsigned long pstate;
        int i;
 
-       save_flags(flags); cli();
+       __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+                            "wrpr      %0, %1, %%pstate\n\t"
+                            "flushw"
+                            : "=r" (pstate)
+                            : "i" (PSTATE_IE));
        for(i = 0; i < 64; i++) {
                if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -465,19 +609,67 @@ void __flush_tlb_all(void)
                        membar("#Sync");
                }
        }
-       restore_flags(flags);
+       __asm__ __volatile__("wrpr      %0, 0, %%pstate"
+                            : : "r" (pstate));
 }
 
-void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx)
+/* We are always protected by scheduler_lock under SMP. */
+void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
 {
-       if((ctx & ~(CTX_VERSION_MASK)) == 0) {
-               flush_tlb_all();
-               ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
-               if(ctx == 1)
-                       ctx = CTX_FIRST_VERSION;
+       unsigned int new_ctx = *ctx;
+
+       if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
+               new_ctx += CTX_FIRST_VERSION;
+               if(new_ctx == 1)
+                       new_ctx = CTX_FIRST_VERSION;
+               *ctx = new_ctx;
+               DO_LOCAL_FLUSH(smp_processor_id());
        }
-       tlb_context_cache = ctx + 1;
-       mm->context = ctx;
+       mm->context = new_ctx;
+       mm->cpu_vm_mask = 0;    /* Callers sets it properly. */
+       (*ctx)++;
+}
+
+#ifndef __SMP__
+unsigned long *pgd_quicklist = NULL;
+unsigned long *pmd_quicklist = NULL;
+unsigned long *pte_quicklist = NULL;
+unsigned long pgtable_cache_size = 0;
+#endif
+
+pgd_t *get_pgd_slow(void)
+{
+       pgd_t *pgd;
+
+       pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+       if(pgd)
+               __init_pgd(pgd);
+       return pgd;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+       pmd_t *pmd;
+
+       pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+       if(pmd) {
+               __init_pmd(pmd);
+               pgd_set(pgd, pmd);
+               return pmd + offset;
+       }
+       return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+       pte_t *pte;
+
+       pte = (pte_t *) get_free_page(GFP_KERNEL);
+       if(pte) {
+               pmd_set(pmd, pte);
+               return pte + offset;
+       }
+       return NULL;
 }
 
 __initfunc(static void
@@ -595,7 +787,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
         */
        pt  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
        pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
-       save_flags(flags); cli();
+       __save_and_cli(flags);
        __asm__ __volatile__("
        stxa    %1, [%0] %3
        stxa    %2, [%5] %4
@@ -608,15 +800,18 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
          "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
        : "memory");
-       restore_flags(flags);
+       __restore_flags(flags);
        
        /* Now set kernel pgd to upper alias so physical page computations
         * work.
         */
        init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
 
-       null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift);
-       null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift);
+       /* The funny offsets are to make page table operations much quicker and
+        * requite less state, see pgtable.h for gory details.
+        */
+       null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
+       null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
 
        pmdp = (pmd_t *) &empty_null_pmd_table;
        for(i = 0; i < 1024; i++)
@@ -658,7 +853,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        flushi((long)&empty_zero_page);
        membar("#Sync");
 
-       inherit_locked_prom_mappings();
+       inherit_locked_prom_mappings(1);
        
        flush_tlb_all();
        
index 18f9a363d5577a80f53b29ef2b76ae922bb24c56..8a745bf0ad72bc1d3bc219ac73fda81b53911515 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
+/* $Id: ultra.S,v 1.18 1997/08/08 08:34:23 jj Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
        .align          32
        .globl          __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
 __flush_tlb_mm:                /* %o0 == (mm->context & 0x1fff) */
-       rdpr            %otherwin, %g1
-       brz,pt          %g1, 1f
-        mov            %o7, %g3
-       call            __flushw_user
-        clr            %g2
-1:     rdpr            %pil, %g1
-9:     mov             SECONDARY_CONTEXT, %g7
-       wrpr            %g0, 15, %pil
-
-       ldxa            [%g7] ASI_DMMU, %g2
+       mov             SECONDARY_CONTEXT, %g7
+9:     ldxa            [%g7] ASI_DMMU, %g2
        cmp             %g2, %o0
-       be,pt           %icc, 1f
+       bne,pn          %icc, 1f
         mov            0x50, %g3
+       stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g3] ASI_IMMU_DEMAP
+       retl
+        flush          %g6
+1:     rdpr            %pstate, %g1
+       wrpr            %g1, PSTATE_IE, %pstate
        stxa            %o0, [%g7] ASI_DMMU
-1:     stxa            %g0, [%g3] ASI_DMMU_DEMAP
-       be,pt           %icc, 1f
-        stxa           %g0, [%g3] ASI_IMMU_DEMAP
-
+       stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g3] ASI_IMMU_DEMAP
+       flush           %g6
        stxa            %g2, [%g7] ASI_DMMU
-1:     wrpr            %g1, 0x0, %pil
+       flush           %g6
        retl
-        flush          %g6
+        wrpr           %g1, 0, %pstate
+       nop
 __flush_tlb_range:     /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
        sethi           %hi(8192 - 1), %g5
        or              %g5, %lo(8192 - 1), %g5
@@ -43,19 +41,13 @@ __flush_tlb_range:  /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
 
        sub             %o2, %o1, %o3
        add             %g5, 1, %g5
-       orcc            %o1, 0x50, %o1
+       orcc            %o1, 0x10, %o1
        srlx            %o3, 13, %o4
-       rdpr            %otherwin, %g1
-       brz,pt          %g1, 1f
-        mov            %o7, %g3
-       call            __flushw_user
-
-        clr            %g2
-1:     cmp             %o4, 96
+       cmp             %o4, 96
        bgu,pn          %icc, 9b
-        rdpr           %pil, %g1
-       mov             SECONDARY_CONTEXT, %g7
-       wrpr            %g0, 15, %pil
+        mov            SECONDARY_CONTEXT, %g7
+       rdpr            %pstate, %g1
+       wrpr            %g1, PSTATE_IE, %pstate
        ldxa            [%g7] ASI_DMMU, %g2
        cmp             %g2, %o0
 
@@ -66,37 +58,37 @@ __flush_tlb_range:  /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
        stxa            %g0, [%o1 + %o3] ASI_IMMU_DEMAP
        brnz,pt         %o3, 1b
         sub            %o3, %g5, %o3
-       nop
+       flush           %g6
 
-       be,pt           %icc, 1f
-        wrpr           %g1, 0x0, %pil
+       be,a,pt         %icc, 1f
+        nop
        stxa            %g2, [%g7] ASI_DMMU
-1:     retl
-        flush          %g6
+1:     flush           %g6
+       wrpr            %g1, 0, %pstate
+       retl
+        nop
 
        .align          32
 __flush_tlb_page:      /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
-       rdpr            %otherwin, %g1
-       brz,pt          %g1, 1f
-        mov            %o7, %g3
-       call            __flushw_user
-        clr            %g2
-1:     rdpr            %pil, %g1
        mov             SECONDARY_CONTEXT, %g7
-       wrpr            %g0, 15, %pil
-
        ldxa            [%g7] ASI_DMMU, %g2
        cmp             %g2, %o0
        be,pt           %icc, 1f
         or             %o1, 0x10, %g3
+       stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g3] ASI_IMMU_DEMAP
+       retl
+        flush          %g6
+1:     rdpr            %pstate, %g1
+       wrpr            %g1, PSTATE_IE, %pstate
        stxa            %o0, [%g7] ASI_DMMU
-1:     stxa            %g0, [%g3] ASI_DMMU_DEMAP
-       be,pt           %icc, 1f
-        stxa           %g0, [%g3] ASI_IMMU_DEMAP
+       stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g3] ASI_IMMU_DEMAP
+       flush           %g6
        stxa            %g2, [%g7] ASI_DMMU
-1:     wrpr            %g1, 0x0, %pil
+       flush           %g6
        retl
-        flush          %g6
+        wrpr           %g1, 0, %pstate
 
 #ifdef __SMP__
        /* These are all called by the slaves of a cross call, at
@@ -111,50 +103,29 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
         *   %g2        scratch 1
         *   %g3        scratch 2
         *   %g4        scratch 3
-        *
-        * NOTE: We do not acknowledge the UPA until we are done
-        *       with the service.  This is what tells the master
-        *       that he can consider the effects of the flush
-        *       "complete" on this cpu.
         */
        .align          32
-       .globl          xcall_flush_tlb_page
+       .globl          xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
 xcall_flush_tlb_page:
        mov             SECONDARY_CONTEXT, %g2
-       nop
+       or              %g6, 0x10, %g4
        ldxa            [%g2] ASI_DMMU, %g3
-       cmp             %g3, %g5
-       be,pt           %icc, 1f
-        or             %g6, 0x10, %g4
        stxa            %g5, [%g2] ASI_DMMU
-1:     stxa            %g0, [%g4] ASI_DMMU_DEMAP
-
-       be,pt           %icc, 1f
-        stxa           %g0, [%g4] ASI_IMMU_DEMAP
+       stxa            %g0, [%g4] ASI_DMMU_DEMAP
+       stxa            %g0, [%g4] ASI_IMMU_DEMAP
        stxa            %g3, [%g2] ASI_DMMU
-1:     b,pt            %xcc, do_ivec_return
-        flush          %g1
+       retry
 
-       .align          32
-       .globl          xcall_flush_tlb_mm
 xcall_flush_tlb_mm:
        mov             SECONDARY_CONTEXT, %g2
-       nop
+       mov             0x50, %g4
        ldxa            [%g2] ASI_DMMU, %g3
-       cmp             %g3, %g5
-       be,pt           %icc, 1f
-        mov            0x50, %g4
        stxa            %g5, [%g2] ASI_DMMU
-1:     stxa            %g0, [%g4] ASI_DMMU_DEMAP
-
-       be,pt           %icc, 1f
-        stxa           %g0, [%g4] ASI_IMMU_DEMAP
+       stxa            %g0, [%g4] ASI_DMMU_DEMAP
+       stxa            %g0, [%g4] ASI_IMMU_DEMAP
        stxa            %g3, [%g2] ASI_DMMU
-1:     b,pt            %xcc, do_ivec_return
-        flush          %g1
+       retry
 
-       .align          32
-       .globl          xcall_flush_tlb_range
 xcall_flush_tlb_range:
        sethi           %hi(8192 - 1), %g2
        or              %g2, %lo(8192 - 1), %g2
@@ -162,26 +133,54 @@ xcall_flush_tlb_range:
        andn            %g7, %g2, %g7
        sub             %g7, %g6, %g3
        add             %g2, 1, %g2
-       orcc            %g6, 0x50, %g6
+       orcc            %g6, 0x10, %g6
        srlx            %g3, 13, %g4
 
        cmp             %g4, 96
        bgu,pn          %icc, xcall_flush_tlb_mm
         mov            SECONDARY_CONTEXT, %g4
        ldxa            [%g4] ASI_DMMU, %g7
-       cmp             %g7, %g5
-       be,pt           %icc, 1f
-        sub            %g3, %g2, %g3
+       sub             %g3, %g2, %g3
        stxa            %g5, [%g4] ASI_DMMU
+       nop
+       nop
 
 1:     stxa            %g0, [%g6 + %g3] ASI_DMMU_DEMAP
        stxa            %g0, [%g6 + %g3] ASI_IMMU_DEMAP
        brnz,pt         %g3, 1b
         sub            %g3, %g2, %g3
-       bne,a,pn        %icc, 1f
-        stxa           %g7, [%g4] ASI_DMMU
-1:     b,pt            %xcc, do_ivec_return
-        flush          %g1     
+       stxa            %g7, [%g4] ASI_DMMU
+       retry
+       nop
+       nop
+
+       .globl          xcall_report_regs
+xcall_report_regs:
+       rdpr            %pstate, %g2
+       wrpr            %g2, PSTATE_IG | PSTATE_AG, %pstate
+       rdpr            %pil, %g2
+       wrpr            %g0, 15, %pil
+       sethi           %hi(109f), %g7
+       b,pt            %xcc, etrap_irq
+109:    or             %g7, %lo(109b), %g7
+       call            __show_regs
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       b,pt            %xcc, rtrap
+        clr            %l6
+
+       .globl          xcall_capture
+xcall_capture:
+       rdpr            %pstate, %g2
+       wrpr            %g2, PSTATE_IG | PSTATE_AG, %pstate
+       rdpr            %pil, %g2
+       wrpr            %g0, 15, %pil
+       sethi           %hi(109f), %g7
+       b,pt            %xcc, etrap_irq
+109:    or             %g7, %lo(109b), %g7
+       call            smp_penguin_jailcell
+        nop
+       b,pt            %xcc, rtrap
+        clr            %l6
 
        /* These two are not performance critical... */
        .globl          xcall_flush_tlb_all
@@ -209,8 +208,8 @@ xcall_flush_tlb_all:
        cmp             %g2, 63
        ble,pt          %icc, 1b
         sll            %g2, 3, %g3
-       b,pt            %xcc, do_ivec_return
-        flush          %g1
+       flush           %g1
+       retry
 
        .globl          xcall_flush_cache_all
 xcall_flush_cache_all:
@@ -222,6 +221,6 @@ xcall_flush_cache_all:
        cmp             %g3, %g2
        bleu,pt         %xcc, 1b
         nop
-       b,pt            %xcc, do_ivec_return
-        flush          %g1
+       flush           %g1
+       retry
 #endif /* __SMP__ */
index 0703b5cd7d92243890647152e53e1b4fe3a870bb..9c5bce2941afa89083d50932733b2377d5591c1c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
+/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -64,7 +64,7 @@ long p1275_cmd (char *service, long fmt, ...)
        long ctx = 0;
        
        p = p1275buf.prom_buffer;
-       save_and_cli(flags);
+       __save_and_cli(flags);
        ctx = spitfire_get_primary_context ();
        if (ctx) {
                flushw_user ();
@@ -149,7 +149,7 @@ long p1275_cmd (char *service, long fmt, ...)
        
        if (ctx)
                spitfire_set_primary_context (ctx);
-       restore_flags(flags);
+       __restore_flags(flags);
        return x;
 }
 
index 32353923761000b4afcdbd0c7098b3f69c02133d..7794f612d977e24747e12dc7f4c110f0f01e57d3 100644 (file)
@@ -1,15 +1,21 @@
-/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
+/* $Id: ranges.c,v 1.7 1997/08/15 06:44:29 davem Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/sbus.h>
+#include <asm/fhc.h>
 #include <asm/system.h>
+#ifdef CONFIG_PCI
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#endif
 
 struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
 int num_obio_ranges;
@@ -62,6 +68,35 @@ void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers
        }
 }
 
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+                          struct linux_prom_registers *regs,
+                          int nregs)
+{
+       if(fhc->num_fhc_ranges)
+               prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
+                                fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void prom_apply_central_ranges(struct linux_central *central,
+                              struct linux_prom_registers *regs, int nregs)
+{
+       if(central->num_central_ranges)
+               prom_adjust_regs(regs, nregs, central->central_ranges,
+                                central->num_central_ranges);
+}
+
+#ifdef CONFIG_PCI
+void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+                           struct linux_prom_registers *regs, int nregs)
+{
+       if (ebus->num_ebus_ranges)
+               prom_adjust_regs(regs, nregs, ebus->ebus_ranges,
+                                ebus->num_ebus_ranges);
+}
+#endif
+
 __initfunc(void prom_ranges_init(void))
 {
 }
@@ -78,6 +113,74 @@ __initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus))
                sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
 }
 
+__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central))
+{
+       int success;
+       
+       central->num_central_ranges = 0;
+       success = prom_getproperty(central->prom_node, "ranges",
+                                  (char *) central->central_ranges,
+                                  sizeof (central->central_ranges));
+       if (success != -1)
+               central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc))
+{
+       int success;
+       
+       fhc->num_fhc_ranges = 0;
+       success = prom_getproperty(fhc->prom_node, "ranges",
+                                  (char *) fhc->fhc_ranges,
+                                  sizeof (fhc->fhc_ranges));
+       if (success != -1)
+               fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+#ifdef CONFIG_PCI
+__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
+{
+       struct ebus_range {
+               unsigned int    cld_space;
+               unsigned int    cld_base;
+               unsigned int    prn_space;
+               unsigned int    prn_base_hi;
+               unsigned int    prn_base_lo;
+               unsigned int    size;
+       } ranges[PROMREG_MAX];
+       int i, success;
+
+       ebus->num_ebus_ranges = 0;
+       success = prom_getproperty(ebus->prom_node, "ranges",
+                                  (char *)ranges, sizeof (ranges));
+       if (success != -1)
+               ebus->num_ebus_ranges = (success/sizeof(struct ebus_range));
+
+       for (i = 0; i < ebus->num_ebus_ranges; i++) {
+               ebus->ebus_ranges[i].ot_child_space = ranges[i].cld_space;
+               ebus->ebus_ranges[i].ot_child_base = ranges[i].cld_base;
+               ebus->ebus_ranges[i].ot_parent_space =
+                               ranges[i].prn_space & 0x0f000000;
+               if (ranges[i].prn_base_hi)
+                       prom_printf("WARNING: %s: ot_parent_base high lost\n");
+               ebus->ebus_ranges[i].ot_parent_base = ranges[i].prn_base_lo;
+               ebus->ebus_ranges[i].or_size = ranges[i].size;
+       }
+}
+
+__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
+{
+       int success;
+
+       pbm->num_pbm_ranges = 0;
+       success = prom_getproperty(pbm->prom_node, "ranges",
+                                  (char *)&pbm->pbm_ranges,
+                                  sizeof(pbm->pbm_ranges));
+       if(success != -1)
+               pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
+}
+#endif
+
 void
 prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
 {
index ae4baf858c5cb6c94d5c6ecb0bc4ac5120eb5cff..c2b3866411831d1dc700184e9697b9e0ca3dcd2f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
+/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -26,7 +26,7 @@ __prom_getchild(int node)
 __inline__ int
 prom_getchild(int node)
 {
-       long cnode;
+       int cnode;
 
        if(node == -1) return 0;
        cnode = __prom_getchild(node);
@@ -37,7 +37,7 @@ prom_getchild(int node)
 __inline__ int
 prom_getparent(int node)
 {
-       long cnode;
+       int cnode;
 
        if(node == -1) return 0;
        cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
@@ -57,12 +57,12 @@ __prom_getsibling(int node)
 __inline__ int
 prom_getsibling(int node)
 {
-       long sibnode;
+       int sibnode;
 
        if(node == -1) return 0;
        sibnode = __prom_getsibling(node);
        if(sibnode == -1) return 0;
-       return (int)sibnode;
+       return sibnode;
 }
 
 /* Return the length in bytes of property 'prop' at node 'node'.
index eac8314cac4cbec9aebe36c505d408ca583a8732..661acc098b1b6cb07aecba387d308fc72b6e6aff 100644 (file)
@@ -52,12 +52,14 @@ SECTIONS
    . += 8192;
    empty_bad_pte_table = .;
    . += 8192;
+   empty_bad_page = .;
+   . += 8192;
+   . += 0x40;
    empty_null_pmd_table = .;
    . += 8192;
+   . += 0x40;
    empty_null_pte_table = .;
    . += 8192;
-   empty_bad_page = .;
-   . += 8192;
   }
   _end = . ;
   PROVIDE (end = .);
index d9db7d5040f41b2ab9a9c97a3c6d0621e19ce7ac..823013c789f262f00326e8120e9845df4e42d75f 100644 (file)
@@ -9,7 +9,7 @@
 
 SUB_DIRS     := block char net misc #streams
 MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp macintosh
 
 ifdef CONFIG_PCI
 SUB_DIRS += pci
@@ -19,6 +19,11 @@ ifdef CONFIG_SBUS
 SUB_DIRS += sbus
 endif
 
+ifdef CONFIG_PPC
+SUB_DIRS += macintosh
+MOD_SUB_DIRS += macintosh
+endif
+
 # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
 # but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
index f8ec1abd99064667f2035fa05e654ba16fbc15a1..de13e072a1abc4eaec5b03e072358833c87b11ef 100644 (file)
@@ -22,6 +22,10 @@ MOD_LIST_NAME := BLOCK_MODULES
 LX_OBJS :=
 MX_OBJS :=
 
+ifeq ($(CONFIG_MAC_FLOPPY),y)
+L_OBJS += swim3.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_FD),y)
 L_OBJS += floppy.o
 else
index a1fc2927de98e327688a27dfb91a03d9314f31f5..490fee987381cb2e3b406be561ea0961e30b3637 100644 (file)
@@ -3969,6 +3969,10 @@ __initfunc(int floppy_init(void))
        }
 
        fdc_state[0].address = FDC1;
+       if (fdc_state[0].address == -1) {
+               unregister_blkdev(MAJOR_NR,"fd");
+               return -ENODEV;
+       }
 #if N_FDC > 1
        fdc_state[1].address = FDC2;
 #endif
index fcb3e0d2010165b96691f053fdbf35568d689879..2dab2564fa7005e409bee6f6b0eee2aa244e6442 100644 (file)
@@ -672,6 +672,132 @@ rdb_done:
 }
 #endif /* CONFIG_AMIGA_PARTITION */
 
+#ifdef CONFIG_MAC_PARTITION
+#include <linux/ctype.h>
+
+/*
+ * Code to understand MacOS partition tables.
+ */
+
+#define MAC_PARTITION_MAGIC    0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
+
+struct mac_partition {
+       __u16   signature;      /* expected to be MAC_PARTITION_MAGIC */
+       __u16   res1;
+       __u32   map_count;      /* # blocks in partition map */
+       __u32   start_block;    /* absolute starting block # of partition */
+       __u32   block_count;    /* number of blocks in partition */
+       char    name[32];       /* partition name */
+       char    type[32];       /* string type description */
+       __u32   data_start;     /* rel block # of first data block */
+       __u32   data_count;     /* number of data blocks */
+       __u32   status;         /* partition status bits */
+       __u32   boot_start;
+       __u32   boot_size;
+       __u32   boot_load;
+       __u32   boot_load2;
+       __u32   boot_entry;
+       __u32   boot_entry2;
+       __u32   boot_cksum;
+       char    processor[16];  /* identifies ISA of boot */
+       /* there is more stuff after this that we don't need */
+};
+
+#define MAC_STATUS_BOOTABLE    8       /* partition is bootable */
+
+#define MAC_DRIVER_MAGIC       0x4552
+
+/* Driver descriptor structure, in block 0 */
+struct mac_driver_desc {
+       __u16   signature;      /* expected to be MAC_DRIVER_MAGIC */
+       __u16   block_size;
+       __u32   block_count;
+    /* ... more stuff */
+};
+
+static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
+{
+       struct buffer_head *bh;
+       int blk, blocks_in_map;
+       int dev_bsize, dev_pos, pos;
+       unsigned secsize;
+       int first_bootable = 1;
+       struct mac_partition *part;
+       struct mac_driver_desc *md;
+
+       dev_bsize = get_ptable_blocksize(dev);
+       dev_pos = 0;
+       /* Get 0th block and look at the first partition map entry. */
+       if ((bh = bread(dev, 0, dev_bsize)) == 0) {
+           printk("%s: error reading partition table\n",
+                  kdevname(dev));
+           return -1;
+       }
+       md = (struct mac_driver_desc *) bh->b_data;
+       if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
+               brelse(bh);
+               return 0;
+       }
+       secsize = be16_to_cpu(md->block_size);
+       if (secsize >= dev_bsize) {
+               brelse(bh);
+               dev_pos = secsize;
+               if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
+                       printk("%s: error reading partition table\n",
+                              kdevname(dev));
+                       return -1;
+               }
+       }
+       part = (struct mac_partition *) (bh->b_data + secsize - dev_pos);
+       if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
+               brelse(bh);
+               return 0;               /* not a MacOS disk */
+       }
+       blocks_in_map = be32_to_cpu(part->map_count);
+       for (blk = 1; blk <= blocks_in_map; ++blk) {
+               pos = blk * secsize;
+               if (pos >= dev_pos + dev_bsize) {
+                       brelse(bh);
+                       dev_pos = pos;
+                       if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) {
+                               printk("%s: error reading partition table\n",
+                                      kdevname(dev));
+                               return -1;
+                       }
+               }
+               part = (struct mac_partition *) (bh->b_data + pos - dev_pos);
+               if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+                       break;
+               blocks_in_map = be32_to_cpu(part->map_count);
+               add_partition(hd, current_minor,
+                       fsec + be32_to_cpu(part->start_block) * (secsize/512),
+                       be32_to_cpu(part->block_count) * (secsize/512));
+
+#ifdef CONFIG_PMAC
+               /*
+                * If this is the first bootable partition, tell the
+                * setup code, in case it wants to make this the root.
+                */
+               if (first_bootable
+                   && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+                   && strcasecmp(part->processor, "powerpc") == 0) {
+                       note_bootable_part(dev, blk);
+                       first_bootable = 0;
+               }
+#endif /* CONFIG_PMAC */
+
+               ++current_minor;
+       }
+       brelse(bh);
+       printk("\n");
+       return 1;
+}
+
+#endif /* CONFIG_MAC_PARTITION */
+
 #ifdef CONFIG_ATARI_PARTITION
 #include <asm/atari_rootsec.h>
 
@@ -847,6 +973,10 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
 #ifdef CONFIG_ATARI_PARTITION
        if(atari_partition(hd, dev, first_sector))
                return;
+#endif
+#ifdef CONFIG_MAC_PARTITION
+       if (mac_partition(hd, dev, first_sector))
+               return;
 #endif
        printk(" unknown partition table\n");
 }
index 988450ce9a9177fc23ec5cea7c0d55f5483fff35..c95d0038eca6144beead026b36c2bdd141160421 100644 (file)
@@ -681,10 +681,13 @@ __initfunc(int blk_dev_init(void))
 #ifdef CONFIG_BLK_DEV_EZ
        ez_init();
 #endif
+#ifdef CONFIG_MAC_FLOPPY
+       swim3_init();
+#endif
 #ifdef CONFIG_BLK_DEV_FD
        floppy_init();
 #else
-#if !defined (__mc68000__)
+#if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)
        outb_p(0xc, 0x3f2);
 #endif
 #endif
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
new file mode 100644 (file)
index 0000000..4dc4426
--- /dev/null
@@ -0,0 +1,1011 @@
+/*
+ * Driver for the SWIM3 (Super Woz Integrated Machine 3)
+ * floppy controller found on Power Macintoshes.
+ *
+ * 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 <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/fd.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR       FLOPPY_MAJOR
+#include <linux/blk.h>
+
+static int floppy_blocksizes[2] = {512};
+static int floppy_sizes[2] = {2880};
+
+enum swim_state {
+       idle,
+       locating,
+       seeking,
+       settling,
+       do_transfer,
+       jogging,
+       available,
+       revalidating,
+       ejecting
+};
+
+#define REG(x) unsigned char x; char x ## _pad[15];
+
+/*
+ * The names for these registers mostly represent speculation on my part.
+ * It will be interesting to see how close they are to the names Apple uses.
+ */
+struct swim3 {
+       REG(data);
+       REG(usecs);             /* counts down at 1MHz */
+       REG(error);
+       REG(mode);
+       REG(select);            /* controls CA0, CA1, CA2 and LSTRB signals */
+       REG(reg5);
+       REG(control);           /* writing bits clears them */
+       REG(status);            /* writing bits sets them in control */
+       REG(intr);
+       REG(nseek);             /* # tracks to seek */
+       REG(ctrack);            /* current track number */
+       REG(csect);             /* current sector number */
+       REG(ssize);             /* sector size code?? */
+       REG(sector);            /* sector # to read or write */
+       REG(nsect);             /* # sectors to read or write */
+       REG(intr_enable);
+};
+
+#define control_bic    control
+#define control_bis    status
+
+/* Bits in select register */
+#define CA_MASK                7
+#define LSTRB          8
+
+/* Bits in control register */
+#define DO_SEEK                0x80
+#define SELECT         0x20
+#define WRITE_SECTORS  0x10
+#define SCAN_TRACK     0x08
+#define DRIVE_ENABLE   0x02
+#define INTR_ENABLE    0x01
+
+/* Bits in status register */
+#define DATA           0x08
+
+/* Bits in intr and intr_enable registers */
+#define ERROR          0x20
+#define DATA_CHANGED   0x10
+#define TRANSFER_DONE  0x08
+#define SEEN_SECTOR    0x04
+#define SEEK_DONE      0x02
+
+/* Select values for swim3_action */
+#define SEEK_POSITIVE  0
+#define SEEK_NEGATIVE  4
+#define STEP           1
+#define MOTOR_ON       2
+#define MOTOR_OFF      6
+#define EJECT          7
+
+/* Select values for swim3_select and swim3_readbit */
+#define STEP_DIR       0
+#define STEPPING       1
+#define MOTOR_ON       2
+#define RELAX          3
+#define READ_DATA_0    4
+#define SINGLE_SIDED   6
+#define DRIVE_PRESENT  7
+#define DISK_IN                8
+#define WRITE_PROT     9
+#define TRACK_ZERO     10
+#define TACHO          11
+#define READ_DATA_1    12
+#define SEEK_COMPLETE  14
+
+struct floppy_state {
+       enum swim_state state;
+       volatile struct swim3 *swim3;   /* hardware registers */
+       struct dbdma_regs *dma; /* DMA controller registers */
+       int     swim3_intr;     /* interrupt number for SWIM3 */
+       int     dma_intr;       /* interrupt number for DMA channel */
+       int     cur_cyl;        /* cylinder head is on, or -1 */
+       int     cur_sector;     /* last sector we saw go past */
+       int     req_cyl;        /* the cylinder for the current r/w request */
+       int     head;           /* head number ditto */
+       int     req_sector;     /* sector number ditto */
+       int     scount;         /* # sectors we're transferring at present */
+       int     retries;
+       int     secpercyl;      /* disk geometry information */
+       int     secpertrack;
+       int     total_secs;
+       int     write_prot;     /* 1 if write-protected, 0 if not, -1 dunno */
+       struct dbdma_cmd *dma_cmd;
+       int     ref_count;
+       int     expect_cyl;
+       struct timer_list timeout;
+       int     ejected;
+       struct wait_queue *wait;
+       int     wanted;
+       char    dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
+};
+
+static struct floppy_state floppy_states[1];
+
+static unsigned short write_preamble[] = {
+       0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, /* gap field */
+       0, 0, 0, 0, 0, 0,                       /* sync field */
+       0x99a1, 0x99a1, 0x99a1, 0x99fb,         /* data address mark */
+       0x990f                                  /* init CRC generator */
+};
+
+static unsigned short write_postamble[] = {
+       0x9904,                                 /* insert CRC */
+       0x4e4e, 0x4e4e,
+       0x9908,                                 /* stop writing */
+       0, 0, 0, 0, 0, 0
+};
+
+static void swim3_select(struct floppy_state *fs, int sel);
+static void swim3_action(struct floppy_state *fs, int action);
+static int swim3_readbit(struct floppy_state *fs, int bit);
+static void do_fd_request(void);
+static void start_request(struct floppy_state *fs);
+static void scan_track(struct floppy_state *fs);
+static void seek_track(struct floppy_state *fs, int n);
+static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count);
+static void setup_transfer(struct floppy_state *fs);
+static void act(struct floppy_state *fs);
+static void scan_timeout(unsigned long data);
+static void seek_timeout(unsigned long data);
+static void xfer_timeout(unsigned long data);
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+                     int interruptible);
+static void release_drive(struct floppy_state *fs);
+static int fd_eject(struct floppy_state *fs);
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long param);
+static int floppy_open(struct inode *inode, struct file *filp);
+static int floppy_release(struct inode *inode, struct file *filp);
+static long floppy_read(struct inode *inode, struct file *filp,
+                       char *buf, unsigned long count);
+static long floppy_write(struct inode *inode, struct file *filp,
+                        const char *buf, unsigned long count);
+static int floppy_check_change(kdev_t dev);
+static int floppy_revalidate(kdev_t dev);
+int swim3_init(void);
+
+#define IOCTL_MODE_BIT 8
+#define OPEN_WRITE_BIT 16
+
+static void swim3_select(struct floppy_state *fs, int sel)
+{
+       volatile struct swim3 *sw = fs->swim3;
+
+       out_8(&sw->select, RELAX);
+       if (sel & 8)
+               out_8(&sw->control_bis, SELECT);
+       else
+               out_8(&sw->control_bic, SELECT);
+       out_8(&sw->select, sel & CA_MASK);
+}
+
+static void swim3_action(struct floppy_state *fs, int action)
+{
+       volatile struct swim3 *sw = fs->swim3;
+
+       swim3_select(fs, action);
+       udelay(1);
+       sw->select |= LSTRB; eieio();
+       udelay(2);
+       sw->select &= ~LSTRB; eieio();
+       udelay(1);
+       out_8(&sw->select, RELAX);
+}
+
+static int swim3_readbit(struct floppy_state *fs, int bit)
+{
+       volatile struct swim3 *sw = fs->swim3;
+       int stat;
+
+       swim3_select(fs, bit);
+       udelay(1);
+       stat = in_8(&sw->status);
+       out_8(&sw->select, RELAX);
+       return (stat & DATA) == 0;
+}
+
+static void do_fd_request(void)
+{
+       start_request(&floppy_states[0]);
+       sti();
+}
+
+static void start_request(struct floppy_state *fs)
+{
+       int drive;
+       unsigned long x;
+
+       if (fs->state == idle && fs->wanted) {
+               fs->state = available;
+               wake_up(&fs->wait);
+               return;
+       }
+       while (CURRENT && fs->state == idle) {
+               if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+                       panic(DEVICE_NAME ": request list destroyed");
+               if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+                       panic(DEVICE_NAME ": block not locked");
+#if 0
+               printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+                      kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd,
+                      CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
+               printk("           rq_status=%d errors=%d current_nr_sectors=%ld\n",
+                      CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
+#endif
+
+               drive = MINOR(CURRENT->rq_dev);
+               if (drive != 0) {
+                       end_request(0);
+                       continue;
+               }
+               if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
+                       end_request(0);
+                       continue;
+               }
+               if (CURRENT->current_nr_sectors == 0) {
+                       end_request(1);
+                       continue;
+               }
+               if (fs->ejected) {
+                       end_request(0);
+                       continue;
+               }
+
+               if (CURRENT->cmd == WRITE) {
+                       if (fs->write_prot < 0)
+                               fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+                       if (fs->write_prot) {
+                               end_request(0);
+                               continue;
+                       }
+               }
+
+               fs->req_cyl = CURRENT->sector / fs->secpercyl;
+               x = CURRENT->sector % fs->secpercyl;
+               fs->head = x / fs->secpertrack;
+               fs->req_sector = x % fs->secpertrack + 1;
+               fs->state = do_transfer;
+               fs->retries = 0;
+
+               act(fs);
+       }
+}
+
+static inline void scan_track(struct floppy_state *fs)
+{
+       volatile struct swim3 *sw = fs->swim3;
+       int xx;
+
+       swim3_select(fs, READ_DATA_0);
+       xx = sw->intr;          /* clear SEEN_SECTOR bit */
+       out_8(&sw->control_bis, SCAN_TRACK);
+       /* enable intr when track found */
+       out_8(&sw->intr_enable, ERROR | SEEN_SECTOR);
+       /* enable timeout */
+       fs->timeout.expires = jiffies + HZ;
+       fs->timeout.function = scan_timeout;
+       fs->timeout.data = (unsigned long) fs;
+       add_timer(&fs->timeout);
+}
+
+static inline void seek_track(struct floppy_state *fs, int n)
+{
+       volatile struct swim3 *sw = fs->swim3;
+
+       if (n >= 0) {
+               swim3_action(fs, SEEK_POSITIVE);
+               sw->nseek = n;
+       } else {
+               swim3_action(fs, SEEK_NEGATIVE);
+               sw->nseek = -n;
+       }
+       fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1;
+       swim3_select(fs, STEP);
+       out_8(&sw->control_bis, DO_SEEK);
+       /* enable intr when seek finished */
+       out_8(&sw->intr_enable, ERROR | SEEK_DONE);
+       /* enable timeout */
+       fs->timeout.expires = jiffies + HZ/2;
+       fs->timeout.function = seek_timeout;
+       fs->timeout.data = (unsigned long) fs;
+       add_timer(&fs->timeout);
+}
+
+static inline void init_dma(struct dbdma_cmd *cp, int cmd,
+                           void *buf, int count)
+{
+       st_le16(&cp->req_count, count);
+       st_le16(&cp->command, cmd);
+       st_le32(&cp->phy_addr, virt_to_bus(buf));
+       cp->xfer_status = 0;
+}
+
+static inline void setup_transfer(struct floppy_state *fs)
+{
+       int n;
+       volatile struct swim3 *sw = fs->swim3;
+       struct dbdma_cmd *cp = fs->dma_cmd;
+       struct dbdma_regs *dr = fs->dma;
+
+       if (CURRENT->current_nr_sectors <= 0) {
+               printk(KERN_ERR "swim3: transfer 0 sectors?\n");
+               return;
+       }
+       if (CURRENT->cmd == WRITE)
+               n = 1;
+       else {
+               n = fs->secpertrack - fs->req_sector + 1;
+               if (n > CURRENT->current_nr_sectors)
+                       n = CURRENT->current_nr_sectors;
+       }
+       fs->scount = n;
+       swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
+       out_8(&sw->sector, fs->req_sector);
+       out_8(&sw->nsect, n);
+       out_8(&sw->ssize, 0);
+       st_le32(&dr->cmdptr, virt_to_bus(cp));
+       if (CURRENT->cmd == WRITE) {
+               /* Set up 3 dma commands: write preamble, data, postamble */
+               init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
+               ++cp;
+               init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512);
+               ++cp;
+               init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble));
+       } else {
+               init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512);
+       }
+       ++cp;
+       out_le16(&cp->command, DBDMA_STOP);
+       out_le32(&dr->control, (RUN << 16) | RUN);
+       out_8(&sw->control_bis,
+             (CURRENT->cmd == WRITE? WRITE_SECTORS: 0) | SCAN_TRACK);
+       /* enable intr when transfer complete */
+       out_8(&sw->intr_enable, ERROR | TRANSFER_DONE);
+       /* enable timeout */
+       fs->timeout.expires = jiffies + 2*HZ;
+       fs->timeout.function = xfer_timeout;
+       fs->timeout.data = (unsigned long) fs;
+       add_timer(&fs->timeout);
+}
+
+static void act(struct floppy_state *fs)
+{
+       volatile struct swim3 *sw = fs->swim3;
+
+       for (;;) {
+               switch (fs->state) {
+               case idle:
+                       return;         /* XXX shouldn't get here */
+
+               case locating:
+                       if (swim3_readbit(fs, TRACK_ZERO)) {
+                               fs->cur_cyl = 0;
+                               if (fs->req_cyl == 0)
+                                       fs->state = do_transfer;
+                               else
+                                       fs->state = seeking;
+                               break;
+                       }
+                       scan_track(fs);
+                       return;
+
+               case seeking:
+                       if (fs->cur_cyl < 0) {
+                               fs->expect_cyl = -1;
+                               fs->state = locating;
+                               break;
+                       }
+                       if (fs->req_cyl == fs->cur_cyl) {
+                               printk("whoops, seeking 0\n");
+                               fs->state = do_transfer;
+                               break;
+                       }
+                       seek_track(fs, fs->req_cyl - fs->cur_cyl);
+                       return;
+
+               case settling:
+                       /* wait for SEEK_COMPLETE to become true */
+                       swim3_select(fs, SEEK_COMPLETE);
+                       udelay(1);
+                       out_8(&sw->intr_enable, ERROR | DATA_CHANGED);
+                       in_8(&sw->intr);        /* clear DATA_CHANGED */
+                       if (in_8(&sw->status) & DATA) {
+                               /* seek_complete is not yet true */
+                               fs->timeout.expires = jiffies + HZ/2;
+                               fs->timeout.function = seek_timeout;
+                               fs->timeout.data = (unsigned long) fs;
+                               add_timer(&fs->timeout);
+                               return;
+                       }
+                       out_8(&sw->intr_enable, 0);
+                       in_8(&sw->intr);
+                       fs->state = locating;
+                       break;
+
+               case do_transfer:
+                       if (fs->cur_cyl != fs->req_cyl) {
+                               if (fs->retries > 5) {
+                                       end_request(0);
+                                       fs->state = idle;
+                                       return;
+                               }
+                               fs->state = seeking;
+                               break;
+                       }
+                       setup_transfer(fs);
+                       return;
+
+               case jogging:
+                       seek_track(fs, -5);
+                       return;
+
+               default:
+                       printk(KERN_ERR"swim3: unknown state %d\n", fs->state);
+                       return;
+               }
+       }
+}
+
+static void scan_timeout(unsigned long data)
+{
+       struct floppy_state *fs = (struct floppy_state *) data;
+       volatile struct swim3 *sw = fs->swim3;
+
+       out_8(&sw->control_bic, SCAN_TRACK);
+       out_8(&sw->select, RELAX);
+       out_8(&sw->intr_enable, 0);
+       fs->cur_cyl = -1;
+       if (fs->retries > 5) {
+               end_request(0);
+               fs->state = idle;
+               start_request(fs);
+       } else {
+               fs->state = jogging;
+               act(fs);
+       }
+}
+
+static void seek_timeout(unsigned long data)
+{
+       struct floppy_state *fs = (struct floppy_state *) data;
+       volatile struct swim3 *sw = fs->swim3;
+
+       if (fs->state == settling) {
+               printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n",
+                      sw->select, sw->control, sw->status, sw->intr, sw->intr_enable);
+       }
+       out_8(&sw->control_bic, DO_SEEK);
+       out_8(&sw->select, RELAX);
+       out_8(&sw->intr_enable, 0);
+       if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) {
+               /* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */
+               fs->state = locating;
+               act(fs);
+               return;
+       }
+       printk(KERN_ERR "swim3: seek timeout\n");
+       end_request(0);
+       fs->state = idle;
+       start_request(fs);
+}
+
+static void xfer_timeout(unsigned long data)
+{
+       struct floppy_state *fs = (struct floppy_state *) data;
+       volatile struct swim3 *sw = fs->swim3;
+       struct dbdma_regs *dr = fs->dma;
+       struct dbdma_cmd *cp = fs->dma_cmd;
+       unsigned long s;
+
+       st_le32(&dr->control, RUN << 16);
+       out_8(&sw->intr_enable, 0);
+       out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+       out_8(&sw->select, RELAX);
+       if (CURRENT->cmd == WRITE)
+               ++cp;
+       if (ld_le16(&cp->xfer_status) != 0)
+               s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
+       else
+               s = 0;
+       CURRENT->sector += s;
+       CURRENT->current_nr_sectors -= s;
+       printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
+              (CURRENT->cmd==WRITE? "writ": "read"), CURRENT->sector);
+       end_request(0);
+       fs->state = idle;
+       start_request(fs);
+}
+
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct floppy_state *fs = (struct floppy_state *) dev_id;
+       volatile struct swim3 *sw = fs->swim3;
+       int intr, err, n;
+       int stat, resid;
+       struct dbdma_regs *dr;
+       struct dbdma_cmd *cp;
+
+       err = in_8(&sw->error);
+       intr = in_8(&sw->intr);
+       if ((intr & ERROR) && fs->state != do_transfer)
+               printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n",
+                      fs->state, CURRENT->cmd, intr, err);
+       switch (fs->state) {
+       case locating:
+               if (intr & SEEN_SECTOR) {
+                       out_8(&sw->control_bic, SCAN_TRACK);
+                       out_8(&sw->select, RELAX);
+                       out_8(&sw->intr_enable, 0);
+                       del_timer(&fs->timeout);
+                       if (sw->ctrack == 0xff) {
+                               printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
+                               fs->cur_cyl = -1;
+                               if (fs->retries > 5) {
+                                       end_request(0);
+                                       fs->state = idle;
+                                       start_request(fs);
+                               } else {
+                                       fs->state = jogging;
+                                       act(fs);
+                               }
+                               break;
+                       }
+                       fs->cur_cyl = sw->ctrack;
+                       fs->cur_sector = sw->csect;
+                       if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl)
+                               printk(KERN_ERR "swim3: expected cyl %d, got %d\n",
+                                      fs->expect_cyl, fs->cur_cyl);
+                       fs->state = do_transfer;
+                       act(fs);
+               }
+               break;
+       case seeking:
+       case jogging:
+               if (sw->nseek == 0) {
+                       out_8(&sw->control_bic, DO_SEEK);
+                       out_8(&sw->select, RELAX);
+                       out_8(&sw->intr_enable, 0);
+                       del_timer(&fs->timeout);
+                       if (fs->state == seeking)
+                               ++fs->retries;
+                       fs->state = settling;
+                       act(fs);
+               }
+               break;
+       case settling:
+               out_8(&sw->intr_enable, 0);
+               del_timer(&fs->timeout);
+               act(fs);
+               break;
+       case do_transfer:
+               if ((intr & (ERROR | TRANSFER_DONE)) == 0)
+                       break;
+               dr = fs->dma;
+               cp = fs->dma_cmd;
+               st_le32(&dr->control, RUN << 16);
+               out_8(&sw->intr_enable, 0);
+               out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+               out_8(&sw->select, RELAX);
+               del_timer(&fs->timeout);
+               if (CURRENT->cmd == WRITE)
+                       ++cp;
+               stat = ld_le16(&cp->xfer_status);
+               resid = ld_le16(&cp->res_count);
+               if (intr & ERROR) {
+                       n = fs->scount - 1 - resid / 512;
+                       if (n > 0) {
+                               CURRENT->sector += n;
+                               CURRENT->current_nr_sectors -= n;
+                               CURRENT->buffer += n * 512;
+                               fs->req_sector += n;
+                       }
+                       if (fs->retries < 5) {
+                               ++fs->retries;
+                               act(fs);
+                       } else {
+                               printk("swim3: error %sing block %ld (err=%x)\n",
+                                      CURRENT->cmd == WRITE? "writ": "read",
+                                      CURRENT->sector, err);
+                               end_request(0);
+                               fs->state = idle;
+                       }
+               } else {
+                       if ((stat & ACTIVE) == 0 || resid != 0) {
+                               /* musta been an error */
+                               printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
+                               printk(KERN_ERR "  state=%d, cmd=%x, intr=%x, err=%x\n",
+                                      fs->state, CURRENT->cmd, intr, err);
+                               end_request(0);
+                               fs->state = idle;
+                               start_request(fs);
+                               break;
+                       }
+                       CURRENT->sector += fs->scount;
+                       CURRENT->current_nr_sectors -= fs->scount;
+                       CURRENT->buffer += fs->scount * 512;
+                       if (CURRENT->current_nr_sectors <= 0) {
+                               end_request(1);
+                               fs->state = idle;
+                       } else {
+                               fs->req_sector += fs->scount;
+                               if (fs->req_sector > fs->secpertrack) {
+                                       fs->req_sector -= fs->secpertrack;
+                                       if (++fs->head > 1) {
+                                               fs->head = 0;
+                                               ++fs->req_cyl;
+                                       }
+                               }
+                               act(fs);
+                       }
+               }
+               if (fs->state == idle)
+                       start_request(fs);
+               break;
+       default:
+               printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
+       }
+}
+
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+                     int interruptible)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (fs->state != idle) {
+               ++fs->wanted;
+               while (fs->state != available) {
+                       if (interruptible
+                           && (current->signal & ~current->blocked)) {
+                               --fs->wanted;
+                               restore_flags(flags);
+                               return -EINTR;
+                       }
+                       interruptible_sleep_on(&fs->wait);
+               }
+               --fs->wanted;
+       }
+       fs->state = state;
+       restore_flags(flags);
+       return 0;
+}
+
+static void release_drive(struct floppy_state *fs)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       fs->state = idle;
+       start_request(fs);
+       restore_flags(flags);
+}
+
+static int fd_eject(struct floppy_state *fs)
+{
+       int err, n;
+
+       err = grab_drive(fs, ejecting, 1);
+       if (err)
+               return err;
+       swim3_action(fs, EJECT);
+       for (n = 2*HZ; n > 0; --n) {
+               if (swim3_readbit(fs, RELAX))
+                       break;
+               if ((current->signal & ~current->blocked) != 0) {
+                       err = -EINTR;
+                       break;
+               }
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + 1;
+               schedule();
+       }
+       fs->ejected = 1;
+       release_drive(fs);
+       return err;
+}
+
+static struct floppy_struct floppy_type =
+       { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };    /*  7 1.44MB 3.5"   */
+
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long param)
+{
+       struct floppy_state *fs;
+       int err;
+
+       if (((cmd & 0x80) && !suser())
+           || ((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))))
+               return -EPERM;
+
+       fs = &floppy_states[0];
+       switch (cmd) {
+       case FDEJECT:
+               if (fs->ref_count != 1)
+                       return -EBUSY;
+               err = fd_eject(fs);
+               return err;
+       case FDGETPRM:
+               err = copy_to_user((void *) param, (void *) &floppy_type,
+                                  sizeof(struct floppy_struct));
+               return err;
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int floppy_open(struct inode *inode, struct file *filp)
+{
+       struct floppy_state *fs;
+       volatile struct swim3 *sw;
+       int n, err;
+
+       if (MINOR(inode->i_rdev) != 0)
+               return -ENODEV;
+       fs = &floppy_states[0];
+       sw = fs->swim3;
+       err = 0;
+       if (fs->ref_count == 0) {
+               out_8(&sw->intr_enable, 0);
+               out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+               swim3_action(fs, MOTOR_ON);
+               fs->write_prot = -1;
+               fs->cur_cyl = -1;
+               for (n = HZ; n > 0; --n) {
+                       if (swim3_readbit(fs, SEEK_COMPLETE))
+                               break;
+                       if ((current->signal & ~current->blocked) != 0) {
+                               err = -EINTR;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + 1;
+                       schedule();
+               }
+               if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
+                                || swim3_readbit(fs, DISK_IN) == 0))
+                       err = -ENXIO;
+               swim3_action(fs, 9);
+
+       } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+               return -EBUSY;
+
+       if (err == 0 && filp && (filp->f_flags & O_NDELAY) == 0
+           && (filp->f_mode & 3)) {
+               check_disk_change(inode->i_rdev);
+               if (fs->ejected)
+                       err = -ENXIO;
+       }
+
+       if (err == 0 && filp && (filp->f_flags & (O_WRONLY | O_RDWR))) {
+               if (fs->write_prot < 0)
+                       fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+               if (fs->write_prot)
+                       err = -EROFS;
+       }
+
+       if (err) {
+               if (fs->ref_count == 0) {
+                       swim3_action(fs, MOTOR_OFF);
+                       out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
+               }
+               return err;
+       }
+
+       if (filp->f_flags & O_EXCL)
+               fs->ref_count = -1;
+       else
+               ++fs->ref_count;
+
+       /* Allow ioctls if we have write-permissions even if read-only open */
+       if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
+               filp->f_mode |= IOCTL_MODE_BIT;
+       if (filp->f_mode & 2)
+               filp->f_mode |= OPEN_WRITE_BIT;
+
+       return 0;
+}
+
+static int floppy_release(struct inode *inode, struct file *filp)
+{
+       struct floppy_state *fs;
+       volatile struct swim3 *sw;
+
+       if (MINOR(inode->i_rdev) != 0)
+               return -ENXIO;
+       fs = &floppy_states[0];
+       if (filp == 0 || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+               block_fsync(inode, filp);
+       sw = fs->swim3;
+       if (fs->ref_count > 0 && --fs->ref_count == 0) {
+               swim3_action(fs, MOTOR_OFF);
+               out_8(&sw->control_bic, 0xff);
+       }
+       return 0;
+}
+
+static int floppy_check_change(kdev_t dev)
+{
+       struct floppy_state *fs;
+
+       if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+               return 0;
+       fs = &floppy_states[0];
+       return fs->ejected;
+}
+
+static int floppy_revalidate(kdev_t dev)
+{
+       struct floppy_state *fs;
+       volatile struct swim3 *sw;
+       int ret, n;
+
+       if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+               return 0;
+       fs = &floppy_states[0];
+       sw = fs->swim3;
+       grab_drive(fs, revalidating, 0);
+       out_8(&sw->intr_enable, 0);
+       out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+       swim3_action(fs, MOTOR_ON);
+       fs->write_prot = -1;
+       fs->cur_cyl = -1;
+       for (n = HZ; n > 0; --n) {
+               if (swim3_readbit(fs, SEEK_COMPLETE))
+                       break;
+               if ((current->signal & ~current->blocked) != 0)
+                       break;
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + 1;
+               schedule();
+       }
+       ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
+               || swim3_readbit(fs, DISK_IN) == 0;
+       if (ret)
+               swim3_action(fs, MOTOR_OFF);
+       else {
+               fs->ejected = 0;
+               swim3_action(fs, 9);
+       }
+
+       release_drive(fs);
+       return ret;
+}
+
+static long floppy_read(struct inode *inode, struct file *filp,
+                       char *buf, unsigned long count)
+{
+       struct floppy_state *fs;
+
+       if (MINOR(inode->i_rdev) != 0)
+               return -ENODEV;
+       fs = &floppy_states[0];
+       if (fs->ejected)
+               return -ENXIO;
+       return block_read(inode, filp, buf, count);
+}
+
+static long floppy_write(struct inode *inode, struct file *filp,
+                        const char *buf, unsigned long count)
+{
+       struct floppy_state *fs;
+
+       if (MINOR(inode->i_rdev) != 0)
+               return -ENODEV;
+       fs = &floppy_states[0];
+       if (fs->ejected)
+               return -ENXIO;
+       return block_write(inode, filp, buf, count);
+}
+
+static void floppy_off(unsigned int nr)
+{
+}
+
+static struct file_operations floppy_fops = {
+       NULL,                   /* lseek */
+       floppy_read,            /* read */
+       floppy_write,           /* write */
+       NULL,                   /* readdir */
+       NULL,                   /* poll */
+       floppy_ioctl,           /* ioctl */
+       NULL,                   /* mmap */
+       floppy_open,            /* open */
+       floppy_release,         /* release */
+       block_fsync,            /* fsync */
+       NULL,                   /* fasync */
+       floppy_check_change,    /* check_media_change */
+       floppy_revalidate,      /* revalidate */
+};
+
+int swim3_init(void)
+{
+       struct device_node *swims;
+       struct floppy_state *fs = &floppy_states[0];
+       volatile struct swim3 *sw;
+
+       swims = find_devices("swim3");
+       if (swims == NULL)
+               return 0;
+
+       if (swims->next != NULL)
+               printk(KERN_ERR "Warning: only using first SWIM3 floppy controller\n");
+       if (swims->n_addrs != 2 || swims->n_intrs != 2) {
+               printk(KERN_ERR "swim3: expecting 2 addrs and 2 intrs! (%d, %d)\n",
+                      swims->n_addrs, swims->n_intrs);
+               return -EINVAL;
+       }
+
+       if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+               printk(KERN_ERR "Unable to get major %d for floppy\n",
+                      MAJOR_NR);
+               return -EBUSY;
+       }
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blksize_size[MAJOR_NR] = floppy_blocksizes;
+       blk_size[MAJOR_NR] = floppy_sizes;
+
+       memset(fs, 0, sizeof(*fs));
+       fs->state = idle;
+       fs->swim3 = (volatile struct swim3 *) swims->addrs[0].address;
+       fs->dma = (struct dbdma_regs *) swims->addrs[1].address;
+       fs->swim3_intr = swims->intrs[0];
+       fs->dma_intr = swims->intrs[1];
+       fs->cur_cyl = -1;
+       fs->cur_sector = -1;
+       fs->secpercyl = 36;
+       fs->secpertrack = 18;
+       fs->total_secs = 2880;
+
+       fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
+       memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
+       st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
+
+       if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
+               printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+               return -EBUSY;
+       }
+       if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
+               printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
+                      fs->dma_intr);
+               return -EBUSY;
+       }
+
+       sw = fs->swim3;
+       out_8(&sw->mode, 0x95);
+       out_8(&sw->control_bic, 0xff);
+       out_8(&sw->reg5, 0x28);
+
+       do_floppy = NULL;
+
+       printk(KERN_INFO "fd0: SWIM3 floppy controller\n");
+
+       return 0;
+}
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
new file mode 100644 (file)
index 0000000..ed92d17
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# Makefile for the Macintosh-specific device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := macintosh.a
+M_OBJS   :=
+L_OBJS   := via-cuda.o adb.o nvram.o
+
+ifeq ($(CONFIG_SERIAL),y)
+  LX_OBJS += macserial.o
+else
+  ifeq ($(CONFIG_SERIAL),m)
+    MX_OBJS += macserial.o
+  endif
+endif
+
+ifdef CONFIG_MAC_KEYBOARD
+L_OBJS += mac_keyb.o mackeymap.o
+endif
+
+ifdef CONFIG_VT
+  ifdef CONFIG_PMAC_CONSOLE
+    L_OBJS += pmac-cons.o control.o platinum.o valkyrie.o
+    ifdef CONFIG_ATY_VIDEO
+      L_OBJS += aty.o
+    endif
+    ifdef CONFIG_IMSTT_VIDEO
+      L_OBJS += imstt.o
+    endif
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+mackeymap.c: mackeymap.map
+       loadkeys --mktable mackeymap.map > mackeymap.c
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
new file mode 100644 (file)
index 0000000..30a7100
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Device driver for the /dev/adb device on macintoshes.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/uaccess.h>
+
+#define ADB_MAJOR      56      /* major number for /dev/adb */
+
+extern void adbdev_init(void);
+
+struct adbdev_state {
+       struct cuda_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+       int ret = 0;
+       struct wait_queue wait = { current, NULL };
+
+       add_wait_queue(&adb_wait, &wait);
+       current->state = TASK_INTERRUPTIBLE;
+
+       while (!state->req.got_reply) {
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       break;
+               }
+               if (current->signal & ~current->blocked) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
+       }
+
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&adb_wait, &wait);
+
+       return ret;
+}
+
+static void adb_write_done(struct cuda_request *req)
+{
+       if (!req->got_reply) {
+               req->reply_len = 0;
+               req->got_reply = 1;
+       }
+       wake_up_interruptible(&adb_wait);
+}
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+       struct adbdev_state *state;
+
+       if (MINOR(inode->i_rdev) > 0)
+               return -ENXIO;
+       state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+       if (state == 0)
+               return -ENOMEM;
+       file->private_data = state;
+       state->req.reply_expected = 0;
+       return 0;
+}
+
+static int adb_release(struct inode *inode, struct file *file)
+{
+       struct adbdev_state *state = file->private_data;
+
+       if (state) {
+               file->private_data = NULL;
+               if (state->req.reply_expected && !state->req.got_reply)
+                       if (adb_wait_reply(state, file))
+                               return 0;
+               kfree(state);
+       }
+       return 0;
+}
+
+static long long adb_lseek(struct inode *inode, struct file *file,
+                          long long offset, int origin)
+{
+       return -ESPIPE;
+}
+
+static long adb_read(struct inode *inode, struct file *file,
+                    char *buf, unsigned long count)
+{
+       int ret;
+       struct adbdev_state *state = file->private_data;
+
+       if (count < 2)
+               return -EINVAL;
+       if (count > sizeof(state->req.reply))
+               count = sizeof(state->req.reply);
+       ret = verify_area(VERIFY_WRITE, buf, count);
+       if (ret)
+               return ret;
+
+       if (!state->req.reply_expected)
+               return 0;
+
+       ret = adb_wait_reply(state, file);
+       if (ret)
+               return ret;
+
+       ret = state->req.reply_len;
+       copy_to_user(buf, state->req.reply, ret);
+       state->req.reply_expected = 0;
+
+       return ret;
+}
+
+static long adb_write(struct inode *inode, struct file *file,
+                     const char *buf, unsigned long count)
+{
+       int ret;
+       struct adbdev_state *state = file->private_data;
+
+       if (count < 2 || count > sizeof(state->req.data))
+               return -EINVAL;
+       ret = verify_area(VERIFY_READ, buf, count);
+       if (ret)
+               return ret;
+
+       if (state->req.reply_expected && !state->req.got_reply) {
+               /* A previous request is still being processed.
+                  Wait for it to finish. */
+               ret = adb_wait_reply(state, file);
+               if (ret)
+                       return ret;
+       }
+
+       state->req.nbytes = count;
+       state->req.done = adb_write_done;
+       copy_from_user(state->req.data, buf, count);
+       state->req.reply_expected = 1;
+       state->req.got_reply = 0;
+       cuda_send_request(&state->req);
+
+       return count;
+}
+
+static struct file_operations adb_fops = {
+       adb_lseek,
+       adb_read,
+       adb_write,
+       NULL,           /* no readdir */
+       NULL,           /* no poll yet */
+       NULL,           /* no ioctl yet */
+       NULL,           /* no mmap */
+       adb_open,
+       adb_release
+};
+
+void adbdev_init()
+{
+       if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+               printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+}
diff --git a/drivers/macintosh/ati-gt.h b/drivers/macintosh/ati-gt.h
new file mode 100644 (file)
index 0000000..7929121
--- /dev/null
@@ -0,0 +1,149 @@
+#if 0          /* not filled inaty_gt_reg_init yet */
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+       { 0x10, 0x28, 0x3c },
+       { },
+       { }     /* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct aty_regvals aty_gt_reg_init_19 = {
+       { 0x10, 0x28, 0x3c },
+       { },
+       { }     /* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_gt_reg_init_18 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+   { 0, 0, 0 },
+
+    { 0x310086, 0x310084, 0x310084 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+    { 0x88, 0x7 }
+};     
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+    { 0, 0, 0 },
+
+    { 0xc0085, 0xc0083, 0xc0083 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a3, 0x2ff031f, 0x30300, 0x20100000,
+    { 0x41, 0x3 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+    { 0, 0, 0 },
+
+    { 0x310086, 0x310084, 0x310084 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+    { 0x88, 0x7 }
+};    
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_gt_reg_init_14 = {
+       { 0, 0, 0 },
+
+       { 0x310086, 0x310084, 0x310084 },
+       { 0x3060200, 0x30d0300, 0x30d0300 },
+       { 0x2002312, 0x3002312, 0x3002312 },
+
+       0x7f00a7, 0x2ff0325, 0x260302, 0x20100000,
+       { 0x6c, 0x6 }
+};  
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_gt_reg_init_13 = {
+       { 0x200, 0x200, 0x200 },
+
+       { 0x28006f, 0x28006d, 0x28006c },
+       { 0x3050200, 0x30b0300, 0x30e0600 },
+       { 0x2002312, 0x3002312, 0x6002312 },
+
+       0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+        { 0x4f, 0x05 }
+};
+
+#if 0          /* not filled in yet */
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_gt_reg_init_12 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_gt_reg_init_11 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_gt_reg_init_10 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_gt_reg_init_7 = {
+       { 0x10, 0x30, 0x68 },
+       { },
+       { }     /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+#endif
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_gt_reg_init_6 = {
+       { 0x200, 0x200, 0x200 },
+
+       { 0x28005b, 0x280059, 0x280058 },
+       { 0x3040200, 0x3060300, 0x30c0600 },
+       { 0x2002312, 0x3002312, 0x6002312 },
+
+       0x4f006b, 0x1df020c, 0x2301e2, 0x14100040,
+        { 0x35, 0x07 }
+};
+
+#if 0          /* not filled in yet */
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_gt_reg_init_5 = {
+       { 0x200, 0x200, 0x200 },
+       { },
+        { 0x35, 0x07 }
+};
+#endif
diff --git a/drivers/macintosh/ati-vt.h b/drivers/macintosh/ati-vt.h
new file mode 100644 (file)
index 0000000..b348923
--- /dev/null
@@ -0,0 +1,147 @@
+#if 0          /* not filled inaty_vt_reg_init yet */
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_vt_reg_init_7 = {
+       { 0x10, 0x30, 0x68 },
+       { },
+       { }     /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+       { 0x10, 0x28, 0x50 },
+       { },
+       { }     /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_vt_reg_init_20 = {
+       { 0, 0, 0 },
+       { 0x2e02a7, 0x2e02a7, 0x2e02a7},
+       { 0x3070200, 0x3070200, 0x3070200},
+       { 0xa00cb22, 0xb00cb23, 0xe00cb24 },
+       
+       0x9f00d2, 0x3ff0429, 0x30400, 0x28000000,
+       { 0x00, 0xaa }
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_vt_reg_init_18 = {
+       { 0, 0, 0 },
+       { 0x300295, 0x300194, 0x300194 },
+       { 0x3060200, 0x30e0300, 0x30e0300 },
+       { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x8f00b5, 0x3650392, 0x230368, 0x24000000,
+    { 0x00, 0x9d }
+       /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_vt_reg_init_17 = {
+    { 0, 0, 0 },
+
+    { 0x2c0283, 0x2c0182, 0x2c0182 },
+    { 0x3060200, 0x30a0300, 0x30a0300 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a3, 0x2ff031f, 0x30300, 0x20000000,
+    { 0x01, 0xf7 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+    { 0, 0, 0 },
+
+    { 0x310284, 0x310183, 0x310183 },
+    { 0x3060200, 0x3090300, 0x3090600 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20000000,
+    { 0x01, 0xeb }
+};    
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_vt_reg_init_14 = {
+       { 0, 0, 0 },
+    { 0x310284, 0x310183, 0x310183 },
+    { 0x3060200, 0x3080300, 0x30f0600 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a7, 0x2ff0325, 0x260302, 0x20000000,
+    { 0x01, 0xcc }
+};  
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_vt_reg_init_13 = {
+       { 0, 0, 0 },
+
+    { 0x28026d, 0x28016c, 0x28016c },
+    { 0x3060200, 0x3080300, 0x30f0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x67008f, 0x26f029a, 0x230270, 0x1a000000,
+    { 0x01, 0xb4 }
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_vt_reg_init_12 = {
+       { 0, 0, 0 },
+    { 0x2a0267, 0x2a0166, 0x2a0565 },
+    { 0x3040200, 0x3060300, 0x30d0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630083, 0x2570270, 0x30258, 0x19000000,
+    { 0x01, 0x9c }
+       /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_vt_reg_init_11 = {
+       { 0, 0, 0 },
+    
+    { 0x2f026c, 0x2f016b, 0x2f056a },
+    { 0x3040200, 0x3060300, 0x30d0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630081, 0x257029b, 0x6027c, 0x19000000,
+    { 0x01, 0x9d }
+       /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_vt_reg_init_10 = {
+       { 0, 0, 0 },
+    { 0x30026a, 0x300169, 0x300568 },
+    { 0x3030200, 0x3050300, 0x30b0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630083, 0x2570273, 0x40258, 0x19000000,
+    { 0x02, 0xfb }
+/* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_vt_reg_init_6 = {
+       { 0, 0, 0 },
+
+    { 0x280259, 0x280158, 0x280557 },
+    { 0x3030200, 0x3040300, 0x3080600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x4f006b, 0x1df020c, 0x2301e2, 0x14000000,
+    { 0x02, 0xbe }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_vt_reg_init_5 = {
+       { 0, 0, 0 },
+       
+    { 0x2c0253, 0x2c0152, 0x2c0551 },
+    { 0x3030200, 0x3040300, 0x3060600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x4f0063, 0x1df020c, 0x2201e9, 0x14000000,
+    { 0x02, 0x9e }
+};
diff --git a/drivers/macintosh/aty.c b/drivers/macintosh/aty.c
new file mode 100644 (file)
index 0000000..007fbd7
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * aty.c: Console support for ATI/mach64 display adaptor cards.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *  written with much help from Jon Howell
+ *  changes to support the vt chip set by harry ac eaton
+ * 
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "aty.h"
+
+struct aty_cmap_regs {
+       unsigned char windex;
+       unsigned char lut;
+       unsigned char mask;
+       unsigned char rindex;
+       unsigned char cntl;
+};
+
+struct aty_regvals {
+     int       offset[3];               /* first pixel address */
+
+     int       crtc_h_sync_strt_wid[3]; /* depth dependant */
+     int       crtc_gen_cntl[3];
+     int       mem_cntl[3];
+
+     int       crtc_h_tot_disp;         /* mode dependant */
+     int       crtc_v_tot_disp;
+     int       crtc_v_sync_strt_wid;
+     int       crtc_off_pitch;
+
+     unsigned char clock_val[2];        /* vals for 20 and 21 */
+};
+
+/*static void set_aty_clock(unsigned char *params);*/
+static int aty_vram_reqd(int vmode, int cmode);
+
+static unsigned char *frame_buffer;
+static int total_vram;         /* total amount of video memory, bytes */
+static int is_vt_chip;         /* whether a vt chip type was detected */
+
+static unsigned long aty_regbase;
+static struct aty_cmap_regs *aty_cmap_regs;
+
+/* this array contains the number of bytes/line for each mode and color depth */
+static int pitch[20][3] = {
+       {0,0,0},  /* mode 1?? */
+       {0,0,0},  /* mode 2?? */
+       {0,0,0},  /* mode 3??*/
+       {0,0,0},  /* mode 4?? */
+       {640, 1280, 2560},  /* mode 5 */
+       {640, 1280, 2560},  /* mode 6 */
+       {640, 1280, 2560},  /* mode 7 */
+       {800, 1600, 3200},  /* mode 8 */
+       {0,0,0},  /* mode 9 ??*/
+       {800, 1600, 3200},  /* mode 10 */
+       {800, 1600, 3200},  /* mode 11 */
+       {800, 1600, 3200},  /* mode 12 */
+       {832, 1664, 3328},  /* mode 13 */
+       {1024, 2048, 4096},  /* mode 14 */
+       {1024, 2048, 4096},  /* mode 15 */
+       {1024, 2048, 4096},  /* mode 16 */
+       {1024, 2048, 4096},  /* mode 17 */
+       {1152, 2304, 4608},  /* mode 18 */
+       {1280, 2560, 5120},  /* mode 19 */
+       {1280, 2560, 5120}   /* mode 20 */
+};
+
+#include "ati-gt.h"
+#include "ati-vt.h"
+
+static struct aty_regvals *aty_gt_reg_init[20] = {
+       NULL, NULL, NULL, NULL,
+       &aty_gt_reg_init_6,
+       &aty_gt_reg_init_6,
+       NULL,
+       NULL, NULL,
+       NULL,
+       NULL,NULL,
+       &aty_gt_reg_init_13,
+       &aty_gt_reg_init_14,
+       &aty_gt_reg_init_15,
+       NULL,
+       &aty_gt_reg_init_17,
+       NULL,
+       NULL,
+       &aty_gt_reg_init_20
+};
+
+static struct aty_regvals *aty_vt_reg_init[20] = {
+       NULL, NULL, NULL, NULL,
+       &aty_vt_reg_init_5,
+       &aty_vt_reg_init_6,
+       NULL,
+       NULL, NULL,
+       &aty_vt_reg_init_10,
+       &aty_vt_reg_init_11,
+       &aty_vt_reg_init_12,
+       &aty_vt_reg_init_13,
+       &aty_vt_reg_init_14,
+       &aty_vt_reg_init_15,
+       NULL,
+       &aty_vt_reg_init_17,
+       &aty_vt_reg_init_18,
+       NULL,
+       &aty_vt_reg_init_20
+};
+
+static inline int aty_vram_reqd(int vmode, int cmode)
+{
+       return vmode_attrs[vmode-1].vres
+               * pitch[vmode-1][cmode];
+}
+
+extern inline unsigned aty_ld_rev(volatile unsigned long addr)
+{
+     unsigned val;
+
+     (long)addr += (long)aty_regbase;
+     asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+     return val;
+}
+
+extern inline void aty_st_rev(volatile unsigned long addr, unsigned val)
+{
+     (long)addr += (long)aty_regbase;
+     asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned char aty_ld_byte(volatile unsigned long addr)
+{
+     unsigned char val;
+
+     val = *(char*)((long)addr+(long)aty_regbase);
+     return val;
+}
+
+extern inline void aty_st_byte(volatile unsigned long addr, unsigned char val)
+{
+     *(unsigned char*)(addr+(unsigned long)aty_regbase) = val;
+}
+
+void
+aty_st_514( int offset, char val )
+{
+     aty_WaitQueue(5);
+     aty_st_byte( DAC_CNTL, 1);
+     aty_st_byte( DAC_W_INDEX, offset & 0xff );   /* right addr byte */
+     aty_st_byte( DAC_DATA, (offset>>8) & 0xff ); /* left addr byte */
+     aty_st_byte( DAC_MASK, val );
+     aty_st_byte( DAC_CNTL, 0 );
+}
+
+void
+aty_st_pll( int offset, char val )
+{
+     aty_WaitQueue(3);
+     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN );   /* write addr byte */
+     aty_st_byte( CLOCK_CNTL + 2, val); /* write the register value */
+     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+}
+
+#if 0
+unsigned char
+aty_ld_514( int offset )
+{
+/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing*/
+}
+#endif
+
+void
+aty_set_palette(unsigned char red[], unsigned char green[],
+               unsigned char blue[], int index, int ncolors)
+{
+     int i,scale;
+
+     aty_WaitQueue(2);
+     aty_st_byte(DAC_CNTL, aty_ld_byte(DAC_CNTL) & 0xfc);
+     aty_st_byte(DAC_REGS + DAC_MASK, 0xff);
+     eieio();
+     scale = (is_vt_chip) ? ((color_mode == CMODE_16) ? 3 : 0) : 0;
+     for (i = 0; i < ncolors; ++i) {
+         aty_WaitQueue(4);
+          aty_cmap_regs->windex = (index + i) << scale;        eieio();
+          aty_cmap_regs->lut = red[i];         eieio();
+          aty_cmap_regs->lut = green[i];       eieio();
+          aty_cmap_regs->lut = blue[i];                eieio();
+     }
+   
+}
+
+void
+map_aty_display(struct device_node *dp)
+{
+     int i, sense;
+     unsigned long addr;
+     unsigned char bus, devfn;
+     unsigned short cmd;
+
+     if (dp->next != 0)
+         printk("Warning: only using first ATI card detected\n");
+     if (dp->n_addrs != 1)
+         panic("expecting 1 addresses for ATY (got %d)", dp->n_addrs);
+
+     aty_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+     aty_cmap_regs = (struct aty_cmap_regs *)(aty_regbase+0xC0);
+
+     /* enable memory-space accesses using config-space command register */
+     if (pci_device_loc(dp, &bus, &devfn) == 0) {
+         pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+         if (cmd != 0xffff) {
+              cmd |= PCI_COMMAND_MEMORY;
+              pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+         }
+     }
+
+     switch( aty_ld_rev(MEM_CNTL)&MEM_SIZE_ALIAS ) {
+     case MEM_SIZE_512K:
+         total_vram = 0x80000;
+         break;
+     case MEM_SIZE_1M:
+         total_vram = 0x100000;
+         break;
+     case MEM_SIZE_2M:
+         total_vram = 0x200000;
+         break;
+     case MEM_SIZE_4M:
+         total_vram = 0x400000;
+         break;
+     case MEM_SIZE_6M:
+         total_vram = 0x600000;
+         break;
+     case MEM_SIZE_8M:
+         total_vram = 0x800000;
+         break;
+     default:
+         total_vram = 0x80000;
+     }
+#if 1
+     printk("aty_display_init: node = %p, addrs = ", dp->node);
+     printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
+     printk(", intrs =");
+     for (i = 0; i < dp->n_intrs; ++i)
+         printk(" %x", dp->intrs[i]);
+     printk( "\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int)aty_regbase, 
+            bus, devfn, total_vram, (int)aty_cmap_regs );
+#endif
+     is_vt_chip = ((aty_ld_rev(CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID);
+     /* Map in frame buffer */
+     addr = dp->addrs[0].address;
+
+     /* use the big-endian aperture (??) */
+     addr += 0x800000;
+     frame_buffer = ioremap(addr, 0x800000);
+     
+
+     /*        sense = read_aty_sense(); XXX not yet, just give it mine */
+     sense = 0x62b;
+     if (video_mode == VMODE_NVRAM) {
+         video_mode = nvram_read_byte(NV_VMODE);
+         if (video_mode <= 0 || video_mode > VMODE_MAX
+             || ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+              video_mode = VMODE_CHOOSE;
+     }
+     if (video_mode == VMODE_CHOOSE)
+         video_mode = map_monitor_sense(sense);
+     if (((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+         video_mode = VMODE_640_480_60;
+
+     /*
+      * Reduce the pixel size if we don't have enough VRAM.
+      */
+
+     if (color_mode == CMODE_NVRAM)
+        color_mode = nvram_read_byte(NV_CMODE);
+     if (color_mode < CMODE_8 || color_mode > CMODE_32)
+       color_mode = CMODE_8;
+     while (aty_vram_reqd(video_mode, color_mode) > total_vram) {
+       while (color_mode > CMODE_8
+           && aty_vram_reqd(video_mode, color_mode) > total_vram)
+         --color_mode;
+        /*
+        * adjust the video mode smaller if there still is not enough VRAM
+        */
+       if (aty_vram_reqd(video_mode, color_mode) > total_vram)
+         while ((((is_vt_chip) ? aty_vt_reg_init[--video_mode - 1]
+               : aty_gt_reg_init[--video_mode -1 ]) == 0) && (video_mode > VMODE_640_480_60)) ;
+    }
+}
+
+#if 0
+static void
+set_aty_clock(unsigned char *params)
+{
+     /* done in aty_init...probably need to change for different modes */
+     printk("tried to set ATY clock\n");
+}
+#endif
+
+void
+RGB514_Program(int cmode)
+{
+     typedef struct {
+          char    pixel_dly;
+          char    misc2_cntl;
+          char    pixel_rep;
+          char    pixel_cntl_index;
+          char    pixel_cntl_v1;
+     } RGB514_DAC_Table;
+
+     static  RGB514_DAC_Table RGB514DAC_Tab[8] = {
+          { 0, 0x41, 0x03, 0x71, 0x45 },          // 8bpp
+          { 0, 0x45, 0x04, 0x0c, 0x01 },          // 555
+          { 0, 0x45, 0x06, 0x0e, 0x00 },          // XRGB
+     };
+     RGB514_DAC_Table *pDacProgTab;
+
+     pDacProgTab = &RGB514DAC_Tab[cmode];
+
+     aty_st_514(0x90, 0x00);
+     aty_st_514(0x04, pDacProgTab->pixel_dly);
+     aty_st_514(0x05, 0x00);
+
+     aty_st_514(0x2, 0x1);
+     aty_st_514(0x71, pDacProgTab->misc2_cntl);
+     aty_st_514(0x0a, pDacProgTab->pixel_rep);
+
+     aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+}
+
+/* The vt chipset seems to need a specialized color table for 15 bit mode */
+void
+VT_Program(int cmode)
+{
+#if 0
+       int i;
+       if (cmode != CMODE_8) {
+               aty_WaitQueue(2);
+               aty_cmap_regs->mask = 0xff; eieio();
+               aty_cmap_regs->windex = 0; eieio();
+               for (i = 0; i < 0x100; i++) {
+                       aty_WaitQueue(3);
+                       aty_cmap_regs->lut = i;
+                       aty_cmap_regs->lut = i;
+                       aty_cmap_regs->lut = i; eieio();
+               }
+       }
+#endif
+}
+
+void
+aty_init()
+{
+     int i, yoff, hres;
+     unsigned *p;
+     struct aty_regvals *init;
+
+     if (video_mode <= 0 || video_mode > VMODE_MAX
+        || (init = ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1])) == 0)
+         panic("aty: display mode %d not supported", video_mode);
+     n_scanlines = vmode_attrs[video_mode-1].vres;
+     hres = vmode_attrs[video_mode-1].hres;
+     pixel_size = 1 << color_mode;
+     line_pitch = pitch[video_mode-1][color_mode];
+     row_pitch = line_pitch * 16;
+
+     aty_st_rev(BUS_CNTL, aty_ld_rev(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
+               
+     /* Reset engine */
+     i = aty_ld_rev(GEN_TEST_CNTL);
+     aty_st_rev(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+     eieio();
+     aty_WaitIdleEmpty();
+     aty_st_rev(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
+     aty_WaitIdleEmpty();
+                       
+     i = aty_ld_byte(CRTC_GEN_CNTL+3);
+     aty_st_byte(CRTC_GEN_CNTL+3, i | (CRTC_EXT_DISP_EN >> 24));
+
+     i = aty_ld_byte(GEN_TEST_CNTL);
+     aty_st_byte(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+
+     if (!is_vt_chip) {                
+       RGB514_Program(color_mode);
+
+       aty_WaitIdleEmpty();
+
+       aty_st_514(0x06, 0x02);
+       aty_st_514(0x10, 0x01);
+       aty_st_514(0x70, 0x01);
+       aty_st_514(0x8f, 0x1f);
+       aty_st_514(0x03, 0x00);
+       aty_st_514(0x05, 0x00);
+     
+       aty_st_514(0x20, init->clock_val[0]);
+       aty_st_514(0x21, init->clock_val[1]);
+     } else {
+       VT_Program(color_mode);
+       aty_st_pll(PLL_MACRO_CNTL, 0xb5);
+       aty_st_pll(PLL_REF_DIV, 0x2d);
+       aty_st_pll(PLL_GEN_CNTL, 0x14);
+       aty_st_pll(MCLK_FB_DIV, 0xbd);
+       aty_st_pll(PLL_VCLK_CNTL, 0x0b);
+       aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
+       aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
+       aty_st_pll(VCLK1_FB_DIV, 0xd6);
+       aty_st_pll(VCLK2_FB_DIV, 0xee);
+       aty_st_pll(VCLK3_FB_DIV, 0xf8);
+       aty_st_pll(PLL_XCLK_CNTL, 0x0);
+       aty_st_pll(PLL_TEST_CTRL, 0x0);
+       aty_st_pll(PLL_TEST_COUNT, 0x0);
+     }
+               
+     aty_ld_byte( DAC_REGS ); /* clear counter */
+                       
+     aty_WaitIdleEmpty();
+
+     aty_st_rev(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
+     aty_st_rev(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]);
+     aty_st_rev(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
+     aty_st_rev(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+
+     aty_st_byte(CLOCK_CNTL, 0);
+     aty_st_byte(CLOCK_CNTL, CLOCK_STROBE);
+
+     aty_st_rev(CRTC_OFF_PITCH, init->crtc_off_pitch);
+     
+     aty_st_rev(CRTC_VLINE_CRNT_VLINE, 0x14e01d0);
+/* The magic constant below translates into: 
+ * 5   = No RDY delay, 1 wait st for mem write, increment during burst transfer
+ * 9   = DAC access delayed, 1 wait state for DAC
+ * 0   = Disables interupts for FIFO errors
+ * e   = Allows FIFO to generate 14 wait states before generating error
+ * 1   = DAC snooping disabled, ROM disabled
+ * 0   = ROM page at 0 (disabled so doesn't matter)
+ * f   = 15 ROM wait states (disabled so doesn't matter) 
+ * f   = 15 BUS wait states (I'm not sure this applies to PCI bus types)
+ * at some point it would be good to experiment with bench marks to see if
+ * we can gain some speed by fooling with the wait states etc.
+ */
+     aty_st_rev(BUS_CNTL, 0x590e10ff);
+     i = aty_ld_rev(MEM_CNTL) & MEM_SIZE_ALIAS;
+     if (total_vram >= 0x400000)
+        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] &0xffff0000) | 0x0538 | i);
+     else
+        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] & ~MEM_SIZE_ALIAS) | i ); 
+     aty_st_rev(CRTC_INT_CNTL, 0x2);
+     aty_WaitIdleEmpty();
+/* These magic constants are harder to figure out
+ * on the vt chipset bit 3 set makes the screen brighter
+ * and bit 15 makes the screen black! But nothing else
+ * seems to matter for the vt DAC_CNTL
+ */
+     if (is_vt_chip)
+       aty_st_rev(DAC_CNTL, 0x47012104);
+     else
+        aty_st_rev(DAC_CNTL, 0x47012100);
+
+     aty_st_byte(DAC_MASK, 0xff);
+
+     aty_st_rev(CRTC_INT_CNTL, 0x00000002);
+     
+     aty_st_byte(CRTC_FIFO, ((char*)&init->crtc_gen_cntl[color_mode])[1] );
+     aty_st_byte(CRTC_PIX_WIDTH, ((char*)&init->crtc_gen_cntl[color_mode])[2] );
+     aty_st_byte(CRTC_EXT_DISP, ((char*)&init->crtc_gen_cntl[color_mode])[0] );
+     
+     aty_st_rev(GEN_TEST_CNTL, 0x300); /* gui_en block_en*/
+
+     pmac_init_palette();              /* Initialize colormap */
+     yoff = (n_scanlines % 16) / 2;
+     fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+     /* Clear screen */
+     p = (unsigned *) fb_start;
+
+     for (i = n_scanlines * line_pitch * pixel_size / sizeof(unsigned); i != 0; --i)
+         *p++ = 0;
+     display_info.height = n_scanlines;
+     display_info.width = hres;
+     display_info.depth = pixel_size * 8;
+     display_info.pitch = line_pitch;
+     display_info.mode = video_mode;
+     strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name));
+     display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+     display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
+     display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
+     display_info.disp_reg_address = aty_regbase;
+}
+
+int
+aty_setmode(struct vc_mode *mode, int doit)
+{
+       int cmode;
+#if 0
+       if (mode->mode == 21) {
+               printk("hace: about to set 0x%x to 0x%x\n",mode->depth, mode->pitch & 0xff);
+               aty_st_byte(mode->depth, mode->pitch & 0xff);
+               return 0;
+       }
+
+       if (mode->mode == 0) {
+               printk("hace: 0x%x contains 0x%x\n",mode->depth, aty_ld_byte(mode->depth));
+               return 0;
+       }
+#endif         
+       
+       if (mode->mode <= 0 || mode->mode > VMODE_MAX
+           || ((is_vt_chip) ? aty_vt_reg_init[mode->mode-1] : aty_gt_reg_init[mode->mode-1]) == NULL)
+               return -EINVAL;
+       switch (mode->depth) {
+       case 24:
+       case 32:
+               cmode = CMODE_32;
+               break;
+       case 16:
+               cmode = CMODE_16;
+               break;
+       case 8:
+       case 0:         /* (default) */
+               cmode = CMODE_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (aty_vram_reqd(mode->mode, cmode) > total_vram) {
+               return -EINVAL;
+       }
+       if (doit) {
+               video_mode = mode->mode;
+               color_mode = cmode;
+               aty_init();
+       }
+       return 0;
+}
+
+void
+aty_set_blanking(int blank_mode)
+{
+       char gen_cntl;
+
+       gen_cntl = aty_ld_byte(CRTC_GEN_CNTL);
+       if (blank_mode & VESA_VSYNC_SUSPEND)
+               gen_cntl |= 0x8;
+       if (blank_mode & VESA_HSYNC_SUSPEND)
+               gen_cntl |= 0x4;
+       if ((blank_mode & VESA_POWERDOWN) == VESA_POWERDOWN)
+               gen_cntl |= 0x40;
+       if (blank_mode == VESA_NO_BLANKING)
+               gen_cntl &= ~(0x4c);
+       aty_st_byte(CRTC_GEN_CNTL, gen_cntl);
+}
diff --git a/drivers/macintosh/aty.h b/drivers/macintosh/aty.h
new file mode 100644 (file)
index 0000000..27ba7bd
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Exported procedures for the ATI/mach64 display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *  written with much help from Jon Howell
+ *     
+ * 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.
+ */
+
+extern void map_aty_display(struct device_node *);
+extern void aty_init(void);
+extern int aty_setmode(struct vc_mode *mode, int doit);
+extern void aty_set_palette(unsigned char red[], unsigned char green[],
+                           unsigned char blue[], int index, int ncolors);
+extern void aty_set_blanking(int blank_mode);
+
+/*
+ * most of the rest of this file comes from ATI sample code
+ */
+#ifndef REGMACH64_H
+#define REGMACH64_H
+
+/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
+
+#define CRTC_H_TOTAL_DISP       0x0000  /* Dword offset 00 */
+#define CRTC_H_SYNC_STRT_WID    0x0004  /* Dword offset 01 */
+#define CRTC_H_SYNC_STRT        0x0004
+#define CRTC_H_SYNC_DLY         0x0005
+#define CRTC_H_SYNC_WID         0x0006
+
+#define CRTC_V_TOTAL_DISP       0x0008  /* Dword offset 02 */
+#define CRTC_V_TOTAL            0x0008
+#define CRTC_V_DISP             0x000a
+#define CRTC_V_SYNC_STRT_WID    0x000C  /* Dword offset 03 */
+#define CRTC_V_SYNC_STRT        0x000c
+#define CRTC_V_SYNC_WID         0x000e
+
+#define CRTC_VLINE_CRNT_VLINE   0x0010  /* Dword offset 04 */
+#define CRTC_OFF_PITCH          0x0014  /* Dword offset 05 */
+#define CRTC_OFFSET             0x0014
+#define CRTC_PITCH              0x0016
+
+#define CRTC_INT_CNTL           0x0018  /* Dword offset 06 */
+#define CRTC_GEN_CNTL           0x001C  /* Dword offset 07 */
+#define CRTC_PIX_WIDTH          0x001d
+#define CRTC_FIFO               0x001e
+#define CRTC_EXT_DISP           0x001f
+
+#define OVR_CLR                 0x0040  /* Dword offset 10 */
+#define OVR_WID_LEFT_RIGHT      0x0044  /* Dword offset 11 */
+#define OVR_WID_TOP_BOTTOM      0x0048  /* Dword offset 12 */
+
+#define CUR_CLR0                0x0060  /* Dword offset 18 */
+#define CUR_CLR1                0x0064  /* Dword offset 19 */
+#define CUR_OFFSET              0x0068  /* Dword offset 1A */
+#define CUR_HORZ_VERT_POSN      0x006C  /* Dword offset 1B */
+#define CUR_HORZ_VERT_OFF       0x0070  /* Dword offset 1C */
+
+#define SCRATCH_REG0            0x0080  /* Dword offset 20 */
+#define SCRATCH_REG1            0x0084  /* Dword offset 21 */
+
+#define CLOCK_CNTL              0x0090  /* Dword offset 24 */
+#define CLOCK_SEL_CNTL          0x0090  // Dword offset 24
+
+#define BUS_CNTL                0x00A0  /* Dword offset 28 */
+
+#define MEM_CNTL                0x00B0  /* Dword offset 2C */
+
+#define MEM_VGA_WP_SEL          0x00B4  /* Dword offset 2D */
+#define MEM_VGA_RP_SEL          0x00B8  /* Dword offset 2E */
+
+#define DAC_REGS                0x00C0  /* Dword offset 30 */
+#define DAC_W_INDEX             0x00C0  /* Dword offset 30 */
+#define DAC_DATA                0x00C1  /* Dword offset 30 */
+#define DAC_MASK                0x00C2  /* Dword offset 30 */
+#define DAC_R_INDEX             0x00C3  /* Dword offset 30 */
+#define DAC_CNTL                0x00C4  /* Dword offset 31 */
+
+#define GEN_TEST_CNTL           0x00D0  /* Dword offset 34 */
+
+#define CONFIG_CNTL            0x00DC  /* Dword offset 37 (CT, ET, VT) */
+#define CONFIG_CHIP_ID          0x00E0  /* Dword offset 38 */
+#define CONFIG_STAT0            0x00E4  /* Dword offset 39 */
+#define CONFIG_STAT1            0x00E8  /* Dword offset 3A */
+
+
+/* GUI MEMORY MAPPED Registers */
+
+#define DST_OFF_PITCH           0x0100  /* Dword offset 40 */
+#define DST_X                   0x0104  /* Dword offset 41 */
+#define DST_Y                   0x0108  /* Dword offset 42 */
+#define DST_Y_X                 0x010C  /* Dword offset 43 */
+#define DST_WIDTH               0x0110  /* Dword offset 44 */
+#define DST_HEIGHT              0x0114  /* Dword offset 45 */
+#define DST_HEIGHT_WIDTH        0x0118  /* Dword offset 46 */
+#define DST_X_WIDTH             0x011C  /* Dword offset 47 */
+#define DST_BRES_LNTH           0x0120  /* Dword offset 48 */
+#define DST_BRES_ERR            0x0124  /* Dword offset 49 */
+#define DST_BRES_INC            0x0128  /* Dword offset 4A */
+#define DST_BRES_DEC            0x012C  /* Dword offset 4B */
+#define DST_CNTL                0x0130  /* Dword offset 4C */
+
+#define SRC_OFF_PITCH           0x0180  /* Dword offset 60 */
+#define SRC_X                   0x0184  /* Dword offset 61 */
+#define SRC_Y                   0x0188  /* Dword offset 62 */
+#define SRC_Y_X                 0x018C  /* Dword offset 63 */
+#define SRC_WIDTH1              0x0190  /* Dword offset 64 */
+#define SRC_HEIGHT1             0x0194  /* Dword offset 65 */
+#define SRC_HEIGHT1_WIDTH1      0x0198  /* Dword offset 66 */
+#define SRC_X_START             0x019C  /* Dword offset 67 */
+#define SRC_Y_START             0x01A0  /* Dword offset 68 */
+#define SRC_Y_X_START           0x01A4  /* Dword offset 69 */
+#define SRC_WIDTH2              0x01A8  /* Dword offset 6A */
+#define SRC_HEIGHT2             0x01AC  /* Dword offset 6B */
+#define SRC_HEIGHT2_WIDTH2      0x01B0  /* Dword offset 6C */
+#define SRC_CNTL                0x01B4  /* Dword offset 6D */
+
+#define HOST_DATA0              0x0200  /* Dword offset 80 */
+#define HOST_DATA1              0x0204  /* Dword offset 81 */
+#define HOST_DATA2              0x0208  /* Dword offset 82 */
+#define HOST_DATA3              0x020C  /* Dword offset 83 */
+#define HOST_DATA4              0x0210  /* Dword offset 84 */
+#define HOST_DATA5              0x0214  /* Dword offset 85 */
+#define HOST_DATA6              0x0218  /* Dword offset 86 */
+#define HOST_DATA7              0x021C  /* Dword offset 87 */
+#define HOST_DATA8              0x0220  /* Dword offset 88 */
+#define HOST_DATA9              0x0224  /* Dword offset 89 */
+#define HOST_DATAA              0x0228  /* Dword offset 8A */
+#define HOST_DATAB              0x022C  /* Dword offset 8B */
+#define HOST_DATAC              0x0230  /* Dword offset 8C */
+#define HOST_DATAD              0x0234  /* Dword offset 8D */
+#define HOST_DATAE              0x0238  /* Dword offset 8E */
+#define HOST_DATAF              0x023C  /* Dword offset 8F */
+#define HOST_CNTL               0x0240  /* Dword offset 90 */
+
+#define PAT_REG0                0x0280  /* Dword offset A0 */
+#define PAT_REG1                0x0284  /* Dword offset A1 */
+#define PAT_CNTL                0x0288  /* Dword offset A2 */
+
+#define SC_LEFT                 0x02A0  /* Dword offset A8 */
+#define SC_RIGHT                0x02A4  /* Dword offset A9 */
+#define SC_LEFT_RIGHT           0x02A8  /* Dword offset AA */
+#define SC_TOP                  0x02AC  /* Dword offset AB */
+#define SC_BOTTOM               0x02B0  /* Dword offset AC */
+#define SC_TOP_BOTTOM           0x02B4  /* Dword offset AD */
+
+#define DP_BKGD_CLR             0x02C0  /* Dword offset B0 */
+#define DP_FRGD_CLR             0x02C4  /* Dword offset B1 */
+#define DP_WRITE_MASK           0x02C8  /* Dword offset B2 */
+#define DP_CHAIN_MASK           0x02CC  /* Dword offset B3 */
+#define DP_PIX_WIDTH            0x02D0  /* Dword offset B4 */
+#define DP_MIX                  0x02D4  /* Dword offset B5 */
+#define DP_SRC                  0x02D8  /* Dword offset B6 */
+
+#define CLR_CMP_CLR             0x0300  /* Dword offset C0 */
+#define CLR_CMP_MASK            0x0304  /* Dword offset C1 */
+#define CLR_CMP_CNTL            0x0308  /* Dword offset C2 */
+
+#define FIFO_STAT               0x0310  /* Dword offset C4 */
+
+#define CONTEXT_MASK            0x0320  /* Dword offset C8 */
+#define CONTEXT_LOAD_CNTL       0x032C  /* Dword offset CB */
+
+#define GUI_TRAJ_CNTL           0x0330  /* Dword offset CC */
+#define GUI_STAT                0x0338  /* Dword offset CE */
+
+
+/* CRTC control values (mostly CRTC_GEN_CNTL) */
+
+#define CRTC_H_SYNC_NEG                0x00200000
+#define CRTC_V_SYNC_NEG                0x00200000
+
+#define CRTC_DBL_SCAN_EN       0x00000001
+#define CRTC_INTERLACE_EN      0x00000002
+#define CRTC_HSYNC_DIS         0x00000004
+#define CRTC_VSYNC_DIS         0x00000008
+#define CRTC_CSYNC_EN          0x00000010
+#define CRTC_PIX_BY_2_EN       0x00000020
+#define CRTC_BLANK             0x00000040
+
+#define CRTC_PIX_WIDTH_MASK            0x00000700
+#define CRTC_PIX_WIDTH_4BPP            0x00000100
+#define CRTC_PIX_WIDTH_8BPP            0x00000200
+#define CRTC_PIX_WIDTH_15BPP   0x00000300
+#define CRTC_PIX_WIDTH_16BPP   0x00000400
+#define CRTC_PIX_WIDTH_24BPP   0x00000500
+#define CRTC_PIX_WIDTH_32BPP   0x00000600
+
+#define CRTC_BYTE_PIX_ORDER    0x00000800
+#define CRTC_PIX_ORDER_MSN_LSN 0x00000000
+#define CRTC_PIX_ORDER_LSN_MSN 0x00000800
+
+#define CRTC_FIFO_LWM          0x000f0000
+#define CRTC_EXT_DISP_EN       0x01000000
+#define CRTC_EXT_EN            0x02000000
+
+#define CRTC_CRNT_VLINE                0x07f00000
+#define CRTC_VBLANK            0x00000001
+
+/* DAC control values */
+
+#define DAC_EXT_SEL_RS2                0x01
+#define DAC_EXT_SEL_RS3                0x02
+#define DAC_8BIT_EN            0x00000100
+#define DAC_PIX_DLY_MASK       0x00000600
+#define DAC_PIX_DLY_0NS                0x00000000
+#define DAC_PIX_DLY_2NS                0x00000200
+#define DAC_PIX_DLY_4NS                0x00000400
+#define DAC_BLANK_ADJ_MASK     0x00001800
+#define DAC_BLANK_ADJ_0                0x00000000
+#define DAC_BLANK_ADJ_1                0x00000800
+#define DAC_BLANK_ADJ_2                0x00001000
+
+
+/* Mix control values */
+
+#define MIX_NOT_DST                     0x0000
+#define MIX_0                           0x0001
+#define MIX_1                           0x0002
+#define MIX_DST                         0x0003
+#define MIX_NOT_SRC                     0x0004
+#define MIX_XOR                         0x0005
+#define MIX_XNOR                        0x0006
+#define MIX_SRC                         0x0007
+#define MIX_NAND                        0x0008
+#define MIX_NOT_SRC_OR_DST              0x0009
+#define MIX_SRC_OR_NOT_DST              0x000a
+#define MIX_OR                          0x000b
+#define MIX_AND                         0x000c
+#define MIX_SRC_AND_NOT_DST             0x000d
+#define MIX_NOT_SRC_AND_DST             0x000e
+#define MIX_NOR                         0x000f
+
+/* Maximum engine dimensions */
+#define ENGINE_MIN_X        0
+#define ENGINE_MIN_Y        0
+#define ENGINE_MAX_X        4095
+#define ENGINE_MAX_Y        16383
+
+/* Mach64 engine bit constants - these are typically ORed together */
+
+/* BUS_CNTL register constants */
+#define BUS_FIFO_ERR_ACK        0x00200000
+#define BUS_HOST_ERR_ACK        0x00800000
+
+/* GEN_TEST_CNTL register constants */
+#define GEN_OVR_OUTPUT_EN       0x20
+#define HWCURSOR_ENABLE         0x80
+#define GUI_ENGINE_ENABLE       0x100
+#define BLOCK_WRITE_ENABLE      0x200
+
+/* CLOCK_CNTL register constants */
+#define CLOCK_SEL              0x0f
+#define CLOCK_DIV              0x30
+#define CLOCK_DIV1             0x00
+#define CLOCK_DIV2             0x10
+#define CLOCK_DIV4             0x20
+#define CLOCK_STROBE   0x40
+#define PLL_WR_EN              0x02
+
+/* PLL registers */
+#define PLL_MACRO_CNTL         0x01
+#define PLL_REF_DIV            0x02
+#define PLL_GEN_CNTL           0x03
+#define MCLK_FB_DIV            0x04
+#define PLL_VCLK_CNTL          0x05
+#define VCLK_POST_DIV          0x06
+#define VCLK0_FB_DIV           0x07
+#define VCLK1_FB_DIV           0x08
+#define VCLK2_FB_DIV           0x09
+#define VCLK3_FB_DIV           0x0A
+#define PLL_XCLK_CNTL          0x0B
+#define PLL_TEST_CTRL          0x0E
+#define PLL_TEST_COUNT         0x0F
+
+/* Fields in PLL registers */
+#define PLL_PC_GAIN            0x07
+#define PLL_VC_GAIN            0x18
+#define PLL_DUTY_CYC   0xE0
+#define PLL_OVERRIDE   0x01
+#define PLL_MCLK_RST   0x02
+#define OSC_EN                 0x04
+#define EXT_CLK_EN             0x08
+#define MCLK_SRC_SEL   0x70
+#define EXT_CLK_CNTL   0x80
+#define VCLK_SRC_SEL   0x03
+#define PLL_VCLK_RST   0x04
+#define VCLK_INVERT            0x08
+#define VCLK0_POST             0x03
+#define VCLK1_POST             0x0C
+#define VCLK2_POST             0x30
+#define VCLK3_POST             0xC0
+
+/* CONFIG_CNTL register constants */
+#define APERTURE_4M_ENABLE      1
+#define APERTURE_8M_ENABLE      2
+#define VGA_APERTURE_ENABLE     4
+
+/* CONFIG_STAT0 register constants (GX, CX) */
+#define CFG_BUS_TYPE           0x00000007
+#define CFG_MEM_TYPE           0x00000038
+#define CFG_INIT_DAC_TYPE      0x00000e00
+
+/* CONFIG_STAT0 register constants (CT, ET, VT) */
+#define CFG_MEM_TYPE_xT                0x00000007
+
+#define ISA                    0
+#define EISA           1
+#define LOCAL_BUS      6
+#define PCI                    7
+
+/* Memory types for GX, CX */
+#define DRAMx4                 0
+#define VRAMx16                        1
+#define VRAMx16ssr             2
+#define DRAMx16                        3
+#define GraphicsDRAMx16                4
+#define EnhancedVRAMx16                5
+#define EnhancedVRAMx16ssr     6
+
+/* Memory types for CT, ET, VT, GT */
+#define DRAM                   0
+#define EDO_DRAM               1
+#define PSEUDO_EDO             2
+#define SDRAM                  3
+
+#define DAC_INTERNAL           0x00
+#define DAC_IBMRGB514          0x01
+#define DAC_ATI68875           0x02
+#define DAC_TVP3026_A          0x72
+#define DAC_BT476                      0x03
+#define DAC_BT481                      0x04
+#define DAC_ATT20C491          0x14
+#define DAC_SC15026                    0x24
+#define DAC_MU9C1880           0x34
+#define DAC_IMSG174                    0x44
+#define DAC_ATI68860_B         0x05
+#define DAC_ATI68860_C         0x15
+#define DAC_TVP3026_B          0x75
+#define DAC_STG1700                    0x06
+#define DAC_ATT498                     0x16
+#define DAC_STG1702                    0x07
+#define DAC_SC15021                    0x17
+#define DAC_ATT21C498          0x27
+#define DAC_STG1703                    0x37
+#define DAC_CH8398                     0x47
+#define DAC_ATT20C408          0x57
+
+#define CLK_ATI18818_0         0
+#define CLK_ATI18818_1         1
+#define CLK_STG1703                    2
+#define CLK_CH8398                     3
+#define CLK_INTERNAL           4
+#define CLK_ATT20C408          5
+#define CLK_IBMRGB514          6
+
+/* MEM_CNTL register constants */
+#define MEM_SIZE_ALIAS         0x00000007
+#define MEM_SIZE_512K          0x00000000
+#define MEM_SIZE_1M            0x00000001
+#define MEM_SIZE_2M            0x00000002
+#define MEM_SIZE_4M            0x00000003
+#define MEM_SIZE_6M            0x00000004
+#define MEM_SIZE_8M            0x00000005
+#define MEM_SIZE_ALIAS_GTB     0x0000000F
+#define MEM_SIZE_2M_GTB                0x00000003
+#define MEM_SIZE_4M_GTB                0x00000007
+#define MEM_SIZE_6M_GTB                0x00000009
+#define MEM_SIZE_8M_GTB                0x0000000B
+#define MEM_BNDRY               0x00030000
+#define MEM_BNDRY_0K            0x00000000
+#define MEM_BNDRY_256K          0x00010000
+#define MEM_BNDRY_512K          0x00020000
+#define MEM_BNDRY_1M            0x00030000
+#define MEM_BNDRY_EN            0x00040000
+
+/* ATI PCI constants */
+#define PCI_ATI_VENDOR_ID      0x1002
+#define PCI_MACH64_GX          0x4758
+#define PCI_MACH64_CX          0x4358
+#define PCI_MACH64_CT          0x4354
+#define PCI_MACH64_ET          0x4554
+#define PCI_MACH64_VT          0x5654
+#define PCI_MACH64_GT          0x4754
+
+/* CONFIG_CHIP_ID register constants */
+#define CFG_CHIP_TYPE          0x0000FFFF
+#define CFG_CHIP_CLASS         0x00FF0000
+#define CFG_CHIP_REV           0xFF000000
+#define CFG_CHIP_VERSION       0x07000000
+#define CFG_CHIP_FOUNDRY       0x38000000
+#define CFG_CHIP_REVISION      0xC0000000
+
+/* Chip IDs read from CONFIG_CHIP_ID */
+#define MACH64_GX_ID           0xD7
+#define MACH64_CX_ID           0x57
+#define MACH64_CT_ID           0x4354
+#define MACH64_ET_ID           0x4554
+#define MACH64_VT_ID           0x5654
+#define MACH64_GT_ID           0x4754
+
+/* Mach64 chip types */
+#define MACH64_UNKNOWN         0
+#define MACH64_GX              1
+#define MACH64_CX              2
+#define MACH64_CT              3
+#define MACH64_ET              4
+#define MACH64_VT              5
+#define MACH64_GT              6
+
+/* DST_CNTL register constants */
+#define DST_X_RIGHT_TO_LEFT     0
+#define DST_X_LEFT_TO_RIGHT     1
+#define DST_Y_BOTTOM_TO_TOP     0
+#define DST_Y_TOP_TO_BOTTOM     2
+#define DST_X_MAJOR             0
+#define DST_Y_MAJOR             4
+#define DST_X_TILE              8
+#define DST_Y_TILE              0x10
+#define DST_LAST_PEL            0x20
+#define DST_POLYGON_ENABLE      0x40
+#define DST_24_ROTATION_ENABLE  0x80
+
+/* SRC_CNTL register constants */
+#define SRC_PATTERN_ENABLE      1
+#define SRC_ROTATION_ENABLE     2
+#define SRC_LINEAR_ENABLE       4
+#define SRC_BYTE_ALIGN          8
+#define SRC_LINE_X_RIGHT_TO_LEFT 0
+#define SRC_LINE_X_LEFT_TO_RIGHT 0x10
+
+/* HOST_CNTL register constants */
+#define HOST_BYTE_ALIGN         1
+
+/* GUI_TRAJ_CNTL register constants */
+#define PAT_MONO_8x8_ENABLE     0x01000000
+#define PAT_CLR_4x2_ENABLE      0x02000000
+#define PAT_CLR_8x1_ENABLE      0x04000000
+
+/* DP_CHAIN_MASK register constants */
+#define DP_CHAIN_4BPP          0x8888
+#define DP_CHAIN_7BPP          0xD2D2
+#define DP_CHAIN_8BPP          0x8080
+#define DP_CHAIN_8BPP_RGB      0x9292
+#define DP_CHAIN_15BPP         0x4210
+#define DP_CHAIN_16BPP         0x8410
+#define DP_CHAIN_24BPP         0x8080
+#define DP_CHAIN_32BPP         0x8080
+
+/* DP_PIX_WIDTH register constants */
+#define DST_1BPP                0
+#define DST_4BPP                1
+#define DST_8BPP                2
+#define DST_15BPP               3
+#define DST_16BPP               4
+#define DST_32BPP               6
+#define SRC_1BPP                0
+#define SRC_4BPP                0x100
+#define SRC_8BPP                0x200
+#define SRC_15BPP               0x300
+#define SRC_16BPP               0x400
+#define SRC_32BPP               0x600
+#define HOST_1BPP               0
+#define HOST_4BPP               0x10000
+#define HOST_8BPP               0x20000
+#define HOST_15BPP              0x30000
+#define HOST_16BPP              0x40000
+#define HOST_32BPP              0x60000
+#define BYTE_ORDER_MSB_TO_LSB   0
+#define BYTE_ORDER_LSB_TO_MSB   0x1000000
+
+/* DP_MIX register constants */
+#define BKGD_MIX_NOT_D              0
+#define BKGD_MIX_ZERO               1
+#define BKGD_MIX_ONE                2
+#define BKGD_MIX_D                  3
+#define BKGD_MIX_NOT_S              4
+#define BKGD_MIX_D_XOR_S            5
+#define BKGD_MIX_NOT_D_XOR_S        6
+#define BKGD_MIX_S                  7
+#define BKGD_MIX_NOT_D_OR_NOT_S     8
+#define BKGD_MIX_D_OR_NOT_S         9
+#define BKGD_MIX_NOT_D_OR_S         10
+#define BKGD_MIX_D_OR_S             11
+#define BKGD_MIX_D_AND_S            12
+#define BKGD_MIX_NOT_D_AND_S        13
+#define BKGD_MIX_D_AND_NOT_S        14
+#define BKGD_MIX_NOT_D_AND_NOT_S    15
+#define BKGD_MIX_D_PLUS_S_DIV2      0x17
+#define FRGD_MIX_NOT_D              0
+#define FRGD_MIX_ZERO               0x10000
+#define FRGD_MIX_ONE                0x20000
+#define FRGD_MIX_D                  0x30000
+#define FRGD_MIX_NOT_S              0x40000
+#define FRGD_MIX_D_XOR_S            0x50000
+#define FRGD_MIX_NOT_D_XOR_S        0x60000
+#define FRGD_MIX_S                  0x70000
+#define FRGD_MIX_NOT_D_OR_NOT_S     0x80000
+#define FRGD_MIX_D_OR_NOT_S         0x90000
+#define FRGD_MIX_NOT_D_OR_S         0xa0000
+#define FRGD_MIX_D_OR_S             0xb0000
+#define FRGD_MIX_D_AND_S            0xc0000
+#define FRGD_MIX_NOT_D_AND_S        0xd0000
+#define FRGD_MIX_D_AND_NOT_S        0xe0000
+#define FRGD_MIX_NOT_D_AND_NOT_S    0xf0000
+#define FRGD_MIX_D_PLUS_S_DIV2      0x170000
+
+/* DP_SRC register constants */
+#define BKGD_SRC_BKGD_CLR           0
+#define BKGD_SRC_FRGD_CLR           1
+#define BKGD_SRC_HOST               2
+#define BKGD_SRC_BLIT               3
+#define BKGD_SRC_PATTERN            4
+#define FRGD_SRC_BKGD_CLR           0
+#define FRGD_SRC_FRGD_CLR           0x100
+#define FRGD_SRC_HOST               0x200
+#define FRGD_SRC_BLIT               0x300
+#define FRGD_SRC_PATTERN            0x400
+#define MONO_SRC_ONE                0
+#define MONO_SRC_PATTERN            0x10000
+#define MONO_SRC_HOST               0x20000
+#define MONO_SRC_BLIT               0x30000
+
+/* CLR_CMP_CNTL register constants */
+#define COMPARE_FALSE               0
+#define COMPARE_TRUE                1
+#define COMPARE_NOT_EQUAL           4
+#define COMPARE_EQUAL               5
+#define COMPARE_DESTINATION         0
+#define COMPARE_SOURCE              0x1000000
+
+/* FIFO_STAT register constants */
+#define FIFO_ERR                    0x80000000
+
+/* CONTEXT_LOAD_CNTL constants */
+#define CONTEXT_NO_LOAD             0
+#define CONTEXT_LOAD                0x10000
+#define CONTEXT_LOAD_AND_DO_FILL    0x20000
+#define CONTEXT_LOAD_AND_DO_LINE    0x30000
+#define CONTEXT_EXECUTE             0
+#define CONTEXT_CMD_DISABLE         0x80000000
+
+/* GUI_STAT register constants */
+#define ENGINE_IDLE                 0
+#define ENGINE_BUSY                 1
+#define SCISSOR_LEFT_FLAG           0x10
+#define SCISSOR_RIGHT_FLAG          0x20
+#define SCISSOR_TOP_FLAG            0x40
+#define SCISSOR_BOTTOM_FLAG         0x80
+
+/* ATI VGA Extended Regsiters */
+#define sioATIEXT      0x1ce
+#define bioATIEXT      0x3ce
+
+#define ATI2E          0xae
+#define ATI32          0xb2
+#define ATI36          0xb6
+
+/* VGA Graphics Controller Registers */
+#define VGAGRA         0x3ce
+#define GRA06          0x06
+
+/* VGA Seququencer Registers */
+#define VGASEQ         0x3c4
+#define SEQ02          0x02
+#define SEQ04          0x04
+
+#define MACH64_MAX_X   ENGINE_MAX_X
+#define MACH64_MAX_Y   ENGINE_MAX_Y
+
+#define INC_X           0x0020
+#define INC_Y           0x0080
+
+#define RGB16_555               0x0000
+#define RGB16_565               0x0040
+#define RGB16_655               0x0080
+#define RGB16_664               0x00c0
+
+#define POLY_TEXT_TYPE          0x0001
+#define IMAGE_TEXT_TYPE         0x0002
+#define TEXT_TYPE_8_BIT         0x0004
+#define TEXT_TYPE_16_BIT        0x0008
+#define POLY_TEXT_TYPE_8        (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define IMAGE_TEXT_TYPE_8       (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define POLY_TEXT_TYPE_16       (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
+#define IMAGE_TEXT_TYPE_16      (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
+
+#define MACH64_NUM_CLOCKS      16
+#define MACH64_NUM_FREQS       50
+
+/* Wait until "v" queue entries are free */
+#define aty_WaitQueue(v)    { while ((aty_ld_rev(FIFO_STAT) & 0xffff) > \
+                        ((unsigned short)(0x8000 >> (v)))); }
+
+/* Wait until GP is idle and queue is empty */
+#define aty_WaitIdleEmpty() { aty_WaitQueue(16); \
+                         while ((aty_ld_rev(GUI_STAT) & 1) != 0); }
+
+#define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5))
+
+#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \
+{ \
+    aty_WaitQueue(5); \
+    aty_st_rev(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \
+    aty_st_rev(SRC_WIDTH1, (_w)); \
+    aty_st_rev(DST_CNTL, (_dir)); \
+    aty_st_rev(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \
+    aty_st_rev(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \
+}
+#endif /* REGMACH64_H */
+
diff --git a/drivers/macintosh/control.c b/drivers/macintosh/control.c
new file mode 100644 (file)
index 0000000..fac8b05
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * control.c: Console support for PowerMac "control" display adaptor.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "control.h"
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+       unsigned char addr;
+       char pad1[15];
+       unsigned char d1;
+       char pad2[15];
+       unsigned char d2;
+       char pad3[15];
+       unsigned char lut;
+       char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor".
+ */
+#define PAD(x) char x[12]
+
+struct preg {                  /* padded register */
+       unsigned r;
+       char pad[12];
+};
+
+struct control_regs {
+       struct preg vcount;     /* vertical counter */
+       /* Vertical parameters are in units of 1/2 scan line */
+       struct preg vswin;      /* between vsblank and vssync */
+       struct preg vsblank;    /* vert start blank */
+       struct preg veblank;    /* vert end blank (display start) */
+       struct preg vewin;      /* between vesync and veblank */
+       struct preg vesync;     /* vert end sync */
+       struct preg vssync;     /* vert start sync */
+       struct preg vperiod;    /* vert period */
+       struct preg reg8;
+       /* Horizontal params are in units of 2 pixels */
+       struct preg hperiod;    /* horiz period - 2 */
+       struct preg hsblank;    /* horiz start blank */
+       struct preg heblank;    /* horiz end blank */
+       struct preg hesync;     /* horiz end sync */
+       struct preg hssync;     /* horiz start sync */
+       struct preg rege;
+       struct preg regf;
+       struct preg reg10;
+       struct preg reg11;
+       struct preg ctrl;       /* display control */
+       struct preg start_addr; /* start address: 5 lsbs zero */
+       struct preg pitch;      /* addrs diff between scan lines */
+       struct preg mon_sense;  /* monitor sense bits */
+       struct preg flags;
+       struct preg mode;
+       struct preg reg18;
+       struct preg reg19;
+       struct preg res[6];
+};
+
+static void set_control_clock(unsigned char *params);
+static int read_control_sense(void);
+static int control_vram_reqd(int vmode, int cmode);
+
+static int total_vram;         /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct control_regs *disp_regs;
+static int control_use_bank2;
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+       int     pitch[3];               /* bytes/line, indexed by color_mode */
+       int     offset[3];              /* first pixel address */
+       unsigned regs[16];              /* for vswin .. reg10 */
+       unsigned char mode[3];          /* indexed by color_mode */
+       unsigned char radacal_ctrl[3];
+       unsigned char clock_params[3];
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+       { 1280, 2560, 0 },
+       { 0x10, 0x20, 0 },
+       { 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+         420, 411, 91, 35, 421, 18, 211, 386, },
+       { 1, 1, 1},
+       { 0x50, 0x64, 0x64 },
+       { 13, 56, 3 }   /* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+       { 1280, 2560, 0 },
+       { 0x10, 0x20, 0 },
+       { 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+         418, 409, 89, 35, 419, 18, 210, 384, },
+       { 1, 1, 1 },
+       { 0x50, 0x64, 0x64 },
+       { 31, 125, 3 }  /* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+       { 1152, 2304, 4608 },
+       { 0x10, 0x28, 0x50 },
+       { 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+         726, 705, 129, 63, 727, 32, 364, 664 },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 19, 61, 3 }   /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+         662, 641, 129, 47, 663, 24, 332, 616 },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 11, 28, 3 }   /* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+         670, 653, 141, 67, 671, 34, 336, 604, },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 12, 30, 3 }   /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+       { 1024, 2048, 4096 },
+       { 0x10, 0x28, 0x50 },
+       { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+         670, 653, 141, 67, 671, 34, 336, 604, },
+       { 2, 1, 1 },
+       { 0x10, 0x14, 0x28 },
+       { 15, 31, 3 }   /* pixel clock = 64.58MHz for V=59.62Hz */
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+       { 832, 1664, 3328 },
+       { 0x10, 0x28, 0x50 },
+       { 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+         574, 553, 137, 31, 575, 16, 288, 544 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 23, 42, 3 }   /* pixel clock = 57.07MHz for V=74.27Hz */
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+         526, 513, 113, 39, 527, 20, 264, 488, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 7, 11, 3 }    /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+         518, 485, 85, 59, 519, 30, 260, 460, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 17, 27, 3 }   /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+       { 800, 1600, 3200 },
+       { 0x10, 0x28, 0x50 },
+       { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+         518, 485, 85, 59, 519, 30, 260, 460, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 20, 53, 2 }   /* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+        { 640, 1280, 2560 },
+       { 0x10, 0x30, 0x68 },
+       { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+         0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 9, 33, 2 }    /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+       { 640, 1280, 2560 },
+       { 0, 8, 0x10 },
+       { 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+         430, 393, 73, 31, 431, 16, 216, 400 },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 14, 27, 2 }   /* pixel clock = 30.13MHz for V=66.43Hz */
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+       { 640, 1280, 2560 },
+       { 0x10, 0x28, 0x50 },
+       { 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+         398, 385, 65, 47, 399, 24, 200, 352, },
+       { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+       { 23, 37, 2 }   /* pixel clock = 25.14MHz for V=59.85Hz */
+};
+
+static struct control_regvals *control_reg_init[20] = {
+       NULL, NULL, NULL, NULL,
+       &control_reg_init_5,
+       &control_reg_init_6,
+       &control_reg_init_7,
+       NULL, NULL,
+       &control_reg_init_10,
+       &control_reg_init_11,
+       &control_reg_init_12,
+       &control_reg_init_13,
+       &control_reg_init_14,
+       &control_reg_init_15,
+       NULL,
+       &control_reg_init_17,
+       &control_reg_init_18,
+       &control_reg_init_19,
+       &control_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_control_sense()
+{
+       int sense;
+
+       out_le32(&disp_regs->mon_sense.r, 7);   /* drive all lines high */
+       __delay(200);
+       out_le32(&disp_regs->mon_sense.r, 077); /* turn off drivers */
+       __delay(2000);
+       sense = (in_le32(&disp_regs->mon_sense.r) & 0x1c0) << 2;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       out_le32(&disp_regs->mon_sense.r, 033); /* drive A low */
+       __delay(2000);
+       sense |= (in_le32(&disp_regs->mon_sense.r) & 0xc0) >> 2;
+       out_le32(&disp_regs->mon_sense.r, 055); /* drive B low */
+       __delay(2000);
+       sense |= ((in_le32(&disp_regs->mon_sense.r) & 0x100) >> 5)
+               | ((in_le32(&disp_regs->mon_sense.r) & 0x40) >> 4);
+       out_le32(&disp_regs->mon_sense.r, 066); /* drive C low */
+       __delay(2000);
+       sense |= (in_le32(&disp_regs->mon_sense.r) & 0x180) >> 7;
+
+       out_le32(&disp_regs->mon_sense.r, 077); /* turn off drivers */
+       return sense;
+}
+
+static inline int control_vram_reqd(int vmode, int cmode)
+{
+       return vmode_attrs[vmode-1].vres
+               * control_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_control_display(struct device_node *dp)
+{
+       int i, sense;
+       unsigned long addr, size;
+       int bank1, bank2;
+
+       if (dp->next != 0)
+               printk("Warning: only using first control display device\n");
+       if (dp->n_addrs != 2)
+               panic("expecting 2 addresses for control (got %d)", dp->n_addrs);
+
+#if 0
+       printk("pmac_display_init: node = %p, addrs =", dp->node);
+       for (i = 0; i < dp->n_addrs; ++i)
+               printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+       printk(", intrs =");
+       for (i = 0; i < dp->n_intrs; ++i)
+               printk(" %x", dp->intrs[i]);
+       printk("\n");
+#endif
+
+       /* Map in frame buffer and registers */
+       for (i = 0; i < dp->n_addrs; ++i) {
+               addr = dp->addrs[i].address;
+               size = dp->addrs[i].size;
+               if (size >= 0x800000) {
+                       /* use the big-endian aperture (??) */
+                       addr += 0x800000;
+                       /* map at most 8MB for the frame buffer */
+                       frame_buffer = ioremap(addr, 0x800000);
+               } else {
+                       disp_regs = ioremap(addr, size);
+               }
+       }
+       cmap_regs = ioremap(0xf301b000, 0x1000);        /* XXX not in prom? */
+
+       /* Work out which banks of VRAM we have installed. */
+       frame_buffer[0] = 0x5a;
+       frame_buffer[1] = 0xc7;
+       bank1 = frame_buffer[0] == 0x5a && frame_buffer[1] == 0xc7;
+       frame_buffer[0x600000] = 0xa5;
+       frame_buffer[0x600001] = 0x38;
+       bank2 = frame_buffer[0x600000] == 0xa5 && frame_buffer[0x600001] == 0x38;
+       total_vram = (bank1 + bank2) * 0x200000;
+       /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+       control_use_bank2 = !bank1;
+       if (control_use_bank2)
+               frame_buffer += 0x600000;
+
+       sense = read_control_sense();
+       if (video_mode == VMODE_NVRAM) {
+               video_mode = nvram_read_byte(NV_VMODE);
+               if (video_mode <= 0 || video_mode > VMODE_MAX
+                   || control_reg_init[video_mode-1] == 0)
+                       video_mode = VMODE_CHOOSE;
+       }
+       if (video_mode == VMODE_CHOOSE)
+               video_mode = map_monitor_sense(sense);
+       if (control_reg_init[video_mode-1] == 0)
+               video_mode = VMODE_640_480_60;
+
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       if (color_mode == CMODE_NVRAM)
+               color_mode = nvram_read_byte(NV_CMODE);
+       if (color_mode < CMODE_8 || color_mode > CMODE_32)
+               color_mode = CMODE_8;
+       while (color_mode > CMODE_8
+              && control_vram_reqd(video_mode, color_mode) > total_vram)
+               --color_mode;
+
+       printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_control_clock(unsigned char *params)
+{
+       struct cuda_request req;
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+                            0x50, i + 1, params[i]);
+               while (!req.got_reply)
+                       cuda_poll();
+       }
+}
+
+void
+control_init()
+{
+       struct preg *rp;
+       int i, yoff, hres;
+       int ctrl, flags;
+       unsigned *p;
+       struct control_regvals *init;
+
+       if (video_mode <= 0 || video_mode > VMODE_MAX
+           || (init = control_reg_init[video_mode-1]) == 0)
+               panic("control: display mode %d not supported", video_mode);
+       n_scanlines = vmode_attrs[video_mode-1].vres;
+       hres = vmode_attrs[video_mode-1].hres;
+       pixel_size = 1 << color_mode;
+       line_pitch = init->pitch[color_mode];
+       row_pitch = line_pitch * 16;
+
+       if (control_vram_reqd(video_mode, color_mode) > 0x200000)
+               flags = 0x51;
+       else if (control_use_bank2)
+               flags = 0x39;
+       else
+               flags = 0x31;
+       if (video_mode >= VMODE_1280_960_75 && color_mode >= CMODE_16)
+               ctrl = 0x7f;
+       else
+               ctrl = 0x3b;
+
+       /* Initialize display timing registers */
+       out_le32(&disp_regs->ctrl.r, 0x43b);
+       set_control_clock(init->clock_params);
+       cmap_regs->addr = 0x20; cmap_regs->d2 = init->radacal_ctrl[color_mode];
+       cmap_regs->addr = 0x21; cmap_regs->d2 = control_use_bank2? 0: 1;
+       cmap_regs->addr = 0x10; cmap_regs->d2 = 0;
+       cmap_regs->addr = 0x11; cmap_regs->d2 = 0;
+       rp = &disp_regs->vswin;
+       for (i = 0; i < 16; ++i, ++rp)
+               out_le32(&rp->r, init->regs[i]);
+       out_le32(&disp_regs->pitch.r, line_pitch);
+       out_le32(&disp_regs->mode.r, init->mode[color_mode]);
+       out_le32(&disp_regs->flags.r, flags);
+       out_le32(&disp_regs->start_addr.r, 0);
+       out_le32(&disp_regs->reg18.r, 0x1e5);
+       out_le32(&disp_regs->reg19.r, 0);
+
+       pmac_init_palette();    /* Initialize colormap */
+
+       /* Turn on display */
+       out_le32(&disp_regs->ctrl.r, ctrl);
+
+       yoff = (n_scanlines % 16) / 2;
+       fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+       /* Clear screen */
+       p = (unsigned *) (frame_buffer + init->offset[color_mode]);
+       for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+               *p++ = 0;
+
+       display_info.height = n_scanlines;
+       display_info.width = hres;
+       display_info.depth = pixel_size * 8;
+       display_info.pitch = line_pitch;
+       display_info.mode = video_mode;
+       strncpy(display_info.name, "control", sizeof(display_info.name));
+       display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+       display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+control_setmode(struct vc_mode *mode, int doit)
+{
+       int cmode;
+
+       if (mode->mode <= 0 || mode->mode > VMODE_MAX
+           || control_reg_init[mode->mode-1] == 0)
+               return -EINVAL;
+       switch (mode->depth) {
+       case 24:
+       case 32:
+               cmode = CMODE_32;
+               break;
+       case 16:
+               cmode = CMODE_16;
+               break;
+       case 8:
+       case 0:         /* (default) */
+               cmode = CMODE_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (control_vram_reqd(mode->mode, cmode) > total_vram)
+               return -EINVAL;
+       if (doit) {
+               video_mode = mode->mode;
+               color_mode = cmode;
+               control_init();
+       }
+       return 0;
+}
+
+void
+control_set_palette(unsigned char red[], unsigned char green[],
+                   unsigned char blue[], int index, int ncolors)
+{
+       int i;
+
+       for (i = 0; i < ncolors; ++i) {
+               cmap_regs->addr = index + i;    eieio();
+               cmap_regs->lut = red[i];        eieio();
+               cmap_regs->lut = green[i];      eieio();
+               cmap_regs->lut = blue[i];       eieio();
+       }
+}
+
+void
+control_set_blanking(int blank_mode)
+{
+       int ctrl;
+
+       ctrl = ld_le32(&disp_regs->ctrl.r) | 0x33;
+       if (blank_mode & VESA_VSYNC_SUSPEND)
+               ctrl &= ~3;
+       if (blank_mode & VESA_HSYNC_SUSPEND)
+               ctrl &= ~0x30;
+       out_le32(&disp_regs->ctrl.r, ctrl);
+}
diff --git a/drivers/macintosh/control.h b/drivers/macintosh/control.h
new file mode 100644 (file)
index 0000000..edf87fe
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 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.
+ */
+
+extern void map_control_display(struct device_node *);
+extern void control_init(void);
+extern int control_setmode(struct vc_mode *mode, int doit);
+extern void control_set_palette(unsigned char red[], unsigned char green[],
+                               unsigned char blue[], int index, int ncolors);
+extern void control_set_blanking(int blank_mode);
diff --git a/drivers/macintosh/imstt.c b/drivers/macintosh/imstt.c
new file mode 100644 (file)
index 0000000..2f74a15
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * imstt.c: Console support for PowerMac "imstt" display adaptor.
+ *
+ * Copyright (C) 1997 Sigurdur Asgeirsson
+ *     
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "imstt.h"
+
+enum
+{
+  S1SA         =  0, /* 0x00 */
+  S2SA         =  1, /* 0x04 */
+  SP           =  2, /* 0x08 */
+  DSA          =  3, /* 0x0C */
+  CNT          =  4, /* 0x10 */
+  DP_OCTRL     =  5, /* 0x14 */
+  BLTCTL       = 10, /* 0x28 */
+               
+  //   Scan Timing Generator Registers
+  HES          = 12, /* 0x30 */
+  HEB          = 13, /* 0x34 */
+  HSB          = 14, /* 0x38 */
+  HT           = 15, /* 0x3C */
+  VES          = 16, /* 0x40 */
+  VEB          = 17, /* 0x44 */
+  VSB          = 18, /* 0x48 */
+  VT           = 19, /* 0x4C */
+  HCIV         = 20, /* 0x50 */
+  VCIV         = 21, /* 0x54 */
+  TCDR         = 22, /* 0x58 */
+  VIL          = 23, /* 0x5C */
+  STGCTL       = 24, /* 0x60 */
+       
+  //   Screen Refresh Generator Registers
+  SSR          = 25, /* 0x64 */
+  HRIR         = 26, /* 0x68 */
+  SPR          = 27, /* 0x6C */
+  CMR          = 28, /* 0x70 */
+  SRGCTL       = 29, /* 0x74 */
+               
+  //   RAM Refresh Generator Registers
+  RRCIV                = 30, /* 0x78 */
+  RRSC         = 31, /* 0x7C */
+  RRCR         = 34, /* 0x88 */
+               
+  //   System Registers
+  GIOE         = 32, /* 0x80 */
+  GIO          = 33, /* 0x84 */
+  SCR          = 35, /* 0x8C */
+  SSTATUS      = 36, /* 0x90 */
+  PRC          = 37, /* 0x94 */
+
+#if 0  
+  //   PCI Registers
+  DVID         = 0x00000000L,
+  SC           = 0x00000004L,
+  CCR          = 0x00000008L,
+  OG           = 0x0000000CL,
+  BARM         = 0x00000010L,
+  BARER                = 0x00000030L,
+#endif
+};
+
+enum
+{
+ PADDRW                = 0x00,
+ PDATA         = 0x04,
+ PPMASK                = 0x08,
+ PADDRR                = 0x0C,
+ PIDXLO                = 0x10, 
+ PIDXHI                = 0x14, 
+ PIDXDATA      = 0x18,
+ PIDXCTL       = 0x1C,
+
+ PPIXREP       = 0x0A,
+ PM0           = 0x20,
+ PN0           = 0x21,
+ PP0           = 0x22,
+ PC0           = 0x23
+};
+
+struct initvalues
+{
+  unsigned char        addr, value;
+};
+
+static struct initvalues initregs[] = 
+{
+ { 0x02, 0x21 },       /* (0x01) Miscellaneous Clock Control */
+ { 0x03, 0x00 },       /* (0x00) Sync Control */
+ { 0x04, 0x00 },       /* (0x00) Horizontal Sync Position */
+ { 0x05, 0x00 },       /* (0x00) Power Management */
+ { 0x06, 0x0B },       /* (0x02) DAC Operation */
+ { 0x07, 0x00 },       /* (0x00) Palette Control */
+ { 0x08, 0x01 },       /* (0x01) System Clock Control */
+ { 0x0B, 0x00 },       /* (U) 8 BPP Control */
+ { 0x0C, 0xC4 },       /* (U) 16 BPP Control */
+ { 0x0D, 0x00 },       /* (U) 24 BPP Packed Control */
+ { 0x0E, 0x03 },       /* (U) 32 BPP Control */
+ { 0x10, 0x05 },       /* (0x00) Pixel PLL Control 1 */
+ { 0x11, 0x00 },       /* (0x00) Pixel PLL Control 2 */
+ { 0x15, 0x08 },       /* (0x08) SYSCLK N (System PLL Reference Divider) */
+ { 0x16, 0x57 },       /* (0x41) SYSCLK M (System PLL VCO Divider) */
+ { 0x17, 0x00 },       /* (U) SYSCLK P */
+ { 0x18, 0x00 },       /* (U) SYSCLK C */
+ { 0x30, 0x00 },       /* (0x00) Cursor Control */
+ { 0x60, 0xFF },       /* (U) Border Color Red */
+ { 0x61, 0xFF },       /* (U) Border Color Green */
+ { 0x62, 0xFF },       /* (U) Border Color Blue */
+ { 0x70, 0x01 },       /* (0x00) Miscellaneous Control 1 */
+ { 0x71, 0x45 },       /* (0x00) Miscellaneous Control 2 */
+ { 0x72, 0x00 },       /* (0x00) Miscellaneous Control 3 */
+ { 0x78, 0x00 },       /* (0x00) Key Control/DB Operation */
+};
+
+static void set_imstt_clock(unsigned char *params);
+static int read_imstt_sense(void);
+static int imstt_vram_reqd(int vmode, int cmode);
+
+static int total_vram = 2 * 1024 * 1024;               /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *cmap_regs;
+static unsigned *dc_regs;
+
+
+/*
+ * Register initialization tables for the imstt display.
+ *
+ * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
+ * where m = clk[0], n = clk[1], p = clk[2]
+ * clk[3] is c, charge pump bias which depends on the VCO frequency  
+ */
+struct imstt_regvals {
+       unsigned short          cfg[8];
+       unsigned char           clk[4];
+       unsigned long           pitch[3];
+} imsttmode;
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct imstt_regvals imstt_reg_init_17 = {
+  { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 }, 
+  { 0x07, 0x00, 0x01, 0x02 },
+  { 0x0400, 0x0800, 0x1000 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct imstt_regvals imstt_reg_init_13 = {
+  { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
+  { 0x3E, 0x0A, 0x01, 0x02 },
+  { 832, 832 * 2, 832 * 4 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct imstt_regvals imstt_reg_init_6 = {
+  { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
+  { 0x78, 0x13, 0x02, 0x02 },
+  { 640, 640 * 2, 640 * 4 }
+};
+
+static struct imstt_regvals *imstt_reg_init[20] = {
+       NULL, NULL, NULL, NULL,
+       &imstt_reg_init_6, // fake'm out
+       &imstt_reg_init_6,
+       NULL, NULL, NULL,
+       NULL, NULL, NULL,
+       &imstt_reg_init_13,
+       NULL, NULL, NULL,
+       &imstt_reg_init_17,
+       NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_imstt_sense()
+{
+#if 0
+       int sense;
+       unsigned gio, gioe;
+
+       gio = ld_le32(dc_regs + GIO) & ~0x0038;
+       gioe = ld_le32(dc_
+       
+       out_le32(dc_regs + GIOE, reg);  /* drive all lines high */
+       __delay(200);
+       out_le32(dc_regs + GIOE, 077);  /* turn off drivers */
+       __delay(2000);
+       sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       out_le32(dc_regs + GIOE, 033);  /* drive A low */
+       __delay(2000);
+       sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2;
+       out_le32(dc_regs + GIOE, 055);  /* drive B low */
+       __delay(2000);
+       sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5)
+               | ((in_le32(dc_regs + GIOE) & 0x40) >> 4);
+       out_le32(dc_regs + GIOE, 066);  /* drive C low */
+       __delay(2000);
+       sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7;
+
+       out_le32(dc_regs + GIOE, 077);  /* turn off drivers */
+       return sense;
+#else
+       return 0;
+#endif
+}
+
+static inline int imstt_vram_reqd(int vmode, int cmode)
+{
+       return vmode_attrs[vmode-1].vres
+               * imstt_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_imstt_display(struct device_node *dp)
+{
+       int i, sense;
+       unsigned long addr, size, tmp;
+       unsigned char bus, devfn;
+       unsigned short cmd;
+
+       if (dp->next != 0)
+               printk("Warning: only using first imstt display device\n");
+
+#if 1
+       printk("pmac_display_init: node = %p, addrs =", dp->node);
+       for (i = 0; i < dp->n_addrs; ++i)
+               printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+       printk(", intrs =");
+       for (i = 0; i < dp->n_intrs; ++i)
+               printk(" %x", dp->intrs[i]);
+       printk("\n");
+#endif
+
+       /* Map in frame buffer and registers */
+       for (i = 0; i < dp->n_addrs; ++i) {
+               addr = dp->addrs[i].address;
+               size = dp->addrs[i].size;
+               if (size >= 0x02000000) {
+                       frame_buffer = ioremap(addr, size);
+                       dc_regs = (unsigned*)(frame_buffer + 0x00800000);
+                       cmap_regs = (unsigned char*)(frame_buffer + 0x00840000);
+
+                       printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size);
+                       printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs);
+               }
+       }
+
+       /* enable memory-space accesses using config-space command register */
+       if (pci_device_loc(dp, &bus, &devfn) == 0) {
+         pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+         
+         printk("command word 0x%04X\n", cmd);
+         
+         if (cmd != 0xffff) {
+           cmd |= PCI_COMMAND_MEMORY;
+           pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+         }
+       }
+       else
+         printk("unable to find pci device\n");
+
+       tmp = in_le32(dc_regs + SSTATUS);
+       printk("chip version %ld, ", (tmp & 0x0F00) >> 8);
+
+       tmp = in_le32(dc_regs + PRC);
+       total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
+       printk("VRAM size %ldM\n", total_vram / 0x000100000L);
+
+       sense = read_imstt_sense();
+       printk("Monitor sense value = 0x%x, ", sense);
+#if 0
+       if (video_mode == VMODE_NVRAM) {
+               video_mode = nvram_read_byte(NV_VMODE);
+               if (video_mode <= 0 || video_mode > VMODE_MAX
+                   || imstt_reg_init[video_mode-1] == 0)
+                       video_mode = VMODE_CHOOSE;
+       }
+       if (video_mode == VMODE_CHOOSE)
+               video_mode = map_monitor_sense(sense);
+       if (imstt_reg_init[video_mode-1] == 0)
+               video_mode = VMODE_640_480_67;
+
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       if (color_mode == CMODE_NVRAM)
+               color_mode = nvram_read_byte(NV_CMODE);
+       if (color_mode < CMODE_8 || color_mode > CMODE_32)
+               color_mode = CMODE_8;
+       while (color_mode > CMODE_8
+              && imstt_vram_reqd(video_mode, color_mode) > total_vram)
+               --color_mode;
+
+#endif
+
+       video_mode = VMODE_640_480_67;
+       color_mode = CMODE_8;
+}
+
+static void
+set_imstt_clock(unsigned char *params)
+{
+  cmap_regs[PIDXHI] = 0; eieio();
+  cmap_regs[PIDXLO] = PM0; eieio();
+  cmap_regs[PIDXDATA] = params[0]; eieio();
+
+  cmap_regs[PIDXLO] = PN0; eieio();
+  cmap_regs[PIDXDATA] = params[1]; eieio();
+
+  cmap_regs[PIDXLO] = PP0; eieio();
+  cmap_regs[PIDXDATA] = params[2]; eieio();
+       
+  cmap_regs[PIDXLO] = PC0; eieio();
+  cmap_regs[PIDXDATA] = params[3]; eieio();
+}
+
+void
+imstt_init()
+{
+  int                   i, yoff, hres;
+  unsigned long                 ctl, pitch, tmp;
+  unsigned char                 pformat;
+  unsigned               *p;
+  struct imstt_regvals   *init;
+
+  if (video_mode <= 0 || video_mode > VMODE_MAX
+      || (init = imstt_reg_init[video_mode-1]) == 0)
+    panic("imstt: display mode %d not supported", video_mode);
+
+  n_scanlines = vmode_attrs[video_mode-1].vres;
+  hres = vmode_attrs[video_mode-1].hres;
+  pixel_size = 1 << color_mode;
+  line_pitch = init->pitch[color_mode];
+  row_pitch = line_pitch * 16;
+
+  /* initialize the card */
+  tmp = in_le32(dc_regs + STGCTL);
+  out_le32(dc_regs + STGCTL, tmp & ~0x1);
+#if 0
+  out_le32(dc_regs + SCR, 0);
+#endif
+
+  cmap_regs[PPMASK] = 0xFF;
+  /* set default values for DAC registers */ 
+  cmap_regs[PIDXHI] = 0; eieio();
+  for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) {
+    cmap_regs[PIDXLO] = initregs[i].addr; eieio();
+    cmap_regs[PIDXDATA] = initregs[i].value; eieio();
+  }
+  set_imstt_clock(init->clk);
+
+  switch(color_mode) {
+  case CMODE_32:
+    ctl = 0x17b5;
+    pitch = init->pitch[2] / 4;
+    pformat = 0x06;
+    break;
+  case CMODE_16:
+    ctl = 0x17b3;
+    pitch = init->pitch[1] / 4;
+    pformat = 0x04;
+    break;
+  case CMODE_8:
+  default:
+    ctl = 0x17b1;
+    pitch = init->pitch[0] / 4;
+    pformat = 0x03;
+    break;
+  }
+
+  out_le32(&dc_regs[HES], init->cfg[0]);
+  out_le32(&dc_regs[HEB], init->cfg[1]);
+  out_le32(&dc_regs[HSB], init->cfg[2]);
+  out_le32(&dc_regs[HT], init->cfg[3]);
+  out_le32(&dc_regs[VES], init->cfg[4]);
+  out_le32(&dc_regs[VEB], init->cfg[5]);
+  out_le32(&dc_regs[VSB], init->cfg[6]);
+  out_le32(&dc_regs[VT], init->cfg[7]);
+  out_le32(&dc_regs[HCIV], 1);
+  out_le32(&dc_regs[VCIV], 1);
+  out_le32(&dc_regs[TCDR], 4);
+  out_le32(&dc_regs[VIL], 0);
+       
+  out_le32(&dc_regs[SSR], 0);
+  out_le32(&dc_regs[HRIR], 0x0200);
+  out_le32(&dc_regs[CMR], 0x01FF);
+  out_le32(&dc_regs[SRGCTL], 0x0003);
+  if(total_vram == 0x000200000)
+     out_le32(&dc_regs[SCR], 0x0059D);
+  else {
+    pitch /= 2;
+    out_le32(&dc_regs[SCR], 0x00D0DC);
+  }
+
+  out_le32(&dc_regs[SPR], pitch);
+
+  cmap_regs[PIDXLO] = PPIXREP; eieio();
+  cmap_regs[PIDXDATA] = pformat; eieio();
+
+
+  pmac_init_palette(); /* Initialize colormap */
+
+  out_le32(&dc_regs[STGCTL], ctl);
+
+  yoff = (n_scanlines % 16) / 2;
+  fb_start = frame_buffer + yoff * line_pitch;
+
+  /* Clear screen */
+  p = (unsigned *)frame_buffer;
+  for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+    *p++ = 0;
+
+  display_info.height = n_scanlines;
+  display_info.width = hres;
+  display_info.depth = pixel_size * 8;
+  display_info.pitch = line_pitch;
+  display_info.mode = video_mode;
+  strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
+  display_info.fb_address = (unsigned long) frame_buffer;
+  display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW];
+  display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA];
+  display_info.disp_reg_address = (unsigned long) NULL;
+}
+
+int
+imstt_setmode(struct vc_mode *mode, int doit)
+{
+       int cmode;
+
+       if (mode->mode <= 0 || mode->mode > VMODE_MAX
+           || imstt_reg_init[mode->mode-1] == 0)
+               return -EINVAL;
+       switch (mode->depth) {
+       case 24:
+       case 32:
+               cmode = CMODE_32;
+               break;
+       case 16:
+               cmode = CMODE_16;
+               break;
+       case 8:
+       case 0:         /* (default) */
+               cmode = CMODE_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (imstt_vram_reqd(mode->mode, cmode) > total_vram)
+               return -EINVAL;
+       if (doit) {
+               video_mode = mode->mode;
+               color_mode = cmode;
+               imstt_init();
+       }
+       return 0;
+}
+
+void
+imstt_set_palette(unsigned char red[], unsigned char green[],
+                   unsigned char blue[], int index, int ncolors)
+{
+       int i;
+
+       for (i = 0; i < ncolors; ++i) {
+               cmap_regs[PADDRW] = index + i;  eieio();
+               cmap_regs[PDATA] = red[i];      eieio();
+               cmap_regs[PDATA] = green[i];    eieio();
+               cmap_regs[PDATA] = blue[i];     eieio();
+       }
+}
+
+void
+imstt_set_blanking(int blank_mode)
+{
+       long ctrl;
+
+       ctrl = ld_le32(dc_regs + STGCTL) | 0x0030;
+       if (blank_mode & VESA_VSYNC_SUSPEND)
+               ctrl &= ~0x0020;
+       if (blank_mode & VESA_HSYNC_SUSPEND)
+               ctrl &= ~0x0010;
+       out_le32(dc_regs + STGCTL, ctrl);
+}
diff --git a/drivers/macintosh/imstt.h b/drivers/macintosh/imstt.h
new file mode 100644 (file)
index 0000000..853e8f0
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 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.
+ */
+
+extern void map_imstt_display(struct device_node *);
+extern void imstt_init(void);
+extern int imstt_setmode(struct vc_mode *mode, int doit);
+extern void imstt_set_palette(unsigned char red[], unsigned char green[],
+                               unsigned char blue[], int index, int ncolors);
+extern void imstt_set_blanking(int blank_mode);
+
diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
new file mode 100644 (file)
index 0000000..fbb39d7
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * drivers/char/mac_keyb.c
+ *
+ * Keyboard driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/char/keyboard.c by Paul Mackerras
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/cuda.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+
+#define KEYB_KEYREG    0       /* register # for key up/down data */
+#define KEYB_LEDREG    2       /* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG  0       /* reg# for movement/button codes from mouse */
+
+unsigned char kbd_read_mask = 0;       /* XXX */
+
+static void kbd_repeat(unsigned long);
+static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static int last_keycode;
+
+static void keyboard_input(unsigned char *, int, struct pt_regs *);
+static void input_keycode(int, int);
+static void leds_done(struct cuda_request *);
+
+extern struct kbd_struct kbd_table[];
+
+extern void handle_scancode(unsigned char);
+extern void put_queue(int);
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */
+       0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       return -EINVAL;
+}
+
+int mackbd_getkeycode(unsigned int scancode)
+{
+       return -EINVAL;
+}
+
+int mackbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+       return 1;
+}
+
+int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
+                    char raw_mode)
+{
+       if (!raw_mode) {
+               /*
+                * Convert R-shift/control/option to L version.
+                * Remap keycode 0 (A) to the unused keycode 0x5a.
+                * Other parts of the system assume 0 is not a valid keycode.
+                */
+               switch (keycode) {
+               case 0x7b: keycode = 0x38; break; /* R-shift */
+               case 0x7c: keycode = 0x3a; break; /* R-option */
+               case 0x7d: keycode = 0x36; break; /* R-control */
+               case 0:    keycode = 0x5a; break; /* A */
+               }
+       }
+       *keycodep = keycode;
+       return 1;
+}
+
+int mackbd_unexpected_up(unsigned char keycode)
+{
+       return 0x80;
+}
+
+static void
+keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+       /* first check this is from register 0 */
+       if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
+               return;         /* ignore it */
+       kbd_pt_regs = regs;
+       input_keycode(data[3], 0);
+       if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
+               input_keycode(data[4], 0);
+}
+
+static void
+input_keycode(int keycode, int repeat)
+{
+       struct kbd_struct *kbd;
+       int up_flag;
+
+       kbd = kbd_table + fg_console;
+       up_flag = (keycode & 0x80);
+        keycode &= 0x7f;
+       if (!repeat)
+               del_timer(&repeat_timer);
+
+       if (kbd->kbdmode != VC_RAW) {
+               if (!up_flag && !dont_repeat[keycode]) {
+                       last_keycode = keycode;
+                       repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
+                       add_timer(&repeat_timer);
+               }
+
+               /*
+                * XXX fix caps-lock behaviour by turning the key-up
+                * transition into a key-down transition.
+                */
+               if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
+                       up_flag = 0;
+       }
+
+       handle_scancode(keycode + up_flag);
+}
+
+static void
+kbd_repeat(unsigned long xxx)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       input_keycode(last_keycode, 1);
+       restore_flags(flags);
+}
+
+static void
+mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+  /* [ACA:23-Mar-97] Three button mouse support.  This is designed to
+     function with MkLinux DR-2.1 style X servers.  It only works with
+     three-button mice that conform to Apple's multi-button mouse
+     protocol. */
+
+  /*
+    The X server for MkLinux DR2.1 uses the following unused keycodes to
+    read the mouse:
+
+    0x7e  This indicates that the next two keycodes should be interpreted
+          as mouse information.  The first following byte's high bit
+          represents the state of the left button.  The lower seven bits
+          represent the x-axis acceleration.  The lower seven bits of the
+          second byte represent y-axis acceleration.
+
+    0x3f  The x server interprets this keycode as a middle button
+          release.
+
+    0xbf  The x server interprets this keycode as a middle button
+          depress.
+
+    0x40  The x server interprets this keycode as a right button
+          release.
+
+    0xc0  The x server interprets this keycode as a right button
+          depress.
+
+    NOTES: There should be a better way of handling mice in the X server.
+    The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
+    of two.  The three mouse buttons should then, in the X server, be read
+    as the high-bits of all three bytes.  The x and y motions can still be
+    in the first two bytes.  Maybe I'll do this...
+  */
+
+  /*
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+               BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = 0100 0000 Extended protocol register.
+             Bits 6-7 are the device id, which should be 1.
+             Bits 4-5 are resolution which is in "units/inch".
+             The Logitech MouseMan returns these bits clear but it has
+             200/300cpi resolution.
+             Bits 0-3 are unique vendor id.
+    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+             Bits 2-3 should be 8 + 4.
+                     Bits 4-7 should be 3 for a mouse device.
+    data[3] = bxxx xxxx Left button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+    data[5] = byyy bxxx Third button and fourth button.  Y is additional
+             high bits of y-axis motion.  XY is additional
+             high bits of x-axis motion.
+
+    NOTE: data[0] and data[2] are confirmed by the parent function and
+    need not be checked here.
+  */
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = ???? ???? (?)
+    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+    data[3] = bxxx xxxx First button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+
+    NOTE: data[0] is confirmed by the parent function and need not be
+    checked here.
+  */
+       struct kbd_struct *kbd;
+
+       kbd = kbd_table + fg_console;
+
+       /* Only send mouse codes when keyboard is in raw mode. */
+       if (kbd->kbdmode == VC_RAW) {
+               static unsigned char uch_ButtonStateSecond = 0;
+               unsigned char uchButtonSecond;
+
+               /* Send first button, second button and movement. */
+               put_queue( 0x7e );
+               put_queue( data[3] );
+               put_queue( data[4] );
+
+               /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
+
+               /* Store the button state. */
+               uchButtonSecond = (data[4] & 0x80);
+
+               /* Send second button. */
+               if (uchButtonSecond != uch_ButtonStateSecond) {
+                       put_queue( 0x3f | uchButtonSecond );
+                       uch_ButtonStateSecond = uchButtonSecond;
+               }
+
+               /* Macintosh 3-button mouse (handler 4). */
+               if ((nb == 6) && (data[1] & 0x40)) {
+                       static unsigned char uch_ButtonStateThird = 0;
+                       unsigned char uchButtonThird;
+
+                       /* Store the button state for speed. */
+                       uchButtonThird = (data[5] & 0x80);
+
+                       /* Send third button. */
+                       if (uchButtonThird != uch_ButtonStateThird) {
+                               put_queue( 0x40 | uchButtonThird );
+                               uch_ButtonStateThird = uchButtonThird;
+                       }
+               }
+       }
+}
+
+/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
+static unsigned char mac_ledmap[8] = {
+    0,         /* none */
+    4,         /* scroll lock */
+    1,         /* num lock */
+    5,         /* scroll + num lock */
+    2,         /* caps lock */
+    6,         /* caps + scroll lock */
+    3,         /* caps + num lock */
+    7,         /* caps + num + scroll lock */
+};
+
+static struct cuda_request led_request;
+static int leds_pending;
+
+void mackbd_leds(unsigned char leds)
+{
+       if (led_request.got_reply) {
+               cuda_request(&led_request, leds_done, 4, ADB_PACKET,
+                            ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
+                            0xff, ~mac_ledmap[leds]);
+       } else
+               leds_pending = leds | 0x100;
+}
+
+static void leds_done(struct cuda_request *req)
+{
+       int leds;
+
+       if (leds_pending) {
+               leds = leds_pending & 0xff;
+               leds_pending = 0;
+               mackbd_leds(leds);
+       }
+}
+
+void mackbd_init_hw(void)
+{
+       struct cuda_request req;
+
+       adb_register(ADB_KEYBOARD, keyboard_input);
+       adb_register(ADB_MOUSE, mouse_input);
+
+       /* turn on ADB auto-polling in the CUDA */
+       cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+       while (!req.got_reply)
+           cuda_poll();
+
+       /* turn off all leds */
+       cuda_request(&req, NULL, 4, ADB_PACKET,
+                    ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff);
+       while (!req.got_reply)
+           cuda_poll();
+
+       /* get the keyboard to send separate codes for
+          left and right shift, control, option keys. */
+       cuda_request(&req, NULL, 4, ADB_PACKET,
+                    ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+       while (!req.got_reply)
+           cuda_poll();
+
+       led_request.got_reply = 1;
+
+       /* Try to switch the mouse (id 3) to handler 4, for three-button
+          mode. (0x20 is Service Request Enable, 0x03 is Device ID). */
+       cuda_request(&req, NULL, 4, ADB_PACKET,
+                    ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+       while (!req.got_reply)
+               cuda_poll();
+}
+
diff --git a/drivers/macintosh/mackeymap.c b/drivers/macintosh/mackeymap.c
new file mode 100644 (file)
index 0000000..3f1eedc
--- /dev/null
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+       0xf200, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+       0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+       0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+       0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+       0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+       0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+       0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+       0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+       0xf200, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+       0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+       0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+       0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+       0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+       0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+       0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+       0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+       0xf200, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+       0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+       0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+       0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+       0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+       0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+       0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+       0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+       0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+       0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+       0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+       0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+       0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+       0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+       0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+       0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+       0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+       0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+       0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+       0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+       0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+       0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c,
+};
+
+u_short alt_map[NR_KEYS] = {
+       0xf200, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+       0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+       0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+       0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+       0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+       0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+       0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+       0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+       0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+       0xf200, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+       0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+       0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+       0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+       0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+       0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+       plain_map, shift_map, altgr_map, 0,
+       ctrl_map, shift_ctrl_map, 0, 0,
+       alt_map, 0, 0, 0,
+       ctrl_alt_map,   0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+       '\033', '[', '[', 'A', 0, 
+       '\033', '[', '[', 'B', 0, 
+       '\033', '[', '[', 'C', 0, 
+       '\033', '[', '[', 'D', 0, 
+       '\033', '[', '[', 'E', 0, 
+       '\033', '[', '1', '7', '~', 0, 
+       '\033', '[', '1', '8', '~', 0, 
+       '\033', '[', '1', '9', '~', 0, 
+       '\033', '[', '2', '0', '~', 0, 
+       '\033', '[', '2', '1', '~', 0, 
+       '\033', '[', '2', '3', '~', 0, 
+       '\033', '[', '2', '4', '~', 0, 
+       '\033', '[', '2', '5', '~', 0, 
+       '\033', '[', '2', '6', '~', 0, 
+       '\033', '[', '2', '8', '~', 0, 
+       '\033', '[', '2', '9', '~', 0, 
+       '\033', '[', '3', '1', '~', 0, 
+       '\033', '[', '3', '2', '~', 0, 
+       '\033', '[', '3', '3', '~', 0, 
+       '\033', '[', '3', '4', '~', 0, 
+       '\033', '[', '1', '~', 0, 
+       '\033', '[', '2', '~', 0, 
+       '\033', '[', '3', '~', 0, 
+       '\033', '[', '4', '~', 0, 
+       '\033', '[', '5', '~', 0, 
+       '\033', '[', '6', '~', 0, 
+       '\033', '[', 'M', 0, 
+       '\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+       func_buf + 0,
+       func_buf + 5,
+       func_buf + 10,
+       func_buf + 15,
+       func_buf + 20,
+       func_buf + 25,
+       func_buf + 31,
+       func_buf + 37,
+       func_buf + 43,
+       func_buf + 49,
+       func_buf + 55,
+       func_buf + 61,
+       func_buf + 67,
+       func_buf + 73,
+       func_buf + 79,
+       func_buf + 85,
+       func_buf + 91,
+       func_buf + 97,
+       func_buf + 103,
+       func_buf + 109,
+       func_buf + 115,
+       func_buf + 120,
+       func_buf + 125,
+       func_buf + 130,
+       func_buf + 135,
+       func_buf + 140,
+       func_buf + 145,
+       0,
+       0,
+       func_buf + 149,
+       0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+       {'`', 'A', '\300'},     {'`', 'a', '\340'},
+       {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
+       {'^', 'A', '\302'},     {'^', 'a', '\342'},
+       {'~', 'A', '\303'},     {'~', 'a', '\343'},
+       {'"', 'A', '\304'},     {'"', 'a', '\344'},
+       {'O', 'A', '\305'},     {'o', 'a', '\345'},
+       {'0', 'A', '\305'},     {'0', 'a', '\345'},
+       {'A', 'A', '\305'},     {'a', 'a', '\345'},
+       {'A', 'E', '\306'},     {'a', 'e', '\346'},
+       {',', 'C', '\307'},     {',', 'c', '\347'},
+       {'`', 'E', '\310'},     {'`', 'e', '\350'},
+       {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
+       {'^', 'E', '\312'},     {'^', 'e', '\352'},
+       {'"', 'E', '\313'},     {'"', 'e', '\353'},
+       {'`', 'I', '\314'},     {'`', 'i', '\354'},
+       {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
+       {'^', 'I', '\316'},     {'^', 'i', '\356'},
+       {'"', 'I', '\317'},     {'"', 'i', '\357'},
+       {'-', 'D', '\320'},     {'-', 'd', '\360'},
+       {'~', 'N', '\321'},     {'~', 'n', '\361'},
+       {'`', 'O', '\322'},     {'`', 'o', '\362'},
+       {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
+       {'^', 'O', '\324'},     {'^', 'o', '\364'},
+       {'~', 'O', '\325'},     {'~', 'o', '\365'},
+       {'"', 'O', '\326'},     {'"', 'o', '\366'},
+       {'/', 'O', '\330'},     {'/', 'o', '\370'},
+       {'`', 'U', '\331'},     {'`', 'u', '\371'},
+       {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
+       {'^', 'U', '\333'},     {'^', 'u', '\373'},
+       {'"', 'U', '\334'},     {'"', 'u', '\374'},
+       {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
+       {'T', 'H', '\336'},     {'t', 'h', '\376'},
+       {'s', 's', '\337'},     {'"', 'y', '\377'},
+       {'s', 'z', '\337'},     {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/macintosh/mackeymap.map b/drivers/macintosh/mackeymap.map
new file mode 100644 (file)
index 0000000..714985e
--- /dev/null
@@ -0,0 +1,346 @@
+# Kernel keymap for Macintoshes. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# We use the Command (pretzel) key as Alt, and the Option key as AltGr.
+#
+keycode 0x00 =
+keycode 0x01 = s               
+keycode 0x02 = d
+       altgr   keycode 0x02 = Hex_D   
+keycode 0x03 = f
+       altgr   keycode 0x03 = Hex_F               
+keycode 0x04 = h               
+keycode 0x05 = g  
+keycode 0x06 = z
+keycode 0x07 = x               
+keycode 0x08 = c
+       altgr   keycode 0x08 = Hex_C   
+keycode 0x09 = v
+keycode 0x0a =
+keycode 0x0b = b
+       altgr   keycode 0x0b = Hex_B
+keycode 0x0c = q               
+keycode 0x0d = w               
+keycode 0x0e = e
+       altgr   keycode 0x0e = Hex_E   
+keycode 0x0f = r               
+keycode 0x10 = y               
+keycode 0x11 = t               
+keycode 0x12 = one              exclam          
+       alt     keycode 0x12 = Meta_one        
+keycode 0x13 = two              at               at              
+       control keycode 0x13 = nul             
+       shift   control keycode 0x13 = nul             
+       alt     keycode 0x13 = Meta_two        
+keycode 0x14 = three            numbersign      
+       control keycode 0x14 = Escape          
+       alt     keycode 0x14 = Meta_three      
+keycode 0x15 = four             dollar           dollar          
+       control keycode 0x15 = Control_backslash
+       alt     keycode 0x15 = Meta_four       
+keycode 0x16 = six              asciicircum     
+       control keycode 0x16 = Control_asciicircum
+       alt     keycode 0x16 = Meta_six        
+keycode 0x17 = five             percent         
+       control keycode 0x17 = Control_bracketright
+       alt     keycode 0x17 = Meta_five       
+keycode 0x18 = equal            plus            
+       alt     keycode 0x18 = Meta_equal      
+keycode 0x19 = nine             parenleft        bracketright    
+       alt     keycode 0x19 = Meta_nine       
+keycode 0x1a = seven            ampersand        braceleft       
+       control keycode 0x1a = Control_underscore
+       alt     keycode 0x1a = Meta_seven      
+keycode 0x1b = minus            underscore       backslash       
+       control keycode 0x1b = Control_underscore
+       shift   control keycode 0x1b = Control_underscore
+       alt     keycode 0x1b = Meta_minus      
+keycode 0x1c = eight            asterisk         bracketleft     
+       control keycode 0x1c = Delete          
+       alt     keycode 0x1c = Meta_eight      
+keycode 0x1d = zero             parenright       braceright      
+       alt     keycode 0x1d = Meta_zero       
+keycode 0x1e = bracketright     braceright       asciitilde      
+       control keycode 0x1e = Control_bracketright
+       alt     keycode 0x1e = Meta_bracketright
+keycode 0x1f = o               
+keycode 0x20 = u               
+keycode 0x21 = bracketleft      braceleft       
+       control keycode 0x21 = Escape          
+       alt     keycode 0x21 = Meta_bracketleft
+keycode 0x22 = i               
+keycode 0x23 = p               
+keycode 0x24 = Return          
+       alt     keycode 0x24 = Meta_Control_m  
+keycode 0x25 = l               
+keycode 0x26 = j               
+keycode 0x27 = apostrophe       quotedbl        
+       control keycode 0x27 = Control_g       
+       alt     keycode 0x27 = Meta_apostrophe 
+keycode 0x28 = k               
+keycode 0x29 = semicolon        colon           
+       alt     keycode 0x29 = Meta_semicolon  
+keycode 0x2a = backslash        bar             
+       control keycode 0x2a = Control_backslash
+       alt     keycode 0x2a = Meta_backslash  
+keycode 0x2b = comma            less            
+       alt     keycode 0x2b = Meta_comma      
+keycode 0x2c = slash            question        
+       control keycode 0x2c = Delete          
+       alt     keycode 0x2c = Meta_slash      
+keycode 0x2d = n
+keycode 0x2e = m               
+keycode 0x2f = period           greater         
+       control keycode 0x2f = Compose         
+       alt     keycode 0x2f = Meta_period     
+keycode 0x30 = Tab              Tab             
+       alt     keycode 0x30 = Meta_Tab        
+keycode 0x31 = space            space           
+       control keycode 0x31 = nul             
+       alt     keycode 0x31 = Meta_space      
+keycode 0x32 = grave            asciitilde      
+       control keycode 0x32 = nul             
+       alt     keycode 0x32 = Meta_grave      
+keycode 0x33 = Delete           Delete          
+       control keycode 0x33 = BackSpace
+       alt     keycode 0x33 = Meta_Delete     
+keycode 0x34 =
+keycode 0x35 = Escape           Escape          
+       alt     keycode 0x35 = Meta_Escape     
+keycode 0x36 = Control         
+keycode 0x37 = Alt             
+keycode 0x38 = Shift
+keycode 0x39 = Caps_Lock       
+keycode 0x3a = AltGr           
+keycode 0x3b = Left            
+       alt     keycode 0x3b = Decr_Console
+keycode 0x3c = Right           
+       alt     keycode 0x3c = Incr_Console
+keycode 0x3d = Down            
+keycode 0x3e = Up              
+keycode 0x3f =
+keycode 0x40 =
+keycode 0x41 = KP_Period       
+keycode 0x42 =
+keycode 0x43 = KP_Multiply     
+keycode 0x44 =
+keycode 0x45 = KP_Add          
+keycode 0x46 =
+keycode 0x47 = Num_Lock
+#      shift   keycode 0x47 = Bare_Num_Lock
+keycode 0x48 =
+keycode 0x49 =
+keycode 0x4a =
+keycode 0x4b = KP_Divide       
+keycode 0x4c = KP_Enter        
+keycode 0x4d =
+keycode 0x4e = KP_Subtract     
+keycode 0x4f =
+keycode 0x50 =
+keycode 0x51 =
+#keycode 0x51 = KP_Equals
+keycode 0x52 = KP_0            
+       alt     keycode 0x52 = Ascii_0         
+       altgr   keycode 0x52 = Hex_0         
+keycode 0x53 = KP_1            
+       alt     keycode 0x53 = Ascii_1         
+       altgr   keycode 0x53 = Hex_1         
+keycode 0x54 = KP_2            
+       alt     keycode 0x54 = Ascii_2         
+       altgr   keycode 0x54 = Hex_2         
+keycode 0x55 = KP_3            
+       alt     keycode 0x55 = Ascii_3         
+       altgr   keycode 0x55 = Hex_3         
+keycode 0x56 = KP_4            
+       alt     keycode 0x56 = Ascii_4         
+       altgr   keycode 0x56 = Hex_4         
+keycode 0x57 = KP_5            
+       alt     keycode 0x57 = Ascii_5         
+       altgr   keycode 0x57 = Hex_5         
+keycode 0x58 = KP_6            
+       alt     keycode 0x58 = Ascii_6         
+       altgr   keycode 0x58 = Hex_6         
+keycode 0x59 = KP_7            
+       alt     keycode 0x59 = Ascii_7         
+       altgr   keycode 0x59 = Hex_7
+# keycode 0 (A) is remapped to here         
+keycode 0x5a = a
+       altgr   keycode 0x00 = Hex_A
+keycode 0x5b = KP_8            
+       alt     keycode 0x5b = Ascii_8         
+       altgr   keycode 0x5b = Hex_8         
+keycode 0x5c = KP_9            
+       alt     keycode 0x5c = Ascii_9         
+       altgr   keycode 0x5c = Hex_9         
+keycode 0x5d =
+keycode 0x5e =
+keycode 0x5f =
+keycode 0x60 = F5               F15              Console_17      
+       control keycode 0x60 = F5              
+       alt     keycode 0x60 = Console_5       
+       control alt     keycode 0x60 = Console_5       
+keycode 0x61 = F6               F16              Console_18      
+       control keycode 0x61 = F6              
+       alt     keycode 0x61 = Console_6       
+       control alt     keycode 0x61 = Console_6       
+keycode 0x62 = F7               F17              Console_19      
+       control keycode 0x62 = F7              
+       alt     keycode 0x62 = Console_7       
+       control alt     keycode 0x62 = Console_7       
+keycode 0x63 = F3               F13              Console_15      
+       control keycode 0x63 = F3              
+       alt     keycode 0x63 = Console_3       
+       control alt     keycode 0x63 = Console_3       
+keycode 0x64 = F8               F18              Console_20      
+       control keycode 0x64 = F8              
+       alt     keycode 0x64 = Console_8       
+       control alt     keycode 0x64 = Console_8       
+keycode 0x65 = F9               F19              Console_21      
+       control keycode 0x65 = F9              
+       alt     keycode 0x65 = Console_9       
+       control alt     keycode 0x65 = Console_9       
+keycode 0x66 =
+keycode 0x67 = F11              F11              Console_23      
+       control keycode 0x67 = F11             
+       alt     keycode 0x67 = Console_11      
+       control alt     keycode 0x67 = Console_11      
+keycode 0x68 =
+keycode 0x69 = F13             
+keycode 0x6a =
+keycode 0x6b = Scroll_Lock      Show_Memory      Show_Registers  
+       control keycode 0x6b = Show_State      
+       alt     keycode 0x6b = Scroll_Lock     
+keycode 0x6c =
+keycode 0x6d = F10              F20              Console_22      
+       control keycode 0x6d = F10             
+       alt     keycode 0x6d = Console_10      
+       control alt     keycode 0x6d = Console_10      
+keycode 0x6e =
+keycode 0x6f = F12              F12              Console_24      
+       control keycode 0x6f = F12             
+       alt     keycode 0x6f = Console_12      
+       control alt     keycode 0x6f = Console_12      
+keycode 0x70 =
+keycode 0x71 = Pause
+keycode 0x72 = Insert          
+keycode 0x73 = Home
+keycode 0x74 = Prior           
+       shift   keycode 0x74 = Scroll_Backward 
+keycode 0x75 = Remove          
+keycode 0x76 = F4               F14              Console_16      
+       control keycode 0x76 = F4              
+       alt     keycode 0x76 = Console_4       
+       control alt     keycode 0x76 = Console_4       
+keycode 0x77 = End
+keycode 0x78 = F2               F12              Console_14      
+       control keycode 0x78 = F2              
+       alt     keycode 0x78 = Console_2       
+       control alt     keycode 0x78 = Console_2       
+keycode 0x79 = Next            
+       shift   keycode 0x79 = Scroll_Forward  
+keycode 0x7a = F1               F11              Console_13      
+       control keycode 0x7a = F1              
+       alt     keycode 0x7a = Console_1       
+       control alt     keycode 0x7a = Console_1       
+keycode 0x7b = Shift
+keycode 0x7c = AltGr
+keycode 0x7d = Control
+keycode 0x7e =
+keycode 0x7f =
+#keycode 0x7f = Power
+       control shift   keycode 0x7f = Boot
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
new file mode 100644 (file)
index 0000000..724950c
--- /dev/null
@@ -0,0 +1,1923 @@
+/*
+ * macserial.c: Serial port driver for Power Macintoshes.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "macserial.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL     2               /* Max number of ZS chips supported */
+#define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
+
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+   but we need the eieio to make sure that the accesses occur
+   in the order we want. */
+#define RECOVERY_DELAY eieio()
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct mac_serial zs_soft[NUM_CHANNELS];
+int zs_channels_found;
+struct mac_serial *zs_chain;   /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chan = 0;
+struct mac_serial *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+/*
+ * Initialization values for when a channel is used for
+ * kernel gdb support.
+ */
+static unsigned char kgdb_regs[16] = {
+       0, 0, 0,                /* write 0, 1, 2 */
+       (Rx8 | RxENABLE),       /* write 3 */
+       (X16CLK | SB1),         /* write 4 */
+       (Tx8 | TxENAB | RTS),   /* write 5 */
+       0, 0, 0,                /* write 6, 7, 8 */
+       (NV),                   /* write 9 */
+       (NRZ),                  /* write 10 */
+       (TCBR | RCBR),          /* write 11 */
+       1, 0,                   /* 38400 baud divisor, write 12 + 13 */
+       (BRENABL),              /* write 14 */
+       (DCDIE)                 /* write 15 */
+};
+
+#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL     1
+#define SERIAL_TYPE_CALLOUT    2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+static void change_speed(struct mac_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct mac_serial *info,
+                                       dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%d, %d) in %s\n";
+       static const char *badinfo =
+               "Warning: null mac_serial for (%d, %d) in %s\n";
+
+       if (!info) {
+               printk(badinfo, MAJOR(device), MINOR(device), routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, MAJOR(device), MINOR(device), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 0 };
+
+/* 
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+                                      unsigned char reg)
+{
+       unsigned char retval;
+
+       if (reg != 0) {
+               *channel->control = reg;
+               RECOVERY_DELAY;
+       }
+       retval = *channel->control;
+       RECOVERY_DELAY;
+       return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+                              unsigned char reg, unsigned char value)
+{
+       if (reg != 0) {
+               *channel->control = reg;
+               RECOVERY_DELAY;
+       }
+       *channel->control = value;
+       RECOVERY_DELAY;
+       return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+       unsigned char retval;
+
+       retval = *channel->data;
+       RECOVERY_DELAY;
+       return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+                               unsigned char value)
+{
+       *channel->data = value;
+       RECOVERY_DELAY;
+       return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+                              unsigned char *regs)
+{
+       ZS_CLEARERR(channel);
+       ZS_CLEARFIFO(channel);
+       /* Load 'em up */
+       write_zsreg(channel, R4, regs[R4]);
+       write_zsreg(channel, R10, regs[R10]);
+       write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+       write_zsreg(channel, R1, regs[R1]);
+       write_zsreg(channel, R9, regs[R9]);
+       write_zsreg(channel, R11, regs[R11]);
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+       write_zsreg(channel, R14, regs[R14]);
+       write_zsreg(channel, R15, regs[R15]);
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+       return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct mac_serial *ss, int set)
+{
+       if (set)
+               ss->curregs[5] |= (RTS | DTR);
+       else
+               ss->curregs[5] &= ~(RTS | DTR);
+       write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+       return;
+}
+
+static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
+{
+       int brg;
+
+       if (intson) {
+               kgdb_regs[R1] = INT_ALL_Rx;
+               kgdb_regs[R9] |= MIE;
+       } else {
+               kgdb_regs[R1] = 0;
+               kgdb_regs[R9] &= ~MIE;
+       }
+       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+       kgdb_regs[R12] = brg;
+       kgdb_regs[R13] = brg >> 8;
+       load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct mac_serial *ss)
+{
+       struct mac_zschannel *channel = ss->zs_channel;
+       int brg;
+
+       if ((ss->curregs[R11] & TCBR) == 0) {
+               /* higher rates don't use the baud rate generator */
+               return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
+       }
+       /* The baud rate is split up between two 8-bit registers in
+        * what is termed 'BRG time constant' format in my docs for
+        * the chip, it is a function of the clk rate the chip is
+        * receiving which happens to be constant.
+        */
+       brg = (read_zsreg(channel, 13) << 8);
+       brg |= read_zsreg(channel, 12);
+       return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct mac_zschannel *zsc)
+{
+       write_zsreg(zsc, 0, ERR_RES);
+       write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct mac_serial *info,
+                                 int event)
+{
+       info->event |= 1 << event;
+       queue_task(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static _INLINE_ void receive_chars(struct mac_serial *info,
+                                  struct pt_regs *regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch, stat, flag;
+
+       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+               stat = read_zsreg(info->zs_channel, R1);
+               ch = read_zsdata(info->zs_channel);
+
+#if 0  /* KGDB not yet supported */
+               /* Look for kgdb 'stop' character, consult the gdb documentation
+                * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+                * to see how all this works.
+                */
+               if ((info->kgdb_channel) && (ch =='\003')) {
+                       breakpoint();
+                       continue;
+               }
+#endif
+
+               if (!tty)
+                       continue;
+               queue_task(&tty->flip.tqueue, &tq_timer);
+
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                       static int flip_buf_ovf;
+                       ++flip_buf_ovf;
+                       continue;
+               }
+               tty->flip.count++;
+               {
+                       static int flip_max_cnt;
+                       if (flip_max_cnt < tty->flip.count)
+                               flip_max_cnt = tty->flip.count;
+               }
+               if (stat & Rx_OVR) {
+                       flag = TTY_OVERRUN;
+                       /* reset the error indication */
+                       write_zsreg(info->zs_channel, 0, ERR_RES);
+               } else if (stat & FRM_ERR) {
+                       /* this error is not sticky */
+                       flag = TTY_FRAME;
+               } else if (stat & PAR_ERR) {
+                       flag = TTY_PARITY;
+                       /* reset the error indication */
+                       write_zsreg(info->zs_channel, 0, ERR_RES);
+               } else
+                       flag = 0;
+               *tty->flip.flag_buf_ptr++ = flag;
+               *tty->flip.char_buf_ptr++ = ch;
+       }
+}
+
+static void transmit_chars(struct mac_serial *info)
+{
+       if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+               return;
+       info->tx_active = 0;
+
+       if (info->x_char) {
+               /* Send next char */
+               write_zsdata(info->zs_channel, info->x_char);
+               info->x_char = 0;
+               info->tx_active = 1;
+               return;
+       }
+
+       if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+               write_zsreg(info->zs_channel, 0, RES_Tx_P);
+               return;
+       }
+
+       /* Send char */
+       write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+       info->xmit_cnt--;
+       info->tx_active = 1;
+
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static _INLINE_ void status_handle(struct mac_serial *info)
+{
+       unsigned char status;
+
+       /* Get status from Read Register 0 */
+       status = read_zsreg(info->zs_channel, 0);
+
+       /* Check for DCD transitions */
+       if (((status ^ info->read_reg_zero) & DCD) != 0
+           && info->tty && !C_CLOCAL(info->tty)) {
+               if (status & DCD) {
+                       wake_up_interruptible(&info->open_wait);
+               } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+                       queue_task(&info->tqueue_hangup, &tq_scheduler);
+               }
+       }
+
+       /* Check for CTS transitions */
+       if (info->tty && C_CRTSCTS(info->tty)) {
+               /*
+                * For some reason, on the Power Macintosh,
+                * it seems that the CTS bit is 1 when CTS is
+                * *negated* and 0 when it is asserted.
+                * The DCD bit doesn't seem to be inverted
+                * like this.
+                */
+               if ((status & CTS) == 0) {
+                       if (info->tx_stopped) {
+                               info->tx_stopped = 0;
+                               if (!info->tx_active)
+                                       transmit_chars(info);
+                       }
+               } else {
+                       info->tx_stopped = 1;
+               }
+       }
+
+       /* Clear status condition... */
+       write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+       info->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct mac_serial *info = (struct mac_serial *) dev_id;
+       unsigned char zs_intreg;
+       int shift;
+
+       /* NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+       if (info->zs_chan_a == info->zs_channel)
+               shift = 3;      /* Channel A */
+       else
+               shift = 0;      /* Channel B */
+
+       for (;;) {
+               zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+               if ((zs_intreg & CHAN_IRQMASK) == 0)
+                       break;
+
+               if (zs_intreg & CHBRxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHBTxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHBEXT)
+                       status_handle(info);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "rs_stop"))
+               return;
+       
+#if 0
+       save_flags(flags); cli();
+       if (info->curregs[5] & TxENAB) {
+               info->curregs[5] &= ~TxENAB;
+               info->pendregs[5] &= ~TxENAB;
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       }
+       restore_flags(flags);
+#endif
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_start"))
+               return;
+       
+       save_flags(flags); cli();
+#if 0
+       if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+               info->curregs[5] |= TxENAB;
+               info->pendregs[5] = info->curregs[5];
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       }
+#else
+       if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
+               transmit_chars(info);
+       }
+#endif
+       restore_flags(flags);
+}
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+       run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+       struct mac_serial       *info = (struct mac_serial *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+       struct mac_serial       *info = (struct mac_serial *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+static void rs_timer(void)
+{
+}
+
+static int startup(struct mac_serial * info)
+{
+       unsigned long flags;
+
+       if (info->flags & ZILOG_INITIALIZED)
+               return 0;
+
+       if (!info->xmit_buf) {
+               info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+               if (!info->xmit_buf)
+                       return -ENOMEM;
+       }
+
+       save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+       /*
+        * Clear the receive FIFO.
+        */
+       ZS_CLEARFIFO(info->zs_channel);
+       info->xmit_fifo_size = 1;
+
+       /*
+        * Clear the interrupt registers.
+        */
+       write_zsreg(info->zs_channel, 0, ERR_RES);
+       write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+       /*
+        * Turn on RTS and DTR.
+        */
+       zs_rtsdtr(info, 1);
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+       info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+       info->pendregs[1] = info->curregs[1];
+       info->curregs[3] |= (RxENABLE | Rx8);
+       info->pendregs[3] = info->curregs[3];
+       info->curregs[5] |= (TxENAB | Tx8);
+       info->pendregs[5] = info->curregs[5];
+       info->curregs[9] |= (NV | MIE);
+       info->pendregs[9] = info->curregs[9];
+       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       write_zsreg(info->zs_channel, 9, info->curregs[9]);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * Set the speed of the serial port
+        */
+       change_speed(info);
+
+       /* Save the current value of RR0 */
+       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+       info->flags |= ZILOG_INITIALIZED;
+       restore_flags(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct mac_serial * info)
+{
+       unsigned long   flags;
+
+       if (!(info->flags & ZILOG_INITIALIZED))
+               return;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              info->irq);
+#endif
+       
+       save_flags(flags); cli(); /* Disable interrupts */
+       
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = 0;
+       }
+
+       info->pendregs[1] = info->curregs[1] = 0;
+       write_zsreg(info->zs_channel, 1, 0);    /* no interrupts */
+
+       info->curregs[3] &= ~RxENABLE;
+       info->pendregs[3] = info->curregs[3];
+       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+
+       info->curregs[5] &= ~TxENAB;
+       if (!info->tty || C_HUPCL(info->tty))
+               info->curregs[5] &= ~(DTR | RTS);
+       info->pendregs[5] = info->curregs[5];
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags &= ~ZILOG_INITIALIZED;
+       restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct mac_serial *info)
+{
+       unsigned short port;
+       unsigned cflag;
+       int     i;
+       int     brg;
+       unsigned long flags;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+       i = cflag & CBAUD;
+
+       save_flags(flags); cli();
+       info->zs_baud = baud_table[i];
+       info->clk_divisor = 16;
+
+       switch (info->zs_baud) {
+       case ZS_CLOCK/16:       /* 230400 */
+               info->curregs[4] = X16CLK;
+               info->curregs[11] = 0;
+               break;
+       case ZS_CLOCK/32:       /* 115200 */
+               info->curregs[4] = X32CLK;
+               info->curregs[11] = 0;
+               break;
+       default:
+               info->curregs[4] = X16CLK;
+               info->curregs[11] = TCBR | RCBR;
+               brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+               info->curregs[12] = (brg & 255);
+               info->curregs[13] = ((brg >> 8) & 255);
+               info->curregs[14] = BRENABL;
+       }
+
+       /* byte size and parity */
+       info->curregs[3] &= ~RxNBITS_MASK;
+       info->curregs[5] &= ~TxNBITS_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               info->curregs[3] |= Rx5;
+               info->curregs[5] |= Tx5;
+               break;
+       case CS6:
+               info->curregs[3] |= Rx6;
+               info->curregs[5] |= Tx6;
+               break;
+       case CS7:
+               info->curregs[3] |= Rx7;
+               info->curregs[5] |= Tx7;
+               break;
+       case CS8:
+       default: /* defaults to 8 bits */
+               info->curregs[3] |= Rx8;
+               info->curregs[5] |= Tx8;
+               break;
+       }
+       info->pendregs[3] = info->curregs[3];
+       info->pendregs[5] = info->curregs[5];
+
+       info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+       if (cflag & CSTOPB) {
+               info->curregs[4] |= SB2;
+       } else {
+               info->curregs[4] |= SB1;
+       }
+       if (cflag & PARENB) {
+               info->curregs[4] |= PAR_ENA;
+       }
+       if (!(cflag & PARODD)) {
+               info->curregs[4] |= PAR_EVEN;
+       }
+       info->pendregs[4] = info->curregs[4];
+
+       if (!(cflag & CLOCAL)) {
+               if (!(info->curregs[15] & DCDIE))
+                       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+               info->curregs[15] |= DCDIE;
+       } else
+               info->curregs[15] &= ~DCDIE;
+       if (cflag & CRTSCTS) {
+               info->curregs[15] |= CTSIE;
+               if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+                       info->tx_stopped = 1;
+       } else {
+               info->curregs[15] &= ~CTSIE;
+               info->tx_stopped = 0;
+       }
+       info->pendregs[15] = info->curregs[15];
+
+       /* Load up the new values */
+       load_zsregs(info->zs_channel, info->curregs);
+
+       restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+       struct mac_zschannel *chan = zs_conschan;
+       int loops = 0;
+       unsigned long flags;
+
+       if(!chan)
+               return;
+
+       save_flags(flags); cli();
+       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+               if (++loops >= 1000000)
+                       break;
+       write_zsdata(chan, ch);
+       restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+
+       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+
+       while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+               udelay(5);
+       return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+       int left;               /* Output no more than that */
+       unsigned long flags;
+       struct mac_serial *info = zs_consinfo;
+       char c;
+
+       if (info == 0) return;
+       if (info->xmit_buf == 0) return;
+
+       save_flags(flags);  cli();
+       left = info->xmit_cnt;
+       while (left != 0) {
+               c = info->xmit_buf[info->xmit_tail];
+               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+               restore_flags(flags);
+
+               rs_put_char(c);
+
+               save_flags(flags);  cli();
+               left = MIN(info->xmit_cnt, left-1);
+       }
+
+       restore_flags(flags);
+       return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+       char c;
+
+       while ((c = *(p++)) != 0) {
+               if (c == '\n')
+                       rs_put_char('\r');
+               rs_put_char(c);
+       }
+
+       /* Comment this if you want to have a strict interrupt-driven output */
+       rs_fair_output();
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+               return;
+
+       if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
+           !info->xmit_buf)
+               return;
+
+       /* Enable transmitter */
+       save_flags(flags); cli();
+       transmit_chars(info);
+       restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, total = 0;
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf)
+               return 0;
+
+       save_flags(flags);
+       while (1) {
+               cli();          
+               c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
+               if (c <= 0)
+                       break;
+
+               if (from_user) {
+                       down(&tmp_buf_sem);
+                       copy_from_user(tmp_buf, buf, c);
+                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       up(&tmp_buf_sem);
+               } else
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt += c;
+               restore_flags(flags);
+               buf += c;
+               count -= c;
+               total += c;
+       }
+       if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+           && !info->tx_active)
+               transmit_chars(info);
+       restore_flags(flags);
+       return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       int     ret;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+               return 0;
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+               return 0;
+       return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+               return;
+       cli();
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       sti();
+       wake_up_interruptible(&tty->write_wait);
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               save_flags(flags); cli();
+               info->x_char = STOP_CHAR(tty);
+               if (!info->tx_active)
+                       transmit_chars(info);
+               restore_flags(flags);
+       }
+
+       if (C_CRTSCTS(tty)) {
+               /*
+                * Here we want to turn off the RTS line.  On Macintoshes,
+                * we only get the DTR line, which goes to both DTR and
+                * RTS on the modem.  RTS doesn't go out to the serial
+                * port socket.  So you should make sure your modem is
+                * set to ignore DTR if you're using CRTSCTS.
+                */
+               save_flags(flags); cli();
+               info->curregs[5] &= ~(DTR | RTS);
+               info->pendregs[5] &= ~(DTR | RTS);
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+               restore_flags(flags);
+       }
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               save_flags(flags); cli();
+               if (info->x_char)
+                       info->x_char = 0;
+               else {
+                       info->x_char = START_CHAR(tty);
+                       if (!info->tx_active)
+                               transmit_chars(info);
+               }
+               restore_flags(flags);
+       }
+
+       if (C_CRTSCTS(tty)) {
+               /* Assert RTS and DTR lines */
+               save_flags(flags); cli();
+               info->curregs[5] |= DTR | RTS;
+               info->pendregs[5] |= DTR | RTS;
+               write_zsreg(info->zs_channel, 5, info->curregs[5]);
+               restore_flags(flags);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct mac_serial * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+  
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = info->port;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct mac_serial * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct mac_serial old_info;
+       int                     retval = 0;
+
+       if (!new_info)
+               return -EFAULT;
+       copy_from_user(&new_serial,new_info,sizeof(new_serial));
+       old_info = *info;
+
+       if (!suser()) {
+               if ((new_serial.baud_base != info->baud_base) ||
+                   (new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~ZILOG_USR_MASK) !=
+                    (info->flags & ~ZILOG_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+                              (new_serial.flags & ZILOG_USR_MASK));
+               info->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~ZILOG_FLAGS) |
+                       (new_serial.flags & ZILOG_FLAGS));
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+       retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct mac_serial * info, unsigned int *value)
+{
+       unsigned char status;
+
+       cli();
+       status = read_zsreg(info->zs_channel, 0);
+       sti();
+       put_user(status,value);
+       return 0;
+}
+
+static int get_modem_info(struct mac_serial *info, unsigned int *value)
+{
+       unsigned char control, status;
+       unsigned int result;
+
+       cli();
+       control = info->curregs[5];
+       status = read_zsreg(info->zs_channel, 0);
+       sti();
+       result =  ((control & RTS) ? TIOCM_RTS: 0)
+               | ((control & DTR) ? TIOCM_DTR: 0)
+               | ((status  & DCD) ? TIOCM_CAR: 0)
+               | ((status  & CTS) ? 0: TIOCM_CTS);
+       put_user(result,value);
+       return 0;
+}
+
+static int set_modem_info(struct mac_serial *info, unsigned int cmd,
+                         unsigned int *value)
+{
+       int error;
+       unsigned int arg, bits;
+
+       error = verify_area(VERIFY_READ, value, sizeof(int));
+       if (error)
+               return error;
+       get_user(arg, value);
+       bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
+       cli();
+       switch (cmd) {
+       case TIOCMBIS:
+               info->curregs[5] |= bits;
+               break;
+       case TIOCMBIC:
+               info->curregs[5] &= ~bits;
+               break;
+       case TIOCMSET:
+               info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
+               break;
+       default:
+               sti();
+               return -EINVAL;
+       }
+       info->pendregs[5] = info->curregs[5];
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       sti();
+       return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(        struct mac_serial * info, int duration)
+{
+       if (!info->port)
+               return;
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + duration;
+       cli();
+       info->curregs[5] |= SND_BRK;
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       schedule();
+       info->curregs[5] &= ~SND_BRK;
+       write_zsreg(info->zs_channel, 5, info->curregs[5]);
+       sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+       int retval;
+
+       if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (!arg)
+                               send_break(info, HZ/4); /* 1/4 second */
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       return 0;
+               case TIOCGSOFTCAR:
+                       return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+               case TIOCSSOFTCAR:
+                       error = get_user(arg, (int *) arg);
+                       if (error)
+                               return error;
+                       tty->termios->c_cflag =
+                               ((tty->termios->c_cflag & ~CLOCAL) |
+                                (arg ? CLOCAL : 0));
+                       return 0;
+               case TIOCMGET:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                               sizeof(unsigned int));
+                       if (error)
+                               return error;
+                       return get_modem_info(info, (unsigned int *) arg);
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return set_modem_info(info, cmd, (unsigned int *) arg);
+               case TIOCGSERIAL:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct serial_struct));
+                       if (error)
+                               return error;
+                       return get_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERGETLSR: /* Get line status register */
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                               sizeof(unsigned int));
+                       if (error)
+                               return error;
+                       else
+                           return get_lsr_info(info, (unsigned int *) arg);
+
+               case TIOCSERGSTRUCT:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct mac_serial));
+                       if (error)
+                               return error;
+                       copy_from_user((struct mac_serial *) arg,
+                                      info, sizeof(struct mac_serial));
+                       return 0;
+                       
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       int was_stopped;
+
+       if (tty->termios->c_cflag == old_termios->c_cflag)
+               return;
+       was_stopped = info->tx_stopped;
+
+       change_speed(info);
+
+       if (was_stopped && !info->tx_stopped)
+               rs_start(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.
+ * Wait for the last remaining data to be sent.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
+       unsigned long timeout;
+
+       if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+               return;
+       
+       save_flags(flags); cli();
+       
+       if (tty_hung_up_p(filp)) {
+               restore_flags(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ZILOG_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ZILOG_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       if (info->flags & ZILOG_CALLOUT_ACTIVE)
+               info->callout_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receiver and receive interrupts.
+        */
+       /** if (!info->iscons) ... **/
+       info->curregs[3] &= ~RxENABLE;
+       info->pendregs[3] = info->curregs[3];
+       write_zsreg(info->zs_channel, 3, info->curregs[3]);
+       info->curregs[1] &= ~(0x18);    /* disable any rx ints */
+       info->pendregs[1] = info->curregs[1];
+       write_zsreg(info->zs_channel, 1, info->curregs[1]);
+       ZS_CLEARFIFO(info->zs_channel);
+       if (info->flags & ZILOG_INITIALIZED) {
+               /*
+                * Before we drop DTR, make sure the SCC transmitter
+                * has completely drained.
+                */
+               timeout = jiffies+HZ;
+               while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + info->timeout;
+                       schedule();
+                       if (jiffies > timeout)
+                               break;
+               }
+       }
+
+       shutdown(info);
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer(tty);
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+               if (tty->ldisc.close)
+                       (tty->ldisc.close)(tty);
+               tty->ldisc = ldiscs[N_TTY];
+               tty->termios->c_line = N_TTY;
+               if (tty->ldisc.open)
+                       (tty->ldisc.open)(tty);
+       }
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + info->close_delay;
+                       schedule();
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+                        ZILOG_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+       struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+               return;
+
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+       info->tty = 0;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct mac_serial *info)
+{
+       struct wait_queue wait = { current, NULL };
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (info->flags & ZILOG_CLOSING) {
+               interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ZILOG_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If this is a callout device, then just make sure the normal
+        * device isn't being used.
+        */
+       if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+               if (info->flags & ZILOG_NORMAL_ACTIVE)
+                       return -EBUSY;
+               if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   (info->flags & ZILOG_SESSION_LOCKOUT) &&
+                   (info->session != current->session))
+                   return -EBUSY;
+               if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   (info->flags & ZILOG_PGRP_LOCKOUT) &&
+                   (info->pgrp != current->pgrp))
+                   return -EBUSY;
+               info->flags |= ZILOG_CALLOUT_ACTIVE;
+               return 0;
+       }
+       
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR))) {
+               if (info->flags & ZILOG_CALLOUT_ACTIVE)
+                       return -EBUSY;
+               info->flags |= ZILOG_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+               if (info->normal_termios.c_cflag & CLOCAL)
+                       do_clocal = 1;
+       } else {
+               if (tty->termios->c_cflag & CLOCAL)
+                       do_clocal = 1;
+       }
+       
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       cli();
+       if (!tty_hung_up_p(filp)) 
+               info->count--;
+       sti();
+       info->blocked_open++;
+       while (1) {
+               cli();
+               if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   (tty->termios->c_cflag & CBAUD))
+                       zs_rtsdtr(info, 1);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ZILOG_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+                   !(info->flags & ZILOG_CLOSING) &&
+                   (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
+                       break;
+               if (current->signal & ~current->blocked) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               schedule();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ZILOG_NORMAL_ACTIVE;
+       return 0;
+}      
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct mac_serial       *info;
+       int                     retval, line;
+
+       line = MINOR(tty->device) - tty->driver.minor_start;
+       if ((line < 0) || (line >= zs_channels_found))
+               return -ENODEV;
+       info = zs_soft + line;
+
+       /* Is the kgdb running over this line? */
+       if (info->kgdb_channel)
+               return -ENODEV;
+       if (serial_paranoia_check(info, tty->device, "rs_open"))
+               return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+              info->count);
+#endif
+
+       info->count++;
+       tty->driver_data = info;
+       info->tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+               if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                       *tty->termios = info->normal_termios;
+               else 
+                       *tty->termios = info->callout_termios;
+               change_speed(info);
+       }
+
+       info->session = current->session;
+       info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttys%d successful...", info->line);
+#endif
+       return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+       struct device_node *dev, *ch;
+       struct mac_serial **pp;
+       int n;
+
+       n = 0;
+       pp = &zs_chain;
+       for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+               if (n >= NUM_CHANNELS) {
+                       printk("Sorry, can't use %s: no more channels\n",
+                              dev->full_name);
+                       continue;
+               }
+               for (ch = dev->child; ch != 0; ch = ch->sibling) {
+                       if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+                               printk("Can't use %s: %d addrs %d intrs\n",
+                                     ch->full_name, ch->n_addrs, ch->n_intrs);
+                               continue;
+                       }
+                       zs_channels[n].control = (volatile unsigned char *)
+                               ch->addrs[0].address;
+                       zs_channels[n].data = zs_channels[n].control
+                               + ch->addrs[0].size / 2;
+                       zs_soft[n].zs_channel = &zs_channels[n];
+                       zs_soft[n].irq = ch->intrs[0];
+                       if (request_irq(ch->intrs[0], rs_interrupt, 0,
+                                       "SCC", &zs_soft[n]))
+                               panic("macserial: can't get irq %d",
+                                     ch->intrs[0]);
+                       /* XXX this assumes the prom puts chan A before B */
+                       if (n & 1)
+                               zs_soft[n].zs_chan_a = &zs_channels[n-1];
+                       else
+                               zs_soft[n].zs_chan_a = &zs_channels[n];
+
+                       *pp = &zs_soft[n];
+                       pp = &zs_soft[n].zs_next;
+                       ++n;
+               }
+       }
+       *pp = 0;
+       zs_channels_found = n;
+}
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+       int channel, i;
+       unsigned long flags;
+       struct mac_serial *info;
+
+       /* Setup base handler, and timer table. */
+       init_bh(SERIAL_BH, do_serial_bh);
+       timer_table[RS_TIMER].fn = rs_timer;
+       timer_table[RS_TIMER].expires = 0;
+
+       /* Find out how many Z8530 SCCs we have */
+       if (zs_chain == 0)
+               probe_sccs();
+
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       /* Not all of this is exactly right for us. */
+
+       memset(&serial_driver, 0, sizeof(struct tty_driver));
+       serial_driver.magic = TTY_DRIVER_MAGIC;
+       serial_driver.name = "ttyS";
+       serial_driver.major = TTY_MAJOR;
+       serial_driver.minor_start = 64;
+       serial_driver.num = zs_channels_found;
+       serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver.subtype = SERIAL_TYPE_NORMAL;
+       serial_driver.init_termios = tty_std_termios;
+
+       serial_driver.init_termios.c_cflag =
+               B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver.flags = TTY_DRIVER_REAL_RAW;
+       serial_driver.refcount = &serial_refcount;
+       serial_driver.table = serial_table;
+       serial_driver.termios = serial_termios;
+       serial_driver.termios_locked = serial_termios_locked;
+
+       serial_driver.open = rs_open;
+       serial_driver.close = rs_close;
+       serial_driver.write = rs_write;
+       serial_driver.flush_chars = rs_flush_chars;
+       serial_driver.write_room = rs_write_room;
+       serial_driver.chars_in_buffer = rs_chars_in_buffer;
+       serial_driver.flush_buffer = rs_flush_buffer;
+       serial_driver.ioctl = rs_ioctl;
+       serial_driver.throttle = rs_throttle;
+       serial_driver.unthrottle = rs_unthrottle;
+       serial_driver.set_termios = rs_set_termios;
+       serial_driver.stop = rs_stop;
+       serial_driver.start = rs_start;
+       serial_driver.hangup = rs_hangup;
+
+       /*
+        * The callout device is just like normal device except for
+        * major number and the subtype code.
+        */
+       callout_driver = serial_driver;
+       callout_driver.name = "cua";
+       callout_driver.major = TTYAUX_MAJOR;
+       callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+       if (tty_register_driver(&serial_driver))
+               panic("Couldn't register serial driver\n");
+       if (tty_register_driver(&callout_driver))
+               panic("Couldn't register callout driver\n");
+
+       save_flags(flags); cli();
+
+       for (channel = 0; channel < zs_channels_found; ++channel) {
+               zs_soft[channel].clk_divisor = 16;
+               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+
+               /* If console serial line, then enable interrupts. */
+               if (zs_soft[channel].is_cons) {
+                       write_zsreg(zs_soft[channel].zs_channel, R1,
+                                   (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+                       write_zsreg(zs_soft[channel].zs_channel, R9,
+                                   (NV | MIE));
+               }
+               /* If this is the kgdb line, enable interrupts because we
+                * now want to receive the 'control-c' character from the
+                * client attached to us asynchronously.
+                */
+               if (zs_soft[channel].kgdb_channel)
+                       kgdb_chaninit(&zs_soft[channel], 1,
+                                     zs_soft[channel].zs_baud);
+       }
+
+       for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+       {
+               info->magic = SERIAL_MAGIC;
+               info->port = (int) info->zs_channel->control;
+               info->line = i;
+               info->tty = 0;
+               info->custom_divisor = 16;
+               info->close_delay = 50;
+               info->closing_wait = 3000;
+               info->x_char = 0;
+               info->event = 0;
+               info->count = 0;
+               info->blocked_open = 0;
+               info->tqueue.routine = do_softint;
+               info->tqueue.data = info;
+               info->tqueue_hangup.routine = do_serial_hangup;
+               info->tqueue_hangup.data = info;
+               info->callout_termios =callout_driver.init_termios;
+               info->normal_termios = serial_driver.init_termios;
+               info->open_wait = 0;
+               info->close_wait = 0;
+               printk("tty%02d at 0x%08x (irq = %d)", info->line, 
+                      info->port, info->irq);
+               printk(" is a Z8530 ESCC\n");
+       }
+
+       restore_flags(flags);
+
+       return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* PowerMac: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+       return -1;
+}
+
+void unregister_serial(int line)
+{
+       return;
+}
+
+extern void register_console(void (*proc)(const char *));
+
+/*
+ * Initialization values for when a channel is used for
+ * a serial console.
+ */
+static unsigned char cons_init_regs[16] = {
+       0, 0, 0,                /* write 0, 1, 2 */
+       (Rx8 | RxENABLE),       /* write 3 */
+       (X16CLK | SB1),         /* write 4 */
+       (Tx8 | TxENAB | RTS),   /* write 5 */
+       0, 0, 0,                /* write 6, 7, 8 */
+       0,                      /* write 9 */
+       (NRZ),                  /* write 10 */
+       (TCBR | RCBR),          /* write 11 */
+       1, 0,                   /* 38400 baud divisor, write 12 + 13 */
+       (BRENABL),              /* write 14 */
+       0                       /* write 15 */
+};
+
+/*
+ * Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 1=modem, 2=printer.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+       int brg;
+
+       if (!out)
+               return;
+       if (zs_consinfo != 0) {
+               printk("rs_cons_hook called twice?\n");
+               return;
+       }
+       if (zs_chain == 0)
+               probe_sccs();
+       --channel;
+       if (channel < 0 || channel >= zs_channels_found) {
+               printk("rs_cons_hook: channel = %d?\n", channel);
+               return;
+       }
+
+       zs_cons_chan = channel;
+       zs_consinfo = &zs_soft[channel];
+       zs_conschan = zs_consinfo->zs_channel;
+       zs_consinfo->clk_divisor = 16;
+       zs_consinfo->zs_baud = 38400;
+       zs_consinfo->is_cons = 1;
+
+       memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
+       brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
+       zs_consinfo->curregs[R12] = brg;
+       zs_consinfo->curregs[R13] = brg >> 8;
+       load_zsregs(zs_conschan, zs_consinfo->curregs);
+
+       register_console(zs_console_print);
+       printk("zs%d: console I/O\n", channel);
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+       if (zs_chain == 0)
+               probe_sccs();
+       zs_kgdbchan = zs_soft[tty_num].zs_channel;
+       zs_soft[tty_num].clk_divisor = 16;
+       zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+       zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
+       zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+       /* Turn on transmitter/receiver at 8-bits/char */
+       kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+       ZS_CLEARERR(zs_kgdbchan);
+       ZS_CLEARFIFO(zs_kgdbchan);
+}
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
new file mode 100644 (file)
index 0000000..83e6dc9
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MACSERIAL_H
+#define _MACSERIAL_H
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+       int     type;
+       int     line;
+       int     port;
+       int     irq;
+       int     flags;
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     baud_base;
+       unsigned short  close_delay;
+       char    reserved_char[2];
+       int     hub6;
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+       int     reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE        65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define ZILOG_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK      0x0004  /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS    0x0FFF  /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430  /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED      0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING          0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW         0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD         0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct mac_zschannel {
+       volatile unsigned char *control;
+       volatile unsigned char *data;
+};
+
+struct mac_serial {
+       struct mac_serial *zs_next;     /* For IRQ servicing chain */
+       struct mac_zschannel *zs_channel; /* Channel registers */
+       struct mac_zschannel *zs_chan_a;        /* A side registers */
+       unsigned char read_reg_zero;
+
+       char soft_carrier;  /* Use soft carrier on this channel */
+       char break_abort;   /* Is serial console in, so process brk/abrt */
+       char kgdb_channel;  /* Kgdb is running on this channel */
+       char is_cons;       /* Is this our console. */
+       unsigned char tx_active; /* character is being xmitted */
+       unsigned char tx_stopped; /* output is suspended */
+
+       /* We need to know the current clock divisor
+        * to read the bps rate the chip has currently
+        * loaded.
+        */
+       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+       int zs_baud;
+
+       /* Current write register values */
+       unsigned char curregs[NUM_ZSREGS];
+
+       /* Values we need to set next opportunity */
+       unsigned char pendregs[NUM_ZSREGS];
+
+       char change_needed;
+
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+       int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     xmit_fifo_size;
+       int                     custom_divisor;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       long                    session; /* Session of opening process */
+       long                    pgrp; /* pgrp of opening process */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+       int                     xmit_cnt;
+       struct tq_struct        tqueue;
+       struct tq_struct        tqueue_hangup;
+       struct termios          normal_termios;
+       struct termios          callout_termios;
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENABLE        0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxNBITS_MASK   0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENA         0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxNBITS_MASK   0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENABL 1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        ZCIE    2       /* Zero count IE */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC_HUNT       0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        FRM_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+                                    garbage = read_zsdata(channel); \
+                                    garbage = read_zsdata(channel); \
+                                    garbage = read_zsdata(channel); \
+                               } while(0)
+
+#endif /* !(_MACSERIAL_H) */
diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c
new file mode 100644 (file)
index 0000000..9bb6166
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * /dev/nvram driver for Power Macintosh.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#define NVRAM_SIZE     8192
+
+static long long nvram_llseek(struct inode *inode, struct file *file,
+                             loff_t offset, int origin)
+{
+       switch (origin) {
+       case 1:
+               offset += file->f_pos;
+               break;
+       case 2:
+               offset += NVRAM_SIZE;
+               break;
+       }
+       if (offset < 0)
+               return -EINVAL;
+       file->f_pos = offset;
+       return file->f_pos;
+}
+
+static long read_nvram(struct inode *inode, struct file *file,
+       char *buf, unsigned long count)
+{
+       unsigned int i = file->f_pos;
+       char *p = buf;
+
+       for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+               put_user(nvram_read_byte(i), p);
+       file->f_pos = i;
+       return p - buf;
+}
+
+static long write_nvram(struct inode *inode, struct file *file,
+       const char *buf, unsigned long count)
+{
+       unsigned int i = file->f_pos;
+       const char *p = buf;
+       char c;
+
+       for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+               get_user(c, p);
+               nvram_write_byte(i, c);
+       }
+       file->f_pos = i;
+       return p - buf;
+}
+
+static int nvram_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+struct file_operations nvram_fops = {
+       nvram_llseek,
+       read_nvram,
+       write_nvram,
+       NULL,           /* nvram_readdir */
+       NULL,           /* nvram_select */
+       NULL,           /* nvram_ioctl */
+       NULL,           /* nvram_mmap */
+       nvram_open,
+       NULL,           /* no special release code */
+       NULL            /* fsync */
+};
+
+static struct miscdevice nvram_dev = {
+       NVRAM_MINOR,
+       "nvram",
+       &nvram_fops
+};
+
+__initfunc(int nvram_init(void))
+{
+       misc_register(&nvram_dev);
+       return 0;
+}
diff --git a/drivers/macintosh/platinum.c b/drivers/macintosh/platinum.c
new file mode 100644 (file)
index 0000000..34f314d
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *     
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "platinum.h"
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+       unsigned char addr;
+       char pad1[15];
+       unsigned char d1;
+       char pad2[15];
+       unsigned char d2;
+       char pad3[15];
+       unsigned char lut;
+       char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+#define PAD(x) char x[12]
+
+struct preg {                  /* padded register */
+       unsigned r;
+       char pad[12];
+};
+
+struct platinum_regs {
+       struct preg reg[128];
+};
+
+static void set_platinum_clock(unsigned char *clksel);
+static int read_platinum_sense(void);
+static int platinum_vram_reqd(int vmode, int cmode);
+
+static int total_vram;         /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *base_frame_buffer;
+static struct cmap_regs *cmap_regs;
+static volatile struct platinum_regs *plat_regs;
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there.  Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ *     F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ *     F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct plat_regvals {
+       int     fb_offset;
+       int     pitch[3];
+       unsigned regs[26];
+       unsigned char plat_offset[3];
+       unsigned char mode[3];
+       unsigned char dacula_ctrl[3];
+       unsigned char clocksel[2][2];
+};
+
+#define DIV2   0x20
+#define DIV4   0x40
+#define DIV8   0x60
+#define DIV16  0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct plat_regvals platinum_reg_init_20 = {
+       0x5c00,
+       { 1312, 2592, 2592 },
+       { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+         0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+         0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+         0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+       { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+       {{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct plat_regvals platinum_reg_init_19 = {
+       0x5c00,
+       { 1312, 2592, 2592 },
+       { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+         0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+         0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+         0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+       { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+       {{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct plat_regvals platinum_reg_init_18 = {
+       0x11b0,
+       { 1184, 2336, 4640 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+         0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+         0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+         0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct plat_regvals platinum_reg_init_17 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+         0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+         0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct plat_regvals platinum_reg_init_16 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+         0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+         0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct plat_regvals platinum_reg_init_15 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+         0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+         0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct plat_regvals platinum_reg_init_14 = {
+       0x10b0,
+       { 1056, 2080, 4128 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+         0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+         0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct plat_regvals platinum_reg_init_13 = {
+       0x70,
+       { 864, 1680, 3360 },    /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+       { 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+         0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+         0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+         0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct plat_regvals platinum_reg_init_12 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+         0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+         0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct plat_regvals platinum_reg_init_11 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+         0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+         0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct plat_regvals platinum_reg_init_10 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+         0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+         0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct plat_regvals platinum_reg_init_9 = {
+       0x1010,
+       { 832, 1632, 3232 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+         0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+         0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct plat_regvals platinum_reg_init_8 = {
+       0x1010,
+       { 800, 1568, 3104 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+         0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+         0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct plat_regvals platinum_reg_init_7 = {
+       0xb10,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+         0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+         0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct plat_regvals platinum_reg_init_6 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+         0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+         0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+         0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct plat_regvals platinum_reg_init_5 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+         0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+         0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct plat_regvals platinum_reg_init_4 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+         0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+         0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct plat_regvals platinum_reg_init_3 = {
+       0x1010,
+       { 672, 1312, 2592 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+         0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+         0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct plat_regvals platinum_reg_init_2 = {
+       0x1010,
+       { 544, 1056, 2080 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+         0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+         0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct plat_regvals platinum_reg_init_1 = {
+       0x1010,
+       { 544, 1056, 2080 },
+       { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+         0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+         0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+         0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+       { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+       {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+static struct plat_regvals *platinum_reg_init[VMODE_MAX] = {
+       &platinum_reg_init_1,
+       &platinum_reg_init_2,
+       &platinum_reg_init_3,
+       &platinum_reg_init_4,
+       &platinum_reg_init_5,
+       &platinum_reg_init_6,
+       &platinum_reg_init_7,
+       &platinum_reg_init_8,
+       &platinum_reg_init_9,
+       &platinum_reg_init_10,
+       &platinum_reg_init_11,
+       &platinum_reg_init_12,
+       &platinum_reg_init_13,
+       &platinum_reg_init_14,
+       &platinum_reg_init_15,
+       &platinum_reg_init_16,
+       &platinum_reg_init_17,
+       &platinum_reg_init_18,
+       &platinum_reg_init_19,
+       &platinum_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_platinum_sense()
+{
+       int sense;
+
+       plat_regs->reg[23].r = 7;       /* turn off drivers */
+       eieio(); __delay(2000);
+       sense = (~plat_regs->reg[23].r & 7) << 8;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       plat_regs->reg[23].r = 3;       /* drive A low */
+       eieio(); __delay(2000);
+       sense |= (~plat_regs->reg[23].r & 3) << 4;
+       eieio();
+       plat_regs->reg[23].r = 5;       /* drive B low */
+       eieio(); __delay(2000);
+       sense |= (~plat_regs->reg[23].r & 4) << 1;
+       sense |= (~plat_regs->reg[23].r & 1) << 2;
+       eieio();
+       plat_regs->reg[23].r = 6;       /* drive C low */
+       eieio(); __delay(2000);
+       sense |= (~plat_regs->reg[23].r & 6) >> 1;
+       eieio();
+
+       plat_regs->reg[23].r = 7;       /* turn off drivers */
+       return sense;
+}
+
+static inline int platinum_vram_reqd(int vmode, int cmode)
+{
+        return vmode_attrs[vmode-1].vres
+                * platinum_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_platinum(struct device_node *dp)
+{
+       int i, sense;
+       unsigned long addr, size;
+       int bank0, bank1, bank2, bank3;
+
+       if (dp->next != 0)
+               printk("Warning: only using first platinum display device\n");
+       if (dp->n_addrs != 2)
+               panic("expecting 2 addresses for platinum (got %d)",
+                     dp->n_addrs);
+
+       /* Map in frame buffer and registers */
+       for (i = 0; i < dp->n_addrs; ++i) {
+               addr = dp->addrs[i].address;
+               size = dp->addrs[i].size;
+               if (size >= 0x400000) {
+                       /* frame buffer - map only 4MB */
+                       frame_buffer = ioremap(addr, 0x400000);
+                       base_frame_buffer = frame_buffer;
+               } else {
+                       /* registers */
+                       plat_regs = ioremap(addr, size);
+               }
+       }
+       cmap_regs = ioremap(0xf301b000, 0x1000);        /* XXX not in prom? */
+
+       /* Grok total video ram */
+       plat_regs->reg[16].r = (unsigned)frame_buffer;
+       plat_regs->reg[20].r = 0x1011;  /* select max vram */
+       plat_regs->reg[24].r = 0;       /* switch in vram */
+       eieio();
+       frame_buffer[0x100000] = 0x34;
+       frame_buffer[0x200000] = 0x56;
+       frame_buffer[0x300000] = 0x78;
+       eieio();
+       bank0 = 1; /* builtin 1MB vram, always there */
+       bank1 = frame_buffer[0x100000] == 0x34;
+       bank2 = frame_buffer[0x200000] == 0x56;
+       bank3 = frame_buffer[0x300000] == 0x78;
+       total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+       printk("Total VRAM = %dMB\n", total_vram / 1024 / 1024);
+
+       sense = read_platinum_sense();
+       if (video_mode == VMODE_NVRAM) {
+               video_mode = nvram_read_byte(NV_VMODE);
+               if (video_mode <= 0 || video_mode > VMODE_MAX
+                   || platinum_reg_init[video_mode-1] == 0)
+                       video_mode = VMODE_CHOOSE;
+       }
+       if (video_mode == VMODE_CHOOSE)
+               video_mode = map_monitor_sense(sense);
+       if (platinum_reg_init[video_mode-1] == 0)
+               video_mode = VMODE_640_480_60;
+       printk("Monitor sense value = 0x%x, ", sense);
+
+       if (color_mode == CMODE_NVRAM)
+                color_mode = nvram_read_byte(NV_CMODE);
+        if (color_mode < CMODE_8 || color_mode > CMODE_32)
+                color_mode = CMODE_8;
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       while (color_mode > CMODE_8
+              && platinum_vram_reqd(video_mode, color_mode) > total_vram)
+               --color_mode;
+       /*
+        * Reduce the video mode if we don't have enough VRAM.
+        */
+       while (platinum_vram_reqd(video_mode, color_mode) > total_vram)
+               --video_mode;
+}
+
+#define STORE_D2(a, v) { \
+       out_8(&cmap_regs->addr, (a+32)); \
+       out_8(&cmap_regs->d2, (v)); \
+}
+
+static void
+set_platinum_clock(unsigned char *clksel)
+{
+       STORE_D2(6, 0xc6);
+       out_8(&cmap_regs->addr, 3+32);
+       if (cmap_regs->d2 == 2) {
+               STORE_D2(7, clksel[0]);
+               STORE_D2(8, clksel[1]);
+               STORE_D2(3, 3);
+       } else {
+               STORE_D2(4, clksel[0]);
+               STORE_D2(5, clksel[1]);
+               STORE_D2(3, 2);
+       }
+       __delay(5000);
+       STORE_D2(9, 0xa6);
+}
+
+void
+platinum_init()
+{
+       int i, yoff, width, clkmode, dtype;
+       struct plat_regvals *init;
+       unsigned *p;
+       int one_mb = 0;
+
+       if (total_vram == 0x100000) one_mb=1;
+
+       if (video_mode <= 0 || video_mode > VMODE_MAX
+           || (init = platinum_reg_init[video_mode-1]) == 0)
+               panic("platinum: video mode %d not supported", video_mode);
+
+       frame_buffer = base_frame_buffer + init->fb_offset;
+       /* printk("Frame buffer start address is %p\n", frame_buffer); */
+
+       pixel_size = 1 << color_mode;
+       line_pitch = init->pitch[color_mode];
+       width = vmode_attrs[video_mode-1].hres;
+       n_scanlines = vmode_attrs[video_mode-1].vres;
+       row_pitch = line_pitch * 16;
+
+       /* Initialize display timing registers */
+       out_be32(&plat_regs->reg[24].r, 7);     /* turn display off */
+
+       for (i = 0; i < 26; ++i)
+               plat_regs->reg[i+32].r = init->regs[i];
+       plat_regs->reg[26+32].r = (one_mb ? init->plat_offset[color_mode] + 4 - color_mode : init->plat_offset[color_mode]);
+       plat_regs->reg[16].r = (unsigned) frame_buffer;
+       plat_regs->reg[18].r = line_pitch;
+       plat_regs->reg[19].r = (one_mb ? init->mode[color_mode+1] : init->mode[color_mode]);
+       plat_regs->reg[20].r = (one_mb ? 0x11 : 0x1011);
+       plat_regs->reg[21].r = 0x100;
+       plat_regs->reg[22].r = 1;
+       plat_regs->reg[23].r = 1;
+       plat_regs->reg[26].r = 0xc00;
+       plat_regs->reg[27].r = 0x235;
+       /* plat_regs->reg[27].r = 0x2aa; */
+
+       STORE_D2(0, (one_mb ? init->dacula_ctrl[color_mode] & 0xf : init->dacula_ctrl[color_mode]));
+       STORE_D2(1, 4);
+       STORE_D2(2, 0);
+       /*
+        * Try to determine whether we have an old or a new DACula.
+        */
+       out_8(&cmap_regs->addr, 0x40);
+       dtype = cmap_regs->d2;
+       switch (dtype) {
+       case 0x3c:
+               clkmode = 1;
+               break;
+       case 0x84:
+               clkmode = 0;
+               break;
+       default:
+               clkmode = 0;
+               printk("Unknown DACula type: %x\n", cmap_regs->d2);
+       }
+       set_platinum_clock(init->clocksel[clkmode]);
+
+       out_be32(&plat_regs->reg[24].r, 0);     /* turn display on */
+
+       pmac_init_palette();
+
+       yoff = (n_scanlines % 16) / 2;
+       fb_start = frame_buffer + yoff * line_pitch + 0x10;
+
+       /* Clear screen */
+       p = (unsigned *) (frame_buffer + 0x10);
+       for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+               *p++ = 0;
+
+       display_info.height = n_scanlines;
+       display_info.width = width;
+       display_info.depth = 8 * pixel_size;
+       display_info.pitch = line_pitch;
+       display_info.mode = video_mode;
+       strncpy(display_info.name, "platinum", sizeof(display_info.name));
+       display_info.fb_address = (unsigned long) frame_buffer + 0x10;
+       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+       display_info.disp_reg_address = (unsigned long) &plat_regs;
+}
+
+int
+platinum_setmode(struct vc_mode *mode, int doit)
+{
+       int cmode;
+
+       if (mode->mode <= 0 || mode->mode > VMODE_MAX
+           || platinum_reg_init[mode->mode-1] == 0)
+               return -EINVAL;
+       if (mode->depth != 8 && mode->depth != 16 && mode->depth != 24 && mode->depth != 32)
+               return -EINVAL;
+
+       switch (mode->depth) {
+        case 24:
+        case 32:
+                cmode = CMODE_32;
+                break;
+        case 16:
+                cmode = CMODE_16;
+                break;
+        case 8:
+                cmode = CMODE_8;
+                break;
+        default:
+                return -EINVAL;
+        }
+
+       if (platinum_vram_reqd(mode->mode, cmode) > total_vram)
+               return -EINVAL;
+
+       if (doit) {
+               video_mode = mode->mode;
+               color_mode = cmode;
+               platinum_init();
+       }
+       return 0;
+}
+
+void
+platinum_set_palette(unsigned char red[], unsigned char green[],
+                    unsigned char blue[], int index, int ncolors)
+{
+       int i;
+
+       for (i = 0; i < ncolors; ++i) {
+               cmap_regs->addr = index + i;    eieio();
+               cmap_regs->lut = red[i];        eieio();
+               cmap_regs->lut = green[i];      eieio();
+               cmap_regs->lut = blue[i];       eieio();
+       }
+}
+
+void
+platinum_set_blanking(int blank_mode)
+{
+}
diff --git a/drivers/macintosh/platinum.h b/drivers/macintosh/platinum.h
new file mode 100644 (file)
index 0000000..530a89c
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *     
+ * 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.
+ */
+
+extern void map_platinum(struct device_node *);
+extern void platinum_init(void);
+extern int platinum_setmode(struct vc_mode *mode, int doit);
+extern void platinum_set_palette(unsigned char red[], unsigned char green[],
+                                unsigned char blue[], int index, int ncolors);
+extern void platinum_set_blanking(int blank_mode);
diff --git a/drivers/macintosh/pmac-cons.c b/drivers/macintosh/pmac-cons.c
new file mode 100644 (file)
index 0000000..8b7f083
--- /dev/null
@@ -0,0 +1,1312 @@
+/*
+ * pmac-cons.c: Console support for PowerMac (PCI-based).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ * 7200/Platinum code hacked by Mark Abene.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/kd.h>
+#include <linux/version.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/cuda.h>
+#include <asm/linux_logo.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "control.h"
+#include "platinum.h"
+#include "valkyrie.h"
+#ifdef CONFIG_ATY_VIDEO
+#include "aty.h"
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+#include "imstt.h"
+#endif
+
+int video_mode = VMODE_NVRAM;
+int color_mode = CMODE_NVRAM;
+
+/*
+ * The format of "screen_info" is strange, and due to early
+ * i386-setup code. This is just enough to make the console
+ * code think we're on a EGA+ colour display.
+ */
+struct screen_info screen_info = {
+       0, 0,                   /* orig-x, orig-y */
+       {0, 0},                 /* unused1 */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       80,                     /* orig-video-cols */
+       0,                      /* unused [short] */
+       0,                      /* ega_bx */
+       0,                      /* unused [short] */
+       25,                     /* orig-video-lines */
+       0,                      /* isVGA */
+       16                      /* video points */
+};
+
+/*
+ * We allocate enough character+attribute memory for the largest
+ * screen resolution supported.
+ */
+#define MAX_TEXT_COLS  (1280/8)
+#define MAX_TEXT_ROWS  (1024/16)
+
+/*
+ * We get a sense value from the monitor and use it to choose
+ * what resolution to use.  This structure maps sense values
+ * to display mode values (which determine the resolution and
+ * frequencies).
+ */
+struct mon_map {
+       int     sense;
+       int     vmode;
+} monitor_map [] = {
+       {0x000, VMODE_1280_1024_75},    /* 21" RGB */
+       {0x114, VMODE_640_870_75P},     /* Portrait Monochrome */
+       {0x221, VMODE_512_384_60},      /* 12" RGB*/
+       {0x331, VMODE_1280_1024_75},    /* 21" RGB (Radius) */
+       {0x334, VMODE_1280_1024_75},    /* 21" mono (Radius) */
+       {0x335, VMODE_1280_1024_75},    /* 21" mono */
+       {0x40A, VMODE_640_480_60I},     /* NTSC */
+       {0x51E, VMODE_640_870_75P},     /* Portrait RGB */
+       {0x603, VMODE_832_624_75},      /* 12"-16" multiscan */
+       {0x60b, VMODE_1024_768_70},     /* 13"-19" multiscan */
+       {0x623, VMODE_1152_870_75},     /* 13"-21" multiscan */
+       {0x62b, VMODE_640_480_67},      /* 13"/14" RGB */
+       {0x700, VMODE_640_480_50I},     /* PAL */
+       {0x714, VMODE_640_480_60I},     /* NTSC */
+       {0x717, VMODE_800_600_75},      /* VGA */
+       {0x72d, VMODE_832_624_75},      /* 16" RGB (Goldfish) */
+       {0x730, VMODE_768_576_50I},     /* PAL (Alternate) */
+       {0x73a, VMODE_1152_870_75},     /* 3rd party 19" */
+       {-1,    VMODE_640_480_60},      /* catch-all, must be last */
+};
+
+int
+map_monitor_sense(int sense)
+{
+       struct mon_map *map;
+
+       for (map = monitor_map; map->sense >= 0; ++map)
+               if (map->sense == sense)
+                       break;
+       return map->vmode;
+}
+
+/*
+ * Horizontal and vertical resolution for each mode.
+ */
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+       {512, 384, 60, 1},
+       {512, 384, 60},
+       {640, 480, 50, 1},
+       {640, 480, 60, 1},
+       {640, 480, 60},
+       {640, 480, 67},
+       {640, 870, 75},
+       {768, 576, 50, 1},
+       {800, 600, 56},
+       {800, 600, 60},
+       {800, 600, 72},
+       {800, 600, 75},
+       {832, 624, 75},
+       {1024, 768, 60},
+       {1024, 768, 72},
+       {1024, 768, 75},
+       {1024, 768, 75},
+       {1152, 870, 75},
+       {1280, 960, 75},
+       {1280, 1024, 75}
+};
+
+static void invert_cursor(int);
+static int map_unknown(struct device_node *);
+static void unknown_init(void);
+
+struct display_interface {
+       char *name;
+       void (*map_interface)(struct device_node *);
+       void (*init_interface)(void);
+       int  (*setmode)(struct vc_mode *, int);
+       void (*set_palette)(unsigned char red[], unsigned char green[],
+                           unsigned char blue[], int index, int ncolors);
+       void (*set_blanking)(int blank_mode);
+} displays[] = {
+       { "control", map_control_display, control_init,
+         control_setmode, control_set_palette, control_set_blanking },
+       { "platinum", map_platinum, platinum_init,
+         platinum_setmode, platinum_set_palette, platinum_set_blanking },
+       { "valkyrie", map_valkyrie_display, valkyrie_init,
+         valkyrie_setmode, valkyrie_set_palette, valkyrie_set_blanking },
+#ifdef CONFIG_ATY_VIDEO
+       { "ATY,mach64", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+       { "ATY,XCLAIM", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+       { "ATY,264VT", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+       { "ATY,mach64ii", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+#if 0  /* not right for 3D mach64 yet */
+       { "ATY,264GT-B", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+       { "ATY,mach64_3D_pcc", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette },
+#endif
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+       { "IMS,tt128mb", map_imstt_display, imstt_init, 
+         imstt_setmode, imstt_set_palette, imstt_set_blanking },
+#endif
+       { NULL }
+};
+
+struct display_interface unknown_display = {
+       "unknown", NULL, unknown_init, NULL, NULL
+};
+
+static struct display_interface *current_display;
+
+static int cursor_pos = -1;
+static unsigned *cursor_fb;    /* address of cursor pos in frame buffer */
+static unsigned cursor_bits;   /* bits changed to turn cursor on */
+
+int pixel_size;                        /* in bytes */
+int n_scanlines;               /* # of scan lines */
+int line_pitch;                        /* # bytes in 1 scan line */
+int row_pitch;                 /* # bytes in 1 row of characters */
+unsigned char *fb_start;       /* addr of top left pixel of top left char */
+struct vc_mode display_info;
+
+extern int screen_initialized; /* in arch/ppc/pmac/prom.c */
+
+#define cmapsz (16*256)
+extern unsigned char vga_font[cmapsz];
+
+static inline unsigned pixel32(int currcons, int cidx)
+{
+       cidx *= 3;
+       return (palette[cidx] << 16) | (palette[cidx + 1] << 8)
+               | palette[cidx + 2];
+}
+
+static inline unsigned pixel16(int currcons, int cidx)
+{
+       unsigned p;
+
+       p = ((cidx << 10) & 0x7c00) + ((cidx << 5) & 0x03e0)
+               + (cidx & 0x1f);
+       return (p << 16) | p;
+}
+
+void
+__set_origin(unsigned short offset)
+{
+}
+
+static void
+invert_cursor(int cpos)
+{
+       int row, col;
+       int l, c, nw;
+       unsigned *fb, mask;
+       int currcons = fg_console;      /* for `color', which is a macro */
+
+       if (cpos == -1) {
+               /* turning cursor off */
+               fb = cursor_fb;
+               mask = cursor_bits;
+       } else {
+               row = cpos / video_num_columns;
+               col = cpos - row * video_num_columns;
+               fb = (unsigned *) (fb_start + row * row_pitch
+                                  + col * pixel_size * 8);
+               switch (color_mode) {
+               case CMODE_16:
+                       mask = pixel16(currcons, foreground)
+                               ^ pixel16(currcons, background >> 4);
+                       break;
+               default:
+                       mask = (color ^ (color >> 4)) & 0xf;
+                       mask |= mask << 8;
+                       mask |= mask << 16;
+                       break;
+               }
+               cursor_fb = fb;
+               cursor_bits = mask;
+       }
+       nw = pixel_size * 2;    /* pixel_size * 8 (char width) / 4 */
+       for (l = 0; l < 16; ++l) {
+               for (c = 0; c < nw; ++c)
+                       fb[c] ^= mask;
+               fb = (unsigned *) ((char *)fb + line_pitch);
+       }
+}
+
+void
+hide_cursor()
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (cursor_pos != -1) {
+               invert_cursor(-1);
+               cursor_pos = -1;
+       }
+       restore_flags(flags);
+}
+
+void
+set_cursor(int currcons)
+{
+       unsigned long flags;
+       int old_cursor;
+
+       if (currcons != fg_console || console_blanked)
+               return;
+
+       save_flags(flags);
+       cli();
+       if (!deccm) {
+               hide_cursor();
+       } else {
+               old_cursor = cursor_pos;
+               cursor_pos = (pos - video_mem_base) >> 1;
+               if (old_cursor != -1)
+                       invert_cursor(-1);
+               invert_cursor(cursor_pos);
+       }
+       restore_flags(flags);
+}
+
+/*
+ * NOTE: get_scrmem() and set_scrmem() are here only because
+ * the VGA version of set_scrmem() has some direct VGA references.
+ */
+void
+get_scrmem(int currcons)
+{
+       memcpyw((unsigned short *)vc_scrbuf[currcons],
+               (unsigned short *)origin, video_screen_size);
+       origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+       scr_end = video_mem_end = video_mem_start + video_screen_size;
+       pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+       if (video_mem_term - video_mem_base < offset + video_screen_size)
+               offset = 0;
+       memcpyw((unsigned short *)(video_mem_base + offset),
+               (unsigned short *) origin, video_screen_size);
+       video_mem_start = video_mem_base;
+       video_mem_end = video_mem_term;
+       origin = video_mem_base + offset;
+       scr_end = origin + video_screen_size;
+       pos = origin + y*video_size_row + (x<<1);
+}
+
+int
+set_get_cmap(unsigned char *p, int set)
+{
+       int i, j, err;
+
+       err = verify_area(set? VERIFY_READ: VERIFY_WRITE, p, 48);
+       if (err)
+               return err;
+
+       for (i = 0; i < 16; ++i) {
+               if (set) {
+                       get_user(default_red[i], p++);
+                       get_user(default_grn[i], p++);
+                       get_user(default_blu[i], p++);
+               } else {
+                       put_user(default_red[i], p++);
+                       put_user(default_grn[i], p++);
+                       put_user(default_blu[i], p++);
+               }
+       }
+
+       if (set) {
+               for (j = 0; j < MAX_NR_CONSOLES; ++j) {
+                       if (!vc_cons_allocated(j))
+                               continue;
+                       for (i = 0; i < 16; ++i) {
+                               vc_cons[j].d->vc_palette[3*i+0] = default_red[i];
+                               vc_cons[j].d->vc_palette[3*i+1] = default_grn[i];
+                               vc_cons[j].d->vc_palette[3*i+2] = default_blu[i];
+                       }
+               }
+               set_palette();
+       }
+
+       return 0;
+}
+
+int
+set_get_font(char *p, int set, int ch512)
+{
+       return 0;
+}
+
+void
+set_palette()
+{
+       int i, j, n;
+       unsigned char red[16], green[16], blue[16];
+
+       if (console_blanked || current_display == NULL
+           || current_display->set_palette == NULL
+           || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+               return;
+
+       for (i = j = 0; i < 16; ++i) {
+               n = color_table[i] & 0xf;
+               red[n] = vc_cons[fg_console].d->vc_palette[j++];
+               green[n] = vc_cons[fg_console].d->vc_palette[j++];
+               blue[n] = vc_cons[fg_console].d->vc_palette[j++];
+       }
+       (*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+void
+pmac_init_palette()
+{
+       int i, n;
+       unsigned char red[16], green[16], blue[16];
+
+       for (i = 0; i < 16; ++i) {
+               n = color_table[i] & 0xf;
+               red[n] = default_red[i];
+               green[n] = default_grn[i];
+               blue[n] = default_blu[i];
+       }
+       (*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+static int vesa_blanking_mode;
+static int vesa_blanked;
+
+void
+vesa_blank()
+{
+       if (vesa_blanking_mode == 0 || vesa_blanked
+           || current_display == NULL
+           || current_display->set_blanking == NULL)
+               return;
+       (*current_display->set_blanking)(vesa_blanking_mode);
+       vesa_blanked = vesa_blanking_mode;
+}
+
+void
+vesa_unblank()
+{
+       if (vesa_blanked == 0
+           || current_display == NULL
+           || current_display->set_blanking == NULL)
+               return;
+       (*current_display->set_blanking)(VESA_NO_BLANKING);
+       vesa_blanked = VESA_NO_BLANKING;
+}
+
+void
+set_vesa_blanking(const unsigned long arg)
+{
+       unsigned char *argp = (unsigned char *)(arg + 1);
+       unsigned int mode;
+
+       if (verify_area(VERIFY_READ, argp, 1))
+               return;
+
+       get_user(mode, argp);
+       vesa_blanking_mode = (mode <= VESA_POWERDOWN)? mode: \
+               DEFAULT_VESA_BLANKING_MODE;
+}
+
+void
+vesa_powerdown()
+{
+       if (vesa_blanked == 0 || vesa_blanked == VESA_POWERDOWN
+           || current_display == NULL
+           || current_display->set_blanking == NULL)
+               return;
+       (*current_display->set_blanking)(VESA_POWERDOWN);
+       vesa_blanked = VESA_POWERDOWN;
+}
+
+void
+memsetw(unsigned short *p, unsigned short c, unsigned count)
+{
+       count /= 2;
+       if ((unsigned long)(p + count) > video_mem_base
+           && (unsigned long)p < video_mem_term) {
+               for (; p < (unsigned short *) video_mem_base && count != 0; --count)
+                       *p++ = c;
+               for (; p < (unsigned short *) video_mem_term && count != 0; --count) {
+                       if (*p != c) {
+                               *p = c;
+                               pmac_blitc(c, (unsigned long)p);
+                       }
+                       ++p;
+               }
+       }
+       for (; count != 0; --count)
+               *p++ = c;
+}
+
+void
+memcpyw(unsigned short *to, unsigned short *from, unsigned count)
+{
+       unsigned short c;
+
+       count /= 2;
+       if ((unsigned long)(to + count) > video_mem_base
+           && (unsigned long)to < video_mem_term) {
+               for (; to < (unsigned short *) video_mem_base && count != 0; --count)
+                       *to++ = *from++;
+               for (; to < (unsigned short *) video_mem_term && count != 0; --count) {
+                       c = *from++;
+                       if (*to != c) {
+                               *to = c;
+                               pmac_blitc(c, (unsigned long)to);
+                       }
+                       ++to;
+               }
+       }
+       for (; count != 0; --count)
+               *to++ = *from++;
+}
+
+void
+pmac_find_display()
+{
+       struct display_interface *disp;
+       struct device_node *dp;
+       struct vmode_attr *ap;
+
+       current_display = NULL;
+       if (serial_console) 
+               return;
+       for (disp = displays; disp->name != NULL; ++disp) {
+               dp = find_devices(disp->name);
+               if (dp == 0)
+                       continue;
+               current_display = disp;
+               disp->map_interface(dp);
+               break;
+       }
+
+       if (current_display == NULL) {
+               /*
+                * We haven't found a display that we know about,
+                * but if there is a display with sufficient prom support,
+                * we may be able to use it in a limited fashion.
+                * If there is, it has already been opened in prom_init().
+                */
+               if (prom_display_path[0] != 0) {
+                       dp = find_path_device(prom_display_path);
+                       if (dp != 0 && map_unknown(dp))
+                               current_display = &unknown_display;
+                       else
+                               printk(KERN_INFO "Can't use %s for display\n",
+                                      prom_display_path);
+               }
+       }
+
+       if (current_display == NULL
+           || video_mode <= 0 || video_mode > VMODE_MAX) {
+               printk(KERN_INFO "No usable display device found"
+                      "- using serial console\n");
+               serial_console = 1;     /* no screen - fall back to serial */
+               return;
+       }
+       ap = &vmode_attrs[video_mode - 1];
+       screen_info.orig_video_cols = ap->hres / 8;
+       screen_info.orig_video_lines = ap->vres / 16;
+       printk("using video mode %d (%dx%d at %dHz%s), %d bits/pixel\n",
+              video_mode, ap->hres, ap->vres, ap->vfreq,
+              ap->interlaced? " interlaced": "",
+              (color_mode + 1) * 8);
+}
+
+int
+pmac_display_supported(const char *name)
+{
+       struct display_interface *disp;
+
+       for (disp = displays; disp->name != NULL; ++disp)
+               if (strcmp(name, disp->name) == 0)
+                       return 1;
+       return 0;
+}
+
+int
+console_getmode(struct vc_mode *mode)
+{
+       *mode = display_info;
+       return 0;
+}
+
+int
+console_setmode(struct vc_mode *mode, int doit)
+{
+       int err;
+
+       if (current_display == NULL || current_display->setmode == NULL)
+               return -EINVAL;
+       err = (*current_display->setmode)(mode, doit);
+       if (doit && err == 0)
+               memset((void *)video_mem_base, 0, video_screen_size);
+       return err;
+}
+
+int
+console_powermode(int mode)
+{
+       if (mode == VC_POWERMODE_INQUIRY)
+               return vesa_blanked;
+       if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+               return -EINVAL;
+       if (current_display == NULL || current_display->set_blanking == NULL)
+               return -ENXIO;
+       (*current_display->set_blanking)(mode);
+       vesa_blanked = mode;
+       return 0;
+}
+
+void
+pmac_cons_setup(char *str, int *ints)
+{
+       if (strcmp(str, "ttya") == 0 || strcmp(str, "modem") == 0)
+               serial_console = 1;
+       else if (strcmp(str, "ttyb") == 0 || strcmp(str, "printer") == 0)
+               serial_console = 2;
+}
+
+void
+pmac_vmode_setup(char *str, int *ints)
+{
+       if (ints[0] >= 1)
+               video_mode = ints[1];
+       if (ints[0] >= 2)
+               color_mode = ints[2];
+}
+
+unsigned long
+con_type_init(unsigned long mem_start, const char **type_p)
+{
+       if (current_display == NULL)
+               panic("no display available");
+       current_display->init_interface();
+       screen_initialized = 1;         /* inhibits prom_print */
+       can_do_color = 1;
+       video_type = VIDEO_TYPE_PMAC;
+       *type_p = display_info.name;
+       video_mem_base = mem_start;
+       mem_start += MAX_TEXT_COLS * MAX_TEXT_ROWS * 2;
+       video_mem_term = mem_start;
+       memset((char *) video_mem_base, 0, video_screen_size);
+       return mem_start;
+}
+
+static __inline__ void
+draw_logo_8(void)
+{
+       unsigned char *fb = fb_start;
+       unsigned char *p = linux_logo;
+       int yy;
+
+       (*current_display->set_palette)
+               (linux_logo_red, linux_logo_green, linux_logo_blue,
+                32, LINUX_LOGO_COLORS);
+
+       for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+               memcpy(fb, p, LINUX_LOGO_WIDTH);
+               fb += line_pitch;
+               p += LINUX_LOGO_WIDTH;
+       }
+}
+
+static __inline__ void
+draw_logo_15(void)
+{
+       unsigned short *fb;
+       unsigned char *row = fb_start;
+       unsigned char *p = linux_logo;
+       int i, xx, yy;
+       unsigned char grey[16];
+
+       /*
+        * For 15-bit mode, treat the screen as a 4/4/4 TrueColor.
+        */
+       for (i = 0; i < 16; ++i)
+               grey[i] = i << 4;
+       (*current_display->set_palette)(grey, grey, grey, 16, 16);
+
+       for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+               fb = (unsigned short *) row;
+               for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+                       i = *p++ - 32;
+                       *fb++ = 0x4210
+                               + ((linux_logo_red[i] & 0xf0) << 6)
+                               + ((linux_logo_green[i] & 0xf0) << 1)
+                               + (linux_logo_blue[i] >> 4);
+               }
+               row += line_pitch;
+       }
+}
+
+static __inline__ void
+draw_logo_24(void)
+{
+       unsigned long *fb;
+       unsigned char *row = fb_start;
+       unsigned char *p = linux_logo;
+       int xx, yy, v;
+
+       (*current_display->set_palette)
+               (linux_logo_red, linux_logo_green, linux_logo_blue,
+                32, LINUX_LOGO_COLORS);
+
+       for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+               fb = (unsigned long *) row;
+               for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+                       v = *p++;
+                       v |= v << 8;
+                       v |= v << 16;
+                       *fb++ = v;
+               }
+               row += line_pitch;
+       }
+}
+
+void
+con_type_init_finish(void)
+{
+       char *p;
+       int c;
+       unsigned short *addr;
+       char xy[2];
+       int currcons = 0;       /* for `attr', which is a macro */
+
+       if (current_display == NULL
+           || current_display->set_palette == NULL)
+               return;
+
+       switch (color_mode) {
+       case CMODE_8:
+               draw_logo_8();
+               break;
+
+       case CMODE_16:
+               draw_logo_15();
+               break;
+
+       case CMODE_32:
+               draw_logo_24();
+               break;
+       }
+       xy[0] = 0;
+       xy[1] = (LINUX_LOGO_HEIGHT + 16) / 16;
+       putconsxy(0, xy);
+
+       p = "PowerMac/Linux " UTS_RELEASE;
+       addr = (unsigned short *) video_mem_base + 2 * video_num_columns
+               + LINUX_LOGO_WIDTH / 8 + 8;
+       for (; *p; ++p) {
+               c = (attr << 8) + *p;
+               scr_writew(c, addr);
+               ++addr;
+       }
+}
+
+int
+con_adjust_height(unsigned long height)
+{
+       return -EINVAL;
+}
+
+static unsigned long expand_bits_8[16] = {
+       0x00000000,
+       0x000000ff,
+       0x0000ff00,
+       0x0000ffff,
+       0x00ff0000,
+       0x00ff00ff,
+       0x00ffff00,
+       0x00ffffff,
+       0xff000000,
+       0xff0000ff,
+       0xff00ff00,
+       0xff00ffff,
+       0xffff0000,
+       0xffff00ff,
+       0xffffff00,
+       0xffffffff
+};
+
+static unsigned long expand_bits_16[4] = {
+       0x00000000,
+       0x0000ffff,
+       0xffff0000,
+       0xffffffff
+};
+
+void
+pmac_blitc(unsigned charattr, unsigned long addr)
+{
+       int col, row, fg, bg, l, bits;
+       unsigned char *fp;
+       unsigned long *fb;
+       static int cached_row_start, cached_row_end = -1;
+       static unsigned char *cached_fb;
+       static int cached_attr = -1;
+       static unsigned long cached_fg, cached_bg;
+
+       col = (addr - video_mem_base) / 2;
+       if (cursor_pos == col)
+               cursor_pos = -1;
+       if (!(col >= cached_row_start && col < cached_row_end)) {
+               row = col / video_num_columns;
+               cached_row_start = row * video_num_columns;
+               cached_row_end = cached_row_start + video_num_columns;
+               cached_fb = fb_start + row * row_pitch;
+       }
+       fb = (unsigned long *)
+               (cached_fb + (col - cached_row_start) * pixel_size * 8);
+
+       if ((charattr & 0xff00) != cached_attr) {
+               fg = (charattr >> 8) & 0xf;
+               bg = (charattr >> 12) & 0xf;
+               switch (color_mode) {
+               case CMODE_16:
+                       fg = pixel16(fg_console, fg);
+                       bg = pixel16(fg_console, bg);
+                       break;
+               default:
+                       fg += fg << 8;
+                       fg += fg << 16;
+                       bg += bg << 8;
+                       bg += bg << 16;
+               }
+               fg ^= bg;
+               cached_fg = fg;
+               cached_bg = bg;
+       } else {
+               fg = cached_fg;
+               bg = cached_bg;
+       }
+
+       fp = &vga_font[(charattr & 0xff) * 16];
+       switch (color_mode) {
+       case CMODE_32:
+               for (l = 0; l < 16; ++l) {
+                       bits = *fp++;
+                       fb[0] = (-(bits >> 7) & fg) ^ bg;
+                       fb[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+                       fb[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+                       fb[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+                       fb[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+                       fb[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+                       fb[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+                       fb[7] = (-(bits & 1) & fg) ^ bg;
+                       fb = (unsigned long *) ((char *)fb + line_pitch);
+               }
+               break;
+       case CMODE_16:
+               for (l = 0; l < 16; ++l) {
+                       bits = *fp++;
+                       fb[0] = (expand_bits_16[bits >> 6] & fg) ^ bg;
+                       fb[1] = (expand_bits_16[(bits >> 4) & 3] & fg) ^ bg;
+                       fb[2] = (expand_bits_16[(bits >> 2) & 3] & fg) ^ bg;
+                       fb[3] = (expand_bits_16[bits & 3] & fg) ^ bg;
+                       fb = (unsigned long *) ((char *)fb + line_pitch);
+               }
+               break;
+       default:
+               for (l = 0; l < 16; ++l) {
+                       bits = *fp++;
+                       fb[0] = (expand_bits_8[bits >> 4] & fg) ^ bg;
+                       fb[1] = (expand_bits_8[bits & 0xf] & fg) ^ bg;
+                       fb = (unsigned long *) ((char *)fb + line_pitch);
+               }
+       }
+}
+
+
+/*
+ * The following provides a very basic screen driver for displays
+ * that we basically don't know anything about, but which we can
+ * initialize by using their Open Firmware "open" method.
+ */
+
+static int unknown_modes[] = {
+       VMODE_512_384_60,
+       VMODE_640_480_60,
+       VMODE_800_600_60,
+       VMODE_832_624_75,
+       VMODE_1024_768_60,
+       VMODE_1152_870_75,
+       VMODE_1280_960_75,
+       VMODE_1280_1024_75,
+       0
+};
+
+static unsigned char *frame_buffer;
+
+static int map_unknown(struct device_node *dp)
+{
+       int i, mode;
+       int width;
+       int *pp, len;
+       unsigned *up, address;
+
+       printk("map_unknown(%p), name = %s\n", dp, dp->full_name);
+
+       /* check the depth */
+       if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
+           && len == sizeof(int) && *pp != 8) {
+               printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+               return 0;
+       }
+
+       width = 640;            /* default values */
+       n_scanlines = 480;
+       if ((pp = (int *) get_property(dp, "width", &len)) != NULL
+           && len == sizeof(int))
+               width = *pp;
+       if ((pp = (int *) get_property(dp, "height", &len)) != NULL
+           && len == sizeof(int))
+               n_scanlines = *pp;
+       line_pitch = width;
+       if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
+           && len == sizeof(int))
+               line_pitch = *pp;
+       printk(KERN_INFO "width=%d height=%d pitch=%d\n",
+              width, n_scanlines, line_pitch);
+
+       len = n_scanlines * line_pitch;
+       if ((up = (unsigned *) get_property(dp, "address", &len)) != NULL
+           && len == sizeof(unsigned)) {
+               address = *up;
+       } else {
+               for (i = 0; i < dp->n_addrs; ++i)
+                       if (dp->addrs[i].size >= len)
+                               break;
+               if (i >= dp->n_addrs) {
+                       printk("no framebuffer address found for %s\n",
+                              dp->full_name);
+                       return 0;
+               }
+               address = dp->addrs[i].address;
+               /* temporary kludge for valkyrie */
+               if (strcmp(dp->name, "valkyrie") == 0)
+                       address += 0x1000;
+       }
+       printk(KERN_INFO "%s: using address %x\n", dp->full_name, address);
+       frame_buffer = ioremap(address, len);
+
+       video_mode = 0;
+       color_mode = CMODE_8;
+       pixel_size = 1;
+
+       for (i = 0; (mode = unknown_modes[i]) != 0; ++i) {
+               if (vmode_attrs[mode-1].hres <= width
+                   && vmode_attrs[mode-1].vres <= n_scanlines)
+                       video_mode = mode;
+       }
+       if (video_mode == 0) {
+               printk(KERN_INFO "%s: no mode found for %d x %d\n",
+                      dp->full_name, width, n_scanlines);
+               return 0;
+       }
+
+       display_info.height = n_scanlines;
+       display_info.width = width;
+       display_info.depth = 8;
+       display_info.pitch = line_pitch;
+       display_info.mode = video_mode;
+       strncpy(display_info.name, dp->name, sizeof(display_info.name));
+       display_info.fb_address = (unsigned long) frame_buffer;
+       display_info.cmap_adr_address = 0;
+       display_info.cmap_data_address = 0;
+       display_info.disp_reg_address = 0;
+
+       return 1;
+}
+
+static void
+unknown_init()
+{
+       unsigned *p;
+       int i;
+
+       row_pitch = line_pitch * 16;
+       fb_start = frame_buffer;
+
+       /* Clear screen */
+       p = (unsigned *) frame_buffer;
+       for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+               *p++ = 0;
+}
+
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 
+};
diff --git a/drivers/macintosh/pmac-cons.h b/drivers/macintosh/pmac-cons.h
new file mode 100644 (file)
index 0000000..18c2c3c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Definitions for display drivers for console use on PowerMacs.
+ *
+ * Copyright (C) 1997 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.
+ */
+
+extern int serial_console;     /* set to use serial port as console */
+
+/*
+ * Video mode values.
+ * These are supposed to be the same as the values that
+ * Apple uses in MacOS.
+ */
+#define VMODE_NVRAM            0       /* use value stored in nvram */
+#define VMODE_512_384_60I      1       /* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60       2       /* 512x384, 60Hz */
+#define VMODE_640_480_50I      3       /* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I      4       /* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60       5       /* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67       6       /* 640x480, 67Hz */
+#define VMODE_640_870_75P      7       /* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I      8       /* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56       9       /* 800x600, 56Hz */
+#define VMODE_800_600_60       10      /* 800x600, 60Hz */
+#define VMODE_800_600_72       11      /* 800x600, 72Hz */
+#define VMODE_800_600_75       12      /* 800x600, 75Hz */
+#define VMODE_832_624_75       13      /* 832x624, 75Hz */
+#define VMODE_1024_768_60      14      /* 1024x768, 60Hz */
+#define VMODE_1024_768_70      15      /* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V     16      /* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75      17      /* 1024x768, 75Hz */
+#define VMODE_1152_870_75      18      /* 1152x870, 75Hz */
+#define VMODE_1280_960_75      19      /* 1280x960, 75Hz */
+#define VMODE_1280_1024_75     20      /* 1280x1024, 75Hz */
+#define VMODE_MAX              20
+#define VMODE_CHOOSE           99      /* choose based on monitor sense */
+
+/*
+ * Color mode values, used to select number of bits/pixel.
+ */
+#define CMODE_NVRAM            -1      /* use value stored in nvram */
+#define CMODE_8                        0       /* 8 bits/pixel */
+#define CMODE_16               1       /* 16 (actually 15) bits/pixel */
+#define CMODE_32               2       /* 32 (actually 24) bits/pixel */
+
+extern int video_mode;
+extern int color_mode;
+
+/*
+ * Addresses in NVRAM where video mode and pixel size are stored.
+ */
+#define NV_VMODE       0x140f
+#define NV_CMODE       0x1410
+
+/*
+ * Horizontal and vertical resolution information.
+ */
+extern struct vmode_attr {
+       int     hres;
+       int     vres;
+       int     vfreq;
+       int     interlaced;
+} vmode_attrs[VMODE_MAX];
+
+extern struct vc_mode display_info;
+
+#define DEFAULT_VESA_BLANKING_MODE     VESA_NO_BLANKING
+
+extern int pixel_size;         /* in bytes */
+extern int n_scanlines;                /* # of scan lines */
+extern int line_pitch;         /* # bytes in 1 scan line */
+extern int row_pitch;          /* # bytes in 1 row of characters */
+extern unsigned char *fb_start;        /* addr of top left pixel of top left char */
+
+/* map monitor sense value to video mode */
+extern int map_monitor_sense(int sense);
+
+void set_palette(void);
+void pmac_find_display(void);
+void vesa_blank(void);
+void vesa_unblank(void);
+void set_vesa_blanking(const unsigned long);
+void vesa_powerdown(void);
+void hide_cursor(void);
+void pmac_init_palette(void);
diff --git a/drivers/macintosh/valkyrie.c b/drivers/macintosh/valkyrie.c
new file mode 100644 (file)
index 0000000..3d1d877
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * valkyrie.c: Console support for PowerMac "valkyrie" display adaptor.
+ *
+ * Copyright (C) 1997 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "valkyrie.h"
+
+/*
+ * Structure of the registers for the Valkyrie colormap registers.
+ */
+struct cmap_regs {
+       unsigned char addr;
+       char pad1[7];
+       unsigned char lut;
+};
+
+/*
+ * Structure of the registers for the "valkyrie" display adaptor.
+ */
+#define PAD(x) char x[7]
+
+struct valkyrie_regs {
+       unsigned char mode;
+       PAD(pad0);
+       unsigned char depth;
+       PAD(pad1);
+       unsigned char status;
+       PAD(pad2);
+       unsigned char reg3;
+       PAD(pad3);
+       unsigned char intr;
+       PAD(pad4);
+       unsigned char reg5;
+       PAD(pad5);
+       unsigned char intr_enb;
+       PAD(pad6);
+       unsigned char msense;
+       PAD(pad7);
+};
+
+static void set_valkyrie_clock(unsigned char *params);
+static int read_valkyrie_sense(void);
+
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct valkyrie_regs *disp_regs;
+
+/*
+ * Register initialization tables for the valkyrie display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ */
+struct valkyrie_regvals {
+       unsigned char mode;
+       unsigned char clock_params[3];
+       int     pitch[2];               /* bytes/line, indexed by color_mode */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct valkyrie_regvals valkyrie_reg_init_15 = {
+       15,
+       { 12, 30, 3 },  /* pixel clock = 78.12MHz for V=72.12Hz */
+       { 1024, 0 }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct valkyrie_regvals valkyrie_reg_init_14 = {
+       14,
+       { 15, 31, 3 },  /* pixel clock = 64.58MHz for V=59.62Hz */
+       { 1024, 0 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct valkyrie_regvals valkyrie_reg_init_13 = {
+       9,
+       { 23, 42, 3 },  /* pixel clock = 57.07MHz for V=74.27Hz */
+       { 832, 0 }
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+       13,
+       { 17, 27, 3 },  /* pixel clock = 49.63MHz for V=71.66Hz */
+       { 800, 0 }
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct valkyrie_regvals valkyrie_reg_init_10 = {
+       12,
+       { 20, 53, 2 },  /* pixel clock = 41.41MHz for V=59.78Hz */
+       { 800, 0 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct valkyrie_regvals valkyrie_reg_init_6 = {
+       6,
+       { 14, 27, 2 },  /* pixel clock = 30.13MHz for V=66.43Hz */
+       { 640, 1280 }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct valkyrie_regvals valkyrie_reg_init_5 = {
+       11,
+       { 23, 37, 2 },  /* pixel clock = 25.14MHz for V=59.85Hz */
+       { 640, 1280 }
+};
+
+static struct valkyrie_regvals *valkyrie_reg_init[20] = {
+       NULL, NULL, NULL, NULL,
+       &valkyrie_reg_init_5,
+       &valkyrie_reg_init_6,
+       NULL, NULL, NULL,
+       &valkyrie_reg_init_10,
+       &valkyrie_reg_init_11,
+       NULL,
+       &valkyrie_reg_init_13,
+       &valkyrie_reg_init_14,
+       &valkyrie_reg_init_15,
+       NULL, NULL, NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_valkyrie_sense()
+{
+       int sense;
+
+       out_8(&disp_regs->msense, 0);   /* release all lines */
+       __delay(20000);
+       sense = (in_8(&disp_regs->msense) & 0x70) << 4;
+
+       /* drive each sense line low in turn and collect the other 2 */
+       out_8(&disp_regs->msense, 4);   /* drive A low */
+       __delay(20000);
+       sense |= in_8(&disp_regs->msense) & 0x30;
+       out_8(&disp_regs->msense, 2);   /* drive B low */
+       __delay(20000);
+       sense |= ((in_8(&disp_regs->msense) & 0x40) >> 3)
+               | ((in_8(&disp_regs->msense) & 0x10) >> 2);
+       out_8(&disp_regs->msense, 1);   /* drive C low */
+       __delay(20000);
+       sense |= (in_8(&disp_regs->msense) & 0x60) >> 5;
+
+       out_8(&disp_regs->msense, 7);
+       return sense;
+}
+
+void
+map_valkyrie_display(struct device_node *dp)
+{
+       int sense;
+       unsigned long addr;
+
+       if (dp->next != 0)
+               printk("Warning: only using first valkyrie display device\n");
+       if (dp->n_addrs != 1)
+               panic("expecting 1 address for valkyrie (got %d)", dp->n_addrs);
+
+       /* Map in frame buffer and registers */
+       addr = dp->addrs[0].address;
+       frame_buffer = ioremap(addr, 0x100000);
+       disp_regs = ioremap(addr + 0x30a000, 4096);
+       cmap_regs = ioremap(addr + 0x304000, 4096);
+
+       /* Read the monitor sense value and choose the video mode */
+       sense = read_valkyrie_sense();
+       if (video_mode == VMODE_NVRAM) {
+               video_mode = nvram_read_byte(NV_VMODE);
+               if (video_mode <= 0 || video_mode > VMODE_MAX
+                   || valkyrie_reg_init[video_mode-1] == 0)
+                       video_mode = VMODE_CHOOSE;
+       }
+       if (video_mode == VMODE_CHOOSE)
+               video_mode = map_monitor_sense(sense);
+       if (valkyrie_reg_init[video_mode-1] == 0)
+               video_mode = VMODE_640_480_60;
+
+       /*
+        * Reduce the pixel size if we don't have enough VRAM.
+        */
+       if (color_mode == CMODE_NVRAM)
+               color_mode = nvram_read_byte(NV_CMODE);
+       if (color_mode < CMODE_8 || color_mode > CMODE_16
+           || valkyrie_reg_init[video_mode-1]->pitch[color_mode] == 0)
+               color_mode = CMODE_8;
+
+       printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_valkyrie_clock(unsigned char *params)
+{
+       struct cuda_request req;
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+                            0x50, i + 1, params[i]);
+               while (!req.got_reply)
+                       cuda_poll();
+       }
+}
+
+void
+valkyrie_init()
+{
+       int i, yoff, hres;
+       unsigned *p;
+       struct valkyrie_regvals *init;
+
+       if (video_mode <= 0 || video_mode > VMODE_MAX
+           || (init = valkyrie_reg_init[video_mode-1]) == 0)
+               panic("valkyrie: display mode %d not supported", video_mode);
+       n_scanlines = vmode_attrs[video_mode-1].vres;
+       hres = vmode_attrs[video_mode-1].hres;
+       pixel_size = 1 << color_mode;
+       line_pitch = init->pitch[color_mode];
+       row_pitch = line_pitch * 16;
+
+       /* Reset the valkyrie */
+       out_8(&disp_regs->status, 0);
+       udelay(100);
+
+       /* Initialize display timing registers */
+       out_8(&disp_regs->mode, init->mode | 0x80);
+       out_8(&disp_regs->depth, color_mode + 3);
+       set_valkyrie_clock(init->clock_params);
+       udelay(100);
+
+       pmac_init_palette();    /* Initialize colormap */
+
+       /* Turn on display */
+       out_8(&disp_regs->mode, init->mode);
+
+       yoff = (n_scanlines % 16) / 2;
+       fb_start = frame_buffer + yoff * line_pitch + 0x1000;
+
+       /* Clear screen */
+       p = (unsigned *) (frame_buffer + 0x1000);
+       for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+               *p++ = 0;
+
+       display_info.height = n_scanlines;
+       display_info.width = hres;
+       display_info.depth = pixel_size * 8;
+       display_info.pitch = line_pitch;
+       display_info.mode = video_mode;
+       strncpy(display_info.name, "valkyrie", sizeof(display_info.name));
+       display_info.fb_address = (unsigned long) frame_buffer + 0x1000;
+       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+       display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+valkyrie_setmode(struct vc_mode *mode, int doit)
+{
+       int cmode;
+
+       switch (mode->depth) {
+       case 16:
+               cmode = CMODE_16;
+               break;
+       case 8:
+       case 0:         /* (default) */
+               cmode = CMODE_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (mode->mode <= 0 || mode->mode > VMODE_MAX
+           || valkyrie_reg_init[mode->mode-1] == 0
+           || valkyrie_reg_init[mode->mode-1]->pitch[cmode] == 0)
+               return -EINVAL;
+       if (doit) {
+               video_mode = mode->mode;
+               color_mode = cmode;
+               valkyrie_init();
+       }
+       return 0;
+}
+
+void
+valkyrie_set_palette(unsigned char red[], unsigned char green[],
+                   unsigned char blue[], int index, int ncolors)
+{
+       int i;
+
+       for (i = 0; i < ncolors; ++i) {
+               out_8(&cmap_regs->addr, index + i);
+               udelay(1);
+               out_8(&cmap_regs->lut, red[i]);
+               out_8(&cmap_regs->lut, green[i]);
+               out_8(&cmap_regs->lut, blue[i]);
+       }
+}
+
+void
+valkyrie_set_blanking(int blank_mode)
+{
+       /* don't know how to do this yet */
+}
diff --git a/drivers/macintosh/valkyrie.h b/drivers/macintosh/valkyrie.h
new file mode 100644 (file)
index 0000000..90521eb
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the "valkyrie" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 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.
+ */
+
+extern void map_valkyrie_display(struct device_node *);
+extern void valkyrie_init(void);
+extern int valkyrie_setmode(struct vc_mode *mode, int doit);
+extern void valkyrie_set_palette(unsigned char red[], unsigned char green[],
+                                unsigned char blue[], int index, int ncolors);
+extern void valkyrie_set_blanking(int blank_mode);
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
new file mode 100644 (file)
index 0000000..02b4a4a
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Device driver for the via-cuda on Apple Powermacs.
+ *
+ * The VIA (versatile interface adapter) interfaces to the CUDA,
+ * a 6805 microprocessor core which controls the ADB (Apple Desktop
+ * Bus) which connects to the keyboard and mouse.  The CUDA also
+ * controls system power and the RTC (real time clock) chip.
+ *
+ * This file also contains routines to support access to ADB
+ * devices via the /dev/adb interface.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS             0x200           /* skip between registers */
+#define B              0               /* B-side data */
+#define A              RS              /* A-side data */
+#define DIRB           (2*RS)          /* B-side direction (1=output) */
+#define DIRA           (3*RS)          /* A-side direction (1=output) */
+#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
+#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
+#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
+#define T2CL           (8*RS)          /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH           (9*RS)          /* Timer 2 counter (high 8 bits) */
+#define SR             (10*RS)         /* Shift register */
+#define ACR            (11*RS)         /* Auxiliary control register */
+#define PCR            (12*RS)         /* Peripheral control register */
+#define IFR            (13*RS)         /* Interrupt flag register */
+#define IER            (14*RS)         /* Interrupt enable register */
+#define ANH            (15*RS)         /* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ           0x08            /* Transfer request (input) */
+#define TACK           0x10            /* Transfer acknowledge (output) */
+#define TIP            0x20            /* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL                0x1c            /* Shift register control bits */
+#define SR_EXT         0x0c            /* Shift on external clock */
+#define SR_OUT         0x10            /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET                0x80            /* set bits in IER */
+#define IER_CLR                0               /* clear bits in IER */
+#define SR_INT         0x04            /* Shift register full/empty */
+
+static struct adb_handler {
+    void (*handler)(unsigned char *, int, struct pt_regs *);
+} adb_handler[16];
+
+static enum cuda_state {
+    idle,
+    sent_first_byte,
+    sending,
+    reading,
+    read_done,
+    awaiting_reply
+} cuda_state;
+
+static struct cuda_request *current_req;
+static struct cuda_request *last_req;
+static unsigned char cuda_rbuf[16];
+static unsigned char *reply_ptr;
+static int reading_reply;
+static int data_index;
+
+static int init_via(void);
+static void cuda_start(void);
+static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
+
+void
+via_cuda_init()
+{
+    struct device_node *vias;
+
+    vias = find_devices("via-cuda");
+    if (vias == 0) {
+       printk(KERN_WARNING "Warning: no via-cuda\n");
+       vias = find_devices("via-pmu");
+       if (vias == 0)
+           return;
+       printk(KERN_WARNING "Found via-pmu, using it as via-cuda\n");
+    }
+    if (vias->next != 0)
+       printk("Warning: only using 1st via-cuda\n");
+
+#if 0
+    { int i;
+
+    printk("via_cuda_init: node = %p, addrs =", vias->node);
+    for (i = 0; i < vias->n_addrs; ++i)
+       printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
+    printk(", intrs =");
+    for (i = 0; i < vias->n_intrs; ++i)
+       printk(" %x", vias->intrs[i]);
+    printk("\n"); }
+#endif
+
+    if (vias->n_addrs != 1 || vias->n_intrs != 1)
+       panic("via-cuda: expecting 1 address and 1 interrupt");
+    via = (volatile unsigned char *) vias->addrs->address;
+
+    if (!init_via())
+       panic("init_via failed");
+
+    cuda_state = idle;
+
+    if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0))
+       panic("VIA: can't get irq %d\n", vias->intrs[0]);
+
+    /* Clear and enable interrupts */
+    via[IFR] = 0x7f; eieio();  /* clear interrupts by writing 1s */
+    via[IER] = IER_SET|SR_INT; eieio();        /* enable interrupt from SR */
+}
+
+#define WAIT_FOR(cond, what)                           \
+    do {                                               \
+       for (x = 1000; !(cond); --x) {                  \
+           if (x == 0) {                               \
+               printk("Timeout waiting for " what);    \
+               return 0;                               \
+           }                                           \
+           udelay(100);                                        \
+       }                                               \
+    } while (0)
+
+static int
+init_via()
+{
+    int x;
+
+    via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;      /* TACK & TIP out */
+    via[B] |= TACK | TIP;                              /* negate them */
+    via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;         /* SR data in */
+    eieio();
+    x = via[SR]; eieio();      /* clear any left-over data */
+    via[IER] = 0x7f; eieio();  /* disable interrupts from VIA */
+    eieio();
+
+    /* delay 4ms and then clear any pending interrupt */
+    udelay(4000);
+    x = via[SR]; eieio();
+
+    /* sync with the CUDA - assert TACK without TIP */
+    via[B] &= ~TACK; eieio();
+
+    /* wait for the CUDA to assert TREQ in response */
+    WAIT_FOR((via[B] & TREQ) == 0, "CUDA response to sync");
+
+    /* wait for the interrupt and then clear it */
+    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (2)");
+    x = via[SR]; eieio();
+
+    /* finish the sync by negating TACK */
+    via[B] |= TACK; eieio();
+
+    /* wait for the CUDA to negate TREQ and the corresponding interrupt */
+    WAIT_FOR(via[B] & TREQ, "CUDA response to sync (3)");
+    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (4)");
+    x = via[SR]; eieio();
+    via[B] |= TIP; eieio();    /* should be unnecessary */
+
+    return 1;
+}
+
+/* Construct and send a cuda request */
+int
+cuda_request(struct cuda_request *req, void (*done)(struct cuda_request *),
+            int nbytes, ...)
+{
+    va_list list;
+    int i;
+
+    req->nbytes = nbytes;
+    req->done = done;
+    va_start(list, nbytes);
+    for (i = 0; i < nbytes; ++i)
+       req->data[i] = va_arg(list, int);
+    va_end(list);
+    req->reply_expected = 1;
+    return cuda_send_request(req);
+}
+
+int
+cuda_send_request(struct cuda_request *req)
+{
+    unsigned long flags;
+
+    req->next = 0;
+    req->sent = 0;
+    req->got_reply = 0;
+    req->reply_len = 0;
+    save_flags(flags); cli();
+
+    if (current_req != 0) {
+       last_req->next = req;
+       last_req = req;
+    } else {
+       current_req = req;
+       last_req = req;
+       if (cuda_state == idle)
+           cuda_start();
+    }
+
+    restore_flags(flags);
+    return 0;
+}
+
+static void
+cuda_start()
+{
+    unsigned long flags;
+    struct cuda_request *req;
+
+    /* assert cuda_state == idle */
+    /* get the packet to send */
+    req = current_req;
+    if (req == 0)
+       return;
+    save_flags(flags); cli();
+    if ((via[B] & TREQ) == 0) {
+       restore_flags(flags);
+       return;                 /* a byte is coming in from the CUDA */
+    }
+
+    /* set the shift register to shift out and send a byte */
+    via[ACR] |= SR_OUT; eieio();
+    via[SR] = req->data[0]; eieio();
+    via[B] &= ~TIP;
+    cuda_state = sent_first_byte;
+    restore_flags(flags);
+}
+
+void
+cuda_poll()
+{
+    int ie;
+
+    ie = _disable_interrupts();
+    if (via[IFR] & SR_INT)
+       via_interrupt(0, 0, 0);
+    _enable_interrupts(ie);
+}
+
+static void
+via_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+    int x, status;
+    struct cuda_request *req;
+
+    if ((via[IFR] & SR_INT) == 0)
+       return;
+
+    status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
+    /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */
+    switch (cuda_state) {
+    case idle:
+       /* CUDA has sent us the first byte of data - unsolicited */
+       if (status != TREQ)
+           printk("cuda: state=idle, status=%x\n", status);
+       x = via[SR]; eieio();
+       via[B] &= ~TIP; eieio();
+       cuda_state = reading;
+       reply_ptr = cuda_rbuf;
+       reading_reply = 0;
+       break;
+
+    case awaiting_reply:
+       /* CUDA has sent us the first byte of data of a reply */
+       if (status != TREQ)
+           printk("cuda: state=awaiting_reply, status=%x\n", status);
+       x = via[SR]; eieio();
+       via[B] &= ~TIP; eieio();
+       cuda_state = reading;
+       reply_ptr = current_req->reply;
+       reading_reply = 1;
+       break;
+
+    case sent_first_byte:
+       if (status == TREQ + TIP + SR_OUT) {
+           /* collision */
+           via[ACR] &= ~SR_OUT; eieio();
+           x = via[SR]; eieio();
+           via[B] |= TIP | TACK; eieio();
+           cuda_state = idle;
+       } else {
+           /* assert status == TIP + SR_OUT */
+           if (status != TIP + SR_OUT)
+               printk("cuda: state=sent_first_byte status=%x\n", status);
+           via[SR] = current_req->data[1]; eieio();
+           via[B] ^= TACK; eieio();
+           data_index = 2;
+           cuda_state = sending;
+       }
+       break;
+
+    case sending:
+       req = current_req;
+       if (data_index >= req->nbytes) {
+           via[ACR] &= ~SR_OUT; eieio();
+           x = via[SR]; eieio();
+           via[B] |= TACK | TIP; eieio();
+           req->sent = 1;
+           if (req->reply_expected) {
+               cuda_state = awaiting_reply;
+           } else {
+               current_req = req->next;
+               if (req->done)
+                   (*req->done)(req);
+               /* not sure about this */
+               cuda_state = idle;
+               cuda_start();
+           }
+       } else {
+           via[SR] = req->data[data_index++]; eieio();
+           via[B] ^= TACK; eieio();
+       }
+       break;
+
+    case reading:
+       *reply_ptr++ = via[SR]; eieio();
+       if (status == TIP) {
+           /* that's all folks */
+           via[B] |= TACK | TIP; eieio();
+           cuda_state = read_done;
+       } else {
+           /* assert status == TIP | TREQ */
+           if (status != TIP + TREQ)
+               printk("cuda: state=reading status=%x\n", status);
+           via[B] ^= TACK; eieio();
+       }
+       break;
+
+    case read_done:
+       x = via[SR]; eieio();
+       if (reading_reply) {
+           req = current_req;
+           req->reply_len = reply_ptr - req->reply;
+           req->got_reply = 1;
+           current_req = req->next;
+           if (req->done)
+               (*req->done)(req);
+       } else {
+           cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+       }
+       if (status == TREQ) {
+           via[B] &= ~TIP; eieio();
+           cuda_state = reading;
+           reply_ptr = cuda_rbuf;
+           reading_reply = 0;
+       } else {
+           cuda_state = idle;
+           cuda_start();
+       }
+       break;
+
+    default:
+       printk("via_interrupt: unknown cuda_state %d?\n", cuda_state);
+    }
+}
+
+static void
+cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+    int i, id;
+    static int dump_cuda_input = 0;
+
+    switch (buf[0]) {
+    case ADB_PACKET:
+       id = buf[2] >> 4;
+       if (dump_cuda_input) {
+           printk(KERN_INFO "adb packet: ");
+           for (i = 0; i < nb; ++i)
+               printk(" %x", buf[i]);
+           printk(", id = %d\n", id);
+       }
+       if (adb_handler[id].handler != 0) {
+           (*adb_handler[id].handler)(buf, nb, regs);
+       }
+       break;
+
+    default:
+       printk("data from cuda (%d bytes):", nb);
+       for (i = 0; i < nb; ++i)
+           printk(" %.2x", buf[i]);
+       printk("\n");
+    }
+}
+
+/* Ultimately this should return the number of devices with
+   the given default id. */
+int
+adb_register(int default_id,
+            void (*handler)(unsigned char *, int, struct pt_regs *))
+{
+    if (adb_handler[default_id].handler != 0)
+       panic("Two handlers for ADB device %d\n", default_id);
+    adb_handler[default_id].handler = handler;
+    return 1;
+}
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
new file mode 100644 (file)
index 0000000..bcc630f
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * Network device driver for the MACE ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include "mace.h"
+
+#define N_RX_RING      8
+#define N_TX_RING      6
+#define MAX_TX_ACTIVE  1
+#define NCMDS_TX       1       /* dma commands per element in tx ring */
+#define RX_BUFLEN      (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT     HZ      /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR     0x80
+
+struct mace_data {
+    volatile struct mace *mace;
+    volatile struct dbdma_regs *tx_dma;
+    int tx_dma_intr;
+    volatile struct dbdma_regs *rx_dma;
+    int rx_dma_intr;
+    volatile struct dbdma_cmd *tx_cmds;        /* xmit dma command list */
+    volatile struct dbdma_cmd *rx_cmds;        /* recv dma command list */
+    struct sk_buff *rx_bufs[N_RX_RING];
+    int rx_fill;
+    int rx_empty;
+    struct sk_buff *tx_bufs[N_TX_RING];
+    int tx_fill;
+    int tx_empty;
+    unsigned char maccc;
+    unsigned char tx_fullup;
+    unsigned char tx_active;
+    unsigned char tx_bad_runt;
+    struct net_device_stats stats;
+    struct timer_list tx_timeout;
+};
+
+/*
+ * Number of bytes of private data per MACE: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES     (sizeof(struct mace_data) \
+       + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
+
+static int bitrev(int);
+static int mace_open(struct device *dev);
+static int mace_close(struct device *dev);
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *mace_stats(struct device *dev);
+static void mace_set_multicast(struct device *dev);
+static void mace_reset(struct device *dev);
+static int mace_set_address(struct device *dev, void *addr);
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_set_timeout(struct device *dev);
+static void mace_tx_timeout(unsigned long data);
+
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN+2];
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static int
+bitrev(int b)
+{
+    int d = 0, i;
+
+    for (i = 0; i < 8; ++i, b >>= 1)
+       d = (d << 1) | (b & 1);
+    return d;
+}
+
+int
+mace_probe(struct device *dev)
+{
+    int j, rev;
+    struct mace_data *mp;
+    struct device_node *maces;
+    unsigned char *addr;
+
+    maces = find_devices("mace");
+    if (maces == 0)
+       return ENODEV;
+
+    do {
+       if (maces->n_addrs != 3 || maces->n_intrs != 3) {
+           printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n",
+                  maces->full_name);
+           continue;
+       }
+
+       if (dev == NULL)
+           dev = init_etherdev(0, PRIV_BYTES);
+       else {
+           /* XXX this doesn't look right (but it's never used :-) */
+           dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+           if (dev->priv == 0)
+               return -ENOMEM;
+       }
+
+       mp = (struct mace_data *) dev->priv;
+       dev->base_addr = maces->addrs[0].address;
+       mp->mace = (volatile struct mace *) maces->addrs[0].address;
+       dev->irq = maces->intrs[0];
+
+       if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+           printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+           return -EAGAIN;
+       }
+       if (request_irq(maces->intrs[1], mace_txdma_intr, 0, "MACE-txdma",
+                       dev)) {
+           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1]);
+           return -EAGAIN;
+       }
+       if (request_irq(maces->intrs[2], mace_rxdma_intr, 0, "MACE-rxdma",
+                       dev)) {
+           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2]);
+           return -EAGAIN;
+       }
+
+       addr = get_property(maces, "mac-address", NULL);
+       if (addr == NULL) {
+           addr = get_property(maces, "local-mac-address", NULL);
+           if (addr == NULL) {
+               printk(KERN_ERR "Can't get mac-address for MACE at %lx\n",
+                      dev->base_addr);
+               return -EAGAIN;
+           }
+       }
+
+       printk(KERN_INFO "%s: MACE at", dev->name);
+       rev = addr[0] == 0 && addr[1] == 0xA0;
+       for (j = 0; j < 6; ++j) {
+           dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+           printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+       }
+       printk("\n");
+
+       mp = (struct mace_data *) dev->priv;
+       mp->maccc = ENXMT | ENRCV;
+       mp->tx_dma = (volatile struct dbdma_regs *) maces->addrs[1].address;
+       mp->tx_dma_intr = maces->intrs[1];
+       mp->rx_dma = (volatile struct dbdma_regs *) maces->addrs[2].address;
+       mp->rx_dma_intr = maces->intrs[2];
+
+       mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
+       mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
+
+       memset(&mp->stats, 0, sizeof(mp->stats));
+       memset((char *) mp->tx_cmds, 0,
+             (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+
+       mace_reset(dev);
+
+       dev->open = mace_open;
+       dev->stop = mace_close;
+       dev->hard_start_xmit = mace_xmit_start;
+       dev->get_stats = mace_stats;
+       dev->set_multicast_list = mace_set_multicast;
+       dev->set_mac_address = mace_set_address;
+
+       ether_setup(dev);
+
+    } while ((maces = maces->next) != 0);
+
+    return 0;
+}
+
+static void mace_reset(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i;
+
+    /* soft-reset the chip */
+    mb->biucc = SWRST; eieio();
+    udelay(100);
+
+    mb->biucc = XMTSP_64;
+    mb->imr = 0xff;            /* disable all intrs for now */
+    i = mb->ir;
+    mb->maccc = 0;             /* turn off tx, rx */
+    mb->utr = RTRD;
+    mb->fifocc = RCVFW_64;
+    mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+
+    /* load up the hardware address */
+    mb->iac = ADDRCHG | PHYADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+       eieio();
+    for (i = 0; i < 6; ++i) {
+       mb->padr = dev->dev_addr[i];
+       eieio();
+    }
+
+    /* clear the multicast filter */
+    mb->iac = ADDRCHG | LOGADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+       eieio();
+    for (i = 0; i < 8; ++i) {
+       mb->ladrf = 0;
+       eieio();
+    }
+
+    mb->plscc = PORTSEL_GPSI + ENPLSIO;
+}
+
+static int mace_set_address(struct device *dev, void *addr)
+{
+    unsigned char *p = addr;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i;
+    unsigned long flags;
+
+    save_flags(flags); cli();
+
+    /* load up the hardware address */
+    mb->iac = ADDRCHG | PHYADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+       eieio();
+    for (i = 0; i < 6; ++i) {
+       mb->padr = dev->dev_addr[i] = p[i];
+       eieio();
+    }
+    /* note: setting ADDRCHG clears ENRCV */
+    mb->maccc = mp->maccc; eieio();
+
+    restore_flags(flags);
+    return 0;
+}
+
+static int mace_open(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int i;
+    struct sk_buff *skb;
+    unsigned char *data;
+
+    /* initialize list of sk_buffs for receiving and set up recv dma */
+    memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
+    cp = mp->rx_cmds;
+    for (i = 0; i < N_RX_RING - 1; ++i) {
+       skb = dev_alloc_skb(RX_BUFLEN + 2);
+       if (skb == 0) {
+           data = dummy_buf;
+       } else {
+           skb_reserve(skb, 2);        /* so IP header lands on 4-byte bdry */
+           data = skb->data;
+       }
+       mp->rx_bufs[i] = skb;
+       st_le16(&cp->req_count, RX_BUFLEN);
+       st_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+       st_le32(&cp->phy_addr, virt_to_bus(data));
+       cp->xfer_status = 0;
+       ++cp;
+    }
+    mp->rx_bufs[i] = 0;
+    st_le16(&cp->command, DBDMA_STOP);
+    mp->rx_fill = i;
+    mp->rx_empty = 0;
+
+    /* Put a branch back to the beginning of the receive command list */
+    ++cp;
+    st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+    st_le32(&cp->cmd_dep, virt_to_bus(mp->rx_cmds));
+
+    /* start rx dma */
+    out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+    out_le32(&rd->cmdptr, virt_to_bus(mp->rx_cmds));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* put a branch at the end of the tx command list */
+    cp = mp->tx_cmds + NCMDS_TX * N_TX_RING;
+    st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+    st_le32(&cp->cmd_dep, virt_to_bus(mp->tx_cmds));
+
+    /* reset tx dma */
+    out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    out_le32(&td->cmdptr, virt_to_bus(mp->tx_cmds));
+    mp->tx_fill = 0;
+    mp->tx_empty = 0;
+    mp->tx_fullup = 0;
+    mp->tx_active = 0;
+    mp->tx_bad_runt = 0;
+
+    /* turn it on! */
+    mb->maccc = mp->maccc; eieio();
+    /* enable all interrupts except receive interrupts */
+    mb->imr = RCVINT; eieio();
+    return 0;
+}
+
+static int mace_close(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    int i;
+
+    /* disable rx and tx */
+    mb->maccc = 0;
+    mb->imr = 0xff;            /* disable all intrs */
+
+    /* disable rx and tx dma */
+    st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);       /* clear run bit */
+    st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);       /* clear run bit */
+
+    /* free some skb's */
+    for (i = 0; i < N_RX_RING; ++i) {
+       if (mp->rx_bufs[i] != 0) {
+           dev_kfree_skb(mp->rx_bufs[i], FREE_READ);
+           mp->rx_bufs[i] = 0;
+       }
+    }
+    for (i = mp->tx_empty; i != mp->tx_fill; ) {
+       dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+       if (++i >= N_TX_RING)
+           i = 0;
+    }
+
+    return 0;
+}
+
+static inline void mace_set_timeout(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+
+    mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+    mp->tx_timeout.function = mace_tx_timeout;
+    mp->tx_timeout.data = (unsigned long) dev;
+    add_timer(&mp->tx_timeout);
+}
+
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    unsigned long flags;
+    int fill, next, len;
+
+    /* see if there's a free slot in the tx ring */
+    save_flags(flags); cli();
+    fill = mp->tx_fill;
+    next = fill + 1;
+    if (next >= N_TX_RING)
+       next = 0;
+    if (next == mp->tx_empty) {
+       dev->tbusy = 1;
+       mp->tx_fullup = 1;
+       restore_flags(flags);
+       return -1;              /* can't take it at the moment */
+    }
+    restore_flags(flags);
+
+    /* partially fill in the dma command block */
+    len = skb->len;
+    if (len > ETH_FRAME_LEN) {
+       printk(KERN_DEBUG "mace: xmit frame too long (%d)\n", len);
+       len = ETH_FRAME_LEN;
+    }
+    mp->tx_bufs[fill] = skb;
+    cp = mp->tx_cmds + NCMDS_TX * fill;
+    st_le16(&cp->req_count, len);
+    st_le32(&cp->phy_addr, virt_to_bus(skb->data));
+
+    np = mp->tx_cmds + NCMDS_TX * next;
+    out_le16(&np->command, DBDMA_STOP);
+
+    /* poke the tx dma channel */
+    save_flags(flags);
+    cli();
+    mp->tx_fill = next;
+    if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) {
+       out_le16(&cp->xfer_status, 0);
+       out_le16(&cp->command, OUTPUT_LAST);
+       out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+       ++mp->tx_active;
+       mace_set_timeout(dev);
+    }
+    restore_flags(flags);
+
+    return 0;
+}
+
+static struct net_device_stats *mace_stats(struct device *dev)
+{
+    struct mace_data *p = (struct mace_data *) dev->priv;
+
+    return &p->stats;
+}
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define CRC_POLY       0xedb88320
+
+static void mace_set_multicast(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i, j, k, b;
+    unsigned long crc;
+
+    mp->maccc &= ~PROM;
+    if (dev->flags & IFF_PROMISC) {
+       mp->maccc |= PROM;
+    } else {
+       unsigned char multicast_filter[8];
+       struct dev_mc_list *dmi = dev->mc_list;
+
+       if (dev->flags & IFF_ALLMULTI) {
+           for (i = 0; i < 8; i++)
+               multicast_filter[i] = 0xff;
+       } else {
+           for (i = 0; i < 8; i++)
+               multicast_filter[i] = 0;
+           for (i = 0; i < dev->mc_count; i++) {
+               crc = ~0;
+               for (j = 0; j < 6; ++j) {
+                   b = dmi->dmi_addr[j];
+                   for (k = 0; k < 8; ++k) {
+                       if ((crc ^ b) & 1)
+                           crc = (crc >> 1) ^ CRC_POLY;
+                       else
+                           crc >>= 1;
+                       b >>= 1;
+                   }
+               }
+               j = crc >> 26;  /* bit number in multicast_filter */
+               multicast_filter[j >> 3] |= 1 << (j & 7);
+               dmi = dmi->next;
+           }
+       }
+#if 0
+       printk("Multicast filter :");
+       for (i = 0; i < 8; i++)
+           printk("%02x ", multicast_filter[i]);
+       printk("\n");
+#endif
+
+       mb->iac = ADDRCHG | LOGADDR; eieio();
+       while ((mb->iac & ADDRCHG) != 0)
+           eieio();
+       for (i = 0; i < 8; ++i) {
+           mb->ladrf = multicast_filter[i];
+           eieio();
+       }
+    }
+    /* reset maccc */
+    mb->maccc = mp->maccc; eieio();
+}
+
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+{
+    volatile struct mace *mb = mp->mace;
+    static int mace_babbles, mace_jabbers;
+
+    if (intr & MPCO)
+       mp->stats.rx_missed_errors += 256;
+    mp->stats.rx_missed_errors += mb->mpc;     /* reading clears it */
+    if (intr & RNTPCO)
+       mp->stats.rx_length_errors += 256;
+    mp->stats.rx_length_errors += mb->rntpc;   /* reading clears it */
+    if (intr & CERR)
+       ++mp->stats.tx_heartbeat_errors;
+    if (intr & BABBLE)
+       if (mace_babbles++ < 4)
+           printk(KERN_DEBUG "mace: babbling transmitter\n");
+    if (intr & JABBER)
+       if (mace_jabbers++ < 4)
+           printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct device *dev = (struct device *) dev_id;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int intr, fs, i, stat, x;
+    int xcount, dstat;
+    static int mace_last_fs, mace_last_xcount;
+
+    intr = mb->ir;             /* read interrupt register */
+    mace_handle_misc_intrs(mp, intr);
+
+    i = mp->tx_empty;
+    while (mb->pr & XMTSV) {
+       /*
+        * Clear any interrupt indication associated with this status
+        * word.  This appears to unlatch any error indication from
+        * the DMA controller.
+        */
+       intr = mb->ir;
+       if (intr != 0)
+           mace_handle_misc_intrs(mp, intr);
+       if (mp->tx_bad_runt) {
+           fs = mb->xmtfs;
+           eieio();
+           mp->tx_bad_runt = 0;
+           mb->xmtfc = AUTO_PAD_XMIT;
+           del_timer(&mp->tx_timeout);
+           continue;
+       }
+       dstat = ld_le32(&td->status);
+       /* stop DMA controller */
+       out_le32(&td->control, RUN << 16);
+       /*
+        * xcount is the number of complete frames which have been
+        * written to the fifo but for which status has not been read.
+        */
+       xcount = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+       if (xcount == 0 || (dstat & DEAD)) {
+           /*
+            * If a packet was aborted before the DMA controller has
+            * finished transferring it, it seems that there are 2 bytes
+            * which are stuck in some buffer somewhere.  These will get
+            * transmitted as soon as we read the frame status (which
+            * reenables the transmit data transfer request).  Turning
+            * off the DMA controller and/or resetting the MACE doesn't
+            * help.  So we disable auto-padding and FCS transmission
+            * so the two bytes will only be a runt packet which should
+            * be ignored by other stations.
+            */
+           mb->xmtfc = DXMTFCS;
+           eieio();
+       }
+       fs = mb->xmtfs;
+       if ((fs & XMTSV) == 0) {
+           printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+       }
+       cp = mp->tx_cmds + NCMDS_TX * i;
+       stat = ld_le16(&cp->xfer_status);
+       if ((fs & (UFLO|LCOL|LCAR|RTRY)) || (dstat & DEAD) || xcount == 0) {
+           /*
+            * Check whether there were in fact 2 bytes written to
+            * the transmit FIFO.
+            */
+           x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+           if (x != 0) {
+               /* there were two bytes with an end-of-packet indication */
+               mp->tx_bad_runt = 1;
+               mace_set_timeout(dev);
+           } else {
+               /*
+                * Either there weren't the two bytes buffered up, or they
+                * didn't have an end-of-packet indication.  Maybe we ought
+                * to flush the transmit FIFO just in case (by setting the
+                * XMTFWU bit with the transmitter disabled).
+                */
+               mb->xmtfc = AUTO_PAD_XMIT;
+               eieio();
+           }
+       }
+       /* dma should have finished */
+       if (i == mp->tx_fill) {
+           printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+           continue;
+       }
+       /* Update stats */
+       if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+           ++mp->stats.tx_errors;
+           if (fs & LCAR)
+               ++mp->stats.tx_carrier_errors;
+           if (fs & (UFLO|LCOL|RTRY))
+               ++mp->stats.tx_aborted_errors;
+       } else
+           ++mp->stats.tx_packets;
+       dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+       --mp->tx_active;
+       if (++i >= N_TX_RING)
+           i = 0;
+       mace_last_fs = fs;
+       mace_last_xcount = xcount;
+       del_timer(&mp->tx_timeout);
+    }
+
+    mp->tx_empty = i;
+    i += mp->tx_active;
+    if (i >= N_TX_RING)
+       i -= N_TX_RING;
+    if (i != mp->tx_fill && mp->tx_fullup) {
+       mp->tx_fullup = 0;
+       dev->tbusy = 0;
+       mark_bh(NET_BH);
+    }
+    if (!mp->tx_bad_runt && i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE) {
+       do {
+           /* set up the next one */
+           cp = mp->tx_cmds + NCMDS_TX * i;
+           out_le16(&cp->xfer_status, 0);
+           out_le16(&cp->command, OUTPUT_LAST);
+           ++mp->tx_active;
+           if (++i >= N_TX_RING)
+               i = 0;
+       } while (i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE);
+       out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+       mace_set_timeout(dev);
+    }
+}
+
+static void mace_tx_timeout(unsigned long data)
+{
+    struct device *dev = (struct device *) data;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp;
+    unsigned long flags;
+    int i;
+
+    save_flags(flags);
+    cli();
+    if (mp->tx_active == 0 && !mp->tx_bad_runt)
+       goto out;
+
+    /* update various counters */
+    mace_handle_misc_intrs(mp, mb->ir);
+
+    cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
+    printk(KERN_DEBUG "mace: tx dmastat=%x %x bad_runt=%d pr=%x fs=%x fc=%x\n",
+          ld_le32(&td->status), ld_le16(&cp->xfer_status), mp->tx_bad_runt,
+          mb->pr, mb->xmtfs, mb->fifofc);
+
+    /* turn off both tx and rx and reset the chip */
+    mb->maccc = 0;
+    out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    printk(KERN_ERR "mace: transmit timeout - resetting\n");
+    mace_reset(dev);
+
+    /* restart rx dma */
+    cp = bus_to_virt(ld_le32(&rd->cmdptr));
+    out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    out_le16(&cp->xfer_status, 0);
+    out_le32(&rd->cmdptr, virt_to_bus(cp));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* fix up the transmit side */
+    i = mp->tx_empty;
+    mp->tx_active = 0;
+    ++mp->stats.tx_errors;
+    if (mp->tx_bad_runt) {
+       mp->tx_bad_runt = 0;
+    } else if (i != mp->tx_fill) {
+       dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+       if (++i >= N_TX_RING)
+           i = 0;
+       mp->tx_empty = i;
+    }
+    if (mp->tx_fullup) {
+       mp->tx_fullup = 0;
+       dev->tbusy = 0;
+       mark_bh(NET_BH);
+    }
+    if (i != mp->tx_fill) {
+       cp = mp->tx_cmds + NCMDS_TX * i;
+       out_le16(&cp->xfer_status, 0);
+       out_le16(&cp->command, OUTPUT_LAST);
+       out_le32(&td->cmdptr, virt_to_bus(cp));
+       out_le32(&td->control, (RUN << 16) | RUN);
+       ++mp->tx_active;
+       mace_set_timeout(dev);
+    }
+
+    /* turn it back on */
+    out_8(&mb->imr, RCVINT);
+    out_8(&mb->maccc, mp->maccc);
+
+out:
+    restore_flags(flags);
+}
+
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct device *dev = (struct device *) dev_id;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    int i, nb, stat, next;
+    struct sk_buff *skb;
+    unsigned frame_status;
+    static int mace_lost_status;
+    unsigned char *data;
+
+    for (i = mp->rx_empty; i != mp->rx_fill; ) {
+       cp = mp->rx_cmds + i;
+       stat = ld_le16(&cp->xfer_status);
+       if ((stat & ACTIVE) == 0) {
+           next = i + 1;
+           if (next >= N_RX_RING)
+               next = 0;
+           np = mp->rx_cmds + next;
+           if (next != mp->rx_fill
+               && (ld_le16(&np->xfer_status) & ACTIVE) != 0) {
+               printk(KERN_DEBUG "mace: lost a status word\n");
+               ++mace_lost_status;
+           } else
+               break;
+       }
+       nb = ld_le16(&cp->req_count) - ld_le16(&cp->res_count);
+       out_le16(&cp->command, DBDMA_STOP);
+       /* got a packet, have a look at it */
+       skb = mp->rx_bufs[i];
+       if (skb == 0) {
+           ++mp->stats.rx_dropped;
+       } else if (nb > 8) {
+           data = skb->data;
+           frame_status = (data[nb-3] << 8) + data[nb-4];
+           if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
+               ++mp->stats.rx_errors;
+               if (frame_status & RS_OFLO)
+                   ++mp->stats.rx_over_errors;
+               if (frame_status & RS_FRAMERR)
+                   ++mp->stats.rx_frame_errors;
+               if (frame_status & RS_FCSERR)
+                   ++mp->stats.rx_crc_errors;
+           } else {
+               nb -= 8;
+               skb_put(skb, nb);
+               skb->dev = dev;
+               skb->protocol = eth_type_trans(skb, dev);
+               netif_rx(skb);
+               mp->rx_bufs[i] = 0;
+               ++mp->stats.rx_packets;
+           }
+       } else {
+           ++mp->stats.rx_errors;
+           ++mp->stats.rx_length_errors;
+       }
+
+       /* advance to next */
+       if (++i >= N_RX_RING)
+           i = 0;
+    }
+    mp->rx_empty = i;
+
+    i = mp->rx_fill;
+    for (;;) {
+       next = i + 1;
+       if (next >= N_RX_RING)
+           next = 0;
+       if (next == mp->rx_empty)
+           break;
+       cp = mp->rx_cmds + i;
+       skb = mp->rx_bufs[i];
+       if (skb == 0) {
+           skb = dev_alloc_skb(RX_BUFLEN + 2);
+           if (skb != 0) {
+               skb_reserve(skb, 2);
+               mp->rx_bufs[i] = skb;
+           }
+       }
+       st_le16(&cp->req_count, RX_BUFLEN);
+       data = skb? skb->data: dummy_buf;
+       st_le32(&cp->phy_addr, virt_to_bus(data));
+       out_le16(&cp->xfer_status, 0);
+       out_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+#if 0
+       if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+           out_le32(&rd->control, (PAUSE << 16) | PAUSE);
+           while ((in_le32(&rd->status) & ACTIVE) != 0)
+               ;
+       }
+#endif
+       i = next;
+    }
+    if (i != mp->rx_fill) {
+       out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE));
+       mp->rx_fill = i;
+    }
+}
diff --git a/drivers/net/mace.h b/drivers/net/mace.h
new file mode 100644 (file)
index 0000000..a397c83
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * mace.h - definitions for the registers in the Am79C940 MACE
+ * (Medium Access Control for Ethernet) controller.
+ *
+ * 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.
+ */
+
+#define REG(x) volatile unsigned char x; char x ## _pad[15]
+
+struct mace {
+       REG(rcvfifo);           /* receive FIFO */
+       REG(xmtfifo);           /* transmit FIFO */
+       REG(xmtfc);             /* transmit frame control */
+       REG(xmtfs);             /* transmit frame status */
+       REG(xmtrc);             /* transmit retry count */
+       REG(rcvfc);             /* receive frame control */
+       REG(rcvfs);             /* receive frame status (4 bytes) */
+       REG(fifofc);            /* FIFO frame count */
+       REG(ir);                /* interrupt register */
+       REG(imr);               /* interrupt mask register */
+       REG(pr);                /* poll register */
+       REG(biucc);             /* bus interface unit config control */
+       REG(fifocc);            /* FIFO configuration control */
+       REG(maccc);             /* medium access control config control */
+       REG(plscc);             /* phys layer signalling config control */
+       REG(phycc);             /* physical configuration control */
+       REG(chipid_lo);         /* chip ID, lsb */
+       REG(chipid_hi);         /* chip ID, msb */
+       REG(iac);               /* internal address config */
+       REG(reg19);
+       REG(ladrf);             /* logical address filter (8 bytes) */
+       REG(padr);              /* physical address (6 bytes) */
+       REG(reg22);
+       REG(reg23);
+       REG(mpc);               /* missed packet count (clears when read) */
+       REG(reg25);
+       REG(rntpc);             /* runt packet count (clears when read) */
+       REG(rcvcc);             /* recv collision count (clears when read) */
+       REG(reg28);
+       REG(utr);               /* user test reg */
+       REG(reg30);
+       REG(reg31);
+};
+
+/* Bits in XMTFC */
+#define DRTRY          0x80    /* don't retry transmission after collision */
+#define DXMTFCS                0x08    /* don't append FCS to transmitted frame */
+#define AUTO_PAD_XMIT  0x01    /* auto-pad short packets on transmission */
+
+/* Bits in XMTFS: only valid when XMTSV is set in PR and XMTFS */
+#define XMTSV          0x80    /* transmit status (i.e. XMTFS) valid */
+#define UFLO           0x40    /* underflow - xmit fifo ran dry */
+#define LCOL           0x20    /* late collision (transmission aborted) */
+#define MORE           0x10    /* 2 or more retries needed to xmit frame */
+#define ONE            0x08    /* 1 retry needed to xmit frame */
+#define DEFER          0x04    /* MACE had to defer xmission (enet busy) */
+#define LCAR           0x02    /* loss of carrier (transmission aborted) */
+#define RTRY           0x01    /* too many retries (transmission aborted) */
+
+/* Bits in XMTRC: only valid when XMTSV is set in PR (and XMTFS) */
+#define EXDEF          0x80    /* had to defer for excessive time */
+#define RETRY_MASK     0x0f    /* number of retries (0 - 15) */
+
+/* Bits in RCVFC */
+#define LLRCV          0x08    /* low latency receive: early DMA request */
+#define M_RBAR         0x04    /* sets function of EAM/R pin */
+#define AUTO_STRIP_RCV 0x01    /* auto-strip short LLC frames on recv */
+
+/*
+ * Bits in RCVFS.  After a frame is received, four bytes of status
+ * are automatically read from this register and appended to the frame
+ * data in memory.  These are:
+ * Byte 0 and 1: message byte count and frame status
+ * Byte 2: runt packet count
+ * Byte 3: receive collision count
+ */
+#define RS_OFLO                0x8000  /* receive FIFO overflowed */
+#define RS_CLSN                0x4000  /* received frame suffered (late) collision */
+#define RS_FRAMERR     0x2000  /* framing error flag */
+#define RS_FCSERR      0x1000  /* frame had FCS error */
+#define RS_COUNT       0x0fff  /* mask for byte count field */
+
+/* Bits (fields) in FIFOFC */
+#define RCVFC_SH       4       /* receive frame count in FIFO */
+#define RCVFC_MASK     0x0f
+#define XMTFC_SH       0       /* transmit frame count in FIFO */
+#define XMTFC_MASK     0x0f
+
+/*
+ * Bits in IR and IMR.  The IR clears itself when read.
+ * Setting a bit in the IMR will disable the corresponding interrupt.
+ */
+#define JABBER         0x80    /* jabber error - 10baseT xmission too long */
+#define BABBLE         0x40    /* babble - xmitter xmitting for too long */
+#define CERR           0x20    /* collision err - no SQE test (heartbeat) */
+#define RCVCCO         0x10    /* RCVCC overflow */
+#define RNTPCO         0x08    /* RNTPC overflow */
+#define MPCO           0x04    /* MPC overflow */
+#define RCVINT         0x02    /* receive interrupt */
+#define XMTINT         0x01    /* transmitter interrupt */
+
+/* Bits in PR */
+#define XMTSV          0x80    /* XMTFS valid (same as in XMTFS) */
+#define TDTREQ         0x40    /* set when xmit fifo is requesting data */
+#define RDTREQ         0x20    /* set when recv fifo requests data xfer */
+
+/* Bits in BIUCC */
+#define BSWP           0x40    /* byte swap, i.e. big-endian bus */
+#define XMTSP_4                0x00    /* start xmitting when 4 bytes in FIFO */
+#define XMTSP_16       0x10    /* start xmitting when 16 bytes in FIFO */
+#define XMTSP_64       0x20    /* start xmitting when 64 bytes in FIFO */
+#define XMTSP_112      0x30    /* start xmitting when 112 bytes in FIFO */
+#define SWRST          0x01    /* software reset */
+
+/* Bits in FIFOCC */
+#define XMTFW_8                0x00    /* xmit fifo watermark = 8 words free */
+#define XMTFW_16       0x40    /*  16 words free */
+#define XMTFW_32       0x80    /*  32 words free */
+#define RCVFW_16       0x00    /* recv fifo watermark = 16 bytes avail */
+#define RCVFW_32       0x10    /*  32 bytes avail */
+#define RCVFW_64       0x20    /*  64 bytes avail */
+#define XMTFWU         0x08    /* xmit fifo watermark update enable */
+#define RCVFWU         0x04    /* recv fifo watermark update enable */
+#define XMTBRST                0x02    /* enable transmit burst mode */
+#define RCVBRST                0x01    /* enable receive burst mode */
+
+/* Bits in MACCC */
+#define PROM           0x80    /* promiscuous mode */
+#define DXMT2PD                0x40    /* disable xmit two-part deferral algorithm */
+#define EMBA           0x20    /* enable modified backoff algorithm */
+#define DRCVPA         0x08    /* disable receiving physical address */
+#define DRCVBC         0x04    /* disable receiving broadcasts */
+#define ENXMT          0x02    /* enable transmitter */
+#define ENRCV          0x01    /* enable receiver */
+
+/* Bits in PLSCC */
+#define XMTSEL         0x08    /* select DO+/DO- state when idle */
+#define PORTSEL_AUI    0x00    /* select AUI port */
+#define PORTSEL_10T    0x02    /* select 10Base-T port */
+#define PORTSEL_DAI    0x04    /* select DAI port */
+#define PORTSEL_GPSI   0x06    /* select GPSI port */
+#define ENPLSIO                0x01    /* enable optional PLS I/O pins */
+
+/* Bits in PHYCC */
+#define LNKFL          0x80    /* reports 10Base-T link failure */
+#define DLNKTST                0x40    /* disable 10Base-T link test */
+#define REVPOL         0x20    /* 10Base-T receiver polarity reversed */
+#define DAPC           0x10    /* disable auto receiver polarity correction */
+#define LRT            0x08    /* low receive threshold for long links */
+#define ASEL           0x04    /* auto-select AUI or 10Base-T port */
+#define RWAKE          0x02    /* remote wake function */
+#define AWAKE          0x01    /* auto wake function */
+
+/* Bits in IAC */
+#define ADDRCHG                0x80    /* request address change */
+#define PHYADDR                0x04    /* access physical address */
+#define LOGADDR                0x02    /* access multicast filter */
+
+/* Bits in UTR */
+#define RTRE           0x80    /* reserved test register enable. DON'T SET. */
+#define RTRD           0x40    /* reserved test register disable.  Sticky */
+#define RPA            0x20    /* accept runt packets */
+#define FCOLL          0x10    /* force collision */
+#define RCVFCSE                0x08    /* receive FCS enable */
+#define LOOP_NONE      0x00    /* no loopback */
+#define LOOP_EXT       0x02    /* external loopback */
+#define LOOP_INT       0x04    /* internal loopback, excludes MENDEC */
+#define LOOP_MENDEC    0x06    /* internal loopback, includes MENDEC */
index 3ce90092a580e88e84199cfb971546ea3f79ec0c..b9fb60365b8996ab0966592b6b15702ff84e7c2b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
+/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
  * creator.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index 9eaad5bc71ea764590a8006977174d6fb7673912..06474e2c9f28d3074c4cf28c43a987eed97867d6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
+/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index 7de26c2f7039df721ef3956330e76a91d63a4ba2..9365be4dbce4c0644e5ddb7e19e67b7b16dddf7a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
+/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
index f96f984c4f570e142210b43e2d46f625c1ae8da1..a8834fbc01a37bfe435edd0f6ae5e42c711dd2d8 100644 (file)
@@ -108,4 +108,9 @@ dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
   fi
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
+if [ "$CONFIG_SCSI_MESH" != "n" ]; then
+  int '  maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5
+fi
+dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
 endmenu
index 7ad649a668dac02c92f46b031f1f380558fd548a..48eb8f3a8e3d397bc97afa41829b094719488a6c 100644 (file)
@@ -273,6 +273,22 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_MESH),y)
+L_OBJS += mesh.o
+else
+  ifeq ($(CONFIG_SCSI_MESH),m)
+  M_OBJS += mesh.o
+  endif
+endif
+
+ifeq ($(CONFIG_SCSI_MAC53C94),y)
+L_OBJS += mac53c94.o
+else
+  ifeq ($(CONFIG_SCSI_MAC53C94),m)
+  M_OBJS += mac53c94.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DEBUG),y)
 L_OBJS += scsi_debug.o
 else
index 4fa986c9ed2ab7c2033d4ff375d3e95614f8b772..7bf860e8cd3c02926e648517b25f1b4c1b707059 100644 (file)
 #include "ide-scsi.h"
 #endif
 
+#ifdef CONFIG_SCSI_MESH
+#include "mesh.h"
+#endif
+
+#ifdef CONFIG_SCSI_MAC53C94
+#include "mac53c94.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -339,6 +347,12 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_BLK_DEV_IDESCSI
     IDESCSI,
 #endif
+#ifdef CONFIG_SCSI_MESH
+    SCSI_MESH,
+#endif
+#ifdef CONFIG_SCSI_MAC53C94
+    SCSI_MAC53C94,
+#endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
 #endif
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
new file mode 100644 (file)
index 0000000..e7d1470
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * SCSI low-level driver for the 53c94 SCSI bus adaptor found
+ * on Power Macintosh computers, controlling the external SCSI chain.
+ * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mac53c94.h"
+
+struct proc_dir_entry proc_scsi_mac53c94 = {
+       PROC_SCSI_53C94, 5, "53c94",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum fsc_phase {
+       idle,
+       selecting,
+       dataing,
+       completing,
+       busfreeing,
+};
+
+struct fsc_state {
+       volatile struct mac53c94_regs *regs;
+       int     intr;
+       volatile struct dbdma_regs *dma;
+       int     dmaintr;
+       int     clk_freq;
+       struct  Scsi_Host *host;
+       struct  fsc_state *next;
+       Scsi_Cmnd *request_q;
+       Scsi_Cmnd *request_qtail;
+       Scsi_Cmnd *current_req;         /* req we're currently working on */
+       enum fsc_phase phase;           /* what we're currently trying to do */
+       struct dbdma_cmd *dma_cmds;     /* space for dbdma commands, aligned */
+};
+
+static struct fsc_state *all_53c94s;
+
+static void mac53c94_init(struct fsc_state *);
+static void mac53c94_start(struct fsc_state *);
+static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void cmd_done(struct fsc_state *, int result);
+static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
+static int data_goes_out(Scsi_Cmnd *);
+
+int
+mac53c94_detect(Scsi_Host_Template *tp)
+{
+       struct device_node *node;
+       int nfscs;
+       struct fsc_state *state, **prev_statep;
+       struct Scsi_Host *host;
+       void *dma_cmd_space;
+       unsigned char *clkprop;
+       int proplen;
+
+       nfscs = 0;
+       prev_statep = &all_53c94s;
+       for (node = find_devices("53c94"); node != 0; node = node->next) {
+               if (node->n_addrs != 2 || node->n_intrs != 2)
+                       panic("53c94: expected 2 addrs and intrs (got %d/%d)",
+                             node->n_addrs, node->n_intrs);
+               host = scsi_register(tp, sizeof(struct fsc_state));
+               if (host == 0)
+                       panic("couldn't register 53c94 host");
+               host->unique_id = nfscs;
+               note_scsi_host(node, host);
+
+               state = (struct fsc_state *) host->hostdata;
+               if (state == 0)
+                       panic("no 53c94 state");
+               state->host = host;
+               state->regs = (volatile struct mac53c94_regs *)
+                       node->addrs[0].address;
+               state->intr = node->intrs[0];
+               state->dma = (volatile struct dbdma_regs *)
+                       node->addrs[1].address;
+               state->dmaintr = node->intrs[1];
+
+               clkprop = get_property(node, "clock-frequency", &proplen);
+               if (clkprop == NULL || proplen != sizeof(int)) {
+                       printk(KERN_ERR "%s: can't get clock frequency\n",
+                              node->full_name);
+                       state->clk_freq = 25000000;
+               } else
+                       state->clk_freq = *(int *)clkprop;
+
+               /* Space for dma command list: +1 for stop command,
+                  +1 to allow for aligning. */
+               dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
+                                       sizeof(struct dbdma_cmd), GFP_KERNEL);
+               if (dma_cmd_space == 0)
+                       panic("53c94: couldn't allocate dma command space");
+               state->dma_cmds = (struct dbdma_cmd *)
+                       DBDMA_ALIGN(dma_cmd_space);
+               memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
+                      * sizeof(struct dbdma_cmd));
+
+               *prev_statep = state;
+               prev_statep = &state->next;
+
+               if (request_irq(state->intr, mac53c94_interrupt, 0,
+                               "53C94", state)) {
+                       printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
+               }
+
+               mac53c94_init(state);
+
+               ++nfscs;
+       }
+       return nfscs;
+}
+
+int
+mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+       unsigned long flags;
+       struct fsc_state *state;
+
+#if 0
+       if (data_goes_out(cmd)) {
+               int i;
+               printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
+               for (i = 0; i < cmd->cmd_len; ++i)
+                       printk(" %.2x", cmd->cmnd[i]);
+               printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+                      cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+       }
+#endif
+
+       cmd->scsi_done = done;
+       cmd->host_scribble = NULL;
+
+       state = (struct fsc_state *) cmd->host->hostdata;
+
+       save_flags(flags);
+       cli();
+       if (state->request_q == NULL)
+               state->request_q = cmd;
+       else
+               state->request_qtail->host_scribble = (void *) cmd;
+       state->request_qtail = cmd;
+
+       if (state->phase == idle)
+               mac53c94_start(state);
+
+       restore_flags(flags);
+       return 0;
+}
+
+int
+mac53c94_abort(Scsi_Cmnd *cmd)
+{
+       return SCSI_ABORT_SNOOZE;
+}
+
+int
+mac53c94_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+       struct fsc_state *state = (struct fsc_state *) cmd->host->hostdata;
+       volatile struct mac53c94_regs *regs = state->regs;
+       volatile struct dbdma_regs *dma = state->dma;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+       regs->command = CMD_SCSI_RESET; /* assert RST */
+       eieio();
+       udelay(100);                    /* leave it on for a while (>= 25us) */
+       regs->command = CMD_RESET;
+       eieio();
+       udelay(20);
+       mac53c94_init(state);
+       regs->command = CMD_NOP;
+       eieio();
+       restore_flags(flags);
+       return SCSI_RESET_PENDING;
+}
+
+int
+mac53c94_command(Scsi_Cmnd *cmd)
+{
+       printk(KERN_DEBUG "whoops... mac53c94_command called\n");
+       return -1;
+}
+
+static void
+mac53c94_init(struct fsc_state *state)
+{
+       volatile struct mac53c94_regs *regs = state->regs;
+       volatile struct dbdma_regs *dma = state->dma;
+       int x;
+
+       regs->config1 = state->host->this_id | CF1_PAR_ENABLE;
+       regs->sel_timeout = TIMO_VAL(250);      /* 250ms */
+       regs->clk_factor = CLKF_VAL(state->clk_freq);
+       regs->config2 = CF2_FEATURE_EN;
+       regs->config3 = 0;
+       regs->sync_period = 0;
+       regs->sync_offset = 0;
+       eieio();
+       x = regs->interrupt;
+       st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a 53C94.
+ * Should be called with interrupts disabled.
+ */
+static void
+mac53c94_start(struct fsc_state *state)
+{
+       Scsi_Cmnd *cmd;
+       volatile struct mac53c94_regs *regs = state->regs;
+       int i;
+
+       if (state->phase != idle || state->current_req != NULL)
+               panic("inappropriate mac53c94_start (state=%p)", state);
+       if (state->request_q == NULL)
+               return;
+       state->current_req = cmd = state->request_q;
+       state->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+
+       /* Off we go */
+       regs->count_lo = 0;
+       regs->count_mid = 0;
+       regs->count_hi = 0;
+       eieio();
+       regs->command = CMD_NOP + CMD_DMA_MODE;
+       udelay(1);
+       eieio();
+       regs->command = CMD_FLUSH;
+       udelay(1);
+       eieio();
+       regs->dest_id = cmd->target;
+       regs->sync_period = 0;
+       regs->sync_offset = 0;
+       eieio();
+
+       /* load the command into the FIFO */
+       for (i = 0; i < cmd->cmd_len; ++i) {
+               regs->fifo = cmd->cmnd[i];
+               eieio();
+       }
+
+       /* do select without ATN XXX */
+       regs->command = CMD_SELECT;
+       state->phase = selecting;
+
+       if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
+               set_dma_cmds(state, cmd);
+}
+
+static void
+mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+       struct fsc_state *state = (struct fsc_state *) dev_id;
+       volatile struct mac53c94_regs *regs = state->regs;
+       volatile struct dbdma_regs *dma = state->dma;
+       Scsi_Cmnd *cmd = state->current_req;
+       int nb, stat, seq, intr;
+       static int mac53c94_errors;
+
+       /*
+        * Apparently, reading the interrupt register unlatches
+        * the status and sequence step registers.
+        */
+       seq = regs->seqstep;
+       stat = regs->status;
+       intr = regs->interrupt;
+
+#if 0
+       printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
+              intr, stat, seq, state->phase);
+#endif
+
+       if (intr & INTR_RESET) {
+               /* SCSI bus was reset */
+               printk(KERN_INFO "external SCSI bus reset detected\n");
+               regs->command = CMD_NOP;
+               st_le32(&dma->control, RUN << 16);      /* stop dma */
+               cmd_done(state, DID_RESET << 16);
+               return;
+       }
+       if (intr & INTR_ILL_CMD) {
+               printk(KERN_ERR "53c94: illegal cmd, intr=%x stat=%x seq=%x phase=%d\n",
+                      intr, stat, seq, state->phase);
+               cmd_done(state, DID_ERROR << 16);
+               return;
+       }
+       if (stat & STAT_ERROR) {
+#if 0
+               /* XXX these seem to be harmless? */
+               printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n",
+                      intr, stat, seq, state->phase);
+#endif
+               ++mac53c94_errors;
+               regs->command = CMD_NOP + CMD_DMA_MODE;
+               eieio();
+       }
+       if (cmd == 0) {
+               printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
+               return;
+       }
+       if (stat & STAT_PARITY) {
+               printk(KERN_ERR "mac53c94: parity error\n");
+               cmd_done(state, DID_PARITY << 16);
+               return;
+       }
+       switch (state->phase) {
+       case selecting:
+               if (intr & INTR_DISCONNECT) {
+                       /* selection timed out */
+                       cmd_done(state, DID_BAD_TARGET << 16);
+                       return;
+               }
+               if (intr != INTR_BUS_SERV + INTR_DONE) {
+                       printk(KERN_DEBUG "got intr %x during selection\n", intr);
+                       cmd_done(state, DID_ERROR << 16);
+                       return;
+               }
+               if ((seq & SS_MASK) != SS_DONE) {
+                       printk(KERN_DEBUG "seq step %x after command\n", seq);
+                       cmd_done(state, DID_ERROR << 16);
+                       return;
+               }
+               regs->command = CMD_NOP;
+               /* set DMA controller going if any data to transfer */
+               if ((stat & (STAT_MSG|STAT_CD)) == 0
+                   && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+                       nb = cmd->SCp.this_residual;
+                       if (nb > 0xfff0)
+                               nb = 0xfff0;
+                       cmd->SCp.this_residual -= nb;
+                       regs->count_lo = nb;
+                       regs->count_mid = nb >> 8;
+                       eieio();
+                       regs->command = CMD_DMA_MODE + CMD_NOP;
+                       eieio();
+                       st_le32(&dma->cmdptr, virt_to_phys(state->dma_cmds));
+                       st_le32(&dma->control, (RUN << 16) | RUN);
+                       eieio();
+                       regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+                       state->phase = dataing;
+                       break;
+               } else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
+                       /* up to status phase already */
+                       regs->command = CMD_I_COMPLETE;
+                       state->phase = completing;
+               } else {
+                       printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
+                              stat & STAT_PHASE);
+                       cmd_done(state, DID_ERROR << 16);
+                       return;
+               }
+               break;
+
+       case dataing:
+               if (intr != INTR_BUS_SERV) {
+                       printk(KERN_DEBUG "got intr %x before status\n", intr);
+                       cmd_done(state, DID_ERROR << 16);
+                       return;
+               }
+               if (cmd->SCp.this_residual != 0
+                   && (stat & (STAT_MSG|STAT_CD)) == 0) {
+                       /* Set up the count regs to transfer more */
+                       nb = cmd->SCp.this_residual;
+                       if (nb > 0xfff0)
+                               nb = 0xfff0;
+                       cmd->SCp.this_residual -= nb;
+                       regs->count_lo = nb;
+                       regs->count_mid = nb >> 8;
+                       eieio();
+                       regs->command = CMD_DMA_MODE + CMD_NOP;
+                       eieio();
+                       regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+                       break;
+               }
+               if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
+                       printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
+               }
+               st_le32(&dma->control, RUN << 16);      /* stop dma */
+               /* should check dma status */
+               regs->command = CMD_I_COMPLETE;
+               state->phase = completing;
+               break;
+       case completing:
+               if (intr != INTR_DONE) {
+                       printk(KERN_DEBUG "got intr %x on completion\n", intr);
+                       cmd_done(state, DID_ERROR << 16);
+                       return;
+               }
+               cmd->SCp.Status = regs->fifo; eieio();
+               cmd->SCp.Message = regs->fifo; eieio();
+               cmd->result = 
+               regs->command = CMD_ACCEPT_MSG;
+               state->phase = busfreeing;
+               break;
+       case busfreeing:
+               if (intr != INTR_DISCONNECT) {
+                       printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr);
+               }
+               cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8)
+                        + cmd->SCp.Status);
+               break;
+       default:
+               printk(KERN_DEBUG "don't know about phase %d\n", state->phase);
+       }
+}
+
+static void
+cmd_done(struct fsc_state *state, int result)
+{
+       Scsi_Cmnd *cmd;
+
+       cmd = state->current_req;
+       if (cmd != 0) {
+               cmd->result = result;
+               (*cmd->scsi_done)(cmd);
+               state->current_req = NULL;
+       }
+       state->phase = idle;
+       mac53c94_start(state);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
+{
+       int i, dma_cmd, total;
+       struct scatterlist *scl;
+       struct dbdma_cmd *dcmds;
+
+       dma_cmd = data_goes_out(cmd)? OUTPUT_MORE: INPUT_MORE;
+       dcmds = state->dma_cmds;
+       if (cmd->use_sg > 0) {
+               total = 0;
+               scl = (struct scatterlist *) cmd->buffer;
+               for (i = 0; i < cmd->use_sg; ++i) {
+                       if (scl->length > 0xffff)
+                               panic("mac53c94: scatterlist element >= 64k");
+                       total += scl->length;
+                       st_le16(&dcmds->req_count, scl->length);
+                       st_le16(&dcmds->command, dma_cmd);
+                       st_le32(&dcmds->phy_addr, virt_to_phys(scl->address));
+                       dcmds->xfer_status = 0;
+                       ++scl;
+                       ++dcmds;
+               }
+       } else {
+               total = cmd->request_bufflen;
+               if (total > 0xffff)
+                       panic("mac53c94: transfer size >= 64k");
+               st_le16(&dcmds->req_count, total);
+               st_le32(&dcmds->phy_addr, virt_to_phys(cmd->request_buffer));
+               dcmds->xfer_status = 0;
+               ++dcmds;
+       }
+       dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+       st_le16(&dcmds[-1].command, dma_cmd);
+       st_le16(&dcmds->command, DBDMA_STOP);
+       cmd->SCp.this_residual = total;
+}
+
+/*
+ * Work out whether data will be going out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+       switch (cmd->cmnd[0]) {
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:          /* any others? */
+               return 1;
+       default:
+               return 0;
+       }
+}
diff --git a/drivers/scsi/mac53c94.h b/drivers/scsi/mac53c94.h
new file mode 100644 (file)
index 0000000..b423b0c
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * mac53c94.h: definitions for the driver for the 53c94 SCSI bus adaptor
+ * found on Power Macintosh computers, controlling the external SCSI chain.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MAC53C94_H
+#define _MAC53C94_H
+
+extern struct proc_dir_entry proc_scsi_mac53c94;
+
+int mac53c94_detect(Scsi_Host_Template *);
+int mac53c94_command(Scsi_Cmnd *);
+int mac53c94_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mac53c94_abort(Scsi_Cmnd *);
+int mac53c94_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MAC53C94 {                                        \
+       NULL,                   /* next */              \
+       NULL,                   /* usage_count */       \
+       &proc_scsi_mac53c94,    /* proc_dir */          \
+       NULL,                   /* proc_info */         \
+       "53C94",                /* name */              \
+       mac53c94_detect,        /* detect */            \
+       NULL,                   /* release */           \
+       NULL,                   /* info */              \
+       mac53c94_command,       /* command */           \
+       mac53c94_queue,         /* queuecommand */      \
+       mac53c94_abort,         /* abort */             \
+       mac53c94_reset,         /* reset */             \
+       NULL,                   /* slave_attach */      \
+       NULL,                   /* bios_param */        \
+       1,                      /* can_queue */         \
+       7,                      /* this_id */           \
+       SG_ALL,                 /* sg_tablesize */      \
+       1,                      /* cmd_per_lun */       \
+       0,                      /* present */           \
+       0,                      /* unchecked_isa_dma */ \
+       DISABLE_CLUSTERING,     /* use_clustering */    \
+}
+
+/*
+ * Registers in the 53C94 controller.
+ */
+
+struct mac53c94_regs {
+       unsigned char   count_lo;
+       char pad0[15];
+       unsigned char   count_mid;
+       char pad1[15];
+       unsigned char   fifo;
+       char pad2[15];
+       unsigned char   command;
+       char pad3[15];
+       unsigned char   status;
+       char pad4[15];
+       unsigned char   interrupt;
+       char pad5[15];
+       unsigned char   seqstep;
+       char pad6[15];
+       unsigned char   flags;
+       char pad7[15];
+       unsigned char   config1;
+       char pad8[15];
+       unsigned char   clk_factor;
+       char pad9[15];
+       unsigned char   test;
+       char pad10[15];
+       unsigned char   config2;
+       char pad11[15];
+       unsigned char   config3;
+       char pad12[15];
+       unsigned char   config4;
+       char pad13[15];
+       unsigned char   count_hi;
+       char pad14[15];
+       unsigned char   fifo_res;
+       char pad15[15];
+};
+
+/*
+ * Alternate functions for some registers.
+ */
+#define dest_id                status
+#define sel_timeout    interrupt
+#define sync_period    seqstep
+#define sync_offset    flags
+
+/*
+ * Bits in command register.
+ */
+#define CMD_DMA_MODE   0x80
+#define CMD_MODE_MASK  0x70
+#define CMD_MODE_INIT  0x10
+#define CMD_MODE_TARG  0x20
+#define CMD_MODE_DISC  0x40
+
+#define CMD_NOP                0
+#define CMD_FLUSH      1
+#define CMD_RESET      2
+#define CMD_SCSI_RESET 3
+
+#define CMD_XFER_DATA  0x10
+#define CMD_I_COMPLETE 0x11
+#define CMD_ACCEPT_MSG 0x12
+#define CMD_XFER_PAD   0x18
+#define CMD_SET_ATN    0x1a
+#define CMD_CLR_ATN    0x1b
+
+#define CMD_SEND_MSG   0x20
+#define CMD_SEND_STATUS        0x21
+#define CMD_SEND_DATA  0x22
+#define CMD_DISC_SEQ   0x23
+#define CMD_TERMINATE  0x24
+#define CMD_T_COMPLETE 0x25
+#define CMD_DISCONNECT 0x27
+#define CMD_RECV_MSG   0x28
+#define CMD_RECV_CDB   0x29
+#define CMD_RECV_DATA  0x2a
+#define CMD_RECV_CMD   0x2b
+#define CMD_ABORT_DMA  0x04
+
+#define CMD_RESELECT   0x40
+#define CMD_SELECT     0x41
+#define CMD_SELECT_ATN 0x42
+#define CMD_SELATN_STOP        0x43
+#define CMD_ENABLE_SEL 0x44
+#define CMD_DISABLE_SEL        0x45
+#define CMD_SEL_ATN3   0x46
+#define CMD_RESEL_ATN3 0x47
+
+/*
+ * Bits in status register.
+ */
+#define STAT_IRQ       0x80
+#define STAT_ERROR     0x40
+#define STAT_PARITY    0x20
+#define STAT_TC_ZERO   0x10
+#define STAT_DONE      0x08
+#define STAT_PHASE     0x07
+#define STAT_MSG       0x04
+#define STAT_CD                0x02
+#define STAT_IO                0x01
+
+/*
+ * Bits in interrupt register.
+ */
+#define INTR_RESET     0x80    /* SCSI bus was reset */
+#define INTR_ILL_CMD   0x40    /* illegal command */
+#define INTR_DISCONNECT        0x20    /* we got disconnected */
+#define INTR_BUS_SERV  0x10    /* bus service requested */
+#define INTR_DONE      0x08    /* function completed */
+#define INTR_RESELECTED        0x04    /* we were reselected */
+#define INTR_SEL_ATN   0x02    /* we were selected, ATN asserted */
+#define INTR_SELECT    0x01    /* we were selected, ATN negated */
+
+/*
+ * Encoding for the select timeout.
+ */
+#define TIMO_VAL(x)    ((x) * 5000 / 7682)
+
+/*
+ * Bits in sequence step register.
+ */
+#define SS_MASK                7
+#define SS_ARB_SEL     0       /* Selection & arbitration complete */
+#define SS_MSG_SENT    1       /* One message byte sent */
+#define SS_NOT_CMD     2       /* Not in command phase */
+#define SS_PHASE_CHG   3       /* Early phase change, cmd bytes lost */
+#define SS_DONE                4       /* Command was sent OK */
+
+/*
+ * Encoding for sync transfer period.
+ */
+#define SYNCP_MASK     0x1f
+#define SYNCP_MIN      4
+#define SYNCP_MAX      31
+
+/*
+ * Bits in flags register.
+ */
+#define FLAGS_FIFO_LEV 0x1f
+#define FLAGS_SEQ_STEP 0xe0
+
+/*
+ * Encoding for sync offset.
+ */
+#define SYNCO_MASK     0x0f
+#define SYNCO_ASS_CTRL 0x30    /* REQ/ACK assertion control */
+#define SYNCO_NEG_CTRL 0xc0    /* REQ/ACK negation control */
+
+/*
+ * Bits in config1 register.
+ */
+#define CF1_SLOW_CABLE 0x80    /* Slow cable mode */
+#define CF1_NO_RES_REP 0x40    /* Disable SCSI reset reports */
+#define CF1_PAR_TEST   0x20    /* Parity test mode enable */
+#define CF1_PAR_ENABLE 0x10    /* Enable parity checks */
+#define CF1_TEST       0x08    /* Chip tests */
+#define CF1_MY_ID      0x07    /* Controller's address on bus */
+
+/*
+ * Encoding for clk_factor register.
+ */
+#define CLKF_MASK      7
+#define CLKF_VAL(freq) ((((freq) + 4999999) / 5000000) & CLKF_MASK)
+
+/*
+ * Bits in test mode register.
+ */
+#define TEST_TARGET    1       /* target test mode */
+#define TEST_INITIATOR 2       /* initiator test mode */
+#define TEST_TRISTATE  4       /* tristate (hi-z) test mode */
+
+/*
+ * Bits in config2 register.
+ */
+#define CF2_RFB                0x80
+#define CF2_FEATURE_EN 0x40    /* enable features / phase latch */
+#define CF2_BYTECTRL   0x20
+#define CF2_DREQ_HIZ   0x10
+#define CF2_SCSI2      0x08
+#define CF2_PAR_ABORT  0x04    /* bad parity target abort */
+#define CF2_REG_PARERR 0x02    /* register parity error */
+#define CF2_DMA_PARERR 0x01    /* DMA parity error */
+
+/*
+ * Bits in the config3 register.
+ */
+#define CF3_ID_MSG_CHK 0x80
+#define CF3_3B_MSGS    0x40
+#define CF3_CDB10      0x20
+#define CF3_FASTSCSI   0x10    /* enable fast SCSI support */
+#define CF3_FASTCLOCK  0x08
+#define CF3_SAVERESID  0x04
+#define CF3_ALT_DMA    0x02
+#define CF3_THRESH_8   0x01
+
+/*
+ * Bits in the config4 register.
+ */
+#define CF4_EAN                0x04
+#define CF4_TEST       0x02
+#define CF4_BBTE       0x01
+
+#endif /* _MAC53C94_H */
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
new file mode 100644 (file)
index 0000000..66c1f64
--- /dev/null
@@ -0,0 +1,1321 @@
+/*
+ * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
+ * bus adaptor found on Power Macintosh computers.
+ * We assume the MESH is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/config.h>
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mesh.h"
+
+#if 0
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_WARNING
+#endif
+
+#if CONFIG_SCSI_MESH_SYNC_RATE == 0
+int mesh_sync_period = 100;
+int mesh_sync_offset = 0;
+#else
+int mesh_sync_period = 1000 / CONFIG_SCSI_MESH_SYNC_RATE;      /* ns */
+int mesh_sync_offset = 15;
+#endif
+
+int mesh_sync_targets = 0xff;  /* targets to set synchronous (bitmap) */
+int mesh_resel_targets = 0xff; /* targets that we let disconnect (bitmap) */
+int mesh_debug_targets = 0;    /* print debug for these targets */
+
+#define ALLOW_SYNC(tgt)                ((mesh_sync_targets >> (tgt)) & 1)
+#define ALLOW_RESEL(tgt)       ((mesh_resel_targets >> (tgt)) & 1)
+#define ALLOW_DEBUG(tgt)       ((mesh_debug_targets >> (tgt)) & 1)
+#define DEBUG_TARGET(cmd)      ((cmd) && ALLOW_DEBUG((cmd)->target))
+
+struct proc_dir_entry proc_scsi_mesh = {
+       PROC_SCSI_MESH, 4, "mesh",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum mesh_phase {
+       idle,
+       arbitrating,
+       selecting,
+       commanding,
+       dataing,
+       statusing,
+       busfreeing,
+       disconnecting,
+       reselecting
+};
+
+enum msg_phase {
+       msg_none,
+       msg_out,
+       msg_out_xxx,
+       msg_out_last,
+       msg_in,
+};
+
+enum sdtr_phase {
+       do_sdtr,
+       sdtr_sent,
+       sdtr_done
+};
+
+struct mesh_target {
+       enum sdtr_phase sdtr_state;
+       enum mesh_phase phase;
+       int     sync_params;
+       int     data_goes_out;
+       Scsi_Cmnd *current_req;
+       u32     saved_ptr;
+};
+
+struct mesh_state {
+       volatile struct mesh_regs *mesh;
+       int     meshintr;
+       volatile struct dbdma_regs *dma;
+       int     dmaintr;
+       struct  Scsi_Host *host;
+       struct  mesh_state *next;
+       Scsi_Cmnd *request_q;
+       Scsi_Cmnd *request_qtail;
+       enum mesh_phase phase;          /* what we're currently trying to do */
+       enum msg_phase msgphase;
+       int     conn_tgt;               /* target we're connected to */
+       Scsi_Cmnd *current_req;         /* req we're currently working on */
+       int     data_ptr;
+       int     data_goes_out;          /* guess as to data direction */
+       int     dma_started;
+       int     dma_count;
+       int     expect_reply;
+       int     n_msgin;
+       u8      msgin[16];
+       int     n_msgout;
+       int     last_n_msgout;
+       u8      msgout[16];
+       struct dbdma_cmd *dma_cmds;     /* space for dbdma commands, aligned */
+       int     clk_freq;
+       struct mesh_target tgts[8];
+       struct tq_struct tqueue;
+       Scsi_Cmnd *completed_q;
+       Scsi_Cmnd *completed_qtail;
+};
+
+static struct mesh_state *all_meshes;
+
+static void mesh_init(struct mesh_state *);
+static int mesh_notify_reboot(struct notifier_block *, unsigned long, void *);
+static void mesh_dump_regs(struct mesh_state *);
+static void mesh_start(struct mesh_state *);
+static void finish_cmds(void *);
+static void add_sdtr_msg(struct mesh_state *);
+static void set_sdtr(struct mesh_state *, int, int);
+static void start_phase(struct mesh_state *);
+static void get_msgin(struct mesh_state *);
+static int msgin_length(struct mesh_state *);
+static void cmd_complete(struct mesh_state *);
+static void phase_mismatch(struct mesh_state *);
+static void reselected(struct mesh_state *);
+static void handle_reset(struct mesh_state *);
+static void mesh_interrupt(int, void *, struct pt_regs *);
+static void handle_msgin(struct mesh_state *);
+static void mesh_done(struct mesh_state *);
+static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
+static void set_dma_cmds(struct mesh_state *, Scsi_Cmnd *);
+static void halt_dma(struct mesh_state *);
+static int data_goes_out(Scsi_Cmnd *);
+
+static struct notifier_block mesh_notifier = {
+       mesh_notify_reboot,
+       NULL,
+       0
+};
+
+int
+mesh_detect(Scsi_Host_Template *tp)
+{
+       struct device_node *mesh;
+       int nmeshes, tgt, *cfp, minper;
+       struct mesh_state *ms, **prev_statep;
+       struct Scsi_Host *mesh_host;
+       void *dma_cmd_space;
+
+       nmeshes = 0;
+       prev_statep = &all_meshes;
+       for (mesh = find_devices("mesh"); mesh != 0; mesh = mesh->next) {
+               if (mesh->n_addrs != 2 || mesh->n_intrs != 2)
+                       panic("mesh: expected 2 addrs and intrs (got %d/%d)",
+                             mesh->n_addrs, mesh->n_intrs);
+               mesh_host = scsi_register(tp, sizeof(struct mesh_state));
+               if (mesh_host == 0)
+                       panic("couldn't register mesh host");
+               mesh_host->unique_id = nmeshes;
+               note_scsi_host(mesh, mesh_host);
+
+               ms = (struct mesh_state *) mesh_host->hostdata;
+               if (ms == 0)
+                       panic("no mesh state");
+               memset(ms, 0, sizeof(*ms));
+               ms->host = mesh_host;
+               ms->mesh = (volatile struct mesh_regs *)
+                       mesh->addrs[0].address;
+               ms->meshintr = mesh->intrs[0];
+               ms->dma = (volatile struct dbdma_regs *)
+                       mesh->addrs[1].address;
+               ms->dmaintr = mesh->intrs[1];
+
+               /* Space for dma command list: +1 for stop command,
+                  +1 to allow for aligning. */
+               dma_cmd_space = kmalloc((mesh_host->sg_tablesize + 2) *
+                                       sizeof(struct dbdma_cmd), GFP_KERNEL);
+               if (dma_cmd_space == 0)
+                       panic("mesh: couldn't allocate dma command space");
+               ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
+               memset(ms->dma_cmds, 0, (mesh_host->sg_tablesize + 1)
+                      * sizeof(struct dbdma_cmd));
+
+               ms->current_req = 0;
+               for (tgt = 0; tgt < 8; ++tgt) {
+                       ms->tgts[tgt].sdtr_state = do_sdtr;
+                       ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+                       ms->tgts[tgt].current_req = 0;
+               }
+
+               ms->tqueue.routine = finish_cmds;
+               ms->tqueue.data = ms;
+
+               *prev_statep = ms;
+               prev_statep = &ms->next;
+
+               if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+                       printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+               }
+
+               cfp = (int *) get_property(mesh, "clock-frequency", NULL);
+               if (cfp) {
+                       ms->clk_freq = *cfp;
+               } else {
+                       printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+                       ms->clk_freq = 50000000;
+               }
+               /* The maximum sync rate is clock / 5; increase
+                  mesh_sync_period if necessary. */
+               minper = 1000000000 / (ms->clk_freq / 5);       /* ns */
+               if (mesh_sync_period < minper)
+                       mesh_sync_period = minper;
+
+               mesh_init(ms);
+
+               ++nmeshes;
+       }
+       if (nmeshes > 0)
+               register_reboot_notifier(&mesh_notifier);
+
+       return nmeshes;
+}
+
+int
+mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+       unsigned long flags;
+       struct mesh_state *ms;
+
+#if 0
+       if (data_goes_out(cmd)) {
+               printk(KERN_DEBUG "mesh_queue %p: command is", cmd);
+               for (i = 0; i < cmd->cmd_len; ++i)
+                       printk(" %.2x", cmd->cmnd[i]);
+               printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+                      cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+       }
+#endif
+
+       cmd->scsi_done = done;
+       cmd->host_scribble = NULL;
+
+       ms = (struct mesh_state *) cmd->host->hostdata;
+
+       save_flags(flags);
+       cli();
+       if (ms->request_q == NULL)
+               ms->request_q = cmd;
+       else
+               ms->request_qtail->host_scribble = (void *) cmd;
+       ms->request_qtail = cmd;
+
+       if (ms->phase == idle)
+               mesh_start(ms);
+
+       restore_flags(flags);
+       return 0;
+}
+
+int
+mesh_abort(Scsi_Cmnd *cmd)
+{
+       printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+       mesh_dump_regs((struct mesh_state *)(cmd->host->hostdata));
+       return SCSI_ABORT_SNOOZE;
+}
+
+static void
+mesh_dump_regs(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct dbdma_regs *md = ms->dma;
+       int t;
+       struct mesh_target *tp;
+
+       printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n",
+              ms, mr, md);
+       printk(KERN_DEBUG "    ct=%4x seq=%2x bs=%4x fc=%2x exc=%2x err=%2x sp=%2x\n",
+              (mr->count_hi << 8) + mr->count_lo, mr->sequence,
+              (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count,
+              mr->exception, mr->error, mr->sync_params);
+       printk(KERN_DEBUG "    dma stat=%x cmdptr=%x\n",
+              in_le32(&md->status), in_le32(&md->cmdptr));
+       printk(KERN_DEBUG "    phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n",
+              ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr);
+       printk(KERN_DEBUG "    goes_out=%d dma_st=%d dma_ct=%d n_msgout=%d\n",
+              ms->data_goes_out, ms->dma_started, ms->dma_count, ms->n_msgout);
+       for (t = 0; t < 8; ++t) {
+               tp = &ms->tgts[t];
+               if (tp->current_req == NULL)
+                       continue;
+               printk(KERN_DEBUG "    target %d: req=%p phase=%d saved_ptr=%d\n",
+                      t, tp->current_req, tp->phase, tp->saved_ptr);
+       }
+}
+
+int
+mesh_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+       struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
+       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct dbdma_regs *md = ms->dma;
+       unsigned long flags;
+       int ret;
+
+       printk(KERN_DEBUG "mesh_reset %x\n", how);
+       ret = SCSI_RESET_BUS_RESET;
+       save_flags(flags);
+       cli();
+       out_8(&mr->exception, 0xff);    /* clear all exception bits */
+       out_8(&mr->error, 0xff);        /* clear all error bits */
+       out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+       if (how & SCSI_RESET_SUGGEST_HOST_RESET) {
+               out_8(&mr->sequence, SEQ_RESETMESH);
+               ret |= SCSI_RESET_HOST_RESET;
+               udelay(1);
+               out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+       }
+       out_8(&mr->bus_status1, BS1_RST);       /* assert RST */
+       udelay(30);                     /* leave it on for >= 25us */
+       out_8(&mr->bus_status1, 0);     /* negate RST */
+#ifdef DO_ASYNC_RESET
+       if (how & SCSI_RESET_ASYNCHRONOUS) {
+               restore_flags(flags);
+               ret |= SCSI_RESET_PENDING;
+       } else
+#endif
+       {
+               out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+               handle_reset(ms);
+               restore_flags(flags);
+               finish_cmds(ms);
+               ret |= SCSI_RESET_SUCCESS;
+       }
+       return ret;
+}
+
+/*
+ * If we leave drives set for synchronous transfers (especially
+ * CDROMs), and reboot to MacOS, it gets confused, poor thing.
+ * So, on reboot we reset the SCSI bus.
+ */
+static int
+mesh_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+       struct mesh_state *ms;
+       volatile struct mesh_regs *mr;
+
+       if (code == SYS_DOWN || code == SYS_HALT) {
+               printk(KERN_INFO "resetting MESH scsi bus(es)\n");
+               for (ms = all_meshes; ms != 0; ms = ms->next) {
+                       mr = ms->mesh;
+                       out_8(&mr->intr_mask, 0);
+                       out_8(&mr->interrupt,
+                             INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+                       out_8(&mr->bus_status1, BS1_RST);
+                       udelay(30);
+                       out_8(&mr->bus_status1, 0);
+               }
+       }
+       return NOTIFY_DONE;
+}
+
+int
+mesh_command(Scsi_Cmnd *cmd)
+{
+       printk(KERN_WARNING "whoops... mesh_command called\n");
+       return -1;
+}
+
+static void
+mesh_init(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct dbdma_regs *md = ms->dma;
+
+       out_8(&mr->interrupt, 0xff);    /* clear all interrupt bits */
+       out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+       out_8(&mr->source_id, ms->host->this_id);
+       out_8(&mr->sel_timeout, 25);    /* 250ms */
+       out_8(&mr->sync_params, ASYNC_PARAMS);  /* asynchronous initially */
+       out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a MESH.
+ * Should be called with interrupts disabled.
+ */
+static void
+mesh_start(struct mesh_state *ms)
+{
+       Scsi_Cmnd *cmd, *prev, *next;
+       volatile struct mesh_regs *mr = ms->mesh;
+
+       if (ms->phase != idle || ms->current_req != NULL)
+               panic("inappropriate mesh_start (ms=%p)", ms);
+
+       prev = NULL;
+       for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
+               if (cmd == NULL)
+                       return;
+               if (ms->tgts[cmd->target].current_req == NULL)
+                       break;
+               prev = cmd;
+       }
+       next = (Scsi_Cmnd *) cmd->host_scribble;
+       if (prev == NULL)
+               ms->request_q = next;
+       else
+               prev->host_scribble = (void *) next;
+       if (next == NULL)
+               ms->request_qtail = prev;
+
+       ms->current_req = cmd;
+       ms->data_goes_out = data_goes_out(cmd);
+       ms->tgts[cmd->target].current_req = cmd;
+
+#if 1
+       if (DEBUG_TARGET(cmd)) {
+               int i;
+               printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=",
+                      cmd, cmd->serial_number, cmd->target);
+               for (i = 0; i < cmd->cmd_len; ++i)
+                       printk(" %x", cmd->cmnd[i]);
+               printk(" use_sg=%d buffer=%p bufflen=%u\n",
+                      cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+       }
+#endif
+
+       /* Off we go */
+       out_8(&mr->sequence, SEQ_ARBITRATE);
+
+       ms->phase = arbitrating;
+       ms->msgphase = msg_none;
+       ms->data_ptr = 0;
+       ms->dma_started = 0;
+       ms->n_msgout = 0;
+       ms->last_n_msgout = 0;
+       ms->expect_reply = 0;
+       ms->conn_tgt = cmd->target;
+       ms->tgts[cmd->target].saved_ptr = 0;
+}
+
+static void
+finish_cmds(void *data)
+{
+       struct mesh_state *ms = data;
+       Scsi_Cmnd *cmd;
+       unsigned long flags;
+
+       for (;;) {
+               save_flags(flags);
+               cli();
+               cmd = ms->completed_q;
+               if (cmd == NULL) {
+                       restore_flags(flags);
+                       break;
+               }
+               ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;
+               restore_flags(flags);
+               (*cmd->scsi_done)(cmd);
+       }
+}
+
+static inline void
+add_sdtr_msg(struct mesh_state *ms)
+{
+       int i = ms->n_msgout;
+
+       ms->msgout[i] = EXTENDED_MESSAGE;
+       ms->msgout[i+1] = 3;
+       ms->msgout[i+2] = EXTENDED_SDTR;
+       ms->msgout[i+3] = mesh_sync_period/4;
+       ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);
+       ms->n_msgout = i + 5;
+}
+
+static void
+set_sdtr(struct mesh_state *ms, int period, int offset)
+{
+       struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+       volatile struct mesh_regs *mr = ms->mesh;
+       int v, tr;
+
+       tp->sdtr_state = sdtr_done;
+       if (offset == 0) {
+               /* asynchronous */
+               if (SYNC_OFF(tp->sync_params))
+                       printk(KERN_INFO "mesh: target %d now asynchronous\n",
+                              ms->conn_tgt);
+               tp->sync_params = ASYNC_PARAMS;
+               out_8(&mr->sync_params, ASYNC_PARAMS);
+               return;
+       }
+       /*
+        * We need to compute ceil(clk_freq * period / 500e6) - 2
+        * without incurring overflow.
+        */
+       v = (ms->clk_freq / 5000) * period;
+       if (v <= 250000) {
+               /* special case: sync_period == 5 * clk_period */
+               v = 0;
+               /* units of tr are 100kB/s */
+               tr = (ms->clk_freq + 250000) / 500000;
+       } else {
+               /* sync_period == (v + 2) * 2 * clk_period */
+               v = (v + 99999) / 100000 - 2;
+               if (v > 15)
+                       v = 15; /* oops */
+               tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;
+       }
+       if (offset > 15)
+               offset = 15;    /* can't happen */
+       tp->sync_params = SYNC_PARAMS(offset, v);
+       out_8(&mr->sync_params, tp->sync_params);
+       printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",
+              ms->conn_tgt, tr/10, tr%10);
+}
+
+static void
+start_phase(struct mesh_state *ms)
+{
+       int i, seq, nb;
+       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct dbdma_regs *md = ms->dma;
+       Scsi_Cmnd *cmd = ms->current_req;
+       struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+       if (cmd == 0) {
+               printk(KERN_ERR "mesh: start_phase but no cmd?\n");
+               return;
+       }
+       seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+       switch (ms->msgphase) {
+       case msg_none:
+               break;
+
+       case msg_in:
+               out_8(&mr->count_hi, 0);
+               out_8(&mr->count_lo, 1);
+               out_8(&mr->sequence, SEQ_MSGIN + seq);
+               ms->n_msgin = 0;
+               return;
+
+       case msg_out:
+               /*
+                * To make sure ATN drops before we assert ACK for
+                * the last byte of the message, we have to do the
+                * last byte specially.
+                */
+               if (DEBUG_TARGET(cmd)) {
+                       printk(KERN_DEBUG "mesh: sending %d msg bytes:",
+                              ms->n_msgout);
+                       for (i = 0; i < ms->n_msgout; ++i)
+                               printk(" %x", ms->msgout[i]);
+                       printk("\n");
+               }
+               out_8(&mr->count_hi, 0);
+               if (ms->n_msgout == 1) {
+                       out_8(&mr->count_lo, 1);
+                       out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+                       udelay(1);
+                       out_8(&mr->fifo, ms->msgout[0]);
+                       ms->msgphase = msg_out_last;
+               } else {
+                       out_8(&mr->count_lo, ms->n_msgout - 1);
+                       out_8(&mr->sequence, SEQ_MSGOUT + seq);
+                       for (i = 0; i < ms->n_msgout - 1; ++i)
+                               out_8(&mr->fifo, ms->msgout[i]);
+               }
+               return;
+
+       default:
+               printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",
+                      ms->msgphase);
+       }
+
+       switch (ms->phase) {
+       case selecting:
+               out_8(&mr->dest_id, cmd->target);
+               out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);
+               break;
+       case commanding:
+               out_8(&mr->sync_params, tp->sync_params);
+               out_8(&mr->count_hi, 0);
+               out_8(&mr->count_lo, cmd->cmd_len);
+               out_8(&mr->sequence, SEQ_COMMAND + seq);
+               for (i = 0; i < cmd->cmd_len; ++i)
+                       out_8(&mr->fifo, cmd->cmnd[i]);
+               break;
+       case dataing:
+               /* transfer data, if any */
+               if (!ms->dma_started) {
+                       set_dma_cmds(ms, cmd);
+                       out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));
+                       out_le32(&md->control, (RUN << 16) | RUN);
+                       ms->dma_started = 1;
+               }
+               nb = ms->dma_count;
+               if (nb > 0xfff0)
+                       nb = 0xfff0;
+               ms->dma_count -= nb;
+               ms->data_ptr += nb;
+               out_8(&mr->count_lo, nb);
+               out_8(&mr->count_hi, nb >> 8);
+               out_8(&mr->sequence, (ms->data_goes_out?
+                               SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);
+               break;
+       case statusing:
+               out_8(&mr->count_hi, 0);
+               out_8(&mr->count_lo, 1);
+               out_8(&mr->sequence, SEQ_STATUS + seq);
+               break;
+       case busfreeing:
+       case disconnecting:
+               out_8(&mr->sequence, SEQ_ENBRESEL);
+               udelay(1);
+               out_8(&mr->sequence, SEQ_BUSFREE);
+               break;
+       default:
+               printk(KERN_ERR "mesh: start_phase called with phase=%d\n",
+                      ms->phase);
+       }
+
+}
+
+static inline void
+get_msgin(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       int i, n;
+
+       n = mr->fifo_count;
+       if (n != 0) {
+               i = ms->n_msgin;
+               ms->n_msgin = i + n;
+               for (; n > 0; --n)
+                       ms->msgin[i++] = in_8(&mr->fifo);
+       }
+}
+
+static inline int
+msgin_length(struct mesh_state *ms)
+{
+       int b, n;
+
+       n = 1;
+       if (ms->n_msgin > 0) {
+               b = ms->msgin[0];
+               if (b == 1) {
+                       /* extended message */
+                       n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;
+               } else if (0x20 <= b && b <= 0x2f) {
+                       /* 2-byte message */
+                       n = 2;
+               }
+       }
+       return n;
+}
+
+static void
+cmd_complete(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       Scsi_Cmnd *cmd = ms->current_req;
+       struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+       int seq, n, t;
+
+       seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+       switch (ms->msgphase) {
+       case msg_out_xxx:
+               /* huh?  we expected a phase mismatch */
+               ms->n_msgin = 0;
+               ms->msgphase = msg_in;
+               /* fall through */
+
+       case msg_in:
+               /* should have some message bytes in fifo */
+               get_msgin(ms);
+               n = msgin_length(ms);
+               if (ms->n_msgin < n) {
+                       out_8(&mr->count_lo, n - ms->n_msgin);
+                       out_8(&mr->sequence, SEQ_MSGIN + seq);
+               } else {
+                       ms->msgphase = msg_none;
+                       handle_msgin(ms);
+                       start_phase(ms);
+               }
+               break;
+
+       case msg_out:
+               /*
+                * To get the right timing on ATN wrt ACK, we have
+                * to get the MESH to drop ACK, wait until REQ gets
+                * asserted, then drop ATN.  To do this we first
+                * issue a SEQ_MSGOUT with ATN and wait for REQ,
+                * then change the command to a SEQ_MSGOUT w/o ATN.
+                * If we don't see REQ in a reasonable time, we
+                * change the command to SEQ_MSGIN with ATN,
+                * wait for the phase mismatch interrupt, then
+                * issue the SEQ_MSGOUT without ATN.
+                */
+               out_8(&mr->count_lo, 1);
+               out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG + SEQ_ATN);
+               t = 30;         /* wait up to 30us */
+               while ((mr->bus_status0 & BS0_REQ) == 0 && --t >= 0)
+                       udelay(1);
+               if (mr->bus_status0 & BS0_REQ) {
+                       out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+                       udelay(1);
+                       out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+                       ms->msgphase = msg_out_last;
+               } else {
+                       out_8(&mr->sequence, SEQ_MSGIN + SEQ_ACTIVE_NEG + SEQ_ATN);
+                       ms->msgphase = msg_out_xxx;
+               }
+               break;
+
+       case msg_out_last:
+               ms->last_n_msgout = ms->n_msgout;
+               ms->n_msgout = 0;
+               ms->msgphase = ms->expect_reply? msg_in: msg_none;
+               start_phase(ms);
+               break;
+
+       case msg_none:
+               switch (ms->phase) {
+               case selecting:
+                       ms->msgout[0] = IDENTIFY(ALLOW_RESEL(cmd->target), cmd->lun);
+                       ms->n_msgout = 1;
+                       ms->expect_reply = 0;
+                       if (tp->sdtr_state == do_sdtr) {
+                               /* add SDTR message */
+                               add_sdtr_msg(ms);
+                               ms->expect_reply = 1;
+                               tp->sdtr_state = sdtr_sent;
+                       }
+                       ms->msgphase = msg_out;
+                       /*
+                        * We need to wait for REQ before dropping ATN.
+                        * We wait for at most 30us, then fall back to
+                        * a scheme where we issue a SEQ_COMMAND with ATN,
+                        * which will give us a phase mismatch interrupt
+                        * when REQ does come, and then we send the message.
+                        */
+                       t = 30;         /* wait up to 30us */
+                       while ((mr->bus_status0 & BS0_REQ) == 0) {
+                               if (--t < 0) {
+                                       ms->msgphase = msg_none;
+                                       break;
+                               }
+                               udelay(1);
+                       }
+                       break;
+               case dataing:
+                       if (ms->dma_count != 0) {
+                               start_phase(ms);
+                               return;
+                       }
+                       halt_dma(ms);
+                       break;
+               case statusing:
+                       cmd->SCp.Status = mr->fifo;
+                       cmd->result = (DID_OK << 16) + cmd->SCp.Status;
+                       ms->msgphase = msg_in;
+                       if (DEBUG_TARGET(cmd))
+                               printk(KERN_DEBUG "mesh: status is %x\n",
+                                      cmd->SCp.Status);
+                       break;
+               case busfreeing:
+                       mesh_done(ms);
+                       return;
+               case disconnecting:
+                       ms->current_req = 0;
+                       ms->phase = idle;
+                       mesh_start(ms);
+                       return;
+               default:
+                       break;
+               }
+               ++ms->phase;
+               start_phase(ms);
+               break;
+       }
+}
+
+static void phase_mismatch(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       int phase;
+
+       phase = mr->bus_status0 & BS0_PHASE;
+       if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
+               /* output the last byte of the message, without ATN */
+               out_8(&mr->count_lo, 1);
+               out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+               udelay(1);
+               out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+               ms->msgphase = msg_out_last;
+               return;
+       }
+
+       if (ms->msgphase == msg_in) {
+               get_msgin(ms);
+               if (ms->n_msgin)
+                       handle_msgin(ms);
+       }
+
+       if (ms->dma_started)
+               halt_dma(ms);
+       if (mr->fifo_count) {
+               out_8(&mr->sequence, SEQ_FLUSHFIFO);
+               udelay(1);
+       }
+
+       ms->msgphase = msg_none;
+       switch (phase) {
+       case BP_DATAIN:
+               ms->data_goes_out = 0;
+               ms->phase = dataing;
+               break;
+       case BP_DATAOUT:
+               ms->data_goes_out = 1;
+               ms->phase = dataing;
+               break;
+       case BP_COMMAND:
+               ms->phase = commanding;
+               break;
+       case BP_STATUS:
+               ms->phase = statusing;
+               break;
+       case BP_MSGIN:
+               ms->msgphase = msg_in;
+               ms->n_msgin = 0;
+               break;
+       case BP_MSGOUT:
+               ms->msgphase = msg_out;
+               if (ms->n_msgout == 0) {
+                       if (ms->last_n_msgout == 0) {
+                               printk(KERN_DEBUG "mesh: no msg to repeat\n");
+                               ms->msgout[0] = NOP;
+                               ms->last_n_msgout = 1;
+                       }
+                       ms->n_msgout = ms->last_n_msgout;
+               }
+               break;
+       default:
+               printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
+               ms->current_req->result = DID_ERROR << 16;
+               mesh_done(ms);
+               return;
+       }
+
+       start_phase(ms);
+}
+
+static void
+reselected(struct mesh_state *ms)
+{
+       volatile struct mesh_regs *mr = ms->mesh;
+       Scsi_Cmnd *cmd = ms->current_req;
+       struct mesh_target *tp;
+       int b, t;
+
+       switch (ms->phase) {
+       case idle:
+       case arbitrating:
+               break;
+       case busfreeing:
+               ms->phase = reselecting;
+               mesh_done(ms);
+               cmd = NULL;
+               break;
+       case disconnecting:
+               cmd = NULL;
+               break;
+       default:
+               printk(KERN_ERR "mesh: reselected in phase %d/%d\n",
+                      ms->msgphase, ms->phase);
+       }
+       if (cmd) {
+               /* put the command back on the queue */
+               cmd->host_scribble = (void *) ms->request_q;
+               if (ms->request_q == NULL)
+                       ms->request_qtail = cmd;
+               ms->request_q = cmd;
+               tp = &ms->tgts[cmd->target];
+               tp->current_req = NULL;
+               ms->current_req = NULL;
+       }
+
+       /*
+        * Find out who reselected us.
+        */
+       if (mr->fifo_count == 0) {
+               printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
+               return;
+       }
+       /* get the last byte in the fifo */
+       do {
+               b = in_8(&mr->fifo);
+       } while (in_8(&mr->fifo_count));
+       for (t = 0; t < 8; ++t)
+               if ((b & (1 << t)) != 0 && t != ms->host->this_id)
+                       break;
+       if (b != (1 << t) + (1 << ms->host->this_id)) {
+               printk(KERN_ERR "mesh: bad reselection data %x\n", b);
+               return;
+       }
+
+       /*
+        * Set up to continue with that target's transfer.
+        */
+       tp = &ms->tgts[t];
+       if (ALLOW_DEBUG(t)) {
+               printk(KERN_DEBUG "mesh: reselected by target %d\n", t);
+               printk(KERN_DEBUG "mesh: saved_ptr=%x phase=%d cmd=%p\n",
+                      tp->saved_ptr, tp->phase, tp->current_req);
+       }
+       if (tp->current_req == NULL) {
+               printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);
+               return;
+       }
+       ms->current_req = tp->current_req;
+       ms->phase = tp->phase;
+       ms->msgphase = msg_in;
+       ms->data_goes_out = tp->data_goes_out;
+       ms->data_ptr = tp->saved_ptr;
+       ms->conn_tgt = t;
+       ms->dma_started = 0;
+       ms->n_msgout = 0;
+       ms->last_n_msgout = 0;
+       out_8(&mr->sync_params, tp->sync_params);
+       start_phase(ms);
+}
+
+static void
+handle_reset(struct mesh_state *ms)
+{
+       int tgt;
+       struct mesh_target *tp;
+       Scsi_Cmnd *cmd;
+       volatile struct mesh_regs *mr = ms->mesh;
+
+       for (tgt = 0; tgt < 8; ++tgt) {
+               tp = &ms->tgts[tgt];
+               if ((cmd = tp->current_req) != NULL) {
+                       cmd->result = DID_RESET << 16;
+                       tp->current_req = NULL;
+                       mesh_completed(ms, cmd);
+               }
+               ms->tgts[tgt].sdtr_state = do_sdtr;
+               ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+       }
+       ms->current_req = NULL;
+       while ((cmd = ms->request_q) != NULL) {
+               ms->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+               cmd->result = DID_RESET << 16;
+               mesh_completed(ms, cmd);
+       }
+       ms->phase = idle;
+       out_8(&mr->sync_params, ASYNC_PARAMS);
+}
+
+static void
+mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+       struct mesh_state *ms = (struct mesh_state *) dev_id;
+       volatile struct mesh_regs *mr = ms->mesh;
+       Scsi_Cmnd *cmd = ms->current_req;
+       int stat, exc, err, intr;
+
+#if 0
+       if (DEBUG_TARGET(cmd))
+               printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x phase=%d msgphase=%d\n",
+                      mr->bus_status0, mr->interrupt, mr->exception, mr->error, ms->phase, ms->msgphase);
+#endif
+       while ((intr = in_8(&mr->interrupt)) != 0) {
+               if (intr & INT_ERROR) {
+                       stat = DID_BAD_INTR << 16;
+                       err = in_8(&mr->error);
+                       exc = in_8(&mr->exception);
+                       out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+                       if (err & ERR_SCSIRESET) {
+                               /* SCSI bus was reset */
+                               printk(KERN_INFO "mesh: SCSI bus reset detected: "
+                                      "waiting for end...");
+                               while ((mr->bus_status1 & BS1_RST) != 0)
+                                       udelay(1);
+                               printk("done\n");
+                               handle_reset(ms);
+                               /* request_q is empty, no point in mesh_start() */
+                               continue;
+                       } else if (err & ERR_UNEXPDISC) {
+                               /* Unexpected disconnect */
+                               printk(KERN_WARNING "mesh: target %d aborted\n",
+                                      ms->conn_tgt);
+                               stat = DID_ABORT << 16;
+                       } else if (err & ERR_PARITY) {
+                               printk(KERN_ERR "mesh: parity error\n");
+                               stat = DID_PARITY << 16;
+                       } else if ((err & ERR_SEQERR) && (exc & EXC_RESELECTED)
+                                  && ms->phase == arbitrating) {
+                               /* This can happen if we issue a command to
+                                  get the bus just after the target
+                                  reselects us. */
+                               static int mesh_resel_seqerr;
+                               mesh_resel_seqerr++;
+                               reselected(ms);
+                               continue;
+                       } else {
+                               printk(KERN_ERR "mesh: error %x (exc = %x)\n",
+                                      err, exc);
+                               mesh_dump_regs(ms);
+                       }
+                       if (cmd != 0) {
+                               cmd->result = stat;
+                               mesh_done(ms);
+                       }
+
+               } else if (intr & INT_EXCEPTION) {
+                       exc = in_8(&mr->exception);
+                       out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
+                       if (exc & EXC_RESELECTED) {
+                               static int mesh_resel_exc;
+                               mesh_resel_exc++;
+                               reselected(ms);
+                       } else if (cmd && exc == EXC_ARBLOST
+                                  && ms->phase == arbitrating) {
+                               printk(KERN_DEBUG "mesh: lost arbitration\n");
+                               cmd->result = DID_BUS_BUSY << 16;
+                               mesh_done(ms);
+                       } else if (cmd && exc == EXC_SELTO && ms->phase == selecting) {
+                               /* selection timed out */
+                               cmd->result = DID_BAD_TARGET << 16;
+                               mesh_done(ms);
+                       } else if (cmd && exc == EXC_PHASEMM
+                                  && (mr->bus_status0 & BS0_REQ) != 0) {
+                               /* target wants to do something different:
+                          find out what it wants and do it. */
+                               phase_mismatch(ms);
+                       } else {
+                               printk(KERN_ERR "mesh: can't cope with exception %x\n",
+                                      exc);
+                               cmd->result = DID_ERROR << 16;
+                               mesh_done(ms);
+                       }
+
+               } else if (intr & INT_CMDDONE) {
+                       out_8(&mr->interrupt, INT_CMDDONE);
+                       cmd_complete(ms);
+               }
+       }
+}
+
+static void
+handle_msgin(struct mesh_state *ms)
+{
+       int i;
+       Scsi_Cmnd *cmd = ms->current_req;
+       struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+       if (ms->n_msgin == 0)
+               return;
+       if (DEBUG_TARGET(cmd)) {
+               printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin);
+               for (i = 0; i < ms->n_msgin; ++i)
+                       printk(" %x", ms->msgin[i]);
+               printk("\n");
+       }
+
+       ms->expect_reply = 0;
+       ms->n_msgout = 0;
+       if (ms->n_msgin < msgin_length(ms))
+               goto reject;
+       if (cmd)
+               cmd->SCp.Message = ms->msgin[0];
+       switch (ms->msgin[0]) {
+       case COMMAND_COMPLETE:
+               break;
+       case EXTENDED_MESSAGE:
+               switch (ms->msgin[2]) {
+               case EXTENDED_MODIFY_DATA_POINTER:
+                       ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6]
+                               + (ms->msgin[4] << 16) + (ms->msgin[5] << 8);
+                       break;
+               case EXTENDED_SDTR:
+                       if (tp->sdtr_state != sdtr_sent) {
+                               /* reply with an SDTR */
+                               add_sdtr_msg(ms);
+                               /* limit period to at least his value,
+                                  offset to no more than his */
+                               if (ms->msgout[3] < ms->msgin[3])
+                                       ms->msgout[3] = ms->msgin[3];
+                               if (ms->msgout[4] > ms->msgin[4])
+                                       ms->msgout[4] = ms->msgin[4];
+                               set_sdtr(ms, ms->msgout[3], ms->msgout[4]);
+                               ms->msgphase = msg_out;
+                       } else {
+                               set_sdtr(ms, ms->msgin[3], ms->msgin[4]);
+                       }
+                       break;
+               default:
+                       goto reject;
+               }
+               break;
+       case SAVE_POINTERS:
+               tp->saved_ptr = ms->data_ptr;
+               break;
+       case RESTORE_POINTERS:
+               ms->data_ptr = tp->saved_ptr;
+               break;
+       case DISCONNECT:
+               tp->phase = ms->phase;
+               tp->data_goes_out = ms->data_goes_out;
+               ms->phase = disconnecting;
+               break;
+       case ABORT:
+               break;
+       case MESSAGE_REJECT:
+               if (tp->sdtr_state == sdtr_sent)
+                       set_sdtr(ms, 0, 0);
+               break;
+       case NOP:
+               break;
+       default:
+               if (cmd && IDENTIFY_BASE <= ms->msgin[0]
+                   && ms->msgin[0] <= IDENTIFY_BASE + 7) {
+                       i = ms->msgin[0] - IDENTIFY_BASE;
+                       if (i != cmd->lun)
+                               printk(KERN_WARNING "mesh: lun mismatch "
+                                      "(%d != %d) on reselection from "
+                                      "target %d\n", i, cmd->lun,
+                                      ms->conn_tgt);
+                       break;
+               }
+               goto reject;
+       }
+       return;
+
+ reject:
+       printk(KERN_WARNING "mesh: rejecting message %x from target %d\n",
+              ms->msgin[0], ms->conn_tgt);
+       ms->msgout[0] = MESSAGE_REJECT;
+       ms->n_msgout = 1;
+       ms->msgphase = msg_out;
+}
+
+static void
+mesh_done(struct mesh_state *ms)
+{
+       Scsi_Cmnd *cmd;
+       struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+       cmd = ms->current_req;
+       if (DEBUG_TARGET(cmd)) {
+               printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
+                      cmd->result, ms->data_ptr, cmd->request_bufflen);
+               if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
+                   && cmd->request_buffer != 0) {
+                       unsigned char *b = cmd->request_buffer;
+                       printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
+                              b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+               }
+       }
+       tp->current_req = 0;
+       cmd->SCp.this_residual -= ms->data_ptr;
+       ms->current_req = NULL;
+       mesh_completed(ms, cmd);
+       if (ms->phase != reselecting) {
+               ms->phase = idle;
+               mesh_start(ms);
+       }
+}
+
+static void
+mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+       if (ms->completed_q == NULL)
+               ms->completed_q = cmd;
+       else
+               ms->completed_qtail->host_scribble = (void *) cmd;
+       ms->completed_qtail = cmd;
+       cmd->host_scribble = NULL;
+       queue_task(&ms->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+       int i, dma_cmd, total, off, dtot;
+       struct scatterlist *scl;
+       struct dbdma_cmd *dcmds;
+
+       dma_cmd = ms->data_goes_out? OUTPUT_MORE: INPUT_MORE;
+       dcmds = ms->dma_cmds;
+       dtot = 0;
+       cmd->SCp.this_residual = cmd->request_bufflen;
+       if (cmd->use_sg > 0) {
+               total = 0;
+               scl = (struct scatterlist *) cmd->buffer;
+               off = ms->data_ptr;
+               for (i = 0; i < cmd->use_sg; ++i, ++scl) {
+                       total += scl->length;
+                       if (off >= scl->length) {
+                               off -= scl->length;
+                               continue;
+                       }
+                       if (scl->length > 0xffff)
+                               panic("mesh: scatterlist element >= 64k");
+                       st_le16(&dcmds->req_count, scl->length - off);
+                       st_le16(&dcmds->command, dma_cmd);
+                       st_le32(&dcmds->phy_addr,
+                               virt_to_phys(scl->address) + off);
+                       dcmds->xfer_status = 0;
+                       ++dcmds;
+                       dtot += scl->length - off;
+                       off = 0;
+               }
+       } else if (ms->data_ptr < cmd->request_bufflen) {
+               dtot = cmd->request_bufflen - ms->data_ptr;
+               if (dtot > 0xffff)
+                       panic("mesh: transfer size >= 64k");
+               st_le16(&dcmds->req_count, dtot);
+               st_le32(&dcmds->phy_addr,
+                       virt_to_phys(cmd->request_buffer) + ms->data_ptr);
+               dcmds->xfer_status = 0;
+               ++dcmds;
+       }
+       if (dtot == 0) {
+               /* Either the target has overrun our buffer,
+                  or the caller didn't provide a buffer. */
+               static char mesh_extra_buf[64];
+
+               if (cmd->request_bufflen != 0)
+                       printk(KERN_DEBUG "mesh: target %d overrun, "
+                              "data_ptr=%x total=%x goes_out=%d\n",
+                              ms->conn_tgt, ms->data_ptr,
+                              cmd->request_bufflen, ms->data_goes_out);
+               dtot = sizeof(mesh_extra_buf);
+               st_le16(&dcmds->req_count, dtot);
+               st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf));
+               dcmds->xfer_status = 0;
+               ++dcmds;
+       }
+       dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+       st_le16(&dcmds[-1].command, dma_cmd);
+       memset(dcmds, 0, sizeof(*dcmds));
+       st_le16(&dcmds->command, DBDMA_STOP);
+       ms->dma_count = dtot;
+}
+
+static void
+halt_dma(struct mesh_state *ms)
+{
+       volatile struct dbdma_regs *md = ms->dma;
+       volatile struct mesh_regs *mr = ms->mesh;
+       int t, nb;
+
+       if (!ms->data_goes_out) {
+               /* wait a little while until the fifo drains */
+               t = 50;
+               while (t > 0 && mr->fifo_count != 0
+                      && (in_le32(&md->status) & ACTIVE) != 0) {
+                       --t;
+                       udelay(1);
+               }
+       }
+       out_le32(&md->control, RUN << 16);      /* turn off RUN bit */
+       nb = (mr->count_hi << 8) + mr->count_lo;
+       if (ms->data_goes_out)
+               nb += mr->fifo_count;
+       /* nb is the number of bytes not yet transferred
+          to/from the target. */
+       ms->data_ptr -= nb;
+       if (ms->data_ptr < 0) {
+               printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n",
+                      ms->data_ptr, nb, ms);
+               ms->data_ptr = 0;
+       }
+       ms->dma_started = 0;
+}
+
+/*
+ * Work out whether we expect data to go out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+       switch (cmd->cmnd[0]) {
+       case MODE_SELECT:
+       case MODE_SELECT_10:
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:          /* any others? */
+               return 1;
+       default:
+               return 0;
+       }
+}
diff --git a/drivers/scsi/mesh.h b/drivers/scsi/mesh.h
new file mode 100644 (file)
index 0000000..c808cc5
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * mesh.h: definitions for the driver for the MESH SCSI bus adaptor
+ * (Macintosh Enhanced SCSI Hardware) found on Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MESH_H
+#define _MESH_H
+
+extern struct proc_dir_entry proc_scsi_mesh;
+
+int mesh_detect(Scsi_Host_Template *);
+int mesh_command(Scsi_Cmnd *);
+int mesh_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mesh_abort(Scsi_Cmnd *);
+int mesh_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MESH {                                    \
+       NULL,                   /* next */              \
+       NULL,                   /* usage_count */       \
+       &proc_scsi_mesh,        /* proc_dir */          \
+       NULL,                   /* proc_info */         \
+       "MESH",                 /* name */              \
+       mesh_detect,            /* detect */            \
+       NULL,                   /* release */           \
+       NULL,                   /* info */              \
+       mesh_command,           /* command */           \
+       mesh_queue,             /* queuecommand */      \
+       mesh_abort,             /* abort */             \
+       mesh_reset,             /* reset */             \
+       NULL,                   /* slave_attach */      \
+       NULL,                   /* bios_param */        \
+       20,                     /* can_queue */         \
+       7,                      /* this_id */           \
+       SG_ALL,                 /* sg_tablesize */      \
+       2,                      /* cmd_per_lun */       \
+       0,                      /* present */           \
+       0,                      /* unchecked_isa_dma */ \
+       DISABLE_CLUSTERING,     /* use_clustering */    \
+}
+
+/*
+ * Registers in the MESH controller.
+ */
+
+struct mesh_regs {
+       unsigned char   count_lo;
+       char pad0[15];
+       unsigned char   count_hi;
+       char pad1[15];
+       unsigned char   fifo;
+       char pad2[15];
+       unsigned char   sequence;
+       char pad3[15];
+       unsigned char   bus_status0;
+       char pad4[15];
+       unsigned char   bus_status1;
+       char pad5[15];
+       unsigned char   fifo_count;
+       char pad6[15];
+       unsigned char   exception;
+       char pad7[15];
+       unsigned char   error;
+       char pad8[15];
+       unsigned char   intr_mask;
+       char pad9[15];
+       unsigned char   interrupt;
+       char pad10[15];
+       unsigned char   source_id;
+       char pad11[15];
+       unsigned char   dest_id;
+       char pad12[15];
+       unsigned char   sync_params;
+       char pad13[15];
+       unsigned char   mesh_id;
+       char pad14[15];
+       unsigned char   sel_timeout;
+       char pad15[15];
+};
+
+/* Bits in the sequence register. */
+#define SEQ_DMA_MODE   0x80    /* use DMA for data transfer */
+#define SEQ_TARGET     0x40    /* put the controller into target mode */
+#define SEQ_ATN                0x20    /* assert ATN signal */
+#define SEQ_ACTIVE_NEG 0x10    /* use active negation on REQ/ACK */
+#define SEQ_CMD                0x0f    /* command bits: */
+#define SEQ_ARBITRATE  1       /*  get the bus */
+#define SEQ_SELECT     2       /*  select a target */
+#define SEQ_COMMAND    3       /*  send a command */
+#define SEQ_STATUS     4       /*  receive status */
+#define SEQ_DATAOUT    5       /*  send data */
+#define SEQ_DATAIN     6       /*  receive data */
+#define SEQ_MSGOUT     7       /*  send a message */
+#define SEQ_MSGIN      8       /*  receive a message */
+#define SEQ_BUSFREE    9       /*  look for bus free */
+#define SEQ_ENBPARITY  0x0a    /*  enable parity checking */
+#define SEQ_DISPARITY  0x0b    /*  disable parity checking */
+#define SEQ_ENBRESEL   0x0c    /*  enable reselection */
+#define SEQ_DISRESEL   0x0d    /*  disable reselection */
+#define SEQ_RESETMESH  0x0e    /*  reset the controller */
+#define SEQ_FLUSHFIFO  0x0f    /*  clear out the FIFO */
+
+/* Bits in the bus_status0 and bus_status1 registers:
+   these correspond directly to the SCSI bus control signals. */
+#define BS0_REQ                0x20
+#define BS0_ACK                0x10
+#define BS0_ATN                0x08
+#define BS0_MSG                0x04
+#define BS0_CD         0x02
+#define BS0_IO         0x01
+#define BS1_RST                0x80
+#define BS1_BSY                0x40
+#define BS1_SEL                0x20
+
+/* Bus phases defined by the bits in bus_status0 */
+#define BS0_PHASE      (BS0_MSG+BS0_CD+BS0_IO)
+#define BP_DATAOUT     0
+#define BP_DATAIN      BS0_IO
+#define BP_COMMAND     BS0_CD
+#define BP_STATUS      (BS0_CD+BS0_IO)
+#define BP_MSGOUT      (BS0_MSG+BS0_CD)
+#define BP_MSGIN       (BS0_MSG+BS0_CD+BS0_IO)
+
+/* Bits in the exception register. */
+#define EXC_SELWATN    0x20    /* (as target) we were selected with ATN */
+#define EXC_SELECTED   0x10    /* (as target) we were selected w/o ATN */
+#define EXC_RESELECTED 0x08    /* (as initiator) we were reselected */
+#define EXC_ARBLOST    0x04    /* we lost arbitration */
+#define EXC_PHASEMM    0x02    /* SCSI phase mismatch */
+#define EXC_SELTO      0x01    /* selection timeout */
+
+/* Bits in the error register */
+#define ERR_UNEXPDISC  0x40    /* target unexpectedly disconnected */
+#define ERR_SCSIRESET  0x20    /* SCSI bus got reset on us */
+#define ERR_SEQERR     0x10    /* we did something the chip didn't like */
+#define ERR_PARITY     0x01    /* parity error was detected */
+
+/* Bits in the interrupt and intr_mask registers */
+#define INT_ERROR      0x04    /* error interrupt */
+#define INT_EXCEPTION  0x02    /* exception interrupt */
+#define INT_CMDDONE    0x01    /* command done interrupt */
+
+/* Fields in the sync_params register */
+#define SYNC_OFF(x)    ((x) >> 4)      /* offset field */
+#define SYNC_PER(x)    ((x) & 0xf)     /* period field */
+#define SYNC_PARAMS(o, p)      (((o) << 4) | (p))
+#define ASYNC_PARAMS   2       /* sync_params value for async xfers */
+
+/*
+ * Assuming a clock frequency of 50MHz:
+ *
+ * The transfer period with SYNC_PER(sync_params) == x
+ * is (x + 2) * 40ns, except that x == 0 gives 100ns.
+ *
+ * The units of the sel_timeout register are 10ms.
+ */
+
+
+#endif /* _MESH_H */
index 458335638bce3ca2053453f9b7d0d48446466234..517568346c287bebab89205557bbc5491eb981a5 100644 (file)
@@ -1007,12 +1007,13 @@ static void sr_detach(Scsi_Device * SDp)
     for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
        if(cpnt->device == SDp) {
            kdev_t devi = MKDEV(MAJOR_NR, i);
+           struct super_block * sb = get_super(devi);
 
            /*
             * Since the cdrom is read-only, no need to sync the device.
             * We should be kind to our buffer cache, however.
             */
-           invalidate_inodes(devi);
+           if (sb) invalidate_inodes(sb);
            invalidate_buffers(devi);
 
            /*
index cfc6016305abd46d3970a114da86e540cf2b2536..bb5b843ccf7fd51569bcd3486b9eedf323ee8ffe 100644 (file)
@@ -60,5 +60,6 @@ if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
   bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
 fi
+bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
 endmenu
 
index 7777e4763a4314c7a1c10031c83d5d587494e8a8..eb7bfbf48e8346546a986444b3e78df976cf3ae8 100644 (file)
@@ -629,7 +629,7 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
                inode->i_size = pos;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        filp->f_pos    = pos;
-       inode->i_dirt  = 1;
+       mark_inode_dirty(inode);
        iput(ino);
        return written;
 }
@@ -717,7 +717,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, uns
                inode->i_size = pos;
        filp->f_pos = pos;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_dirt  = 1;
+       mark_inode_dirty(inode);
        iput(ino);
        return written;
 }
index a1e380cce33ffdd4bea51093ab7d3845bb05eea7..c0515764c32cf03b9f52307f3968eba69dbcd2f7 100644 (file)
@@ -595,11 +595,11 @@ nobitmap:
 
        s->s_dev       = dev;
        s->s_op        = &affs_sops;
-       s->s_mounted   = iget(s,root_block);
+       s->s_root      = d_alloc_root(iget(s,root_block),NULL);
        s->s_dirt      = 1;
        unlock_super(s);
 
-       if (!(s->s_mounted)) {
+       if (!(s->s_root)) {
                s->s_dev = 0;
                printk(KERN_ERR "AFFS: get root inode failed\n");
                MOD_DEC_USE_COUNT;
@@ -609,9 +609,9 @@ nobitmap:
        /* create data zones if the fs is mounted r/w */
 
        if (!(s->s_flags & MS_RDONLY)) {
-               ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
+               ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0;
                secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
-                                 s->s_mounted)->disk_altered);
+                                 s->s_root->d_inode)->disk_altered);
                affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
                mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
                affs_make_zones(s);
@@ -803,7 +803,6 @@ affs_write_inode(struct inode *inode)
 
        pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
 
-       inode->i_dirt = 0;
        if (!inode->i_nlink)
                return;
        if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
@@ -909,7 +908,7 @@ affs_new_inode(const struct inode *dir)
        inode->i_dev     = sb->s_dev;
        inode->i_uid     = current->fsuid;
        inode->i_gid     = current->fsgid;
-       inode->i_dirt    = 1;
+       mark_inode_dirty(inode);
        inode->i_ino     = block;
        inode->i_op      = NULL;
        inode->i_blocks  = 0;
@@ -1012,7 +1011,7 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
                FILE_END(link_bh->b_data,link)->link_chain   = ntohl(inode->i_ino);
                affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
                link->i_version = ++event;
-               link->i_dirt    = 1;
+               mark_inode_dirty(link);
                mark_buffer_dirty(link_bh,1);
        }
        affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
@@ -1021,8 +1020,8 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
        dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
        unlock_super(inode->i_sb);
 
-       dir->i_dirt    = 1;
-       inode->i_dirt  = 1;
+       mark_inode_dirty(dir);
+       mark_inode_dirty(inode);
        mark_buffer_dirty(dir_bh,1);
        mark_buffer_dirty(inode_bh,1);
 
index ce04df0735d9e836a6e09fa5c6308d2c2dbf14cc..d82f13c7fb5e649fe916cbfab3e3638459117693 100644 (file)
@@ -205,10 +205,10 @@ affs_unlink(struct inode *dir, const char *name, int len)
                goto unlink_done;
 
        inode->i_nlink=0;
-       inode->i_dirt=1;
+       mark_inode_dirty(inode);
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_version = ++event;
-       dir->i_dirt=1;
+       mark_inode_dirty(dir);
 unlink_done:
        affs_brelse(bh);
        iput(inode);
@@ -244,7 +244,7 @@ affs_create(struct inode *dir, const char *name, int len, int mode, struct inode
        if (error) {
                iput(dir);
                inode->i_nlink = 0;
-               inode->i_dirt  = 1;
+               mark_inode_dirty(inode);
                iput(inode);
                return -ENOSPC;
        }
@@ -286,7 +286,7 @@ affs_mkdir(struct inode *dir, const char *name, int len, int mode)
        if (error) {
                iput(dir);
                inode->i_nlink = 0;
-               inode->i_dirt  = 1;
+               mark_inode_dirty(inode);
                iput(inode);
                return error;
        }
@@ -356,10 +356,10 @@ affs_rmdir(struct inode *dir, const char *name, int len)
                goto rmdir_done;
 
        inode->i_nlink=0;
-       inode->i_dirt=1;
+       mark_inode_dirty(inode);
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_version = ++event;
-       dir->i_dirt=1;
+       mark_inode_dirty(dir);
 rmdir_done:
        iput(dir);
        iput(inode);
@@ -392,7 +392,7 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
        if (!bh) {
                iput(dir);
                inode->i_nlink = 0;
-               inode->i_dirt  = 1;
+               mark_inode_dirty(inode);
                iput(inode);
                return -EIO;
        }
@@ -426,7 +426,7 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
        *p = 0;
        mark_buffer_dirty(bh,1);
        affs_brelse(bh);
-       inode->i_dirt = 1;
+       mark_inode_dirty(inode);
        bh = affs_find_entry(dir,name,len,&tmp);
        if (bh) {
                inode->i_nlink = 0;
@@ -438,7 +438,7 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
        i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
        if (i) {
                inode->i_nlink = 0;
-               inode->i_dirt  = 1;
+               mark_inode_dirty(inode);
                iput(inode);
                affs_brelse(bh);
                iput(dir);
@@ -497,7 +497,7 @@ affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
                error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
        if (error) {
                inode->i_nlink = 0;
-               inode->i_dirt  = 1;
+               mark_inode_dirty(inode);
        }
        iput(dir);
        iput(inode);
@@ -616,9 +616,9 @@ start_up:
                        goto retry;
                mark_buffer_dirty(new_bh,1);
                new_dir->i_version = ++event;
-               new_dir->i_dirt    = 1;
+               mark_inode_dirty(new_dir);
                new_inode->i_nlink = 0;
-               new_inode->i_dirt  = 1;
+               mark_inode_dirty(new_inode);
        }
        retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
                                    AFFS_I2HSIZE(old_dir)) + 6,old_ino,
@@ -632,8 +632,8 @@ start_up:
        new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        new_dir->i_version = ++event;
        old_dir->i_version = ++event;
-       new_dir->i_dirt    = 1;
-       old_dir->i_dirt    = 1;
+       mark_inode_dirty(new_dir);
+       mark_inode_dirty(old_dir);
        mark_buffer_dirty(old_bh,1);
        
 end_rename:
@@ -704,7 +704,7 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
                        ofinode->i_size              = inode->i_size;
                        ofinode->i_uid               = inode->i_uid;
                        ofinode->i_gid               = inode->i_gid;
-                       ofinode->i_dirt              = 1;
+                       mark_inode_dirty(ofinode);
                        link_key                     = ofinode->i_ino;
 
                        /* Let all remaining links point to the new file */
@@ -722,7 +722,7 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
                                                           "Inode %d in link chain is not a link",
                                                           key);
                                        ofinode->u.affs_i.i_original = link_key;
-                                       ofinode->i_dirt              = 1;
+                                       mark_inode_dirty(ofinode);
                                        FILE_END(nbh->b_data,inode)->original = htonl(link_key);
                                } else
                                        affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
index 9422237d5de6d56f4894fcca3faeff112c3f5743..cbcefc34ad7b0345eae6e85a763a827d74625137 100644 (file)
@@ -141,6 +141,9 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid
 struct super_block *autofs_read_super(struct super_block *s, void *data,
                                      int silent)
 {
+       struct inode * root_inode;
+       struct dentry * root;
+       struct file * pipe;
        int pipefd;
        struct autofs_sb_info *sbi;
        int minproto, maxproto;
@@ -148,12 +151,13 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
        MOD_INC_USE_COUNT;
 
        lock_super(s);
+       /* Super block already completed? */
+       if (s->s_root)
+               goto out_unlock;
+
        sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
-       if ( !sbi ) {
-               s->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+       if ( !sbi )
+               goto fail_unlock;
        DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
        s->u.generic_sbp = sbi;
@@ -169,50 +173,112 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
        s->s_blocksize_bits = 10;
        s->s_magic = AUTOFS_SUPER_MAGIC;
        s->s_op = &autofs_sops;
-       unlock_super(s);
-       s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
-       if (!s->s_root) {
-               printk("autofs: get root inode failed\n");
-               kfree(sbi);
-               s->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+       s->s_root = NULL;
+       unlock_super(s); /* shouldn't we keep it locked a while longer? */
+
+       /*
+        * Get the root inode and dentry, but defer checking for errors.
+        */
+       root_inode = iget(s, AUTOFS_ROOT_INO);
+       root = d_alloc_root(root_inode, NULL);
+       pipe = NULL;
 
-       if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+       /*
+        * Check whether somebody else completed the super block.
+        */
+       if (s->s_root)
+               goto out_dput;
+
+       if (!root)
+               goto fail_iput;
+
+       /* Can this call block? */
+       if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
                printk("autofs: called with bogus options\n");
-               dput(s->s_root);
-               kfree(sbi);
-               s->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto fail_dput;
        }
 
-       if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+       /* Couldn't this be tested earlier? */
+       if ( minproto > AUTOFS_PROTO_VERSION || 
+            maxproto < AUTOFS_PROTO_VERSION ) {
                printk("autofs: kernel does not match daemon version\n");
-               dput(s->s_root);
-               kfree(sbi);
-               s->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
+               goto fail_dput;
        }
 
        DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
-       sbi->pipe = fget(pipefd);
-       if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) {
-               if ( sbi->pipe ) {
-                       fput(sbi->pipe);
-                       printk("autofs: pipe file descriptor does not contain proper ops\n");
-               } else {
-                       printk("autofs: could not open pipe file descriptor\n");
-               }
-               dput(s->s_root);
-               kfree(sbi);
-               s->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
+       pipe = fget(pipefd);
+       /*
+        * Check whether somebody else completed the super block.
+        */
+       if (s->s_root)
+               goto out_fput;
+       
+       if ( !pipe ) {
+               printk("autofs: could not open pipe file descriptor\n");
+               goto fail_dput;
        }
+       if ( !pipe->f_op || !pipe->f_op->write )
+               goto fail_fput;
+       sbi->pipe = pipe;
+
+       /*
+        * Success! Install the root dentry now to indicate completion.
+        */
+       s->s_root = root;
+       return s;
+
+       /*
+        * Success ... somebody else completed the super block for us. 
+        */ 
+out_unlock:
+       unlock_super(s);
+       goto out_dec;
+out_fput:
+       if (pipe)
+               fput(pipe);
+out_dput:
+       if (root)
+               dput(root);
+       else
+               iput(root_inode);
+out_dec:
+       MOD_DEC_USE_COUNT;
        return s;
+       
+       /*
+        * Failure ... clear the s_dev slot and clean up.
+        */
+fail_fput:
+       printk("autofs: pipe file descriptor does not contain proper ops\n");
+       /*
+        * fput() can block, so we clear the super block first.
+        */
+       s->s_dev = 0;
+       fput(pipe);
+       /* fall through */
+fail_dput:
+       /*
+        * dput() can block, so we clear the super block first.
+        */
+       s->s_dev = 0;
+       dput(root);
+       goto fail_free;
+fail_iput:
+       printk("autofs: get root dentry failed\n");
+       /*
+        * iput() can block, so we clear the super block first.
+        */
+       s->s_dev = 0;
+       iput(root_inode);
+fail_free:
+       kfree(sbi);
+       goto fail_dec;
+fail_unlock:
+       unlock_super(s);
+fail_dec:
+       s->s_dev = 0;
+       MOD_DEC_USE_COUNT;
+       return NULL;
 }
 
 static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
index 1529525186c4853b8209e13d4b7740aafc031b0e..a830ccf804ae08aad3b5c87daaefa17972f8dd2b 100644 (file)
@@ -115,15 +115,17 @@ create_elf_tables(char *p, int argc, int envc,
 
        /*
         * Force 16 byte _final_ alignment here for generality.
+        * Leave an extra 16 bytes free so that on the PowerPC we
+        * can move the aux table up to start on a 16-byte boundary.
         */
-       sp = (elf_addr_t *) (~15UL & (unsigned long) p);
+       sp = (elf_addr_t *) ((~15UL & (unsigned long) p) - 16UL);
        csp = sp;
        csp -= exec ? DLINFO_ITEMS*2 : 2;
        csp -= envc+1;
        csp -= argc+1;
        csp -= (!ibcs ? 3 : 1); /* argc itself */
        if ((unsigned long)csp & 15UL) {
-               sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+               sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
        }
 
        /*
index ee2f4882ba2e738c35fc9ec2351c1893cefbe4b2..c19a7570ff394c644458e60d10e4be533a99c6be 100644 (file)
@@ -34,7 +34,7 @@
 static struct list_head dentry_hashtable[D_HASHSIZE];
 static LIST_HEAD(dentry_unused);
 
-void d_free(struct dentry *dentry)
+static inline void d_free(struct dentry *dentry)
 {
        kfree(dentry->d_name.name);
        kfree(dentry);
@@ -165,10 +165,10 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
        memcpy(str, name->name, name->len);
        str[name->len] = 0;
 
-       dentry->d_count = 0;
+       dentry->d_count = 1;
        dentry->d_flags = 0;
        dentry->d_inode = NULL;
-       dentry->d_parent = parent;
+       dentry->d_parent = dget(parent);
        dentry->d_mounts = dentry;
        dentry->d_covers = dentry;
        INIT_LIST_HEAD(&dentry->d_hash);
@@ -207,7 +207,6 @@ struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
        if (root_inode) {
                res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
                res->d_parent = res;
-               res->d_count = 1;
                d_instantiate(res, root_inode);
        }
        return res;
@@ -238,13 +237,13 @@ static inline struct dentry * __dlookup(struct list_head *head, struct dentry *
                if (parent->d_op && parent->d_op->d_compare) {
                        if (parent->d_op->d_compare(parent, &dentry->d_name, name))
                                continue;
-                       return dentry;
+               } else {
+                       if (dentry->d_name.len != len)
+                               continue;
+                       if (memcmp(dentry->d_name.name, str, len))
+                               continue;
                }
-               if (dentry->d_name.len != len)
-                       continue;
-               if (memcmp(dentry->d_name.name, str, len))
-                       continue;
-               return dentry;
+               return dget(dentry->d_mounts);
        }
        return NULL;
 }
@@ -329,7 +328,7 @@ void d_delete(struct dentry * dentry)
 
 void d_add(struct dentry * entry, struct inode * inode)
 {
-       struct dentry * parent = dget(entry->d_parent);
+       struct dentry * parent = entry->d_parent;
 
        list_add(&entry->d_hash, d_hash(parent, entry->d_name.hash));
        d_instantiate(entry, inode);
index 5b3c3f458c990f55b7a99f2039cecdae2def2201..ede2ef712036aef88abec5d030840d636cecc8d3 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -396,7 +396,7 @@ static void exec_mmap(void)
                *mm = *current->mm;
                init_new_context(mm);
                mm->def_flags = 0;      /* should future lockings be kept? */
-               mm->cpu_vm_mask = (1 << smp_processor_id());
+               mm->cpu_vm_mask = (1UL << smp_processor_id());
                mm->count = 1;
                mm->mmap = mm->mmap_cache = NULL;
                mm->total_vm = 0;
index 1c0be7fdefde3ef4cacbe0908f64a0acbb606724..99555835bc896ddb317223b1b0281857d518137a 100644 (file)
@@ -63,12 +63,14 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
 {
        unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
        unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
-       unsigned int block, i, f_pos, offset, inode_number;
+       unsigned int block, i, f_pos, offset, 
+               inode_number = 0; /* shut gcc up */
        struct buffer_head * bh;
        unsigned int old_offset;
        int dlen, rrflag, match;
        char * dpnt;
-       struct iso_directory_record * de;
+       struct iso_directory_record * de = NULL; /* shut gcc up */
+       char de_not_in_buf = 0;   /* true if de is in kmalloc'd memory */
        char c;
 
        *ino = 0;
@@ -84,17 +86,36 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
   
        while (f_pos < dir->i_size) {
-               de = (struct iso_directory_record *) (bh->b_data + offset);
-               inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
-               /* If byte is zero, this is the end of file, or time to move to
-                  the next sector. Usually 2048 byte boundaries. */
+               /* if de is in kmalloc'd memory, do not point to the
+                   next de, instead we will move to the next sector */
+               if(!de_not_in_buf) {
+                       de = (struct iso_directory_record *) 
+                               (bh->b_data + offset);
+                       inode_number = (block << bufbits) 
+                               + (offset & (bufsize - 1));
+               }
+
+               /* If byte is zero, or we had to fetch this de past
+                  the end of the buffer, this is the end of file, or
+                  time to move to the next sector. Usually 2048 byte
+                  boundaries. */
                
-               if (*((unsigned char *) de) == 0) {
+               if (*((unsigned char *) de) == 0 || de_not_in_buf) {
+                       if(de_not_in_buf) {
+                               /* james@bpgc.com: Since we slopped
+                                   past the end of the last buffer, we
+                                   must start some way into the new
+                                   one */
+                               de_not_in_buf = 0;
+                               kfree(de);
+                               offset -= bufsize;
+                       }
+                       else 
+                               offset = 0;
                        brelse(bh);
-                       offset = 0;
                        f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
-                                + ISOFS_BLOCK_SIZE);
+                                + ISOFS_BLOCK_SIZE) + offset;
 
                        if( f_pos >= dir->i_size )
                          {
@@ -111,11 +132,28 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
                offset += *((unsigned char *) de);
                f_pos += *((unsigned char *) de);
 
-               /* Handle case where the directory entry spans two blocks.
-                  Usually 1024 byte boundaries */
+               /* james@bpgc.com: new code to handle case where the
+                  directory entry spans two blocks.  Usually 1024
+                  byte boundaries */
                if (offset >= bufsize) {
-                       printk("Directory entry extends past end of iso9660 block\n");
-                       return 0;
+                       struct buffer_head *bh_next;
+
+                       /* james@bpgc.com: read the next block, and
+                           copy the split de into a newly kmalloc'd
+                           buffer */
+                       block = isofs_bmap(dir,f_pos>>bufbits);
+                       if (!block || 
+                           !(bh_next = bread(dir->i_dev,block,bufsize)))
+                               return NULL;
+                       
+                       de = (struct iso_directory_record *)
+                               kmalloc(offset - old_offset, GFP_KERNEL);
+                       memcpy((char *)de, bh->b_data + old_offset, 
+                              bufsize - old_offset);
+                       memcpy((char *)de + bufsize - old_offset,
+                              bh_next->b_data, offset - bufsize);
+                       brelse(bh_next);
+                       de_not_in_buf = 1;
                }
                
                dlen = de->name_len[0];
@@ -161,11 +199,15 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
                                           find_rock_ridge_relocation(de,dir));
                        }
                        *ino = inode_number;
+                       if(de_not_in_buf) 
+                               kfree(de);
                        return bh;
                }
        }
  out:
        brelse(bh);
+       if(de_not_in_buf) 
+               kfree(de);
        return NULL;
 }
 
index f49bc3ee3c7b1b7b6139febb956d7374164ee5fb..c88c56760ab1459e137392f47f35ab93e1666e1f 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/uaccess.h>
 
 static int isofs_readlink(struct inode *, char *, int);
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base);
 
 /*
  * symlinks can't do much...
@@ -35,6 +36,7 @@ struct inode_operations isofs_symlink_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        isofs_readlink,         /* readlink */
+       isofs_follow_link,      /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -51,7 +53,6 @@ static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
                buflen = 1023;
        pnt = get_rock_ridge_symlink(inode);
 
-       iput(inode);
        if (!pnt)
                return 0;
 
@@ -63,3 +64,20 @@ static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
        kfree(pnt);
        return i;
 }
+
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base)
+{
+       char * pnt;
+
+       pnt = get_rock_ridge_symlink(inode);
+
+       if(!pnt) {
+               dput(base);
+               return ERR_PTR(-ELOOP);
+       }
+
+       base = lookup_dentry(pnt, base, 1);
+
+       kfree(pnt);
+       return base;
+}
index 68a7f9bad651c39df178102a955ce7a928f97373..d5b5623a9075b1ebff5d81df28a6e76b5cb1a4c8 100644 (file)
@@ -243,15 +243,12 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
        down(&dir->i_sem);
        result = d_lookup(parent, name);
        if (!result) {
-               int error;
-               result = d_alloc(parent, name);
-               result->d_count++;
-               error = dir->i_op->lookup(dir, result);
-               result->d_count--;
-               if (error) {
-                       d_free(result);
-                       result = ERR_PTR(error);
-               }
+               struct dentry * dentry = d_alloc(parent, name);
+               int error = dir->i_op->lookup(dir, dentry);
+               result = ERR_PTR(error);
+               if (!error)
+                       result = dget(dentry->d_mounts);
+               dput(dentry);
        }
        up(&dir->i_sem);
        return result;
@@ -271,11 +268,11 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
        if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
                int validated, (*revalidate)(struct dentry *) = dentry->d_op->d_revalidate;
 
-               dentry->d_count++;
                validated = revalidate(dentry) || d_invalidate(dentry);
-               dput(dentry);
-               if (!validated)
+               if (!validated) {
+                       dput(dentry);
                        dentry = NULL;
+               }
        }
        return dentry;
 }
@@ -302,28 +299,25 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
                        result = parent;
                }
        }
-       return result;
+       return dget(result);
 }
 
 /* In difference to the former version, lookup() no longer eats the dir. */
-static struct dentry * lookup(struct dentry * dir, struct qstr * name)
+static inline struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
        struct dentry * result;
 
        result = reserved_lookup(dir, name);
        if (result)
-               goto done_noerror;
+               goto done;
 
        result = cached_lookup(dir, name);
        if (result)
-               goto done_noerror;
+               goto done;
 
        result = real_lookup(dir, name);
 
-       if (!IS_ERR(result)) {
-done_noerror:
-               result = dget(result->d_mounts);
-       }
+done:
        return result;
 }
 
@@ -538,8 +532,9 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
                        if (dir->i_sb && dir->i_sb->dq_op)
                                dir->i_sb->dq_op->initialize(dir, -1);
                        error = dir->i_op->create(dir, dentry, mode);
-                       /* Don't check for write permission */
+                       /* Don't check for write permission, don't truncate */
                        acc_mode = 0;
+                       flag &= ~O_TRUNC;
                }
                up(&dir->i_sem);
                if (error)
index 3cb50fbbd92f10b2c8a804f79e8565f5bdd72f15..9a302a21347cc8d2d764104355a456445c691648 100644 (file)
@@ -130,8 +130,8 @@ static long ncp_file_read(struct inode *inode, struct file *file, char *buf, uns
        if (!IS_RDONLY(inode)) {
                inode->i_atime = CURRENT_TIME;
        }
-       inode->i_dirt = 1;
-
+       mark_inode_dirty(inode);
+       
        DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
 
        return already_read;
@@ -192,8 +192,8 @@ static long ncp_file_write(struct inode *inode, struct file *file, const char *b
        }
 
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_dirt = 1;
-
+       mark_inode_dirty(inode);
+       
        file->f_pos = pos;
 
        if (pos > inode->i_size) {
index 83309f3a6c7e77e4adf15a02f03040ed197d3818..2e903151e1806e6b37f41e3bb64c04a4e59e1f18 100644 (file)
@@ -165,7 +165,7 @@ struct super_block *
        }
        if ((data->ncp_fd >= NR_OPEN)
            || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
-           || (!S_ISSOCK(ncp_filp->f_inode->i_mode))) {
+           || (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))) {
                printk("ncp_read_super: invalid ncp socket\n");
                sb->s_dev = 0;
                return NULL;
@@ -234,8 +234,8 @@ struct super_block *
 
        ncp_init_root(server);
 
-       if (!(sb->s_mounted = iget(sb, ncp_info_ino(server,
-                                                   &(server->root))))) {
+        if (!(sb->s_root = d_alloc_root(iget(sb,ncp_info_ino(server,
+                                                   &(server->root))),NULL))) {
                sb->s_dev = 0;
                printk("ncp_read_super: get root inode failed\n");
                goto disconnect;
index 937f40cec5d9951ef64b6ec435c2bec14036e3bb..879d48443e96c822f92a18d2dabd5f5e16743d6d 100644 (file)
@@ -32,7 +32,7 @@ static inline int min(int a, int b)
 static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
                                     unsigned long address, int no_share)
 {
-       struct inode *inode = area->vm_inode;
+       struct inode *inode = area->vm_dentry->d_inode;
        unsigned long page;
        unsigned int clear;
        unsigned long tmp;
@@ -130,7 +130,7 @@ int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
                return -EACCES;
        if (!IS_RDONLY(inode)) {
                inode->i_atime = CURRENT_TIME;
-               inode->i_dirt = 1;
+               mark_inode_dirty(inode);
        }
 
        vma->vm_dentry = dget(file->f_dentry);
index 19b42890dc288ee63fda7d00ddc0ad53ed1aed7e..8dce5e0f66235790571d3cf5d7384cbbe8ecc64b 100644 (file)
@@ -102,7 +102,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
        struct ncp_reply_header reply;
 
        file = server->ncp_filp;
-       inode = file->f_inode;
+       inode = file->f_dentry->d_inode;
        sock = &inode->u.socket_i;
        if (!sock) {
                printk("ncp_rpc_call: socki_lookup failed\n");
index a3b2ca2a0d5bbc6d76aa37ed02c6ff9bfeec023f..c0dd8ae4648107746ba6591d56a9506e76011d03 100644 (file)
@@ -561,9 +561,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
        struct nfs_sattr sattr;
-       struct nfs_fattr fattr;
-       struct nfs_fh fhandle;
-       struct inode * inode;
        int error;
 
        dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
@@ -590,12 +587,16 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
        if (error)
                return error;
 
-       inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
-       if (!inode)
-               return -EACCES;
-
        nfs_invalidate_dircache(dir);
-       d_instantiate(dentry, inode);
+       /*  this looks _funny_ doesn't it? But: nfs_proc_symlynk()
+        *  only fills in sattr, not fattr. Thus nfs_fhget() cannot be
+        *  called, it would be pointless, without a valid fattr
+        *  argument. Other possibility: call nfs_proc_lookup()
+        *  HERE. But why? If somebody wants to reference this
+        *  symlink, the cached_lookup() will fail, and
+        *  nfs_proc_symlink() will be called anyway.
+        */
+       d_drop(dentry);
        return 0;
 }
 
index 3d545f7d8e701130e7a736a92535fdc15da8dca1..c739ebe6d0f9c7ce7e815ba707001649ce0e9fd6 100644 (file)
@@ -61,8 +61,8 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
                copy_to_user(buffer, res, len);
                put_user('\0', buffer + len);
                error = len;
+               kfree(mem);
        }
-       kfree(mem);
        return error;
 }
 
@@ -81,7 +81,6 @@ static struct dentry * nfs_follow_link(struct inode * inode, struct dentry *base
 
        if (error) {
                dput(base);
-               kfree(mem);
                return ERR_PTR(error);
        }
        path = kmalloc(len + 1, GFP_KERNEL);
index 36669e4a6d44d9fbe037699de7df0c401747dfef..82fb66cafe1ee49e529f9f3e9ee718f6bb92a09c 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -53,9 +53,6 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
        int error;
 
        lock_kernel();
-       error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
-       if (error)
-               goto out;
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                error = -EBADF;
        else if (!(dentry = file->f_dentry))
@@ -67,8 +64,7 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
        else if (!inode->i_sb->s_op->statfs)
                error = -ENOSYS;
        else
-               inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
-out:
+               error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
        unlock_kernel();
        return error;
 }
index 68e2a34853b97216dcf5e22048b14a261c054c73..d01072a4b15032933a0a3062d559f802d26fd4ac 100644 (file)
@@ -24,4 +24,8 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_PROC_DEVICETREE),y)
+O_OBJS += proc_devtree.o
+endif
+
 include $(TOPDIR)/Rules.make
index 5d98507f03d7dcb114abe3d8f686bdf0d7348738..55f7991faabb36073cdf4a5f7329cd7fdfb23b73 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
+/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
new file mode 100644 (file)
index 0000000..8c5a1bc
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * proc_devtree.c - handles /proc/device-tree
+ *
+ * Copyright 1997 Paul Mackerras
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+static struct proc_dir_entry *proc_device_tree;
+
+/*
+ * Supply data on a read from /proc/device-tree/node/property.
+ */
+static int property_read_proc(char *page, char **start, off_t off,
+                             int count, int *eof, void *data)
+{
+       struct property *pp = data;
+       int n;
+
+       if (off >= pp->length) {
+               *eof = 1;
+               return 0;
+       }
+       n = pp->length - off;
+       if (n > count)
+               n = count;
+       else
+               *eof = 1;
+       memcpy(page, pp->value + off, n);
+       *start = page;
+       return n;
+}
+
+/*
+ * For a node with a name like "gc@10", we make symlinks called "gc"
+ * and "@10" to it.
+ */
+
+static int devtree_readlink(struct inode *, char *, int);
+static struct dentry *devtree_follow_link(struct inode *, struct dentry *);
+
+struct inode_operations devtree_symlink_inode_operations = {
+       NULL,                   /* no file-operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       devtree_readlink,       /* readlink */
+       devtree_follow_link,    /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* smap */
+};
+
+static struct dentry *devtree_follow_link(struct inode *inode,
+                                         struct dentry *base)
+{
+       struct proc_dir_entry * de;
+       char *link;
+
+       de = (struct proc_dir_entry *) inode->u.generic_ip;
+       link = (char *) de->data;
+       return lookup_dentry(link, base, 1);
+}
+
+static int devtree_readlink(struct inode *inode, char *buffer, int buflen)
+{
+       struct proc_dir_entry * de;
+       char *link;
+       int linklen;
+
+       de = (struct proc_dir_entry *) inode->u.generic_ip;
+       link = (char *) de->data;
+       linklen = strlen(link);
+       if (linklen > buflen)
+               linklen = buflen;
+       if (copy_to_user(buffer, link, linklen))
+               return -EFAULT;
+       return linklen;
+}
+
+/*
+ * Process a node, adding entries for its children and its properties.
+ */
+static void add_node(struct device_node *np, struct proc_dir_entry *de)
+{
+       struct property *pp;
+       struct proc_dir_entry *ent;
+       struct device_node *child, *sib;
+       const char *p, *at;
+       int l;
+       struct proc_dir_entry *list, **lastp, *al;
+
+       lastp = &list;
+       for (pp = np->properties; pp != 0; pp = pp->next) {
+               /*
+                * Unfortunately proc_register puts each new entry
+                * at the beginning of the list.  So we rearrange them.
+                */
+               ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+               if (ent == 0)
+                       break;
+               memset(ent, 0, sizeof(struct proc_dir_entry));
+               ent->name = pp->name;
+               ent->namelen = strlen(pp->name);
+               ent->mode = S_IFREG | S_IRUGO;
+               ent->nlink = 1;
+               ent->data = pp;
+               ent->read_proc = property_read_proc;
+               ent->size = pp->length;
+               proc_register(de, ent);
+               *lastp = ent;
+               lastp = &ent->next;
+       }
+       for (child = np->child; child != 0; child = child->sibling) {
+               p = strrchr(child->full_name, '/');
+               if (p == 0)
+                       p = child->full_name;
+               else
+                       ++p;
+               /* chop off '@0' if the name ends with that */
+               l = strlen(p);
+               if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
+                       l -= 2;
+               ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+               if (ent == 0)
+                       break;
+               memset(ent, 0, sizeof(struct proc_dir_entry));
+               ent->name = p;
+               ent->namelen = l;
+               ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+               ent->nlink = 2;
+               proc_register(de, ent);
+               *lastp = ent;
+               lastp = &ent->next;
+               add_node(child, ent);
+
+               /*
+                * If we left the address part on the name, consider
+                * adding symlinks from the name and address parts.
+                */
+               if (p[l] != 0 || (at = strchr(p, '@')) == 0)
+                       continue;
+
+               /*
+                * If this is the first node with a given name property,
+                * add a symlink with the name property as its name.
+                */
+               for (sib = np->child; sib != child; sib = sib->sibling)
+                       if (strcmp(sib->name, child->name) == 0)
+                               break;
+               if (sib == child && strncmp(p, child->name, l) != 0) {
+                       al = kmalloc(sizeof(struct proc_dir_entry),
+                                    GFP_KERNEL);
+                       if (al == 0)
+                               break;
+                       memset(al, 0, sizeof(struct proc_dir_entry));
+                       al->name = child->name;
+                       al->namelen = strlen(child->name);
+                       al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+                       al->nlink = 1;
+                       al->data = (void *) ent->name;
+                       al->ops = &devtree_symlink_inode_operations;
+                       proc_register(de, al);
+                       *lastp = al;
+                       lastp = &al->next;
+               }
+
+               /*
+                * Add another directory with the @address part as its name.
+                */
+               al = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+               if (al == 0)
+                       break;
+               memset(al, 0, sizeof(struct proc_dir_entry));
+               al->name = at;
+               al->namelen = strlen(at);
+               al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+               al->nlink = 1;
+               al->data = (void *) ent->name;
+               al->ops = &devtree_symlink_inode_operations;
+               proc_register(de, al);
+               *lastp = al;
+               lastp = &al->next;
+       }
+       *lastp = 0;
+       de->subdir = list;
+}
+
+/*
+ * Called on initialization to set up the /proc/device-tree subtree
+ */
+void proc_device_tree_init(void)
+{
+       struct device_node *root;
+
+       proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0);
+       if (proc_device_tree == 0)
+               return;
+       root = find_path_device("/");
+       if (root == 0) {
+               printk(KERN_ERR "/proc/device-tree: can't find root\n");
+               return;
+       }
+       add_node(root, proc_device_tree);
+}
index 544e74d05ae959dca877cf1156ebf8f35adcb7f4..dac962324f052e1fcb672fd63fb62d684a04dcbe 100644 (file)
@@ -548,6 +548,13 @@ static struct proc_dir_entry proc_root_omirr = {
        0, &proc_omirr_inode_operations
 };
 #endif
+#ifdef __powerpc__
+static struct proc_dir_entry proc_root_ppc_htab = {
+       PROC_PPC_HTAB, 8, "ppc_htab",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_ppc_htab_inode_operations
+};
+#endif
 
 void proc_root_init(void)
 {
@@ -619,6 +626,12 @@ void proc_root_init(void)
        }
 
        proc_tty_init();
+#ifdef __powerpc__
+       proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+#ifdef CONFIG_PROC_DEVICETREE
+       proc_device_tree_init();
+#endif
 }
 
 /*
index 0451ee427b2e217be50d9cdfbfb93e3b219a9199..98b831c21d1372e06dbb6d78e7a079a570720b4d 100644 (file)
@@ -126,8 +126,8 @@ smb_file_read(struct inode *inode, struct file *file, char *buf, unsigned long c
 
        if (!IS_RDONLY(inode))
                inode->i_atime = CURRENT_TIME;
-       inode->i_dirt = 1;
-
+       mark_inode_dirty(inode);
+       
        DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
 
        return already_read;
@@ -196,8 +196,8 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf,
        }
 
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_dirt = 1;
-
+       mark_inode_dirty(inode);
+       
        file->f_pos = pos;
 
        if (pos > inode->i_size)
index 75d3dbff711d3c5a06ea457bad745b7c2b34ca00..87ae902efad17ecb156dbb1c28157485608afb25 100644 (file)
@@ -228,7 +228,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
                sb->s_dev = 0;
                return NULL;
        }
-       if (!S_ISSOCK(filp->f_inode->i_mode))
+       if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
        {
                printk("smb_read_super: not a socket!\n");
                sb->s_dev = 0;
@@ -305,7 +305,8 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
        }
        smb_init_root_dirent(server, &(server->root.finfo));
 
-       if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root)))))
+       if (!(sb->s_root = d_alloc_root(iget(sb, 
+                                       smb_info_ino(&(server->root))),NULL)))
        {
                sb->s_dev = 0;
                printk("smb_read_super: get root inode failed\n");
index 20a2d0569d29e287d38ba096f42c8ce61f34c220..9dc7d1716e2a89dd3500a4e3e88d2e8a383f55a1 100644 (file)
@@ -27,7 +27,7 @@ static unsigned long
 smb_file_mmap_nopage(struct vm_area_struct *area,
                     unsigned long address, int no_share)
 {
-       struct inode *inode = area->vm_inode;
+       struct inode *inode = area->vm_dentry->d_inode;
        unsigned long page;
        unsigned int clear;
        unsigned long tmp;
@@ -117,7 +117,7 @@ smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
        if (!IS_RDONLY(inode))
        {
                inode->i_atime = CURRENT_TIME;
-               inode->i_dirt = 1;
+               mark_inode_dirty(inode);
        }
 
        vma->vm_dentry = dget(file->f_dentry);
index 4d85b8e663f4ff5ca16ff8e78c45e1374d63296d..fd2fab3c66113ec35489bbaaeb6c3354d7a3cb36 100644 (file)
@@ -128,7 +128,7 @@ smb_catch_keepalive(struct smb_server *server)
 
        if ((server == NULL)
            || ((file = server->sock_file) == NULL)
-           || ((inode = file->f_inode) == NULL)
+           || ((inode = file->f_dentry->d_inode) == NULL)
            || (!S_ISSOCK(inode->i_mode)))
        {
                printk("smb_catch_keepalive: did not get valid server!\n");
@@ -175,7 +175,7 @@ smb_dont_catch_keepalive(struct smb_server *server)
 
        if ((server == NULL)
            || ((file = server->sock_file) == NULL)
-           || ((inode = file->f_inode) == NULL)
+           || ((inode = file->f_dentry->d_inode) == NULL)
            || (!S_ISSOCK(inode->i_mode)))
        {
                printk("smb_dont_catch_keepalive: "
@@ -322,7 +322,7 @@ server_sock(struct smb_server *server)
                return NULL;
        if ((file = server->sock_file) == NULL)
                return NULL;
-       if ((inode = file->f_inode) == NULL)
+       if ((inode = file->f_dentry->d_inode) == NULL)
                return NULL;
        return &(inode->u.socket_i);
 }
index 589dfe956cb3381f38c512d50e0c4f7489f45e4c..ef22465854b291deb912c1f9844bcbe04b53b692 100644 (file)
@@ -159,6 +159,8 @@ extern inline void flush_pages_to_ram (unsigned long address, int n)
     }
 }
 
+#define flush_icache_range(start, end)         do { } while (0)
+
 /*
  * flush all user-space atc entries.
  */
index 59a6ccbbad439a16e2c98d1a7568c504a1ded0fd..a059bb178ae0e051248db34335fda57aacc8505b 100644 (file)
@@ -531,14 +531,16 @@ found_middle:
 #define ext2_find_next_zero_bit(addr, size, offset) \
                 find_next_zero_bit((addr), (size), (offset))
  
+#endif /* !(__MIPSEB__) */
+
 /*
  * Bitmap functions for the minix filesystem.
  * FIXME: These assume that Minix uses the native byte/bitorder.
+ * This limits the Minix filesystem's value for data exchange very much.
  */
 #define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
 #define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
 #define minix_test_bit(nr,addr) test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-#endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_BITOPS_H */
index 776c658d48e78dea0752ba27c9012c246187d3e4..fa53f2241cad842fb8140ed8d939916ad3bd2fbc 100644 (file)
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: checksum.h,v 1.5 1997/08/08 20:22:28 miguel Exp $
  */
 #ifndef __ASM_MIPS_CHECKSUM_H
 #define __ASM_MIPS_CHECKSUM_H
index f639f5aed5e0346bbdbbffdae328a42b902e8d96..4409b538ec2d406ed976b515ba303d0b843395c4 100644 (file)
@@ -71,7 +71,7 @@ extern __inline__ void mips_dma_mem_free(unsigned long addr, unsigned long size)
 {       
 #ifdef CONFIG_MIPS_JAZZ
         if (mips_machgroup == MACH_GROUP_JAZZ)
-               vdma_free(PHYSADDR(addr));
+               vdma_free(vdma_phys2log(PHYSADDR(addr)));
 #endif
        free_pages(addr, __get_order(size));    
 }
diff --git a/include/asm-mips/gfx.h b/include/asm-mips/gfx.h
new file mode 100644 (file)
index 0000000..cf4c9d8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * This is the user-visible SGI GFX interface.
+ *
+ * This must be used verbatim into the GNU libc.  It does not include
+ * any kernel-only bits on it.  
+ *
+ * miguel@nuclecu.unam.mx
+ */
+
+/* The iocls, yes, they do not make sense, but such is life */
+#define GFX_BASE             100
+#define GFX_GETNUM_BOARDS    (GFX_BASE + 1)
+#define GFX_GETBOARD_INFO    (GFX_BASE + 2)
+#define GFX_ATTACH_BOARD     (GFX_BASE + 3)
+#define GFX_DETACH_BOARD     (GFX_BASE + 4)
+#define GFX_IS_MANAGED       (GFX_BASE + 5)
+
+#define GFX_MAPALL           (GFX_BASE + 10)
+
+#define GFX_INFO_NAME_SIZE  16
+#define GFX_INFO_LABEL_SIZE 16
+
+struct gfx_info {
+       char name  [GFX_INFO_NAME_SIZE];  /* board name */
+       char label [GFX_INFO_LABEL_SIZE]; /* label name */
+       unsigned short int xpmax, ypmax;  /* screen resolution */
+       unsigned int lenght;              /* size of a complete gfx_info for this board */
+};
+
+struct gfx_getboardinfo_args {
+       unsigned int board;     /* board number.  starting from zero */
+       void *buf;              /* pointer to gfx_info */
+       unsigned int len;       /* buffer size of buf */
+};
+
+struct gfx_attach_board_args {
+       unsigned int board;     /* board number, starting from zero */
+       void        *vaddr;     /* address where the board registers should be mapped */
+};
+
+#ifdef __KERNEL__
+/* umap.c */
+extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void *vmalloc_uncached (unsigned long size);
+extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+#endif
index 6519a1cefe445603d5d489f2ed3d27078722b3e2..a8e6f11d59b89b5f4e29c3b0ffd71db8705cc40d 100644 (file)
@@ -21,6 +21,7 @@ void vdma_set_mode(int channel, int mode);
 void vdma_set_addr(int channel, long addr);
 void vdma_set_count(int channel, int count);
 int vdma_get_residue(int channel);
+int vdma_get_enable(int channel);
 
 /*
  * some definitions used by the driver functions
index 685b04be1c04718aa6973bef29c7edaa0f124c41..d3c31492b92185b330e2cc988a3506c96532cd8a 100644 (file)
@@ -5,9 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * This file is a mess.  Put on your peril sensitive glasses.
- *
- * $Id: keyboard.h,v 1.4 1997/06/16 00:31:46 ralf Exp $
+ * $Id: keyboard.h,v 1.5 1997/08/08 20:22:31 miguel Exp $
  */
 #ifndef __ASM_MIPS_KEYBOARD_H
 #define __ASM_MIPS_KEYBOARD_H
@@ -17,6 +15,7 @@
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <asm/bootinfo.h>
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
@@ -26,6 +25,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
@@ -34,204 +34,76 @@ extern void pckbd_init_hw(void);
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
 #define kbd_init_hw            pckbd_init_hw
+#define kbd_sysrq_xlate         pckbd_sysrq_xlate
 
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
+#define SYSRQ_KEY 0x54
 
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG      (unsigned int) 0x64
-#define KBD_CNTL_REG        (unsigned int) 0x64
-#define KBD_DATA_REG        (unsigned int) 0x60
+#define INIT_KBD       /* full initialization for the keyboard controller. */
 
-#ifdef CONFIG_SGI
-#include <asm/segment.h>
-#include <asm/sgihpc.h>
-#endif
-#include <asm/bootinfo.h>
-#include <asm/jazz.h>
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
 
-#ifdef CONFIG_SGI
-#define KEYBOARD_IRQ 20
-#else
-/* Not true for Jazz machines, we cheat a bit for 'em. */
-#define KEYBOARD_IRQ 1
-#endif
+/* Pointers to keyboard hardware access and init functions.  */
+unsigned char (*kbd_read_input)(void);
+void (*kbd_write_output)(unsigned char val);
+void (*kbd_write_command)(unsigned char val);
+unsigned char (*kbd_read_status)(void);
 
-#ifdef CONFIG_SGI
-#define DISABLE_KBD_DURING_INTERRUPTS 1
-#else
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-#endif
+void (*keyboard_setup)(void);
 
-#ifndef CONFIG_SGI
-#define KBD_REPORT_ERR
-#endif
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
+#ifdef CONFIG_MIPS_JAZZ
 
-int (*kbd_inb_p)(unsigned short port);
-int (*kbd_inb)(unsigned short port);
-void (*kbd_outb_p)(unsigned char data, unsigned short port);
-void (*kbd_outb)(unsigned char data, unsigned short port);
+/* Not true for Jazz machines, we cheat a bit for 'em. */
+#define KEYBOARD_IRQ 1
 
-#ifdef CONFIG_MIPS_JAZZ
-#define INIT_KBD       /* full initialization for the keyboard controller. */
+/*
+ * No PS/2 style mouse support for Jazz machines
+ */
 
-static volatile keyboard_hardware *jazz_kh;
-
-static int
-jazz_kbd_inb_p(unsigned short port)
-{
-       int result;
-
-       if(port == KBD_DATA_REG)
-               result = jazz_kh->data;
-       else /* Must be KBD_STATUS_REG */
-               result = jazz_kh->command;
-       inb(0x80);
-
-       return result;
-}
-
-static int
-jazz_kbd_inb(unsigned short port)
-{
-       int result;
-
-       if(port == KBD_DATA_REG)
-               result = jazz_kh->data;
-       else /* Must be KBD_STATUS_REG */
-               result = jazz_kh->command;
-
-       return result;
-}
-
-static void
-jazz_kbd_outb_p(unsigned char data, unsigned short port)
-{
-       if(port == KBD_DATA_REG)
-               jazz_kh->data = data;
-       else if(port == KBD_CNTL_REG)
-               jazz_kh->command = data;
-       inb(0x80);
-}
-
-static void
-jazz_kbd_outb(unsigned char data, unsigned short port)
-{
-       if(port == KBD_DATA_REG)
-               jazz_kh->data = data;
-       else if(port == KBD_CNTL_REG)
-               jazz_kh->command = data;
-}
 #endif /* CONFIG_MIPS_JAZZ */
 
 #ifdef CONFIG_SGI
-#define INIT_KBD       /* full initialization for the keyboard controller. */
 
-static volatile struct hpc_keyb *sgi_kh;
-
-static int
-sgi_kbd_inb(unsigned short port)
-{
-       int result;
-
-       if(port == KBD_DATA_REG)
-               result = sgi_kh->data;
-       else /* Must be KBD_STATUS_REG */
-               result = sgi_kh->command;
-
-       return result;
-}
-
-static void
-sgi_kbd_outb(unsigned char data, unsigned short port)
-{
-       if(port == KBD_DATA_REG)
-               sgi_kh->data = data;
-       else if(port == KBD_CNTL_REG)
-               sgi_kh->command = data;
-}
+#define DISABLE_KBD_DURING_INTERRUPTS 1
+
+#define KEYBOARD_IRQ 20
+
+/*
+ * Machine specific bits for the PS/2 driver.
+ * Aux device and keyboard share the interrupt on the Indy.
+ */
+
+#define ps2_request_irq() 0
+#define ps2_free_irq(void) do { } while(0);
+
 #endif /* CONFIG_SGI */
 
+#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI) \
+    || defined(CONFIG_DESKSTATION_RPC44) || defined(CONFIG_DESKSTATION_TYNE)
+#define CONF_KEYBOARD_USES_IO_PORTS
+#endif
+
+#ifdef CONF_KEYBOARD_USES_IO_PORTS
 /*
  * Most other MIPS machines access the keyboard controller via
- * ordinary I/O ports.
+ * memory mapped I/O ports.
  */
-static int
-port_kbd_inb_p(unsigned short port)
-{
-       return inb_p(port);
-}
-
-static int
-port_kbd_inb(unsigned short port)
-{
-       return inb(port);
-}
-
-static void
-port_kbd_outb_p(unsigned char data, unsigned short port)
-{
-       return outb_p(data, port);
-}
-
-static void
-port_kbd_outb(unsigned char data, unsigned short port)
-{
-       return outb(data, port);
-}
-
-extern __inline__ void keyboard_setup(void)
-{
-#ifdef CONFIG_MIPS_JAZZ
-        if (mips_machgroup == MACH_GROUP_JAZZ) {
-               jazz_kh = (void *) JAZZ_KEYBOARD_ADDRESS;
-               kbd_inb_p = jazz_kbd_inb_p;
-               kbd_inb = jazz_kbd_inb;
-               kbd_outb_p = jazz_kbd_outb_p;
-               kbd_outb = jazz_kbd_outb;
-               /*
-                * Enable keyboard interrupts.
-                */
-               *((volatile u16 *)JAZZ_IO_IRQ_ENABLE) |= JAZZ_IE_KEYBOARD;
-               set_cp0_status(IE_IRQ1, IE_IRQ1);
-       } else
-#endif
-       if (mips_machgroup == MACH_GROUP_ARC || /* this is for Deskstation */
-           (mips_machgroup == MACH_GROUP_SNI_RM
-            && mips_machtype == MACH_SNI_RM200_PCI)) {
-               /*
-                * These machines address their keyboard via the normal
-                * port address range.
-                *
-                * Also enable Scan Mode 2.
-                */
-               kbd_inb_p = port_kbd_inb_p;
-               kbd_inb = port_kbd_inb;
-               kbd_outb_p = port_kbd_outb_p;
-               kbd_outb = port_kbd_outb;
-               request_region(0x60,16,"keyboard");
-       }
-#ifdef CONFIG_SGI
-       if (mips_machgroup == MACH_GROUP_SGI) {
-               sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
-               kbd_inb_p = sgi_kbd_inb;
-               kbd_inb = sgi_kbd_inb;
-               kbd_outb_p = sgi_kbd_outb;
-               kbd_outb = sgi_kbd_outb;
-       }
-#endif
-}
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ 1
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define ps2_request_irq()                                              \
+       request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)
+
+#define ps2_free_irq(inode) free_irq(AUX_IRQ, NULL)
+
+#endif /* CONF_KEYBOARD_USES_IO_PORTS */
 
 #endif /* __KERNEL */
 #endif /* __ASM_MIPS_KEYBOARD_H */
diff --git a/include/asm-mips/ng1.h b/include/asm-mips/ng1.h
new file mode 100644 (file)
index 0000000..e7f3b6e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SGI/Newport video card ioctl definitions
+ *
+ */
+
+typedef struct {
+        int flags;
+        u16 w, h;
+        u16 fields_sec;
+} ng1_vof_info_t;
+
+struct ng1_info {
+       struct gfx_info gfx_info;
+       u8 boardrev;
+        u8 rex3rev;
+        u8 vc2rev;
+        u8 monitortype;
+        u8 videoinstalled;
+        u8 mcrev;
+        u8 bitplanes;
+        u8 xmap9rev;
+        u8 cmaprev;
+        ng1_vof_info_t ng1_vof_info;
+        u8 bt445rev;
+        u8 paneltype;
+};
index ee549ea42459299306500566909e2999471c46bb..f52fe471f8096513670075acd31dea56fdceb6be 100644 (file)
@@ -16,6 +16,7 @@
  *  - flush_cache_page(mm, vmaddr) flushes a single page
  *  - flush_cache_range(mm, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
+ *
  */
 extern void (*flush_cache_all)(void);
 extern void (*flush_cache_mm)(struct mm_struct *mm);
@@ -24,6 +25,7 @@ extern void (*flush_cache_range)(struct mm_struct *mm, unsigned long start,
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*flush_cache_sigtramp)(unsigned long addr);
 extern void (*flush_page_to_ram)(unsigned long page);
+#define flush_icache_range(start, end)         do { } while (0)
 
 /* TLB flushing:
  *
@@ -38,6 +40,13 @@ extern void (*flush_tlb_range)(struct mm_struct *mm, unsigned long start,
                               unsigned long end);
 extern void (*flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
+/*
+ * - add_wired_entry() add a fixed TLB entry, and move wired register
+ */
+extern void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+                              unsigned long entryhi, unsigned long pagemask);
+
+
 /* Basically we have the same two-level (which is the logical three level
  * Linux page table layout folded) page tables as the i386.  Some day
  * when we have proper page coloring support we can have a 1% quicker
@@ -108,21 +117,25 @@ extern void (*flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 #define _CACHE_CACHABLE_ACCELERATED (7<<9)  /* R10000 only             */
 #define _CACHE_MASK                 (7<<9)
 
-#define __READABLE     (_PAGE_READ|_PAGE_SILENT_READ|_PAGE_ACCESSED)
-#define __WRITEABLE    (_PAGE_WRITE|_PAGE_SILENT_WRITE|_PAGE_MODIFIED)
+#define __READABLE     (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
+#define __WRITEABLE    (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
 
 #define _PAGE_CHG_MASK  (PAGE_MASK | __READABLE | __WRITEABLE | _CACHE_MASK)
 
 #define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                         _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
-                       _PAGE_ACCESSED | _CACHE_CACHABLE_NONCOHERENT)
+                       _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_READ | \
                        _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_READ | \
                        _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
                        _CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_USERIO     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+                       _CACHE_UNCACHED)
+#define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
+                       _CACHE_UNCACHED)
 
 /*
  * MIPS can't do page protection for execute, and considers that the same like
@@ -217,7 +230,7 @@ extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT;
  */
 extern inline void set_pte(pte_t *ptep, pte_t pteval)
 {
-        *ptep = pteval;
+       *ptep = pteval;
 }
 
 extern inline void pte_clear(pte_t *ptep)
@@ -230,7 +243,7 @@ extern inline void pte_clear(pte_t *ptep)
  */
 extern inline int pmd_none(pmd_t pmd)
 {
-       return pmd_val(pmd) == ((unsigned long) invalid_pte_table);
+       return pmd_val(pmd) == (unsigned long) invalid_pte_table;
 }
 
 extern inline int pmd_bad(pmd_t pmd)
@@ -288,7 +301,7 @@ extern inline pte_t pte_mkclean(pte_t pte)
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-       pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ|_PAGE_SILENT_WRITE);
+       pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ);
        return pte;
 }
 
@@ -319,12 +332,8 @@ extern inline pte_t pte_mkdirty(pte_t pte)
 extern inline pte_t pte_mkyoung(pte_t pte)
 {
        pte_val(pte) |= _PAGE_ACCESSED;
-       if (pte_val(pte) & _PAGE_READ) {
+       if (pte_val(pte) & _PAGE_READ)
                pte_val(pte) |= _PAGE_SILENT_READ;
-               if ((pte_val(pte) & (_PAGE_WRITE|_PAGE_MODIFIED)) ==
-                   (_PAGE_WRITE|_PAGE_MODIFIED))
-                       pte_val(pte) |= _PAGE_SILENT_WRITE;
-       }
        return pte;
 }
 
@@ -541,7 +550,7 @@ extern inline unsigned long get_pagemask(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $5\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
        return val;
@@ -553,7 +562,7 @@ extern inline void set_pagemask(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $5\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -567,7 +576,7 @@ extern inline unsigned long get_entrylo0(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $2\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
        return val;
@@ -579,7 +588,7 @@ extern inline void set_entrylo0(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $2\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -592,7 +601,7 @@ extern inline unsigned long get_entrylo1(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $3\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder" : "=r" (val));
 
        return val;
@@ -604,7 +613,7 @@ extern inline void set_entrylo1(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $3\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -618,7 +627,7 @@ extern inline unsigned long get_entryhi(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $10\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
 
@@ -631,7 +640,7 @@ extern inline void set_entryhi(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $10\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -645,7 +654,7 @@ extern inline unsigned long get_index(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $0\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
        return val;
@@ -657,7 +666,7 @@ extern inline void set_index(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $0\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder\n\t"
                : : "r" (val));
 }
@@ -671,7 +680,7 @@ extern inline unsigned long get_wired(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $6\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder\n\t"
                : "=r" (val));
        return val;
@@ -683,7 +692,7 @@ extern inline void set_wired(unsigned long val)
                "\n\t.set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $6\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -697,7 +706,7 @@ extern inline unsigned long get_taglo(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $28\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
        return val;
@@ -709,7 +718,7 @@ extern inline void set_taglo(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $28\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -722,7 +731,7 @@ extern inline unsigned long get_taghi(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $29\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
        return val;
@@ -734,7 +743,7 @@ extern inline void set_taghi(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $29\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
@@ -748,7 +757,7 @@ extern inline unsigned long get_context(void)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mfc0 %0, $4\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : "=r" (val));
 
@@ -761,14 +770,11 @@ extern inline void set_context(unsigned long val)
                ".set noreorder\n\t"
                ".set mips3\n\t"
                "mtc0 %0, $4\n\t"
-               ".set mips2\n\t"
+               ".set mips0\n\t"
                ".set reorder"
                : : "r" (val));
 }
 
 #endif /* !defined (__LANGUAGE_ASSEMBLY__) */
 
-#define module_map      vmalloc
-#define module_unmap    vfree
-
 #endif /* __ASM_MIPS_PGTABLE_H */
diff --git a/include/asm-mips/rrm.h b/include/asm-mips/rrm.h
new file mode 100644 (file)
index 0000000..501fa6c
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * SGI Rendering Resource Manager API (?).
+ *
+ * written by Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Ok, even if SGI choosed to do mmap trough ioctls, their
+ * kernel support for virtualizing the graphics card is nice.
+ *
+ * We should be able to make graphic applications on Linux
+ * fly.
+ *
+ * This header file should be included from GNU libc as well.
+ */
+
+
+/* Why like this you say?  Well, gdb can print enums */
+#define RRM_BASE 1000
+#define RRM_CMD_LIMIT (RRM_BASE + 100)
+
+enum {
+       RRM_OPENRN = RRM_BASE,  /* open rendering node */
+       RRM_CLOSERN,
+       RRM_BINDPROCTORN,       /* set current rendering region for node */
+       RRM_BINDRNTOCLIP,
+       RRM_UNBINDRNFROMCLIP,
+       RRM_SWAPBUF,
+       RRM_SETSWAPINTERVAL,
+       RRM_WAITFORRETRACE,
+       RRM_SETDISPLAYMODE,
+       RRM_MESSAGE,
+       RRM_INVALIDATERN,
+       RRM_VALIDATECLIP,
+       RRM_VALIDATESWAPBUF,
+       RRM_SWAPGROUP,
+       RRM_SWAPUNGROUP,
+       RRM_VALIDATEMESSAGE,
+       RRM_GETDISPLAYMODES,
+       RRM_LOADDISPLAYMODE,
+       RRM_CUSHIONBUFFER,
+       RRM_SWAPREADY,
+       RRM_MGR_SWAPBUF,
+       RRM_SETVSYNC,
+       RRM_GETVSYNC,
+       RRM_WAITVSYNC,
+       RRM_BINDRNTOREADANDCLIP,
+       RRM_MAPCLIPTOSWPBUFID
+};
+
+/* Parameters for the above ioctls
+ *
+ * All of the ioctls take as their first argument the rendering node id.
+ *
+ */
+
+/*
+ * RRM_OPENRN:
+ *
+ * This is called by the IRIX X server with:
+ * rnid = 0xffffffff rmask = 0
+ *
+ * Returns a number like this: 0x10001.
+ * If you run the X server over and over, you get a value
+ * that is of the form (n * 0x10000) + 1.
+ *
+ * The return value seems to be the RNID.
+ */
+struct RRM_OpenRN {
+       int      rnid;
+       unsigned int rmask;
+};
+
+struct RRM_CloseRN {
+       int rnid;
+};
+
+/*
+ * RRM_BINDPROCTORN:
+ *
+ * Return value when the X server calls it: 0
+ */ 
+struct RRM_BindProcToRN {
+       int      rnid;
+};
+
+#ifdef __KERNEL__
+int rrm_command (unsigned int cmd, void *arg);
+int rrm_close (struct inode *inode, struct file *file);
+#endif
diff --git a/include/asm-mips/shmiq.h b/include/asm-mips/shmiq.h
new file mode 100644 (file)
index 0000000..2e84511
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Please note that the comments on this file may be out of date
+ * and that they represent what I have figured about the shmiq device
+ * so far in IRIX.
+ *
+ * This also contains some streams and idev bits.
+ *
+ * They may contain errors, please, refer to the source code of the Linux  
+ * kernel for a definitive answer on what we have implemented
+ *
+ * Miguel.
+ */
+
+/* STREAMs ioctls */
+#define STRIOC    ('S' << 8)
+#define I_STR     (STRIOC | 010)
+#define I_PUSH    (STRIOC | 02)
+#define I_LINK    (STRIOC | 014)
+#define I_UNLINK  (STRIOC | 015)
+
+/* Data structure passed on I_STR ioctls */
+struct strioctl {
+        int     ic_cmd;                 /* streams ioctl command */
+        int     ic_timout;              /* timeout */
+        int     ic_len;                 /* lenght of data */
+        void    *ic_dp;                 /* data */
+};
+
+/*
+ * For mapping the shared memory input queue, you have to:
+ *
+ * 1. Map /dev/zero for the number of bytes you want to use
+ *    for your shared memory input queue plus the size of the
+ *    sharedMemoryInputQueue structure + 4 (I still have not figured
+ *    what this one is for
+ *
+ * 2. Open /dev/shmiq
+ *
+ * 3. Open /dev/qcntlN N is [0..Nshmiqs]
+ *
+ * 4. Fill a shmiqreq structure.  user_vaddr should point to the return
+ *    address from the /dev/zero mmap.  Arg is the number of shmqevents
+ *    that fit into the /dev/zero region (remember that at the beginning there
+ *    is a sharedMemoryInputQueue header).
+ *
+ * 5. Issue the ioctl (qcntlfd, QIOCATTACH, &your_shmiqreq);
+ */
+
+struct shmiqreq {
+       char *user_vaddr;
+       int  arg;
+};
+
+/* map the shmiq into the process address space */
+#define QIOCATTACH       _IOW('Q',1,struct shmiqreq)
+
+/* remove mappings */
+#define QIOCDETACH       _IO('Q',2)
+
+/*
+ * A shared memory input queue event.
+ */
+struct shmqdata {
+       unsigned char device;          /* device major */
+        unsigned char which;           /* device minor */
+        unsigned char type;            /* event type */
+        unsigned char flags;           /* little event data */
+        union {
+            int pos;                   /* big event data */
+            short ptraxis [2];         /* event data for PTR events */
+        } un;
+};
+
+/* indetifies the shmiq and the device */
+struct shmiqlinkid {
+        short int devminor;
+        short int index;
+};
+
+struct shmqevent {
+       union {
+                int time;
+                struct shmiqlinkid id;
+        } un ;
+        struct shmqdata data ;
+};
+
+/*
+ * sharedMemoryInputQueue: this describes the shared memory input queue.
+ *
+ * head   is the user index into the events, user can modify this one.
+ * tail   is managed by the kernel.
+ * flags  is one of SHMIQ_OVERFLOW or SHMIQ_CORRUPTED
+ *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called 
+ *        to notify the kernel.
+ * events where the kernel sticks the events.
+ */
+struct sharedMemoryInputQueue {
+       volatile int head;           /* user's index into events */
+        volatile int tail;          /* kernel's index into events */
+        volatile unsigned int flags; /* place for out-of-band data */
+#define SHMIQ_OVERFLOW  1
+#define SHMIQ_CORRUPTED 2
+        struct shmqevent events[1];  /* input event buffer */
+};
+
+/* have to figure this one out */
+#define QIOCGETINDX      _IOWR('Q', 8, int)
+
+
+/* acknowledge shmiq overflow */
+#define QIOCSERVICED     _IO('Q', 3)
+
+/* Double indirect I_STR ioctl, yeah, fun fun fun */
+
+struct muxioctl {
+        int index;             /* lower stream index */
+        int realcmd;           /* the actual command for the subdevice */
+};
+/* Double indirect ioctl */
+#define QIOCIISTR        _IOW('Q', 7, struct muxioctl)
+
+/* Cursor ioclts: */
+
+/* set cursor tracking mode */
+#define QIOCURSTRK      _IOW('Q', 4, int)
+
+/* set cursor filter box */
+#define QIOCURSIGN      _IOW('Q', 5, int [4])
+
+/* set cursor axes */
+struct shmiqsetcurs {
+        short index;
+        short axes;
+};
+
+#define QIOCSETCURS     _IOWR('Q',  9, struct shmiqsetcurs)
+
+/* set cursor position */
+struct shmiqsetcpos {
+        short   x;
+        short   y;
+};
+#define QIOCSETCPOS     _IOWR('Q', 10, struct shmiqsetcpos)
+
+/* get time since last event */
+#define QIOCGETITIME    _IOR('Q', 11, time_t)
+
+/* set curent screen */
+#define QIOCSETSCRN     _IOW('Q',6,int)
+
+
+/* -------------------- iDev stuff -------------------- */
+
+#define IDEV_MAX_NAME_LEN 15
+#define IDEV_MAX_TYPE_LEN 15
+
+typedef struct {
+        char            devName[IDEV_MAX_NAME_LEN+1];
+        char            devType[IDEV_MAX_TYPE_LEN+1];
+        unsigned short  nButtons;
+        unsigned short  nValuators;
+        unsigned short  nLEDs;
+        unsigned short  nStrDpys;
+        unsigned short  nIntDpys;
+        unsigned char   nBells;
+        unsigned char   flags;
+#define IDEV_HAS_KEYMAP                0x01
+#define IDEV_HAS_PROXIMITY     0x02
+#define IDEV_HAS_PCKBD                 0x04
+} idevDesc;
+
+typedef struct {
+       char *nothing_for_now;
+} idevInfo;
+
+typedef struct {
+        char name [16];
+} idevKeymapDesc;
+
+#define IDEVINITDEVICE         _IOW('i', 51, unsigned int)
+#define IDEVGETDEVICEDESC      _IOWR('i', 0, idevDesc)
+#define IDEVGETKEYMAPDESC      _IOWR('i', 2, idevKeymapDesc)
+
+#ifdef __KERNEL__
+
+/* These are only interpreted by SHMIQ-attacheable devices and are internal
+ * to the kernel
+ */
+#define SHMIQ_OFF        _IO('Q',1)
+#define SHMIQ_ON         _IO('Q',2)
+
+void shmiq_push_event (struct shmqevent *e);
+int get_sioc (struct strioctl *sioc, unsigned long arg);
+#endif
index 2fb241775e1d6e2c1681f73f0fc9e41d6ec85583..2c10d8423f204e5420748da76bd41c0691abeac2 100644 (file)
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (c) 1994, 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: string.h,v 1.4 1997/08/08 20:22:34 miguel Exp $
  */
 #ifndef __ASM_MIPS_STRING_H
 #define __ASM_MIPS_STRING_H
@@ -117,7 +119,7 @@ extern __inline__ int strncmp(__const__ char *__cs, __const__ char *__ct, size_t
 }
 
 #define __HAVE_ARCH_MEMSET
-extern void *memset(void *__s, char __c, size_t __count);
+extern void *memset(void *__s, int __c, size_t __count);
 
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
index 2c752a0c09264ccba46e9c563d8b773a2fe1033a..117d6c0621e28b95355e6f5306779da46825e960 100644 (file)
@@ -252,7 +252,7 @@ static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int
        return x;
 }
 
-extern unsigned long IRQ_vectors[16];
+extern unsigned long IRQ_vectors[32];
 extern unsigned long exception_handlers[32];
 
 #define set_int_vector(n,addr) \
index 3b8a24575d9e12bdd049ff82a69346eb3cce657e..0a848013d3bd190d5ab202cda9b2b7dc7ef1bb13 100644 (file)
@@ -1,17 +1,26 @@
+/*
+ * $Id: bitops.h,v 1.7 1997/08/03 00:12:07 paulus Exp $
+ * bitops.h: Bit string operations on the ppc
+ */
+
 #ifndef _ASM_PPC_BITOPS_H_
 #define _ASM_PPC_BITOPS_H_
 
 #include <asm/system.h>
 #include <asm/byteorder.h>
-#include <linux/kernel.h> /* for printk */
-
-#define BIT(n) 1<<(n&0x1F)
-typedef unsigned long BITFIELD;
 
+extern void set_bit(int nr, volatile void *addr);
+extern void clear_bit(int nr, volatile void *addr);
+extern void change_bit(int nr, volatile void *addr);
+extern int test_and_set_bit(int nr, volatile void *addr);
+extern int test_and_clear_bit(int nr, volatile void *addr);
+extern int test_and_change_bit(int nr, volatile void *addr);
 
 /*
- * These are ifdef'd out here because using : "cc" as a constraing
+ * These are if'd out here because using : "cc" as a constraint
  * results in errors from gcc. -- Cort
+ * Besides, they need to be changed so we have both set_bit
+ * and test_and_set_bit, etc.
  */
 #if 0
 extern __inline__ int set_bit(int nr, void * addr)
@@ -20,9 +29,6 @@ extern __inline__ int set_bit(int nr, void * addr)
        unsigned long mask = 1 << (nr & 0x1f);
        unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
        
-       if ((unsigned long)addr & 3)
-               printk("set_bit(%lx, %p)\n", nr, addr);
-
        __asm__ __volatile__(
                "1:lwarx %0,0,%3 \n\t"
                "or     %1,%0,%2 \n\t"
@@ -32,7 +38,7 @@ extern __inline__ int set_bit(int nr, void * addr)
                : "r" (mask), "r" (p)
                /*: "cc" */);
 
-n      return (old & mask) != 0;
+       return (old & mask) != 0;
 }
 
 extern __inline__  unsigned long clear_bit(unsigned long nr, void *addr)
@@ -41,8 +47,6 @@ extern __inline__  unsigned long clear_bit(unsigned long nr, void *addr)
        unsigned long mask = 1 << (nr & 0x1f);
        unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
 
-       if ((unsigned long)addr & 3)
-               printk("clear_bit(%lx, %p)\n", nr, addr);
        __asm__ __volatile__("\n\
 1:     lwarx   %0,0,%3
        andc    %1,%0,%2
@@ -61,8 +65,6 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
        unsigned long mask = 1 << (nr & 0x1f);
        unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
 
-       if ((unsigned long)addr & 3)
-               printk("change_bit(%lx, %p)\n", nr, addr);
        __asm__ __volatile__("\n\
 1:     lwarx   %0,0,%3
        xor     %1,%0,%2
@@ -76,10 +78,19 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 }
 #endif
 
+extern __inline__ unsigned long test_bit(int nr, __const__ volatile void *addr)
+{
+       __const__ unsigned int *p = (__const__ unsigned int *) addr;
+
+       return (p[nr >> 5] >> (nr & 0x1f)) & 1UL;
+}
+
 extern __inline__ int ffz(unsigned int x)
 {
        int n;
 
+       if (x == ~0)
+               return 32;
        x = ~x & (x+1);         /* set LS zero to 1, other bits to 0 */
        __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
        return 31 - n;
@@ -89,34 +100,11 @@ extern __inline__ int ffz(unsigned int x)
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
  */
+#define find_first_zero_bit(addr, size) \
+       find_next_zero_bit((addr), (size), 0)
 
-extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
-{
-       unsigned int * p = ((unsigned int *) addr);
-       unsigned int result = 0;
-       unsigned int tmp;
-
-       if (size == 0)
-               return 0;
-       while (size & ~31UL) {
-               if (~(tmp = *(p++)))
-                       goto found_middle;
-               result += 32;
-               size -= 32;
-       }
-       if (!size)
-               return result;
-       tmp = *p;
-       tmp |= ~0UL << size;
-found_middle:
-       return result + ffz(tmp);
-}
-
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
-                                unsigned long offset)
+extern __inline__ unsigned long find_next_zero_bit(void * addr,
+       unsigned long size, unsigned long offset)
 {
        unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
        unsigned int result = offset & ~31UL;
@@ -127,17 +115,17 @@ extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long si
        size -= result;
        offset &= 31UL;
        if (offset) {
-               tmp = *(p++);
+               tmp = *p++;
                tmp |= ~0UL >> (32-offset);
                if (size < 32)
                        goto found_first;
-               if (~tmp)
+               if (tmp != ~0U)
                        goto found_middle;
                size -= 32;
                result += 32;
        }
-       while (size & ~31UL) {
-               if (~(tmp = *(p++)))
+       while (size >= 32) {
+               if ((tmp = *p++) != ~0U)
                        goto found_middle;
                result += 32;
                size -= 32;
@@ -153,101 +141,98 @@ found_middle:
 
 
 #define _EXT2_HAVE_ASM_BITOPS_
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
 
+#ifdef __KERNEL__
+/*
+ * test_and_{set,clear}_bit guarantee atomicity without
+ * disabling interrupts.
+ */
+#define ext2_set_bit(nr, addr)         test_and_set_bit((nr) ^ 0x18, addr)
+#define ext2_clear_bit(nr, addr)       test_and_clear_bit((nr) ^ 0x18, addr)
 
+#else
 extern __inline__ int ext2_set_bit(int nr, void * addr)
 {
-#ifdef __KERNEL__
-  int s = _disable_interrupts();
-#endif
-  int                  mask;
-  unsigned char        *ADDR = (unsigned char *) addr;
-  int oldbit;
-  
-  ADDR += nr >> 3;
-  mask = 1 << (nr & 0x07);
-  oldbit = (*ADDR & mask) ? 1 : 0;
-  *ADDR |= mask;
-#ifdef __KERNEL__      
-  _enable_interrupts(s);
-#endif
-  return oldbit;
+       int             mask;
+       unsigned char   *ADDR = (unsigned char *) addr;
+       int oldbit;
+
+       ADDR += nr >> 3;
+       mask = 1 << (nr & 0x07);
+       oldbit = (*ADDR & mask) ? 1 : 0;
+       *ADDR |= mask;
+       return oldbit;
 }
 
 extern __inline__ int ext2_clear_bit(int nr, void * addr)
 {
-#ifdef __KERNEL__
-  int s = _disable_interrupts();
-#endif
-  int          mask;
-  unsigned char        *ADDR = (unsigned char *) addr;
-  int oldbit;
-  
-  ADDR += nr >> 3;
-  mask = 1 << (nr & 0x07);
-  oldbit = (*ADDR & mask) ? 1 : 0;
-  *ADDR = *ADDR & ~mask;
-#ifdef __KERNEL__      
-  _enable_interrupts(s);
-#endif
-  return oldbit;
-}
+       int             mask;
+       unsigned char   *ADDR = (unsigned char *) addr;
+       int oldbit;
 
-
-/* The following routine need not be atomic. */
-extern __inline__ unsigned long test_bit(int nr, void *addr)
-{
-       return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31));
+       ADDR += nr >> 3;
+       mask = 1 << (nr & 0x07);
+       oldbit = (*ADDR & mask) ? 1 : 0;
+       *ADDR = *ADDR & ~mask;
+       return oldbit;
 }
+#endif /* __KERNEL__ */
 
 extern __inline__ int ext2_test_bit(int nr, __const__ void * addr)
 {
-       int                     mask;
        __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
 
-       ADDR += nr >> 3;
-       mask = 1 << (nr & 0x07);
-       return ((mask & *ADDR) != 0);
+       return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 }
 
-extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+/*
+ * This implementation of ext2_find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
+ */
+
+#define ext2_find_first_zero_bit(addr, size) \
+        ext2_find_next_zero_bit((addr), (size), 0)
+
+extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
+       unsigned long size, unsigned long offset)
 {
-       unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-       unsigned long result = offset & ~31UL;
-       unsigned long tmp;
+       unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+       unsigned int result = offset & ~31UL;
+       unsigned int tmp;
 
        if (offset >= size)
                return size;
        size -= result;
        offset &= 31UL;
-       if(offset) {
-               tmp = *(p++);
-               tmp |= le32_to_cpu(~0UL >> (32-offset));
-               if(size < 32)
+       if (offset) {
+               tmp = cpu_to_le32p(p++);
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
                        goto found_first;
-               if(~tmp)
+               if (tmp != ~0U)
                        goto found_middle;
                size -= 32;
                result += 32;
        }
-       while(size & ~31UL) {
-               if(~(tmp = *(p++)))
+       while (size >= 32) {
+               if ((tmp = cpu_to_le32p(p++)) != ~0U)
                        goto found_middle;
                result += 32;
                size -= 32;
        }
-       if(!size)
+       if (!size)
                return result;
-       tmp = *p;
-
+       tmp = cpu_to_le32p(p);
 found_first:
-       return result + ffz(le32_to_cpu(tmp) | (~0UL << size));
+       tmp |= ~0U << size;
 found_middle:
-       return result + ffz(le32_to_cpu(tmp));
+       return result + ffz(tmp);
 }
 
-#endif /* _ASM_PPC_BITOPS_H */
-
+/* Bitmap functions for the minix filesystem.  */
+#define minix_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
 
+#endif /* _ASM_PPC_BITOPS_H */
index eab03c752650538d553a0b52698095718113606f..8fee6e46f01c7ff986b33f31bc965f10d73e0778 100644 (file)
@@ -4,17 +4,17 @@
 #include <asm/types.h>
 
 #ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN   4321
 #endif
 
 #ifndef __BIG_ENDIAN_BITFIELD
 #define __BIG_ENDIAN_BITFIELD
 #endif
 
-#define ntohl(x) (x)
-#define ntohs(x) (x)
-#define htonl(x) (x)
-#define htons(x) (x)
+#define ntohl(x) ((unsigned long)(x))
+#define ntohs(x) ((unsigned short)(x))
+#define htonl(x) ((unsigned long)(x))
+#define htons(x) ((unsigned short)(x))
 
 #define __htonl(x) ntohl(x)
 #define __htons(x) ntohs(x)
@@ -54,7 +54,7 @@ extern inline void st_le32(volatile unsigned *addr, unsigned val)
        asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
 }
 
-
+#if 0
 extern __inline__ __u16 cpu_to_le16(__u16 value)
 {
        return ld_le16(&value);
@@ -63,6 +63,29 @@ extern __inline__ __u32 cpu_to_le32(__u32 value)
 {
        return ld_le32(&value);
 }
+#else
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+       __u16 result;
+
+       asm("rlwimi %0,%1,8,16,23"
+           : "=r" (result)
+           : "r" (value), "0" (value >> 8));
+       return result;
+}
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+       __u32 result;
+
+       asm("rlwimi %0,%1,24,16,23\n\t"
+           "rlwimi %0,%1,8,8,15\n\t"
+           "rlwimi %0,%1,24,0,7"
+           : "=r" (result)
+           : "r" (value), "0" (value >> 24));
+       return result;
+}
+#endif /* 0 */
+
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
 
index 7b55f0032a443f7e0ec001e7ded2386bde9ef757..1395cb0aae1a874429d333c688410a1a30a88fb0 100644 (file)
@@ -2,22 +2,6 @@
 #define _PPC_CHECKSUM_H
 
 
-/*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- */
-extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
-                                          unsigned long daddr,
-                                          unsigned short len,
-                                          unsigned short proto,
-                                          unsigned int sum);
-
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
@@ -30,43 +14,76 @@ extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+extern unsigned int csum_partial(const unsigned char * buff, int len,
+                                unsigned int sum);
 
 /*
- * the same as csum_partial, but copies from src while it
- * checksums
+ * 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 (if that pointer is not
+ * NULL), and, for an error on src, zeroes the rest of dst.
  *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
+ * Like csum_partial, this must be called with even lengths,
+ * except for the last fragment.
  */
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
+                                             int len, unsigned int sum,
+                                             int *src_err, int *dst_err);
+
+#define csum_partial_copy_from_user(src, dst, len, sum, errp)  \
+       csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
 
 /*
- * the same as csum_partial, but copies from user space (but on the alpha
- * we have just one address space, so this is identical to the above)
+ * Old versions which ignore errors.
  */
-#define csum_partial_copy_fromuser csum_partial_copy
+#define csum_partial_copy(src, dst, len, sum)  \
+       csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+#define csum_partial_copy_fromuser(src, dst, len, sum) \
+       csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+
 
 /*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
- *
- * right now - it just calls csum_partial_copy()
- *   -- Cort
+ * turns a 32-bit partial checksum (e.g. from csum_partial) into a
+ * 1's complement 16-bit checksum.
  */
-extern __inline__
-unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
-                                               int len, int sum, int *err_ptr)
+static inline unsigned int csum_fold(unsigned int sum)
 {
-       int *dst_err_ptr=NULL;
-       return csum_partial_copy( src, dst, len, sum);
+       unsigned int tmp;
+
+       /* swap the two 16-bit halves of sum */
+       __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
+       /* if there is a carry from adding the two 16-bit halves,
+          it will carry from the lower half into the upper half,
+          giving us the correct sum in the upper half. */
+       sum = ~(sum + tmp) >> 16;
+       return sum;
 }
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
-A */
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+       return csum_fold(csum_partial(buff, len, 0));
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.  ihl is the number
+ * of 32-bit words and is always >= 5.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short csum_tcpudp_magic(unsigned long saddr,
+                                       unsigned long daddr,
+                                       unsigned short len,
+                                       unsigned short proto,
+                                       unsigned int sum);
 
-extern unsigned short ip_compute_csum(unsigned char * buff, int len);
-extern unsigned int csum_fold(unsigned int sum);
 #endif
diff --git a/include/asm-ppc/cuda.h b/include/asm-ppc/cuda.h
new file mode 100644 (file)
index 0000000..3f1a47c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Definitions for talking to the CUDA.  The CUDA is a microcontroller
+ * which controls the ADB, system power, RTC, and various other things.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+/* First byte sent to or received from CUDA */
+#define ADB_PACKET     0
+#define CUDA_PACKET    1
+#define ERROR_PACKET   2
+#define TIMER_PACKET   3
+#define POWER_PACKET   4
+#define MACIIC_PACKET  5
+
+/* ADB commands (2nd byte) */
+#define ADB_BUSRESET           0
+#define ADB_FLUSH(id)          (1 + ((id) << 4))
+#define ADB_WRITEREG(id, reg)  (8 + (reg) + ((id) << 4))
+#define ADB_READREG(id, reg)   (0xc + (reg) + ((id) << 4))
+
+/* ADB default device IDs (upper 4 bits of 2nd byte) */
+#define ADB_DONGLE     1       /* "software execution control" devices */
+#define ADB_KEYBOARD   2
+#define ADB_MOUSE      3
+#define ADB_TABLET     4
+#define ADB_MODEM      5
+#define ADB_MISC       7       /* maybe a monitor */
+
+/* CUDA commands (2nd byte) */
+#define CUDA_WARM_START                0
+#define CUDA_AUTOPOLL          1
+#define CUDA_GET_6805_ADDR     2
+#define CUDA_GET_TIME          3
+#define CUDA_GET_PRAM          7
+#define CUDA_SET_6805_ADDR     8
+#define CUDA_SET_TIME          9
+#define CUDA_POWERDOWN         0xa
+#define CUDA_POWERUP_TIME      0xb
+#define CUDA_SET_PRAM          0xc
+#define CUDA_MS_RESET          0xd
+#define CUDA_SEND_DFAC         0xe
+#define CUDA_RESET_SYSTEM      0x11
+#define CUDA_SET_IPL           0x12
+#define CUDA_SET_AUTO_RATE     0x14
+#define CUDA_GET_AUTO_RATE     0x16
+#define CUDA_SET_DEVICE_LIST   0x19
+#define CUDA_GET_DEVICE_LIST   0x1a
+#define CUDA_GET_SET_IIC       0x22
+
+#ifdef __KERNEL__
+
+struct cuda_request {
+    unsigned char data[16];
+    int nbytes;
+    unsigned char reply[16];
+    int reply_len;
+    unsigned char reply_expected;
+    unsigned char sent;
+    unsigned char got_reply;
+    void (*done)(struct cuda_request *);
+    void *arg;
+    struct cuda_request *next;
+};
+
+void via_cuda_init(void);
+int cuda_request(struct cuda_request *req,
+                void (*done)(struct cuda_request *), int nbytes, ...);
+int cuda_send_request(struct cuda_request *req);
+void cuda_poll(void);
+int adb_register(int default_id,
+                void (*handler)(unsigned char *, int, struct pt_regs *));
+
+#endif /* __KERNEL */
index d7a0a9215ee8ba6350d0ab7a2fd83dc215d80065..49415ce9f4f10df3474f2d9f7423cb1bc516b70e 100644 (file)
@@ -1,10 +1,9 @@
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
 
-#include <linux/config.h>
-
-extern struct task_struct *current_set[1];
-
-register struct task_struct *current asm("r2");
+/*
+ * We keep `current' in r2 for speed.
+ */
+register struct task_struct *current asm ("r2");
 
 #endif /* !(_PPC_CURRENT_H) */
diff --git a/include/asm-ppc/dbdma.h b/include/asm-ppc/dbdma.h
new file mode 100644 (file)
index 0000000..38cd158
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Definitions for using the Apple Descriptor-Based DMA controller
+ * in Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#ifndef _ASM_DBDMA_H_
+#define _ASM_DBDMA_H_
+/*
+ * DBDMA control/status registers.  All little-endian.
+ */
+struct dbdma_regs {
+    unsigned int control;      /* lets you change bits in status */
+    unsigned int status;       /* DMA and device status bits (see below) */
+    unsigned int cmdptr_hi;    /* upper 32 bits of command address */
+    unsigned int cmdptr;       /* (lower 32 bits of) command address (phys) */
+    unsigned int intr_sel;     /* select interrupt condition bit */
+    unsigned int br_sel;       /* select branch condition bit */
+    unsigned int wait_sel;     /* select wait condition bit */
+    unsigned int xfer_mode;
+    unsigned int data2ptr_hi;
+    unsigned int data2ptr;
+    unsigned int res1;
+    unsigned int address_hi;
+    unsigned int br_addr_hi;
+    unsigned int res2[3];
+};
+
+/* Bits in control and status registers */
+#define RUN    0x8000
+#define PAUSE  0x4000
+#define FLUSH  0x2000
+#define WAKE   0x1000
+#define DEAD   0x0800
+#define ACTIVE 0x0400
+#define BT     0x0100
+#define DEVSTAT        0x00ff
+
+/*
+ * DBDMA command structure.  These fields are all little-endian!
+ */
+struct dbdma_cmd {
+    unsigned short req_count;  /* requested byte transfer count */
+    unsigned short command;    /* command word (has bit-fields) */
+    unsigned int   phy_addr;   /* physical data address */
+    unsigned int   cmd_dep;    /* command-dependent field */
+    unsigned short res_count;  /* residual count after completion */
+    unsigned short xfer_status;        /* transfer status */
+};
+
+/* DBDMA command values in command field */
+#define OUTPUT_MORE    0       /* transfer memory data to stream */
+#define OUTPUT_LAST    0x1000  /* ditto followed by end marker */
+#define INPUT_MORE     0x2000  /* transfer stream data to memory */
+#define INPUT_LAST     0x3000  /* ditto, expect end marker */
+#define STORE_WORD     0x4000  /* write word (4 bytes) to device reg */
+#define LOAD_WORD      0x5000  /* read word (4 bytes) from device reg */
+#define DBDMA_NOP      0x6000  /* do nothing */
+#define DBDMA_STOP     0x7000  /* suspend processing */
+
+/* Key values in command field */
+#define KEY_STREAM0    0       /* usual data stream */
+#define KEY_STREAM1    0x100   /* control/status stream */
+#define KEY_STREAM2    0x200   /* device-dependent stream */
+#define KEY_STREAM3    0x300   /* device-dependent stream */
+#define KEY_REGS       0x500   /* device register space */
+#define KEY_SYSTEM     0x600   /* system memory-mapped space */
+#define KEY_DEVICE     0x700   /* device memory-mapped space */
+
+/* Interrupt control values in command field */
+#define INTR_NEVER     0       /* don't interrupt */
+#define INTR_IFSET     0x10    /* intr if condition bit is 1 */
+#define INTR_IFCLR     0x20    /* intr if condition bit is 0 */
+#define INTR_ALWAYS    0x30    /* always interrupt */
+
+/* Branch control values in command field */
+#define BR_NEVER       0       /* don't branch */
+#define BR_IFSET       0x4     /* branch if condition bit is 1 */
+#define BR_IFCLR       0x8     /* branch if condition bit is 0 */
+#define BR_ALWAYS      0xc     /* always branch */
+
+/* Wait control values in command field */
+#define WAIT_NEVER     0       /* don't wait */
+#define WAIT_IFSET     1       /* wait if condition bit is 1 */
+#define WAIT_IFCLR     2       /* wait if condition bit is 0 */
+#define WAIT_ALWAYS    3       /* always wait */
+
+/* Align an address for a DBDMA command structure */
+#define DBDMA_ALIGN(x) (((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \
+                        & -sizeof(struct dbdma_cmd))
+#endif /* _ASM_DBDMA_H_ */
index 7becf0190253cc004073f9e67e52cfa249bc2081..6e0253591801f60a14cb9fab5c4641b28e318fda 100644 (file)
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#define MAX_DMA_CHANNELS       8
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+/* Doesn't really apply... */
+#define MAX_DMA_ADDRESS      0xFFFFFFFF
+
 #ifdef CONFIG_PREP
 #include <asm/io.h>            /* need byte IO */
 
  *
  */
 
-#define MAX_DMA_CHANNELS       8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-/* Doesn't really apply... */
-#define MAX_DMA_ADDRESS      0xFFFFFFFF
+#define POWERSTACK_SND_DMA 6
+#define POWERSTACK_SND_DMA2 7
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
 #define DMA_HI_PAGE_6              0x489
 #define DMA_HI_PAGE_7              0x48A
 
+#define DMA1_EXT_REG               0x40B
+#define DMA2_EXT_REG               0x4D6
+
 #define DMA_MODE_READ  0x44    /* I/O to memory, no autoinit, increment, single mode */
 #define DMA_MODE_WRITE 0x48    /* memory to I/O, no autoinit, increment, single mode */
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
@@ -214,9 +220,11 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
        switch(dmanr) {
                case 0:
                        dma_outb(pagenr, DMA_LO_PAGE_0);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_0);
                        break;
                case 1:
                        dma_outb(pagenr, DMA_LO_PAGE_1);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_1);
                        break;
                case 2:
                        dma_outb(pagenr, DMA_LO_PAGE_2);
@@ -225,15 +233,24 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
                case 3:
                        dma_outb(pagenr, DMA_LO_PAGE_3);
                        break;
-               case 5:
+               case 5:
                        dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_5);
                        break;
                case 6:
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+                       if (POWERSTACK_SND_DMA == 6 || POWERSTACK_SND_DMA2 == 6)
+                               dma_outb(pagenr, DMA_LO_PAGE_6);
+                       else
+                               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+                       dma_outb(pagenr>>8, DMA_HI_PAGE_6);
                        break;
                case 7:
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
-                       break;
+                       if (POWERSTACK_SND_DMA == 7 || POWERSTACK_SND_DMA2 == 7)
+                               dma_outb(pagenr, DMA_LO_PAGE_7);
+                       else
+                               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+                       dma_outb(pagenr>>8, DMA_HI_PAGE_7);
+                 break;
        }
 }
 
@@ -247,8 +264,14 @@ static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys)
            dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
             dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
        }  else  {
+         if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+           dma_outb( phys  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+           dma_outb( (phys>>8)  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+           dma_outb( (dmanr&3), DMA2_EXT_REG);
+         } else {
            dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
            dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+         }
        }
        set_dma_page(dmanr, phys>>16);
 }
@@ -269,8 +292,13 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
            dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
            dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
         } else {
+         if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+           dma_outb( count & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+           dma_outb( (count>>8) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+         } else {
            dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
            dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+         }
         }
 }
 
@@ -297,10 +325,14 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
        return (dmanr<=3)? count : (count<<1);
 }
 
+#else /* CONFIG_PREP */
 
-/* These are in kernel/dma.c: */
-extern void free_dma(unsigned int dmanr);      /* release it again */
+#define DMA_MODE_READ  1
+#define DMA_MODE_WRITE 2
 
 #endif /* CONFIG_PREP */
 
+/* These are in kernel/dma.c: */
+extern void free_dma(unsigned int dmanr);      /* release it again */
+
 #endif /* _ASM_DMA_H */
index d0e758efd907b01afd4e45bf76d0f92c9841f633..59e7655c9789b7b0b7fd5fd310dd267ec74734ec 100644 (file)
@@ -6,8 +6,8 @@
  */
 #include <asm/ptrace.h>
 
-#define ELF_NGREG      32
-#define ELF_NFPREG     32
+#define ELF_NGREG      48      /* includes nip, msr, lr, etc. */
+#define ELF_NFPREG     33      /* includes fpscr */
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -30,4 +30,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+#define ELF_CORE_COPY_REGS(gregs, regs) \
+       memcpy(gregs, regs, \
+              sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
+              sizeof(struct pt_regs): sizeof(elf_gregset_t));
+
 #endif
index bc16288a8a50937637550246485ffd213fd0acb4..6352fe068603bce830deb038571a9e8ec15827eb 100644 (file)
@@ -107,7 +107,7 @@ extern __inline__ ide_ioreg_t ide_default_io_base(int index)
        return index;
 }
 
-extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 
 typedef union {
        unsigned all                    : 8;    /* all of the bits together */
index e2dfcc49aacd4dd3288717e1f0cbb71db3ebae77..9a1c7b8e70cc6ebb3d01381f904dd6f41d1b29db 100644 (file)
@@ -5,7 +5,6 @@
 #include <asm/page.h>
 #include <asm/byteorder.h>
 
-#ifdef CONFIG_PREP
 /* from the Carolina Technical Spec -- Cort */
 #define IBM_ACORN 0x82A
 #define SIO_CONFIG_RA  0x398
 #define IBM_L2_INVALIDATE 0x814
 #define IBM_SYS_CTL       0x81c
 
+extern unsigned long io_base;
 #define SLOW_DOWN_IO
 
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET  0x80000000
-#endif
+#define _IO_BASE io_base
+#undef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET  _IO_BASE
 
 #define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
+#define readw(addr) ld_le16((volatile unsigned short *)(addr))
+#define readl(addr) ld_le32(addr)
 #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
-
-void outsl(int port, long *ptr, int len);
-
-__inline__ unsigned char outb(unsigned char val, int port);
-__inline__ unsigned short outw(unsigned short val, int port);
-__inline__ unsigned long outl(unsigned long val, int port);
-__inline__ unsigned char inb(int port);
-__inline__ unsigned short inw(int port);
-__inline__ unsigned long inl(int port);
-
-#define inb_p inb
-#define inw_p inw
-#define inl_p inl
-#define outb_p outb
-#define outw_p outw
-#define outl_p outl
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
-/*
- * Read and write the non-volatile RAM.
- */
-extern int nvram_readb(int addr);
-extern void nvram_writeb(int addr, int val);
-
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET  0
-#endif
-
-#define inb(port)              in_8((unsigned char *)(port))
-#define outb(val, port)                out_8((unsigned char *)(port), (val))
-#define inw(port)              in_le16((unsigned short *)(port))
-#define outw(val, port)                out_le16((unsigned short *)(port), (val))
-#define inl(port)              in_le32((unsigned long *)(port))
-#define outl(val, port)                out_le32((unsigned long *)(port), (val))
-
-#define inb_p(port)            in_8((unsigned char *)(port))
-#define outb_p(val, port)      out_8((unsigned char *)(port), (val))
-#define inw_p(port)            in_le16((unsigned short *)(port))
-#define outw_p(val, port)      out_le16((unsigned short *)(port), (val))
-#define inl_p(port)            in_le32(((unsigned long *)port))
-#define outl_p(val, port)      out_le32((unsigned long *)(port), (val))
-
-#define insw(port, buf, ns)    _insw((unsigned short *)(port), (buf), (ns))
-#define outsw(port, buf, ns)   _outsw((unsigned short *)(port), (buf), (ns))
-#define insl(port, buf, nl)    _insl((unsigned long *)(port), (buf), (nl))
-#define outsl(port, buf, nl)   _outsl((unsigned long *)(port), (buf), (nl))
-#endif /* CONFIG_PMAC */
-
+#define writew(b,addr) st_le16((volatile unsigned short *)(addr),(b))
+#define writel(b,addr) st_le32((addr),(b))
+
+#define insb(port, buf, ns)    _insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define outsb(port, buf, ns)   _outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define insw(port, buf, ns)    _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns)   _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl)    _insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl)   _outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+
+#define inb(port)              in_8((unsigned char *)((port)+_IO_BASE))
+#define outb(val, port)                out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw(port)              in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw(val, port)                out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl(port)              in_le32((unsigned *)((port)+_IO_BASE))
+#define outl(val, port)                out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+#define inb_p(port)            in_8((unsigned char *)((port)+_IO_BASE))
+#define outb_p(val, port)      out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw_p(port)            in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw_p(val, port)      out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl_p(port)            in_le32(((unsigned *)port))
+#define outl_p(val, port)      out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+extern void _insb(volatile unsigned char *port, void *buf, int ns);
+extern void _outsb(volatile unsigned char *port, const void *buf, int ns);
+extern void _insw(volatile unsigned short *port, void *buf, int ns);
+extern void _outsw(volatile unsigned short *port, const void *buf, int ns);
+extern void _insl(volatile unsigned long *port, void *buf, int nl);
+extern void _outsl(volatile unsigned long *port, const void *buf, int nl);
+
+#ifdef __KERNEL__
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
  * run Big-Endian.  Thus all values which cross the [PCI] barrier
@@ -88,14 +68,16 @@ extern void nvram_writeb(int addr, int val);
  */
 extern inline unsigned long virt_to_bus(volatile void * address)
 {
-        if (address == (void *)0) return 0;
-        return ((unsigned long)((long)address - KERNELBASE + PCI_DRAM_OFFSET));
+        if (address == (void *)0)
+               return 0;
+        return (unsigned long)address - KERNELBASE + PCI_DRAM_OFFSET;
 }
 
 extern inline void * bus_to_virt(unsigned long address)
 {
-        if (address == 0) return 0;
-        return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
+        if (address == 0)
+               return 0;
+        return (void *)(address - PCI_DRAM_OFFSET + KERNELBASE);
 }
 
 /*
@@ -105,29 +87,20 @@ extern inline void * bus_to_virt(unsigned long address)
 extern void *ioremap(unsigned long address, unsigned long size);
 
 /*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
+ * Change virtual addresses to physical addresses and vv, for
+ * addresses in the area where the kernel has the RAM mapped.
  */
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
-       return (unsigned long) address;
+       return (unsigned long) address - KERNELBASE;
 }
 
 extern inline void * phys_to_virt(unsigned long address)
 {
-       return (void *) address;
+       return (void *) (address + KERNELBASE);
 }
 
-#define _IO_BASE ((unsigned long)0x80000000)
-
-/*
- * These are much more useful le/be io functions from Paul
- * than leXX_to_cpu() style functions since the ppc has
- * load/store byte reverse instructions
- *  -- Cort
- */
+#endif /* __KERNEL__ */
 
 /*
  * Enforce In-order Execution of I/O:
index 2039f4954e6f4699be8e83f9e9dada4576e84d36..f56e53db7db867c75a7f35fdc7405437f93ca963 100644 (file)
@@ -83,8 +83,8 @@
 #define TIOCGETD       0x5424
 #define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT 0x5426  /* For debugging only */
-#define TIOCSBRK       0x5427  /* BSD compatibility */
-#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index f368d14c8d20d3024b84fbc302144a063b141583..1872790e40424039fe74d6fc54688bb465daa09f 100644 (file)
@@ -1,10 +1,10 @@
-#ifndef __i386_IPC_H__
-#define __i386_IPC_H__
+#ifndef __PPC_IPC_H__
+#define __PPC_IPC_H__
 
 /* 
- * These are used to wrap system calls on x86.
+ * These are used to wrap system calls on PowerPC.
  *
- * See arch/i386/kernel/sys_i386.c for ugly details..
+ * See arch/ppc/kernel/syscalls.c for ugly details..
  */
 struct ipc_kludge {
        struct msgbuf *msgp;
@@ -25,4 +25,4 @@ struct ipc_kludge {
 
 #define IPCCALL(version,op)    ((version)<<16 | (op))
 
-#endif
+#endif /* __PPC_IPC_H__ */
index ebffe2bcb6893faf5882ef6720dc2a1b2f78a687..70ad74ecd24b5b6b2cb582152349f5a01a462f35 100644 (file)
@@ -3,11 +3,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_PMAC
-#define NR_IRQS        32
-#else
-#define NR_IRQS        16
-#endif
+#define NR_IRQS 32
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff --git a/include/asm-ppc/linux_logo.h b/include/asm-ppc/linux_logo.h
new file mode 100644 (file)
index 0000000..7e88d4c
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot
+ * (pinched from the sparc port).
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * values have to start from 0x20
+ * (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
+ */
+#include <linux/init.h>
+
+#define LINUX_LOGO_HEIGHT      80
+#define LINUX_LOGO_WIDTH       80
+#define LINUX_LOGO_COLORS      221
+
+unsigned char linux_logo_red[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
+  0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
+  0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
+  0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
+  0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
+  0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
+  0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
+  0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
+  0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
+  0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
+  0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
+  0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
+  0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
+  0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
+  0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
+  0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
+  0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_green[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
+  0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
+  0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
+  0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
+  0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
+  0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
+  0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
+  0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
+  0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
+  0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
+  0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
+  0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
+  0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
+  0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
+  0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
+  0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
+  0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_blue[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
+  0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
+  0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
+  0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
+  0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
+  0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
+  0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
+  0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
+  0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
+  0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
+  0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
+  0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
+  0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
+  0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
+  0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
+  0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
+  0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
+  0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo[] __initdata = {
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
+  0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
+  0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
+  0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
+  0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
+  0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
+  0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
+  0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
+  0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
+  0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
+  0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
+  0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+  0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
+  0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
+  0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
+  0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
+  0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
+  0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
+  0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
+  0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
+  0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
+  0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
+  0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
+  0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
+  0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
+  0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
+  0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
+  0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
+  0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
+  0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
+  0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
+  0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
+  0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
+  0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
+  0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
+  0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
+  0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
+  0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
+  0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
+  0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
+  0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
+  0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
+  0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
+  0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
+  0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
+  0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
+  0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
+  0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
+  0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
+  0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
+  0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
+  0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
+  0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
+  0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
+  0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
+  0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
+  0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
+  0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
+  0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
+  0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
+  0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
+  0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
+  0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
+  0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
+  0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
+  0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
+  0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
+  0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
+  0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
+  0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
+  0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
+  0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
+  0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
+  0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
+  0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
+  0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
+  0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
+  0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
+  0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
+  0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
+  0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
+  0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
+  0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
+  0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
+  0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
+  0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
+  0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
+  0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
+  0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
+  0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
+  0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
+  0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
+  0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
+  0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
+  0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
+  0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
+  0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
+  0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
+  0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
+  0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
+  0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
+  0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
+  0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
+  0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
+  0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
+  0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
+  0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
+  0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
+  0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
+  0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
+  0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
+  0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
+  0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
+  0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
+  0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
+  0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
+  0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
+  0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
+  0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
+  0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
+  0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
+  0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
+  0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
+  0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
+  0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
+  0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
+  0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
+  0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
+  0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
+  0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
+  0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
+  0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
+  0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
+  0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
+  0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
+  0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
+  0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
+  0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
+  0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
+  0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
+  0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
+  0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
+  0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
+  0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
+  0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
+  0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
+  0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
+  0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
+  0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
+  0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
+  0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
+  0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
+  0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
+  0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
+  0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
+  0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
+  0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
+  0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
+  0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
+  0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
+  0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
+  0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
+  0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
+  0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
+  0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
+  0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
+  0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
+  0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
+  0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
+  0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
+  0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
+  0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
+  0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
+  0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
+  0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
+  0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
+  0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
+  0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
+  0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
+  0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
+  0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
+  0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
+  0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
+  0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
+  0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
+  0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
+  0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
+  0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
+  0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
+  0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
+  0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
+  0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
+  0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
+  0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
+  0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
+  0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
+  0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
+  0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
+  0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
+  0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
+  0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
+  0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
+  0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
+  0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
+  0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
+  0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
+  0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
+  0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
+  0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
+  0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
+  0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
+  0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
+  0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
+  0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
+  0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
+  0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
+  0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
+  0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
+  0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
+  0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
+  0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
+  0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
+  0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
+  0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
+  0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
+  0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
+  0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
+  0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
+  0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
+  0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
+  0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
+  0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
+  0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
+  0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
+  0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
+  0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
+  0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
+  0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
+  0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
+  0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
+  0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
+  0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
+  0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
+  0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
+  0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
+  0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
+  0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
+  0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
+  0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
+  0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
+  0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
+  0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
+  0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
+  0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
+  0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
+  0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
+  0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
+  0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
+  0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
+  0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
+  0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
+  0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
+  0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
+  0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
+  0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
+  0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
+  0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
+  0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
+  0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
+  0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
+  0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+  0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
+  0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
+  0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
+  0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
+  0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
+  0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
+  0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+  0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
+  0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
+  0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
+  0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
+  0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
+  0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
+  0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
+  0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
+  0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
+  0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
+  0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
+  0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
+  0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
+  0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
+  0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
+  0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
+  0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
+  0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
+  0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
+  0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
+  0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
+  0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
+  0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
+  0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
+  0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
+  0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
+  0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
+  0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
+  0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
+  0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
+  0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
+  0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
+  0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
+  0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
+  0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
+  0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
+  0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
+  0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
+  0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
+  0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
+  0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
+  0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
+  0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
+  0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
+  0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
+  0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
+  0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
+  0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
+  0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+  0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
+  0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
+  0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
+  0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
+  0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
+  0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
+  0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
+  0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
+  0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
+  0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
+  0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
+  0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
+  0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
+  0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
+  0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
+  0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
+  0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
+  0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
+  0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
+  0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
+  0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
+  0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
+  0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
+  0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
+  0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
+  0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
+  0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
+  0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
+  0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
+  0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
+  0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
+  0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
+  0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
+  0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
+  0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
+  0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
+  0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
+  0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
+  0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
+  0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
+  0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
+  0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
+  0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
+  0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
+  0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
+  0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
+  0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
+  0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
+  0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
+  0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
+  0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
+  0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
+  0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
+  0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
+  0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
+  0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
+  0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
+  0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
+  0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
+  0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
+  0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
+  0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
+  0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
+  0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
+  0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
+  0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
+  0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
+  0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
+  0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
+  0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
+  0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
+  0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
+  0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
+  0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
+  0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
+  0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
+  0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
+  0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
+  0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
+  0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
+  0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
+  0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
+  0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
+  0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
+  0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
+  0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
+  0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
+  0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
+  0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
+  0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
+  0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
+  0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
+  0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
+  0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
+  0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
+  0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
+  0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
+  0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
+  0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
+  0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
+  0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
+  0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
+  0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
+  0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
+  0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
+  0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
+  0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
+  0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
+  0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
+  0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
+  0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
+  0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
+  0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
+  0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
+  0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
+  0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
+  0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
+  0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
+  0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
+  0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
+  0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
+  0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
+  0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
+  0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
+  0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
+  0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
+  0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
+  0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
+  0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
+  0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
+  0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
+  0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
+  0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
+  0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
+  0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
+  0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
+  0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
+  0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
+  0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
+  0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
+  0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
+  0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
+  0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
+  0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
+  0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
+  0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
+  0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
+  0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
+  0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
+  0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
+  0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
+  0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
+  0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
+  0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
+  0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
+  0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
+  0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
+  0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
+  0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
+  0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
+  0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
+  0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
+  0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
+  0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
+  0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
+  0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
+  0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
+  0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
+  0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
+  0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
+  0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
+  0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
+  0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
+  0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
+  0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
+  0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
+  0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
+  0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
+  0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
+  0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
+  0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
+  0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
+  0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
+  0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
+  0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
+  0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
+  0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
+  0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
+  0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
+  0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
+  0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
+  0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
+  0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
+  0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
+  0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
+  0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
+  0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
+  0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
+  0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
+  0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
+  0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
+  0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
+  0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
+  0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
+  0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
+  0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
+  0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
+  0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
+  0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
+  0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
+  0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
+  0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
+  0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
+  0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
+  0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
+  0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
+  0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
+  0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
+  0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
+  0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
+  0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
+  0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
+  0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
+  0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
+  0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
+  0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
+  0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
+  0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
+  0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
+  0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
+  0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
+  0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
+  0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
+  0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
+  0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
+  0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
+  0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
+  0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
+  0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
+  0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
+  0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
+  0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
+  0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
+  0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
+  0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
+  0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
+  0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
+  0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
+  0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
+  0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
+  0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
+  0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
+  0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
+  0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
+  0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
+  0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
+  0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
+  0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
+  0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
+  0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
+  0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
+  0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
+  0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
+  0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
+  0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
+  0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
+  0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
+  0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
+  0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
+  0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
+  0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
+  0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
+  0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
+  0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
+  0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
+  0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
+  0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
+  0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
+  0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
+  0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
+  0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
+  0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
+  0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
+};
index c6c8352294f33cdb1ecb50d813d10a2301ba8737..57ce8eda8d3177020eda4738d483e5c418044f92 100644 (file)
@@ -144,7 +144,7 @@ typedef struct _MMU_context
       pte      **pmap;         /* Two-level page-map structure */
    } MMU_context;
 
-/* Used to set up SDR register */
+/* Used to set up SDR1 register */
 #define HASH_TABLE_SIZE_64K    0x00010000
 #define HASH_TABLE_SIZE_128K   0x00020000
 #define HASH_TABLE_SIZE_256K   0x00040000
@@ -160,4 +160,12 @@ typedef struct _MMU_context
 #define HASH_TABLE_MASK_2M     0x01F   
 #define HASH_TABLE_MASK_4M     0x03F   
 
+/* invalidate a TLB entry */
+extern inline void _tlbie(unsigned long va)
+{
+       asm volatile ("tlbie %0" : : "r"(va));
+}
+
+extern void _tlbia(void);              /* invalidate all TLB entries */
+
 #endif
index 89a649bb31cc9887f25006d9006e39e1fe91c013..06a7544ecde1b89367366e3abf683c76c0057ec2 100644 (file)
@@ -29,7 +29,6 @@ extern void set_context(int context);
 do {                                                           \
        struct mm_struct *mm = (tsk)->mm;                       \
        if (mm->context == NO_CONTEXT) {                        \
-               int i; \
                if (next_mmu_context == LAST_CONTEXT)           \
                        mmu_context_overflow();                 \
                mm->context = MUNGE_CONTEXT(++next_mmu_context);\
index cf6cba2cae46433146e62c9f1f746e00128f7940..1d4fb73c5610d7e1e820531cbc41d10059599460 100644 (file)
@@ -1,11 +1,12 @@
-/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
- * linux/include/asm-i386/namei.h
+/* $Id: namei.h,v 1.2 1997/07/31 07:10:55 paulus Exp $
+ * linux/include/asm-ppc/namei.h
+ * Adapted from linux/include/asm-alpha/namei.h
  *
  * Included from linux/fs/namei.c
  */
 
-#ifndef __I386_NAMEI_H
-#define __I386_NAMEI_H
+#ifndef __PPC_NAMEI_H
+#define __PPC_NAMEI_H
 
 /* These dummy routines maybe changed to something useful
  * for /usr/gnemul/ emulation stuff.
@@ -18,4 +19,4 @@
 #define translate_open_namei(pathname, flag, mode, res_inode, base) \
        do { } while (0)
 
-#endif /* __I386_NAMEI_H */
+#endif /* __PPC_NAMEI_H */
index 665bc76afe54ddf2d6f4e65bf335b9841a217f3e..ea7bf19146f681f54f3c5d55b39ba733e2d7d433 100644 (file)
 
 /* RTC Offsets */
 
-#define RTC_SECONDS            0x1FF9
-#define RTC_MINUTES            0x1FFA
-#define RTC_HOURS              0x1FFB
-#define RTC_DAY_OF_WEEK                0x1FFC
-#define RTC_DAY_OF_MONTH       0x1FFD
-#define RTC_MONTH              0x1FFE
-#define RTC_YEAR               0x1FFF
-#define RTC_CONTROLA            0x1FF8
-#define RTC_CONTROLB            0x1FF9
+#define MOTO_RTC_SECONDS               0x1FF9
+#define MOTO_RTC_MINUTES               0x1FFA
+#define MOTO_RTC_HOURS         0x1FFB
+#define MOTO_RTC_DAY_OF_WEEK           0x1FFC
+#define MOTO_RTC_DAY_OF_MONTH  0x1FFD
+#define MOTO_RTC_MONTH         0x1FFE
+#define MOTO_RTC_YEAR          0x1FFF
+#define MOTO_RTC_CONTROLA            0x1FF8
+#define MOTO_RTC_CONTROLB            0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
index a18d5e3243cb7a6178451173709d40f0697ff013..ca725e94dbea613e8b63879b28c3832cd4e27d2e 100644 (file)
@@ -81,14 +81,14 @@ typedef unsigned long pgprot_t;
 
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
-/* map phys->virtual and virtual->phys */
+/* map phys->virtual and virtual->phys for RAM pages */
 #define __pa(x)                        ((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)                        ((void *)((unsigned long)(x)+PAGE_OFFSET))
 
-#define MAP_NR(addr)   (__pa(addr) >> PAGE_SHIFT)
+#define MAP_NR(addr)           (__pa(addr) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED      (1<<15)
 
-extern __inline__ unsigned long get_prezerod_page(void);
+extern unsigned long get_prezerod_page(void);
 
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
new file mode 100644 (file)
index 0000000..68a026b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_PCI_BRIDGE_H
+#define _ASM_PCI_BRIDGE_H
+
+unsigned long pmac_find_bridges(unsigned long, unsigned long);
+
+/*
+ * pci_io_base returns the memory address at which you can access
+ * the I/O space for PCI bus number `bus' (or NULL on error).
+ */
+void *pci_io_base(unsigned int bus);
+
+/*
+ * pci_device_loc returns the bus number and device/function number
+ * for a device on a PCI bus, given its device_node struct.
+ * It returns 0 if OK, -1 on error.
+ */
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+                  unsigned char *devfn_ptr);
+
+#endif
index fd52a64c7b4a357d5e3db002109f12ecb726a96b..d6698d9b21b995ff1e9a3acc7456ca2482ffa7cb 100644 (file)
@@ -1,22 +1,25 @@
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
 
-#include <linux/config.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
+#include <linux/mm.h>
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
                            unsigned long end);
-extern void flush_tlb(void);
 
-/* Caches aren't brain-dead on the ppc. */
-#define flush_cache_all()                      
-#define flush_cache_mm(mm)                     
-#define flush_cache_range(mm, start, end)      
-#define flush_cache_page(vma, vmaddr)          
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.
+ */
+#define flush_cache_all()              do { } while (0)
+#define flush_cache_mm(mm)             do { } while (0)
+#define flush_cache_range(mm, a, b)    do { } while (0)
+#define flush_cache_page(vma, p)       do { } while (0)
+extern void flush_icache_range(unsigned long, unsigned long);
+
 /*
  * For the page specified, write modified lines in the data cache
  * out to memory, and invalidate lines in the instruction cache.
@@ -25,6 +28,20 @@ extern void flush_page_to_ram(unsigned long);
 
 extern unsigned long va_to_phys(unsigned long address);
 
+/*
+ * The PowerPC MMU uses a hash table containing PTEs, together with
+ * a set of 16 segment registers (on 32-bit implementations), to define
+ * the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much like
+ * that used by the i386, for the sake of the Linux memory management code.
+ * Low-level assembler code in head.S (procedure hash_page) is responsible
+ * for extracting ptes from the tree and putting them into the hash table
+ * when necessary, and updating the accessed and modified bits in the
+ * page table tree.
+ */
+
 /* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
 #define PMD_SHIFT      22
 #define PMD_SIZE       (1UL << PMD_SHIFT)
@@ -133,9 +150,7 @@ extern unsigned long empty_zero_page[1024];
 
 /* to set the page-dir */
 /* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) ({ \
-       ((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
-})
+#define SET_PAGE_DIR(tsk,pgdir) 
 
 extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_PRESENT; }
@@ -146,7 +161,7 @@ extern inline int pmd_bad(pmd_t pmd)                { return (pmd_val(pmd) & ~PAGE_MASK) != 0;
 extern inline int pmd_present(pmd_t pmd)       { return (pmd_val(pmd) & PAGE_MASK) != 0; }
 extern inline void pmd_clear(pmd_t * pmdp)     { pmd_val(*pmdp) = 0; }
 
-     
+
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -370,13 +385,27 @@ extern pgd_t swapper_pg_dir[1024];
  * as entries are faulted into the hash table by the low-level
  * data/instruction access exception handlers.
  */
-#define update_mmu_cache(vma,address,pte) while(0){}
+#define update_mmu_cache(vma, addr, pte)       do { } while (0)
 
+/*
+ * When flushing the tlb entry for a page, we also need to flush the
+ * hash table entry.  flush_hash_page is assembler (for speed) in head.S.
+ */
+extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
+extern void flush_hash_page(unsigned context, unsigned long va);
+
+extern inline void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       if (vmaddr < TASK_SIZE)
+               flush_hash_page(vma->vm_mm->context, vmaddr);
+}
 
 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
 
-
-#endif /* _PPC_PAGE_H */
+#endif /* _PPC_PGTABLE_H */
index e5feda71b3567f482a62fdcab3030febeb942a83..bcec653c14e4587aecaba1774991a75bc87415d8 100644 (file)
@@ -1,15 +1,12 @@
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
+#ifndef __PPC_POLL_H
+#define __PPC_POLL_H
 
-/* These are specified by iBCS2 */
 #define POLLIN         0x0001
 #define POLLPRI                0x0002
 #define POLLOUT                0x0004
 #define POLLERR                0x0008
 #define POLLHUP                0x0010
 #define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
 #define POLLRDNORM     0x0040
 #define POLLRDBAND     0x0080
 #define POLLWRNORM     0x0100
index 10ca545590089e71d3ab68c9e4a985a4c8559896..6b3ef8f24523003e168d6b2dba2fdbc0ea0b3a5e 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
-#include <linux/config.h>
-
+#include <asm/ptrace.h>
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW                (1<<18)         /* Enable Power Management */
 #define MSR_RI         (1<<1)          /* Recoverable Exception */
 #define MSR_LE         (1<<0)          /* Little-Endian enable */
 
-#define MSR_           MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_           MSR_ME|MSR_FE0|MSR_FE1|MSR_RI
 #define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
-#define MSR_USER       MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
+#define MSR_USER       MSR_KERNEL|MSR_PR|MSR_EE
 
-/* Bit encodings for Hardware Implementation Register (HID0) */
+/* Bit encodings for Hardware Implementation Register (HID0)
+   on PowerPC 603, 604, etc. processors (not 601). */
 #define HID0_EMCP      (1<<31)         /* Enable Machine Check pin */
 #define HID0_EBA       (1<<29)         /* Enable Bus Address Parity */
 #define HID0_EBD       (1<<28)         /* Enable Bus Data Parity */
 #define HID0_DCI       (1<<10)         /* Data Cache Invalidate */
 #define HID0_SIED      (1<<7)          /* Serial Instruction Execution [Disable] */
 #define HID0_BHTE      (1<<2)          /* Branch History Table Enable */
+
 /* fpscr settings */
 #define FPSCR_FX        (1<<31)
 #define FPSCR_FEX       (1<<30)
 
+
 #ifndef __ASSEMBLY__
 /*
  * PowerPC machine specifics
  */
-extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
+struct task_struct;
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
+void release_thread(struct task_struct *);
 
 /*
  * Bus types
@@ -70,49 +74,37 @@ extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long )
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
+/*
+ * User space process size: 2GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
 #define TASK_SIZE      (0x80000000UL)
+
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
-struct thread_struct 
-{
+#define TASK_UNMAPPED_BASE     (TASK_SIZE / 8 * 3)
+
+struct thread_struct {
        unsigned long   ksp;            /* Kernel stack pointer */
-       unsigned long   *pg_tables;     /* MMU information */
-#ifdef CONFIG_PMAC
-       unsigned long   last_pc;        /* PC when last entered system */
-       unsigned long   user_stack;     /* [User] Stack when entered kernel */
-#endif  
-       unsigned long   fpscr_pad;      /* (so we can save fpscr with stfd) */
-       unsigned long   fpscr;          /* fp status reg */
-       double          fpr[32];        /* Complete floating point set */
-       unsigned long   fp_used;
        unsigned long   wchan;          /* Event task is sleeping on */
-       struct pt_regs  *regs;          /* Pointer to saved register state */
+       struct pt_regs  *regs;          /* Pointer to saved register state */
        unsigned long   fs;             /* for get_fs() validation */
        signed long     last_syscall;
-       unsigned long   pad[2]; /* pad to 16-byte boundry */
+       double          fpr[32];        /* Complete floating point set */
+       unsigned long   fpscr_pad;      /* fpr ... fpscr must be contiguous */
+       unsigned long   fpscr;          /* Floating point status */
 };
 
-/* Points to the thread_struct of the thread (if any) which
-   currently owns the FPU. */
-#define fpu_tss (&(last_task_used_math->tss))
-
-#ifdef CONFIG_PMAC
-#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
-#endif
-#ifdef CONFIG_PREP
-#define LAZY_TSS_FPR_INIT 0,0,{0},
-#endif
+#define INIT_SP                (sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_TSS  { \
-       sizeof(init_stack) + (long) &init_stack, /* ksp */ \
-       (long *)swapper_pg_dir, /* pg_tables */ \
-       LAZY_TSS_FPR_INIT \
-       0, /*fp_used*/ 0, /*wchan*/ \
-       sizeof(init_stack) + (long)&init_stack - \
-               sizeof(struct pt_regs), /* regs */ \
-       KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
+       INIT_SP, /* ksp */ \
+       0, /* wchan */ \
+       (struct pt_regs *)INIT_SP - 1, /* regs */ \
+       KERNEL_DS, /*fs*/ \
+       0, /* last_syscall */ \
+       {0}, 0, 0 \
 }
 
 #define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
@@ -124,15 +116,8 @@ struct thread_struct
 static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
        return (t->regs) ? t->regs->nip : 0;
-       /*return (t->last_pc);*/
 }
 
-extern int _machine;
-#define _MACH_Motorola 0
-#define _MACH_IBM      1
-#define _MACH_Be       2
-#define _MACH_Pmac     3
-
 /*
  * NOTE! The task struct and the stack go together
  */
@@ -144,8 +129,16 @@ extern int _machine;
 int ll_printk(const char *, ...);
 void ll_puts(const char *);
 
+extern int _machine;
 #endif /* ndef ASSEMBLY*/
 
+#define _MACH_Motorola 1 /* motorola prep */
+#define _MACH_IBM      2 /* ibm prep */
+#define _MACH_Pmac     4 /* pmac or pmac clone */
+#define _MACH_chrp     8 /* chrp machine */
+
+#define is_prep ((_machine == _MACH_Motorola)||(_machine == _MACH_IBM))
+
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
   
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
new file mode 100644 (file)
index 0000000..f5ec558
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+typedef void *phandle;
+typedef void *ihandle;
+
+extern ihandle prom_stdout;
+extern ihandle prom_chosen;
+extern phandle cpu_node;
+extern char prom_display_path[];
+
+struct reg_property {
+       unsigned int address;
+       unsigned int size;
+};
+
+struct translation_property {
+       unsigned int virt;
+       unsigned int size;
+       unsigned int phys;
+       unsigned int flags;
+};
+
+struct property {
+       char    *name;
+       int     length;
+       unsigned char *value;
+       struct property *next;
+};
+
+struct device_node {
+       char    *name;
+       char    *type;
+       phandle node;
+       int     n_addrs;
+       struct  reg_property *addrs;
+       int     n_intrs;
+       int     *intrs;
+       char    *full_name;
+       struct  property *properties;
+       struct  device_node *parent;
+       struct  device_node *child;
+       struct  device_node *sibling;
+       struct  device_node *next;      /* next device of same type */
+       struct  device_node *allnext;   /* next in list of all nodes */
+};
+
+/* Prototypes */
+void abort(void);
+void prom_exit(void);
+void *call_prom(const char *service, int nargs, int nret, ...);
+void prom_print(const char *msg);
+void prom_init(char *params, int unused, void (*)(void *));
+void set_prom_callback(void);
+unsigned long copy_device_tree(unsigned long, unsigned long);
+struct device_node *find_devices(const char *name);
+struct device_node *find_type_devices(const char *type);
+struct device_node *find_path_device(const char *path);
+unsigned char *get_property(struct device_node *node, const char *name,
+       int *lenp);
+void print_properties(struct device_node *node);
index 13b526172349c9a077231d1717beec5f7db0a679..c46bdb9b79d750e360032171e3d803260ca8e27d 100644 (file)
@@ -2,63 +2,52 @@
 #define _PPC_PTRACE_H
 
 /*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ *
  * this should only contain volatile regs
  * since we can keep non-volatile in the tss
  * should set this up when only volatiles are saved
  * by intr code.
  *
- * I can't find any reference to the above comment (from Gary Thomas)
- * about _underhead/_overhead in the sys V abi for the ppc
- * dated july 25, 1994.
+ * Since this is going on the stack, *CARE MUST BE TAKEN* to insure
+ * that the overall structure is a multiple of 16 bytes in length.
  *
- * the stack must be kept to a size that is a multiple of 16
- * so this includes the stack frame overhead 
- * -- Cort.
- */
-
-/*
- * GCC sometimes accesses words at negative offsets from the stack
- * pointer, although the SysV ABI says it shouldn't.  To cope with
- * this, we leave this much untouched space on the stack on exception
- * entry.
+ * Note that the offsets of the fields in this struct correspond with
+ * the PT_* values below.  This simplifies arch/ppc/kernel/ptrace.c.
  */
-#define STACK_FRAME_OVERHEAD 16
-#define STACK_UNDERHEAD        64
 
 #ifndef __ASSEMBLY__
 struct pt_regs {
        unsigned long gpr[32];
-       unsigned long nip;      
-       unsigned long msr;      
-       unsigned long ctr;      
-       unsigned long link;     
-       unsigned long ccr;      
-       unsigned long xer;      
-       unsigned long dar;      /* Fault registers */
-       unsigned long dsisr;
-#if 0  
-       unsigned long srr1;
-       unsigned long srr0;
-       unsigned long hash1, hash2;
-       unsigned long imiss, dmiss;
-       unsigned long icmp, dcmp;
-#endif  
+       unsigned long nip;
+       unsigned long msr;
        unsigned long orig_gpr3; /* Used for restarting system calls */
-       unsigned long result;   /* Result of a system call */
+       unsigned long ctr;
+       unsigned long link;
+       unsigned long xer;
+       unsigned long ccr;
+       unsigned long mq;       /* 601 only (not used at present) */
        unsigned long trap;     /* Reason for being here */
-       unsigned long marker;   /* Should have DEADDEAD */
+       unsigned long dar;      /* Fault registers */
+       unsigned long dsisr;
+       unsigned long result;   /* Result of a system call */
 };
+#endif
+
+#define STACK_FRAME_OVERHEAD   16      /* size of minimum stack frame */
 
+/* Size of stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE     64
 
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) ((regs)->msr & 0x4000)
-#ifdef KERNEL
-extern void show_regs(struct pt_regs *);
-#endif
 
-/* should include and generate these in ppc_defs.h -- Cort */
-/* Offsets used by 'ptrace' system call interface */
-/* Note: these should correspond to gpr[x]        */
+/*
+ * Offsets used by 'ptrace' system call interface.
+ * These can't be changed without breaking binary compatibility
+ * with MkLinux, etc.
+ */
 #define PT_R0  0
 #define PT_R1  1
 #define PT_R2  2
@@ -94,14 +83,18 @@ extern void show_regs(struct pt_regs *);
 
 #define PT_NIP 32
 #define PT_MSR 33
+#ifdef __KERNEL__
 #define PT_ORIG_R3 34
+#endif
 #define PT_CTR 35
 #define PT_LNK 36
 #define PT_XER 37
 #define PT_CCR 38
+#define PT_MQ  39
 
-#define PT_FPR0        48
-#endif /* __ASSEMBLY__ */
+#define PT_FPR0        48      /* each FP reg occupies 2 slots in this space */
+#define PT_FPR31 (PT_FPR0 + 2*31)
+#define PT_FPSCR (PT_FPR0 + 2*32 + 1)
 
-#endif /* _PPC_PTRACE_H */
+#endif
 
index 3812decf61ade5aef3bab3e83d80479147185b62..1625f196449446d44d356eb75bc53986ca738017 100644 (file)
@@ -311,5 +311,7 @@ typedef struct _RESIDUAL {
   unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
   } RESIDUAL;
 
+
+extern RESIDUAL res;
 #endif  /* ndef _RESIDUAL_ */
 
index bd0d5e02d8cf91757f3aac4db5d33fcfbc2e2786..4555502a280ed599e810ec93aef2eb0069949484 100644 (file)
@@ -7,10 +7,10 @@
 #define RLIMIT_STACK   3               /* max stack size */
 #define RLIMIT_CORE    4               /* max core file size */
 #define RLIMIT_RSS     5               /* max resident set size */
-#define RLIMIT_NOFILE  6               /* max number of open files */
-#define RLIMIT_AS      7               /* address space limit(?) */
-#define RLIMIT_NPROC   8               /* max number of processes */
-#define RLIMIT_MEMLOCK 9               /* max locked-in-memory address space */
+#define RLIMIT_NPROC   6               /* max number of processes */
+#define RLIMIT_NOFILE  7               /* max number of open files */
+#define RLIMIT_MEMLOCK 8               /* max locked-in-memory address space */
+#define RLIMIT_AS      9               /* address space limit(?) */
 
 #define RLIM_NLIMITS   10
 
     {_STK_LIM, _STK_LIM},                      /* RLIMIT_STACK */      \
     {       0, LONG_MAX},                      /* RLIMIT_CORE */       \
     {LONG_MAX, LONG_MAX},                      /* RLIMIT_RSS */        \
-    { NR_OPEN,  NR_OPEN},                      /* RLIMIT_NOFILE */     \
-    {LONG_MAX, LONG_MAX},                      /* RLIMIT_AS */         \
     {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},  /* RLIMIT_NPROC */      \
+    { NR_OPEN,  NR_OPEN},                      /* RLIMIT_NOFILE */     \
     {LONG_MAX, LONG_MAX},                      /* RLIMIT_MEMLOCK */    \
+    {LONG_MAX, LONG_MAX},                      /* RLIMIT_AS */         \
 }
 
 #endif /* __KERNEL__ */
index 80aa3b64ad638ef1f05e6d7f50aea89bbff989bf..f2d4b8b63ba11f4b91dc2579bd1a9ff8140f4fcc 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _PPC_SCATTERLIST_H
 #define _PPC_SCATTERLIST_H
 
+#include <linux/config.h>
+
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
     char * alt_address; /* Location of actual if address is a 
@@ -8,6 +10,18 @@ struct scatterlist {
     unsigned int length;
 };
 
+#ifdef CONFIG_PMAC
+/*
+ * This is used in the scsi code to decide if bounce buffers are needed.
+ * Fortunately the dma controllers on the PowerMac are a bit better
+ * than on PCs...
+ */
+#define ISA_DMA_THRESHOLD (~0UL)
+#endif
+
+#ifdef CONFIG_PREP
+/* PReP systems are like PCs */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
 
 #endif /* !(_PPC_SCATTERLIST_H) */
index a4dfa0312f693a3a816270056e4d6231a675f020..f6a2a59f2efd38f08fd2b2ca2c25fcc8d96a2592 100644 (file)
@@ -44,13 +44,13 @@ static inline int waking_non_zero(struct semaphore *sem)
        __asm__ __volatile__(
                "1:     lwarx %1,0,%2\n"
                "       cmpwi 0,%1,0\n"
-               "       addi %1,%1,-1\n"
+               "       addic %1,%1,-1\n"
                "       ble- 2f\n"
                "       stwcx. %1,0,%2\n"
                "       bne- 1b\n"
-               "       mr %0,%1\n"
+               "       li %0,1\n"
                "2:"
-               : "=r" (ret), "=r" (tmp)
+               : "=r" (ret), "=&r" (tmp)
                : "r" (&sem->waking), "0" (0)
                : "cr0", "memory");
 
index 632717509f8d1f742b69b1d7180377387ee18a36..62a4062cf0ecb94a6c9e48d2be6b6036dd197c09 100644 (file)
@@ -34,4 +34,9 @@
 #define SO_PASSCRED    20
 #define SO_PEERCRED    21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
 #endif /* _ASM_SOCKET_H */
index 207ab36896e083415aab6c5c15f84874fcec71c6..1af5e62700f56aa9612976ca01b7e1104a4ee7b7 100644 (file)
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMCMP
 #define __HAVE_ARCH_MEMCHR
-/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
-extern inline void * memchr(const void * cs,int c,size_t count)
-{
-       unsigned long i = 0;
-       while ( count != i )
-       {
-               if ( (char)c == *(char *)(cs + i) )
-                       return (void *)(cs + i);
-               i--;
-       }
-       return NULL;
-}
+
+extern int strcasecmp(const char *, const char *);
+
 #endif
index df527e474204ea544afd670e3fe219629c526f9b..e199f5cb8e1c11bce62a0c1210c570fb0d92d9d6 100644 (file)
@@ -1,40 +1,67 @@
 #ifndef __PPC_SYSTEM_H
 #define __PPC_SYSTEM_H
 
-#include <linux/delay.h>
+#include <linux/kdev_t.h>
+#include <asm/processor.h>
 
 #define mb()  __asm__ __volatile__ ("sync" : : : "memory")
 
 #define __save_flags(flags)    ({\
        __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
-/* using Paul's in misc.S now -- Cort */
-extern void __restore_flags(unsigned long flags);
+extern __inline__ void __restore_flags(unsigned long flags)
+{
+        extern unsigned lost_interrupts;
+       extern void do_lost_interrupts(unsigned long);
+
+        if ((flags & MSR_EE) && lost_interrupts != 0) {
+                do_lost_interrupts(flags);
+        } else {
+                __asm__ __volatile__ ("sync; mtmsr %0; isync"
+                              : : "r" (flags) : "memory");
+        }
+}
 
+
+#if 0
 /*
-  #define __sti() _soft_sti(void)
-  #define __cli() _soft_cli(void)
+ * Gcc bug prevents us from using this inline func so for now
+ * it lives in misc.S
  */
+void __inline__ __restore_flags(unsigned long flags)
+{
+       extern unsigned lost_interrupts;
+       __asm__ __volatile__ (
+               "andi.  0,%0,%2 \n\t"
+               "beq    2f \n\t"
+               "cmpi   0,%1,0 \n\t"
+               "bne    do_lost_interrupts \n\t"
+               "2:     sync \n\t"
+               "mtmsr  %0 \n\t"
+               "isync \n\t"
+               : 
+               : "r" (flags), "r"(lost_interrupts), "i" (1<<15)/*MSR_EE*/
+               : "0", "cc");
+}
+#endif
+
 extern void __sti(void);
 extern void __cli(void);
-
-extern void _hard_sti(void);
-extern void _hard_cli(void);
-extern void _soft_sti(void);
-extern void _soft_cli(void);
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
+extern void print_backtrace(unsigned long *);
+extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
-extern void find_scsi_boot(void);
+/*extern void note_bootable_part(kdev_t, int);*/
 extern int sd_find_target(void *, int);
 extern int _get_PVR(void);
 extern void via_cuda_init(void);
+extern void pmac_nvram_init(void);
 extern void read_rtc_time(void);
 extern void pmac_find_display(void);
 extern void giveup_fpu(void);
-extern void store_cache_range(unsigned long, unsigned long);
 extern void cvt_fd(float *from, double *to);
 extern void cvt_df(double *from, float *to);
 
index 65cab0612b2b94fd32300d309b5f960b1f152200..df1014281ad1b03d8e4188b08d9d21f0fbbd98bc 100644 (file)
@@ -125,6 +125,7 @@ struct termios {
 #define  B57600   00020
 #define  B115200  00021
 #define  B230400  00022
+#define  B460800  00023
 
 #define CSIZE  00001400
 #define   CS5  00000000
index de8ce568720f1b43b8066311fea402e276069ca0..dd6428edf45cc84f0e3b36bde22726aae3385e39 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.62 1997/06/27 14:55:00 jj Exp $ */
+/* $Id: pgtable.h,v 1.63 1997/08/13 04:44:15 paulus Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -298,6 +298,7 @@ extern void (*flush_cache_mm)(struct mm_struct *);
 extern void (*flush_cache_range)(struct mm_struct *, unsigned long start,
                                 unsigned long end);
 extern void (*flush_cache_page)(struct vm_area_struct *, unsigned long address);
+#define flush_icache_range(start, end)         do { } while (0)
 
 extern void (*flush_tlb_all)(void);
 extern void (*flush_tlb_mm)(struct mm_struct *);
index 12baf0222d97c6bc5d47a87d5a2f0debf606bd31..33341d3996ec7c4bed22207e6cfe8d9cab58554c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.15 1997/07/03 09:18:09 davem Exp $
+/* $Id: atomic.h,v 1.18 1997/08/07 03:38:31 davem Exp $
  * atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
@@ -23,29 +23,29 @@ typedef struct { int counter; } atomic_t;
 extern __inline__ void atomic_add(int i, atomic_t *v)
 {
        __asm__ __volatile__("
-1:     lduw            [%1], %%g1
-       add             %%g1, %0, %%g2
-       cas             [%1], %%g1, %%g2
-       sub             %%g1, %%g2, %%g1
-       brnz,pn         %%g1, 1b
+1:     lduw            [%1], %%g5
+       add             %%g5, %0, %%g7
+       cas             [%1], %%g5, %%g7
+       sub             %%g5, %%g7, %%g5
+       brnz,pn         %%g5, 1b
         nop"
        : /* No outputs */
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "g1", "g2");
+       : "g5", "g7", "memory");
 }
 
 extern __inline__ void atomic_sub(int i, atomic_t *v)
 {
        __asm__ __volatile__("
-1:     lduw            [%1], %%g1
-       sub             %%g1, %0, %%g2
-       cas             [%1], %%g1, %%g2
-       sub             %%g1, %%g2, %%g1
-       brnz,pn         %%g1, 1b
+1:     lduw            [%1], %%g5
+       sub             %%g5, %0, %%g7
+       cas             [%1], %%g5, %%g7
+       sub             %%g5, %%g7, %%g5
+       brnz,pn         %%g5, 1b
         nop"
        : /* No outputs */
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "g1", "g2");
+       : "g5", "g7", "memory");
 }
 
 /* Same as above, but return the result value. */
@@ -53,15 +53,15 @@ extern __inline__ int atomic_add_return(int i, atomic_t *v)
 {
        unsigned long oldval;
        __asm__ __volatile__("
-1:     lduw            [%2], %%g1
-       add             %%g1, %1, %%g2
-       cas             [%2], %%g1, %%g2
-       sub             %%g1, %%g2, %%g1
-       brnz,pn         %%g1, 1b
-        add            %%g2, %1, %0"
+1:     lduw            [%2], %%g5
+       add             %%g5, %1, %%g7
+       cas             [%2], %%g5, %%g7
+       sub             %%g5, %%g7, %%g5
+       brnz,pn         %%g5, 1b
+        add            %%g7, %1, %0"
        : "=&r" (oldval)
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "g1", "g2");
+       : "g5", "g7", "memory");
        return (int)oldval;
 }
 
@@ -69,15 +69,15 @@ extern __inline__ int atomic_sub_return(int i, atomic_t *v)
 {
        unsigned long oldval;
        __asm__ __volatile__("
-1:     lduw            [%2], %%g1
-       sub             %%g1, %1, %%g2
-       cas             [%2], %%g1, %%g2
-       sub             %%g1, %%g2, %%g1
-       brnz,pn         %%g1, 1b
-        sub            %%g2, %1, %0"
+1:     lduw            [%2], %%g5
+       sub             %%g5, %1, %%g7
+       cas             [%2], %%g5, %%g7
+       sub             %%g5, %%g7, %%g5
+       brnz,pn         %%g5, 1b
+        sub            %%g7, %1, %0"
        : "=&r" (oldval)
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "g1", "g2");
+       : "g5", "g7", "memory");
        return (int)oldval;
 }
 
index f0d11e6ef73fa9c366e792f47c2f30eacbdc0ae9..ab4523e9dcee9b257c87d839d7f328fc1bb10db6 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: bitops.h,v 1.19 1997/07/08 10:17:37 davem Exp $
+/* $Id: bitops.h,v 1.22 1997/08/07 02:54:04 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
- * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef _SPARC64_BITOPS_H
 
 extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void *addr)
 {
-       unsigned long oldbit;
-       unsigned long temp0, temp1;
        unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+       unsigned long oldbit;
 
        __asm__ __volatile__("
-       ldx             [%4], %0
-1:
-       andcc           %0, %3, %2
+1:     ldx             [%2], %%g7
+       andcc           %%g7, %1, %0
        bne,pn          %%xcc, 2f
-        xor            %0, %3, %1
-       casx            [%4], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%xcc, 1b
-        ldx            [%4], %0
+        xor            %%g7, %1, %%g5
+       casx            [%2], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
 2:
-"      : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"      : "=&r" (oldbit)
        : "HIr" (1UL << (nr & 63)), "r" (m)
-       : "cc");
+       : "g5", "g7", "cc", "memory");
        return oldbit != 0;
 }
 
 extern __inline__ void set_bit(unsigned long nr, void *addr)
 {
-       (void) test_and_set_bit(nr, addr);
+       unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+       __asm__ __volatile__("
+1:     ldx             [%1], %%g7
+       andcc           %%g7, %0, %%g0
+       bne,pn          %%xcc, 2f
+        xor            %%g7, %0, %%g5
+       casx            [%1], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
+2:
+"      : /* no outputs */
+       : "HIr" (1UL << (nr & 63)), "r" (m)
+       : "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void *addr)
 {
-       unsigned long oldbit;
-       unsigned long temp0, temp1;
        unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+       unsigned long oldbit;
 
        __asm__ __volatile__("
-       ldx             [%4], %0
-1:
-       andcc           %0, %3, %2
+1:     ldx             [%2], %%g7
+       andcc           %%g7, %1, %0
        be,pn           %%xcc, 2f
-        xor            %0, %3, %1
-       casx            [%4], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%xcc, 1b
-        ldx            [%4], %0
+        xor            %%g7, %1, %%g5
+       casx            [%2], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
 2:
-"      : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"      : "=&r" (oldbit)
        : "HIr" (1UL << (nr & 63)), "r" (m)
-       : "cc");
+       : "g5", "g7", "cc", "memory");
        return oldbit != 0;
 }
 
 extern __inline__ void clear_bit(unsigned long nr, void *addr)
 {
-       (void) test_and_clear_bit(nr, addr);
+       unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+       __asm__ __volatile__("
+1:     ldx             [%1], %%g7
+       andcc           %%g7, %0, %%g0
+       be,pn           %%xcc, 2f
+        xor            %%g7, %0, %%g5
+       casx            [%1], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
+2:
+"      : /* no outputs */
+       : "HIr" (1UL << (nr & 63)), "r" (m)
+       : "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void *addr)
 {
-       unsigned long oldbit;
-       unsigned long temp0, temp1;
        unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+       unsigned long oldbit;
 
        __asm__ __volatile__("
-       ldx             [%4], %0
-1:
-       and             %0, %3, %2
-       xor             %0, %3, %1
-       casx            [%4], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%xcc, 1b
-        ldx            [%4], %0
-"      : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+1:     ldx             [%2], %%g7
+       and             %%g7, %1, %0
+       xor             %%g7, %1, %%g5
+       casx            [%2], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
+"      : "=&r" (oldbit)
        : "HIr" (1UL << (nr & 63)), "r" (m)
-       : "cc");
+       : "g5", "g7", "cc", "memory");
        return oldbit != 0;
 }
 
 extern __inline__ void change_bit(unsigned long nr, void *addr)
 {
-       (void) test_and_change_bit(nr, addr);
+       unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+       __asm__ __volatile__("
+1:     ldx             [%1], %%g7
+       xor             %%g7, %0, %%g5
+       casx            [%1], %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%xcc, 1b
+        nop
+"      : /* no outputs */
+       : "HIr" (1UL << (nr & 63)), "r" (m)
+       : "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
@@ -201,47 +234,43 @@ found_middle:
  */
 extern __inline__ int set_le_bit(int nr,void * addr)
 {
-       unsigned long oldbit;
-       unsigned long temp0, temp1;
        unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+       unsigned long oldbit;
 
        __asm__ __volatile__("
-       lduwa           [%4] %5, %0
-1:
-       andcc           %0, %3, %2
+1:     lduwa           [%2] %3, %%g7
+       andcc           %%g7, %1, %0
        bne,pn          %%icc, 2f
-        xor            %0, %3, %1
-       casa            [%4] %5, %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduwa          [%4] %5, %0
+        xor            %%g7, %1, %%g5
+       casa            [%2] %3, %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%icc, 1b
+        nop
 2:
-"      : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"      : "=&r" (oldbit)
        : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-       : "cc");
+       : "g5", "g7", "cc", "memory");
        return oldbit != 0;
 }
 
 extern __inline__ int clear_le_bit(int nr, void * addr)
 {
-       unsigned long oldbit;
-       unsigned long temp0, temp1;
        unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+       unsigned long oldbit;
 
        __asm__ __volatile__("
-       lduwa           [%4] %5, %0
-1:
-       andcc           %0, %3, %2
+1:     lduwa           [%2] %3, %%g7
+       andcc           %%g7, %1, %0
        be,pn           %%icc, 2f
-        xor            %0, %3, %1
-       casa            [%4] %5, %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduwa          [%4] %5, %0
+        xor            %%g7, %1, %%g5
+       casa            [%2] %3, %%g7, %%g5
+       cmp             %%g7, %%g5
+       bne,pn          %%icc, 1b
+        nop
 2:
-"      : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"      : "=&r" (oldbit)
        : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-       : "cc");
+       : "g5", "g7", "cc", "memory");
        return oldbit != 0;
 }
 
index b1ff474c32b00196c59adf1ee42e1dedc9536da6..bb32044c05df78611109e3e9dac554d11438bd59 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.9 1997/06/26 04:05:17 davem Exp $ */
+/* $Id: checksum.h,v 1.10 1997/08/09 18:09:03 jj Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -42,47 +42,25 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum
                        csum_partial_copy_nocheck(src,dst,len,sum)
 #define csum_partial_copy_fromuser(s, d, l, w)  \
                        csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
+
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
                        
 extern __inline__ unsigned int 
 csum_partial_copy_nocheck (const char *src, char *dst, int len, 
                           unsigned int sum)
 {
-       register unsigned long ret asm("o0") = (unsigned long)src;
-       register char *d asm("o1") = dst;
-       register unsigned long l asm("g1") = len;
-
-       __asm__ __volatile__ ("
-               wr      %%g0, %5, %%asi
-               call __csum_partial_copy_sparc_generic
-                mov %4, %%g7
-               srl     %%o0, 0, %%o0
-       " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) :
-       "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-       return (unsigned int)ret;
+       __asm__ __volatile__ ("wr       %%g0, %0, %%asi" : : "i" (ASI_P));
+       return csum_partial_copy_sparc64(src, dst, len, sum);
 }
 
 extern __inline__ unsigned int 
 csum_partial_copy_from_user(const char *src, char *dst, int len, 
                            unsigned int sum, int *err)
 {
-       register unsigned long ret asm("o0") = (unsigned long)src;
-       register char *d asm("o1") = dst;
-       register unsigned long l asm("g1") = len;
-       register unsigned long s asm("g7") = sum;
-
-       __asm__ __volatile__ ("
-       .section __ex_table,#alloc
-       .align 8
-       .xword 1f,2
-       .previous
-       wr      %%g0, %6, %%asi
-1:
-       call __csum_partial_copy_sparc_generic
-        stx %5, [%%sp + 0x7ff + 128]
-       srl     %%o0, 0, %%o0
-       " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) :
-       "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-       return (unsigned int)ret;
+       __asm__ __volatile__ ("wr       %%g0, %0, %%asi
+                              stx      %1, [%%sp + 0x7ff + 128]
+                             " : : "i" (ASI_S), "r" (err));
+       return csum_partial_copy_sparc64(src, dst, len, sum);
 }
 
 #if 0
index f70d99b685c1cfc541ef4bd0d4ca03fed12d0489..eac45ef9a65643eca63f9191f8c4bfebd1cff9ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.5 1997/06/18 12:36:23 jj Exp $
+/* $Id: delay.h,v 1.6 1997/07/29 21:11:22 davem Exp $
  * delay.h: Linux delay routines on the V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
@@ -7,7 +7,9 @@
 #ifndef __SPARC64_DELAY_H
 #define __SPARC64_DELAY_H
 
-extern unsigned long loops_per_sec;
+#ifdef __SMP__
+#include <asm/smp.h>
+#endif 
 
 extern __inline__ void __delay(unsigned long loops)
 {
@@ -23,7 +25,7 @@ extern __inline__ void __delay(unsigned long loops)
        : "cc");
 }
 
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
        usecs *= 0x00000000000010c6UL;          /* 2**32 / 1000000 */
 
@@ -31,11 +33,19 @@ extern __inline__ void udelay(unsigned long usecs)
        mulx    %1, %2, %0
        srlx    %0, 32, %0
 "      : "=r" (usecs)
-       : "r" (usecs), "r" (loops_per_sec));
+       : "r" (usecs), "r" (lps));
 
        __delay(usecs);
 }
 
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
+
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
        return (a*b)/c;
diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h
new file mode 100644 (file)
index 0000000..8fd1e44
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: ebus.h,v 1.1 1997/08/12 04:13:12 ecd Exp $
+ * ebus.h: PCI to Ebus pseudo driver software state.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_EBUS_H
+#define __SPARC64_EBUS_H
+
+#include <asm/oplib.h>
+
+struct linux_ebus_device {
+       struct linux_ebus_device        *next;
+       struct linux_ebus               *parent;
+       int                              prom_node;
+       char                             prom_name[64];
+       struct linux_prom_registers      regs[PROMREG_MAX];
+       int                              num_registers;
+       struct linux_prom_irqs           irqs[PROMINTR_MAX];
+       int                              num_irqs;
+};
+       
+struct linux_ebus {
+       struct linux_ebus               *next;
+       struct linux_ebus_device        *devices;
+       struct linux_pbm_info           *parent;
+       int                              prom_node;
+       char                             prom_name[64];
+       struct linux_prom_ranges         ebus_ranges[PROMREG_MAX];
+       int                              num_ebus_ranges;
+};
+
+extern struct linux_ebus               *ebus_chain;
+
+extern unsigned long ebus_init(unsigned long, unsigned long);
+extern void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+                                  struct linux_prom_registers *regs,
+                                  int nregs);
+
+#define for_each_ebus(bus)                                             \
+        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
+
+#define for_each_ebusdev(dev, bus)                                     \
+        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
+
+#define for_all_ebusdev(dev, bus)                                      \
+       for ((bus) = ebus_chain, ((dev) = (bus) ? (bus)->devices : 0);  \
+            (bus); ((dev) = (dev)->next ? (dev)->next :                \
+            ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+
+#endif /* !(__SPARC64_EBUS_H) */
diff --git a/include/asm-sparc64/fhc.h b/include/asm-sparc64/fhc.h
new file mode 100644 (file)
index 0000000..487a403
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: fhc.h,v 1.1 1997/08/08 04:26:40 davem Exp $
+ * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_FHC_H
+#define _SPARC64_FHC_H
+
+#include <asm/firehose.h>
+#include <asm/oplib.h>
+
+struct linux_fhc;
+
+struct linux_central {
+       struct linux_fhc                *child;
+       int                             prom_node;
+       char                            prom_name[64];
+
+       struct linux_prom_ranges        central_ranges[PROMREG_MAX];
+       int                             num_central_ranges;
+};
+
+struct linux_fhc {
+       struct linux_fhc                *next;
+       struct linux_central            *parent;        /* NULL if not central FHC */
+       struct fhc_regs                 fhc_regs;
+       int                             prom_node;
+       char                            prom_name[64];
+
+       struct linux_prom_ranges        fhc_ranges[PROMREG_MAX];
+       int                             num_fhc_ranges;
+};
+
+extern struct linux_central *central_bus;
+
+extern void prom_apply_central_ranges(struct linux_central *central, 
+                                     struct linux_prom_registers *regs,
+                                     int nregs);
+
+extern void prom_apply_fhc_ranges(struct linux_fhc *fhc, 
+                                  struct linux_prom_registers *regs,
+                                 int nregs);
+
+#endif /* !(_SPARC64_FHC_H) */
index 931671d4f879980d8f2e8e1bfae2eb964a314405..e4f4bb7e7bd221a3a08b7ab9084fd96e65b79311 100644 (file)
@@ -1,6 +1,6 @@
-/* $Id: firehose.h,v 1.1 1997/04/11 02:38:47 davem Exp $
+/* $Id: firehose.h,v 1.2 1997/08/08 04:26:31 davem Exp $
  * firehose.h: Defines for the Fire Hose Controller (FHC) found
- *             on Sunfire/Wildfire systems.
+ *             on Sunfire/Starfire/Wildfire systems.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -33,38 +33,38 @@ struct fhc_internal_regs {
  * for the FHC, thus we have the following few structs...
  */
 struct fhc_ign_reg {
-/*0x2000*/     u64     fhc_ign;        /* FHC Interrupt Group Number           */
+/*0x2000*/     u64     fhc_ign;                /* FHC Interrupt Group Number   */
 };
 
 struct fhc_fanfail_regs {
-/*0x4000*/     u64     fhc_ff_imap;    /* FHC FanFail Interrupt Map            */
-               u64     _unused1;
-/*0x4010*/     u64     fhc_ff_istate;  /* FHC FanFail Interrupt State          */
+/*0x4000*/     u32     _pad0, fhc_ff_imap;     /* FHC FanFail Interrupt Map    */
+               u64     _pad1;
+/*0x4010*/     u32     _pad2, fhc_ff_iclr;     /* FHC FanFail Interrupt Clear  */
 };
 
 struct fhc_system_regs {
-/*0x6000*/     u64     fhc_sys_imap;   /* FHC System Interrupt Map             */
-               u64     _unused1;
-/*0x6010*/     u64     fhc_sys_istate; /* FHC System Interrupt State           */
+/*0x6000*/     u32     _pad0, fhc_sys_imap;    /* FHC System Interrupt Map     */
+               u64     _pad1;
+/*0x6010*/     u32     _pad2, fhc_sys_iclr;    /* FHC System Interrupt Clear   */
 };
 
 struct fhc_uart_regs {
-/*0x8000*/     u64     fhc_uart_imap;  /* FHC UART Interrupt Map               */
-               u64     _unused1;
-/*0x8010*/     u64     fhc_uart_istate;/* FHC UART Interrupt State             */
+/*0x8000*/     u32     _pad0, fhc_uart_imap;   /* FHC UART Interrupt Map       */
+               u64     _pad1;
+/*0x8010*/     u32     _pad2, fhc_uart_iclr;   /* FHC UART Interrupt Clear     */
 };
 
 struct fhc_tod_regs {
-/*0xa000*/     u64     fhc_tod_imap;   /* FHC TOD Interrupt Map                */
-               u64     _unused1;
-/*0xa010*/     u64     fhc_tod_istate; /* FHC TOD Interrupt State              */
+/*0xa000*/     u32     _pad0, fhc_tod_imap;    /* FHC TOD Interrupt Map        */
+               u64     _pad1;
+/*0xa010*/     u32     _pad2, fhc_tod_iclr;    /* FHC TOD Interrupt Clear      */
 };
 
 /* All of the above. */
 struct fhc_regs {
        struct fhc_internal_regs        *pregs;
        struct fhc_ign_reg              *ireg;
-       struct fhc_fanfil_regs          *ffregs;
+       struct fhc_fanfail_regs         *ffregs;
        struct fhc_system_regs          *sregs;
        struct fhc_uart_regs            *uregs;
        struct fhc_tod_regs             *tregs;
index 03ee543b10128ec11d781deea5df1f157b79bd46..5ca51ac776db151de8c61a85342978df1bc33894 100644 (file)
@@ -8,16 +8,20 @@
 
 #include <linux/tasks.h>
 
-extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+#ifndef __SMP__
+extern unsigned int local_irq_count;
+#else
+#define local_irq_count                (cpu_data[smp_processor_id()].irq_count)
+#endif
+#define in_interrupt()         (local_irq_count != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)   (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)   (local_irq_count == 0)
 #define hardirq_endlock(cpu)   do { } while(0)
 
-#define hardirq_enter(cpu)     (local_irq_count[cpu]++)
-#define hardirq_exit(cpu)      (local_irq_count[cpu]--)
+#define hardirq_enter(cpu)     (local_irq_count++)
+#define hardirq_exit(cpu)      (local_irq_count--)
 
 #define synchronize_irq()      do { } while(0)
 
@@ -43,14 +47,16 @@ static inline void release_irqlock(int cpu)
 
 static inline void hardirq_enter(int cpu)
 {
-       ++local_irq_count[cpu];
+       ++cpu_data[cpu].irq_count;
        atomic_inc(&global_irq_count);
+       membar("#StoreLoad | #StoreStore");
 }
 
 static inline void hardirq_exit(int cpu)
 {
+       membar("#StoreStore | #LoadStore");
        atomic_dec(&global_irq_count);
-       --local_irq_count[cpu];
+       --cpu_data[cpu].irq_count;
 }
 
 static inline int hardirq_trylock(int cpu)
@@ -58,13 +64,14 @@ static inline int hardirq_trylock(int cpu)
        unsigned long flags;
 
        __save_and_cli(flags);
-       if(atomic_add_return(1, &global_irq_count) != 1 ||
-          *(((unsigned char *)(&global_irq_lock)))) {
+       atomic_inc(&global_irq_count);
+       if(atomic_read(&global_irq_count) != 1 ||
+          (*(((unsigned char *)(&global_irq_lock)))) != 0) {
                atomic_dec(&global_irq_count);
                __restore_flags(flags);
                return 0;
        }
-       ++local_irq_count[cpu];
+       ++cpu_data[cpu].irq_count;
        return 1;
 }
 
index e3ff516866186897d3119677ed5c5e75578949ab..570e6989f85b0a5779d167f5265dd166781ba3ce 100644 (file)
@@ -1,324 +1,9 @@
-/* $Id: head.h,v 1.27 1997/07/13 17:30:43 davem Exp $ */
+/* $Id: head.h,v 1.30 1997/08/08 08:34:33 jj Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
 #include <asm/pstate.h>
 
 #define KERNBASE    0x400000
-#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
-
-/* We need a "cleaned" instruction... */
-#define CLEAN_WINDOW                                                   \
-       rdpr    %cleanwin, %l0;         add     %l0, 1, %l0;            \
-       wrpr    %l0, 0x0, %cleanwin;                                    \
-       clr     %o0;    clr     %o1;    clr     %o2;    clr     %o3;    \
-       clr     %o4;    clr     %o5;    clr     %o6;    clr     %o7;    \
-       clr     %l0;    clr     %l1;    clr     %l2;    clr     %l3;    \
-       clr     %l4;    clr     %l5;    clr     %l6;    clr     %l7;    \
-       retry;                                                          \
-       nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
-
-#define TRAP(routine)                                  \
-       ba,pt   %xcc, etrap;                            \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;                                    \
-       nop;                                            \
-       nop;
-
-#define TRAP_NOSAVE(routine)                           \
-       ba,pt   %xcc, routine;                          \
-        nop;                                           \
-       nop; nop; nop; nop; nop; nop;
-
-#define TRAPTL1(routine)                               \
-       ba,pt   %xcc, etraptl1;                         \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;                                    \
-       nop;                                            \
-       nop;
-       
-#define TRAP_ARG(routine, arg)                         \
-       ba,pt   %xcc, etrap;                            \
-        rd     %pc, %g7;                               \
-       add     %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       call    routine;                                \
-        mov    arg, %o1;                               \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;                                    \
-       nop;
-       
-#define TRAPTL1_ARG(routine, arg)                      \
-       ba,pt   %xcc, etraptl1;                         \
-        rd     %pc, %g7;                               \
-       add     %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       call    routine;                                \
-        mov    arg, %o1;                               \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;                                    \
-       nop;
-       
-#define SYSCALL_TRAP(routine, systbl)                  \
-       ba,pt   %xcc, etrap;                            \
-        rd     %pc, %g7;                               \
-       sethi   %hi(systbl), %l7;                       \
-       call    routine;                                \
-        or     %l7, %lo(systbl), %l7;                  \
-       nop; nop; nop;
-       
-#define ACCESS_EXCEPTION_TRAP(routine)                 \
-       rdpr    %pstate, %g1;                           \
-       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
-       ba,pt   %xcc, etrap;                            \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;
-
-#define ACCESS_EXCEPTION_TRAPTL1(routine)              \
-       rdpr    %pstate, %g1;                           \
-       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
-       ba,pt   %xcc, etraptl1;                         \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;
-
-#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
-#define        LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
-#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
-#define GETCC_TRAP TRAP(getcc)
-#define SETCC_TRAP TRAP(setcc)
-/* FIXME: Write these actually */      
-#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
-#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
-#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
-#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
-
-#define TRAP_IRQ(routine, level)                       \
-       rdpr    %pil, %g2;                              \
-       wrpr    %g0, 15, %pil;                          \
-       ba,pt   %xcc, etrap_irq;                        \
-        rd     %pc, %g7;                               \
-       mov     level, %o0;                             \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o1;       \
-       ba,a,pt %xcc, rtrap_clr_l6;
-
-/* On UP this is ok, and worth the effort, for SMP we need
- * a different mechanism and thus cannot do it all in trap table. -DaveM
- */
-#ifndef __SMP__
-#define TRAP_IVEC                              \
-       ldxa    [%g2] ASI_UDB_INTR_R, %g3;      \
-       and     %g3, 0x7ff, %g3;                \
-       sllx    %g3, 3, %g3;                    \
-       ldx     [%g1 + %g3], %g5;               \
-       wr      %g5, 0x0, %set_softint;         \
-       stxa    %g0, [%g0] ASI_INTR_RECEIVE;    \
-       membar  #Sync;                          \
-       retry;
-#else
-#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
-#endif
-
-#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
-
-#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
-
-#define FLUSH_WINDOW_TRAP                                              \
-       ba,pt   %xcc, etrap;                                            \
-        rd     %pc, %g7;                                               \
-       flushw;                                                         \
-       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;       \
-       add     %l1, 4, %l2;                                            \
-       stx     %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];        \
-       ba,pt   %xcc, rtrap_clr_l6;                                     \
-        stx    %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
-               
-/* Before touching these macros, you owe it to yourself to go and
- * see how arch/sparc64/kernel/winfixup.S works... -DaveM
- */
-
-/* Normal kernel spill */
-#define SPILL_0_NORMAL                                 \
-       stx     %l0, [%sp + STACK_BIAS + 0x00];         \
-       stx     %l1, [%sp + STACK_BIAS + 0x08];         \
-       stx     %l2, [%sp + STACK_BIAS + 0x10];         \
-       stx     %l3, [%sp + STACK_BIAS + 0x18];         \
-       stx     %l4, [%sp + STACK_BIAS + 0x20];         \
-       stx     %l5, [%sp + STACK_BIAS + 0x28];         \
-       stx     %l6, [%sp + STACK_BIAS + 0x30];         \
-       stx     %l7, [%sp + STACK_BIAS + 0x38];         \
-       stx     %i0, [%sp + STACK_BIAS + 0x40];         \
-       stx     %i1, [%sp + STACK_BIAS + 0x48];         \
-       stx     %i2, [%sp + STACK_BIAS + 0x50];         \
-       stx     %i3, [%sp + STACK_BIAS + 0x58];         \
-       stx     %i4, [%sp + STACK_BIAS + 0x60];         \
-       stx     %i5, [%sp + STACK_BIAS + 0x68];         \
-       stx     %i6, [%sp + STACK_BIAS + 0x70];         \
-       stx     %i7, [%sp + STACK_BIAS + 0x78];         \
-       saved; retry; nop; nop; nop; nop; nop; nop;     \
-       nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit spill */
-#define SPILL_1_GENERIC(xxx)                           \
-       wr      %g0, xxx, %asi;                         \
-       stxa    %l0, [%sp + STACK_BIAS + 0x00] %asi;    \
-       stxa    %l1, [%sp + STACK_BIAS + 0x08] %asi;    \
-       stxa    %l2, [%sp + STACK_BIAS + 0x10] %asi;    \
-       stxa    %l3, [%sp + STACK_BIAS + 0x18] %asi;    \
-       stxa    %l4, [%sp + STACK_BIAS + 0x20] %asi;    \
-       stxa    %l5, [%sp + STACK_BIAS + 0x28] %asi;    \
-       stxa    %l6, [%sp + STACK_BIAS + 0x30] %asi;    \
-       stxa    %l7, [%sp + STACK_BIAS + 0x38] %asi;    \
-       stxa    %i0, [%sp + STACK_BIAS + 0x40] %asi;    \
-       stxa    %i1, [%sp + STACK_BIAS + 0x48] %asi;    \
-       stxa    %i2, [%sp + STACK_BIAS + 0x50] %asi;    \
-       stxa    %i3, [%sp + STACK_BIAS + 0x58] %asi;    \
-       stxa    %i4, [%sp + STACK_BIAS + 0x60] %asi;    \
-       stxa    %i5, [%sp + STACK_BIAS + 0x68] %asi;    \
-       stxa    %i6, [%sp + STACK_BIAS + 0x70] %asi;    \
-       stxa    %i7, [%sp + STACK_BIAS + 0x78] %asi;    \
-       saved; retry; nop; nop; nop; nop; nop; nop;     \
-       nop; nop; nop; nop; nop;                        \
-       b,a,pt  %xcc, spill_fixup_mna;                  \
-       b,a,pt  %xcc, spill_fixup;
-
-/* Normal 32bit spill */
-#define SPILL_2_GENERIC(xxx)                           \
-       wr      %g0, xxx, %asi;                         \
-       srl     %sp, 0, %sp;                            \
-       stwa    %l0, [%sp + 0x00] %asi;                 \
-       stwa    %l1, [%sp + 0x04] %asi;                 \
-       stwa    %l2, [%sp + 0x08] %asi;                 \
-       stwa    %l3, [%sp + 0x0c] %asi;                 \
-       stwa    %l4, [%sp + 0x10] %asi;                 \
-       stwa    %l5, [%sp + 0x14] %asi;                 \
-       stwa    %l6, [%sp + 0x18] %asi;                 \
-       stwa    %l7, [%sp + 0x1c] %asi;                 \
-       stwa    %i0, [%sp + 0x20] %asi;                 \
-       stwa    %i1, [%sp + 0x24] %asi;                 \
-       stwa    %i2, [%sp + 0x28] %asi;                 \
-       stwa    %i3, [%sp + 0x2c] %asi;                 \
-       stwa    %i4, [%sp + 0x30] %asi;                 \
-       stwa    %i5, [%sp + 0x34] %asi;                 \
-       stwa    %i6, [%sp + 0x38] %asi;                 \
-       stwa    %i7, [%sp + 0x3c] %asi;                 \
-       saved; retry; nop; nop; nop; nop;               \
-       nop; nop; nop; nop; nop; nop;                   \
-       b,a,pt  %xcc, spill_fixup_mna;                  \
-       b,a,pt  %xcc, spill_fixup;
-
-#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
-#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
-#define SPILL_3_NORMAL SPILL_0_NORMAL
-#define SPILL_4_NORMAL SPILL_0_NORMAL
-#define SPILL_5_NORMAL SPILL_0_NORMAL
-#define SPILL_6_NORMAL SPILL_0_NORMAL
-#define SPILL_7_NORMAL SPILL_0_NORMAL
-
-#define SPILL_0_OTHER SPILL_0_NORMAL
-#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
-#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
-#define SPILL_3_OTHER SPILL_3_NORMAL
-#define SPILL_4_OTHER SPILL_4_NORMAL
-#define SPILL_5_OTHER SPILL_5_NORMAL
-#define SPILL_6_OTHER SPILL_6_NORMAL
-#define SPILL_7_OTHER SPILL_7_NORMAL
-
-/* Normal kernel fill */
-#define FILL_0_NORMAL                                  \
-       ldx     [%sp + STACK_BIAS + 0x00], %l0;         \
-       ldx     [%sp + STACK_BIAS + 0x08], %l1;         \
-       ldx     [%sp + STACK_BIAS + 0x10], %l2;         \
-       ldx     [%sp + STACK_BIAS + 0x18], %l3;         \
-       ldx     [%sp + STACK_BIAS + 0x20], %l4;         \
-       ldx     [%sp + STACK_BIAS + 0x28], %l5;         \
-       ldx     [%sp + STACK_BIAS + 0x30], %l6;         \
-       ldx     [%sp + STACK_BIAS + 0x38], %l7;         \
-       ldx     [%sp + STACK_BIAS + 0x40], %i0;         \
-       ldx     [%sp + STACK_BIAS + 0x48], %i1;         \
-       ldx     [%sp + STACK_BIAS + 0x50], %i2;         \
-       ldx     [%sp + STACK_BIAS + 0x58], %i3;         \
-       ldx     [%sp + STACK_BIAS + 0x60], %i4;         \
-       ldx     [%sp + STACK_BIAS + 0x68], %i5;         \
-       ldx     [%sp + STACK_BIAS + 0x70], %i6;         \
-       ldx     [%sp + STACK_BIAS + 0x78], %i7;         \
-       restored; retry; nop; nop; nop; nop; nop; nop;  \
-       nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit fill */
-#define FILL_1_GENERIC(xxx)                            \
-       wr      %g0, xxx, %asi;                         \
-       ldxa    [%sp + STACK_BIAS + 0x00] %asi, %l0;    \
-       ldxa    [%sp + STACK_BIAS + 0x08] %asi, %l1;    \
-       ldxa    [%sp + STACK_BIAS + 0x10] %asi, %l2;    \
-       ldxa    [%sp + STACK_BIAS + 0x18] %asi, %l3;    \
-       ldxa    [%sp + STACK_BIAS + 0x20] %asi, %l4;    \
-       ldxa    [%sp + STACK_BIAS + 0x28] %asi, %l5;    \
-       ldxa    [%sp + STACK_BIAS + 0x30] %asi, %l6;    \
-       ldxa    [%sp + STACK_BIAS + 0x38] %asi, %l7;    \
-       ldxa    [%sp + STACK_BIAS + 0x40] %asi, %i0;    \
-       ldxa    [%sp + STACK_BIAS + 0x48] %asi, %i1;    \
-       ldxa    [%sp + STACK_BIAS + 0x50] %asi, %i2;    \
-       ldxa    [%sp + STACK_BIAS + 0x58] %asi, %i3;    \
-       ldxa    [%sp + STACK_BIAS + 0x60] %asi, %i4;    \
-       ldxa    [%sp + STACK_BIAS + 0x68] %asi, %i5;    \
-       ldxa    [%sp + STACK_BIAS + 0x70] %asi, %i6;    \
-       ldxa    [%sp + STACK_BIAS + 0x78] %asi, %i7;    \
-       restored; retry; nop; nop; nop; nop; nop; nop;  \
-       nop; nop; nop; nop; nop;                        \
-       b,a,pt  %xcc, fill_fixup_mna;                   \
-       b,a,pt  %xcc, fill_fixup;
-
-/* Normal 32bit fill */
-#define FILL_2_GENERIC(xxx)                            \
-       wr      %g0, xxx, %asi;                         \
-       srl     %sp, 0, %sp;                            \
-       lduwa   [%sp + 0x00] %asi, %l0;                 \
-       lduwa   [%sp + 0x04] %asi, %l1;                 \
-       lduwa   [%sp + 0x08] %asi, %l2;                 \
-       lduwa   [%sp + 0x0c] %asi, %l3;                 \
-       lduwa   [%sp + 0x10] %asi, %l4;                 \
-       lduwa   [%sp + 0x14] %asi, %l5;                 \
-       lduwa   [%sp + 0x18] %asi, %l6;                 \
-       lduwa   [%sp + 0x1c] %asi, %l7;                 \
-       lduwa   [%sp + 0x20] %asi, %i0;                 \
-       lduwa   [%sp + 0x24] %asi, %i1;                 \
-       lduwa   [%sp + 0x28] %asi, %i2;                 \
-       lduwa   [%sp + 0x2c] %asi, %i3;                 \
-       lduwa   [%sp + 0x30] %asi, %i4;                 \
-       lduwa   [%sp + 0x34] %asi, %i5;                 \
-       lduwa   [%sp + 0x38] %asi, %i6;                 \
-       lduwa   [%sp + 0x3c] %asi, %i7;                 \
-       restored; retry; nop; nop; nop; nop;            \
-       nop; nop; nop; nop; nop; nop;                   \
-       b,a,pt  %xcc, fill_fixup_mna;                   \
-       b,a,pt  %xcc, fill_fixup;
-
-#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
-#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
-#define FILL_3_NORMAL FILL_0_NORMAL
-#define FILL_4_NORMAL FILL_0_NORMAL
-#define FILL_5_NORMAL FILL_0_NORMAL
-#define FILL_6_NORMAL FILL_0_NORMAL
-#define FILL_7_NORMAL FILL_0_NORMAL
-
-#define FILL_0_OTHER FILL_0_NORMAL
-#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
-#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
-#define FILL_3_OTHER FILL_3_NORMAL
-#define FILL_4_OTHER FILL_4_NORMAL
-#define FILL_5_OTHER FILL_5_NORMAL
-#define FILL_6_OTHER FILL_6_NORMAL
-#define FILL_7_OTHER FILL_7_NORMAL
 
 #endif /* !(_SPARC64_HEAD_H) */
index 1d6c1cace33c861625e8eabd7ace796e66665446..8a4a2c91d0176b704d2ea5c69534926f775a06be 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctls.h,v 1.4 1997/06/23 07:26:03 davem Exp $ */
+/* $Id: ioctls.h,v 1.5 1997/08/12 04:13:13 ecd Exp $ */
 #ifndef _ASM_SPARC64_IOCTLS_H
 #define _ASM_SPARC64_IOCTLS_H
 
 #define TIOCSERGETLSR   0x5459 /* Get line status register */
 #define TIOCSERGETMULTI 0x545A /* Get multiport config  */
 #define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT     0x545C /* Wait for change on serial input line(s) */
+#define TIOCGICOUNT    0x545D /* Read serial port inline interrupt counts */
 
 /* Kernel definitions */
 #ifdef __KERNEL__
index fbb43c69a9e204caf151f80109fcf72dd98bc053..f52844fe4f3837f4bb81ab131b995e72b34b697c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <asm/page.h>
 #include <asm/sysio.h>
+#include <asm/spinlock.h>
 
 /* The iommu handles all virtual to physical address translations
  * that occur between the SYSIO and physical memory.  Access by
 #define IOPTE_WRITE         0x0000000000000002 /* Writeable                        */
 
 struct iommu_struct {
-       struct sysio_regs *sysio_regs;
-       iopte_t *page_table;
+       struct sysio_regs       *sysio_regs;
+       unsigned int            *sbuf_flushflag_va;
+       unsigned long           sbuf_flushflag_pa;
+       spinlock_t              iommu_lock;
+
+       iopte_t                 *page_table;
 
        /* For convenience */
        unsigned long start; /* First managed virtual address */
index 1a23abb728d2be3534be91fb8f23fea6b75eaf02..2f946fbabfb9b62f355dccf1345aa7afa107c52d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.4 1997/04/04 00:50:20 davem Exp $
+/* $Id: irq.h,v 1.6 1997/08/07 08:06:40 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -9,7 +9,31 @@
 
 #include <linux/linkage.h>
 
-#include <asm/system.h>     /* For NCPUS */
+/* Sparc64 extensions to the interrupt registry flags.  Mostly this is
+ * for passing along what bus type the device is on and also the true
+ * format of the dev_id cookie, see below.
+ */
+#define SA_BUSMASK     0x0f000
+#define SA_SBUS                0x01000
+#define SA_PCI         0x02000
+#define SA_FHC         0x03000
+#define SA_EBUS                0x04000
+#define SA_BUS(mask)   ((mask) & SA_BUSMASK)
+
+struct devid_cookie {
+       /* Caller specifies these. */
+       void            *real_dev_id;           /* What dev_id would usually contain. */
+       unsigned int    *imap;                  /* Anonymous IMAP register */
+       unsigned int    *iclr;                  /* Anonymous ICLR register */
+       int             pil;                    /* Anonymous PIL */
+       void            *bus_cookie;            /* SYSIO regs, PSYCHO regs, etc. */
+
+       /* Return values. */
+       unsigned int    ret_ino;
+       unsigned int    ret_pil;
+};
+
+#define SA_DCOOKIE     0x10000
 
 #define NR_IRQS    15
 
index 7e7aa0433e6ee231bd1784a59dae4cd10779f921..53745626eef976e7e0b8a18eebb733f54781916d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.17 1997/07/13 19:13:39 davem Exp $ */
+/* $Id: mmu_context.h,v 1.19 1997/08/07 02:54:08 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
 
 #ifndef __ASSEMBLY__
 
-#define destroy_context(mm)    do { } while(0)
-
 extern unsigned long tlb_context_cache;
 
 #define CTX_VERSION_SHIFT      PAGE_SHIFT
 #define CTX_VERSION_MASK       ((~0UL) << CTX_VERSION_SHIFT)
 #define CTX_FIRST_VERSION      ((1UL << CTX_VERSION_SHIFT) + 1UL)
 
-extern void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx);
+extern void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx);
 
-/* Initialize the context related info for a new mm_struct
+/* Initialize/destroy the context related info for a new mm_struct
  * instance.
  */
-#define init_new_context(mm)   get_new_mmu_context((mm), tlb_context_cache)
+#define init_new_context(mm)   ((mm)->context = NO_CONTEXT)
+#define destroy_context(mm)    ((mm)->context = NO_CONTEXT)
+
+#ifdef __SMP__
+#define LOCAL_FLUSH_PENDING(cpu)       \
+       ((cpu_data[(cpu)].last_tlbversion_seen ^ tlb_context_cache) & CTX_VERSION_MASK)
+#define DO_LOCAL_FLUSH(cpu)            do { __flush_tlb_all();                         \
+                                            cpu_data[cpu].last_tlbversion_seen =       \
+                                            tlb_context_cache & CTX_VERSION_MASK;      \
+                                       } while(0)
+#else
+#define LOCAL_FLUSH_PENDING(cpu)       0
+#define DO_LOCAL_FLUSH(cpu)            do { __flush_tlb_all(); } while(0)
+#endif
+
+extern void __flush_tlb_all(void);
 
 extern __inline__ void get_mmu_context(struct task_struct *tsk)
 {
@@ -32,11 +45,13 @@ extern __inline__ void get_mmu_context(struct task_struct *tsk)
        struct mm_struct *mm = tsk->mm;
 
        flushw_user();
+       if(LOCAL_FLUSH_PENDING(current->processor))
+               DO_LOCAL_FLUSH(current->processor);
        if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD)       &&
           !(tsk->flags & PF_EXITING)) {
                unsigned long ctx = tlb_context_cache;
                if((mm->context ^ ctx) & CTX_VERSION_MASK)
-                       get_new_mmu_context(mm, ctx);
+                       get_new_mmu_context(mm, &tlb_context_cache);
 
                /* Don't worry, set_fs() will restore it... */
                tsk->tss.ctx = (tsk->tss.current_ds ?
index 92fddcbf92c433721537890c627600d83ba6a360..7ae72856e61338beeb46f7c52674f02d396c4788 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.4 1997/03/24 06:42:08 davem Exp $ */
+/* $Id: openprom.h,v 1.5 1997/08/15 06:44:51 davem Exp $ */
 #ifndef __SPARC64_OPENPROM_H
 #define __SPARC64_OPENPROM_H
 
@@ -210,6 +210,28 @@ struct linux_prom_ranges {
        unsigned int or_size;
 };
 
+/* Ranges and reg properties are a bit different for PCI. */
+struct linux_prom_pci_registers {
+       unsigned int phys_hi;
+       unsigned int phys_mid;
+       unsigned int phys_lo;
+
+       unsigned int size_hi;
+       unsigned int size_lo;
+};
+
+struct linux_prom_pci_ranges {
+       unsigned int child_phys_hi;     /* Only certain bits are encoded here. */
+       unsigned int child_phys_mid;
+       unsigned int child_phys_lo;
+
+       unsigned int parent_phys_hi;
+       unsigned int parent_phys_lo;
+
+       unsigned int size_hi;
+       unsigned int size_lo;
+};
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_OPENPROM_H) */
index d39d3d4942de6e684a3f9b044d2aa7b81ade472e..a4e8e5a8f2dbcb6ccd14bfddbf6c27671f0f16b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.14 1997/06/26 22:32:03 davem Exp $ */
+/* $Id: page.h,v 1.15 1997/08/09 04:56:54 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -82,13 +82,11 @@ typedef unsigned long iopgprot_t;
 
 #endif /* (STRICT_MM_TYPECHECKS) */
 
-#endif /* !(__ASSEMBLY__) */
+#define TASK_UNMAPPED_BASE     ((current->tss.flags & SPARC_FLAG_32BIT) ? \
+                                (0x0000000070000000UL) : \
+                                (0x0000030000000000UL))
 
-#ifndef __ASSEMBLY__
-#define TASK_UNMAPPED_BASE     0x0000000070000000UL
-#else
-#define TASK_UNMAPPED_BASE     0x0000000070000000
-#endif
+#endif /* !(__ASSEMBLY__) */
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
new file mode 100644 (file)
index 0000000..bbd6c2e
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: pbm.h,v 1.4 1997/08/15 06:44:52 davem Exp $
+ * pbm.h: U2P PCI bus module pseudo driver software state.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_PBM_H
+#define __SPARC64_PBM_H
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/psycho.h>
+#include <asm/oplib.h>
+
+struct linux_psycho;
+
+struct linux_pbm_info {
+       struct linux_psycho             *parent;
+       unsigned long                   *pbm_IO;
+       unsigned long                   *pbm_mem;
+       int                             prom_node;
+       char                            prom_name[64];
+       struct linux_prom_pci_ranges    pbm_ranges[PROMREG_MAX];
+       int                             num_pbm_ranges;
+
+       /* Now things for the actual PCI bus probes. */
+       unsigned int                    pci_first_busno;
+       unsigned int                    pci_last_busno;
+       struct pci_bus                  pci_bus;
+};
+
+struct linux_psycho {
+       struct linux_psycho             *next;
+       struct psycho_regs              *psycho_regs;
+       unsigned long                   *pci_config_space;
+       unsigned long                   *pci_IO_space;
+       unsigned long                   *pci_mem_space;
+       u32                             upa_portid;
+       struct linux_pbm_info           pbm_A;
+       struct linux_pbm_info           pbm_B;
+};
+
+extern struct linux_psycho *psycho_root;
+
+#endif /* !(__SPARC64_PBM_H) */
index 5d31b3bf5cdf00150438510b434036317a3c109d..d5897798125f04334c5f8e3194c86934eda8e1d2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
+/* $Id: pgtable.h,v 1.57 1997/08/13 04:44:20 paulus Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -159,12 +159,13 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 /* Cache and TLB flush operations. */
 
 /* These are the same regardless of whether this is an SMP kernel or not. */
-#define flush_cache_mm(mm)                     do { } while(0)
-#define flush_cache_range(mm, start, end)      do { } while(0)
-#define flush_cache_page(vma, page)            do { } while(0)
+#define flush_cache_mm(mm)                     flushw_user()
+#define flush_cache_range(mm, start, end)      flushw_user()
+#define flush_cache_page(vma, page)            flushw_user()
 
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_page_to_ram(page)                        do { } while (0)
+#define flush_icache_range(start, end)         do { } while (0)
 
 extern void __flush_cache_all(void);
 
@@ -207,7 +208,7 @@ extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
 extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                                unsigned long end);
-extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
 
 #define flush_cache_all()      smp_flush_cache_all()
 #define flush_tlb_all()                smp_flush_tlb_all()
@@ -230,7 +231,7 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT)
-               smp_flush_tlb_page(vma, page);
+               smp_flush_tlb_page(mm, page & PAGE_MASK);
 }
 
 #endif
@@ -259,18 +260,21 @@ extern inline unsigned long pmd_page(pmd_t pmd)
 extern inline unsigned long pgd_page(pgd_t pgd)
 { return (unsigned long) __va(pgd_val(pgd)); }
 
+#define PMD_NONE_MAGIC         0x80
+#define PGD_NONE_MAGIC         0x40
+
 extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_PRESENT; }
 extern inline void pte_clear(pte_t *pte)       { pte_val(*pte) = 0; }
 
-extern inline int pmd_none(pmd_t pmd)          { return pmd_val(pmd)==null_pte_table; }
-extern inline int pmd_bad(pmd_t pmd)           { return (pmd_val(pmd) & ~PAGE_MASK); }
-extern inline int pmd_present(pmd_t pmd)       { return pmd_val(pmd)!=null_pte_table; }
+extern inline int pmd_none(pmd_t pmd)          { return pmd_val(pmd)&PMD_NONE_MAGIC; }
+extern inline int pmd_bad(pmd_t pmd)           { return 0; }
+extern inline int pmd_present(pmd_t pmd)       { return !(pmd_val(pmd)&PMD_NONE_MAGIC);}
 extern inline void pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = null_pte_table; }
 
-extern inline int pgd_none(pgd_t pgd)          { return pgd_val(pgd)==null_pmd_table; }
-extern inline int pgd_bad(pgd_t pgd)           { return (pgd_val(pgd) & ~PAGE_MASK); }
-extern inline int pgd_present(pgd_t pgd)       { return pgd_val(pgd)!=null_pmd_table; }
+extern inline int pgd_none(pgd_t pgd)          { return pgd_val(pgd) & PGD_NONE_MAGIC; }
+extern inline int pgd_bad(pgd_t pgd)           { return 0; }
+extern inline int pgd_present(pgd_t pgd)       { return !(pgd_val(pgd)&PGD_NONE_MAGIC);}
 extern inline void pgd_clear(pgd_t *pgdp)      { pgd_val(*pgdp) = null_pmd_table; }
 
 /* The following only work if pte_present() is true.
@@ -332,148 +336,127 @@ extern inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
 extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
 { return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); }
 
-extern __inline__ void __init_pmd(pmd_t *pmdp)
+/* Very stupidly, we used to get new pgd's and pmd's, init their contents
+ * to point to the NULL versions of the next level page table, later on
+ * completely re-init them the same way, then free them up.  This wasted
+ * a lot of work and caused unnecessary memory traffic.  How broken...
+ * We fix this by caching them.
+ */
+
+#ifdef __SMP__
+/* Sliiiicck */
+#define pgd_quicklist          (cpu_data[smp_processor_id()].pgd_cache)
+#define pmd_quicklist          (cpu_data[smp_processor_id()].pmd_cache)
+#define pte_quicklist          (cpu_data[smp_processor_id()].pte_cache)
+#define pgtable_cache_size     (cpu_data[smp_processor_id()].pgcache_size)
+#else
+extern unsigned long *pgd_quicklist;
+extern unsigned long *pmd_quicklist;
+extern unsigned long *pte_quicklist;
+extern unsigned long pgtable_cache_size;
+#endif
+
+extern pgd_t *get_pgd_slow(void);
+
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-       extern void __bfill64(void *, unsigned long *);
-       
-       __bfill64((void *)pmdp, &null_pte_table);
+       pgd_t *ret;
+
+       if((ret = (pgd_t *)pgd_quicklist) != NULL) {
+               pgd_quicklist = (unsigned long *)pgd_val(*ret);
+               pgd_val(ret[0]) = pgd_val(ret[1]);
+               (pgtable_cache_size)--;
+       } else
+               ret = get_pgd_slow();
+       return ret;
 }
 
-/* Turning this off makes things much faster, but eliminates some
- * sanity checking as well.
- */
-/* #define PGTABLE_SANITY_CHECKS */
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+       pgd_val(*pgd) = (unsigned long) pgd_quicklist;
+       pgd_quicklist = (unsigned long *) pgd;
+       (pgtable_cache_size)++;
+}
 
-/* Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on supervisor
- * bits if any.
- */
-extern inline void pte_free_kernel(pte_t *pte)
-{ free_page((unsigned long)pte); }
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
 
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-       if (pmd_none(*pmd)) {
-               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_set(pmd, page);
-                               return page + address;
-                       }
-                       pmd_set(pmd, BAD_PTE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-#ifdef PGTABLE_SANITY_CHECKS
-       if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, BAD_PTE);
-               return NULL;
+       pmd_t *ret;
+
+       if((ret = (pmd_t *)pmd_quicklist) != NULL) {
+               pmd_quicklist = (unsigned long *)pmd_val(*ret);
+               pmd_val(ret[0]) = pmd_val(ret[1]);
+               (pgtable_cache_size)--;
        }
-#endif
-       return (pte_t *) pmd_page(*pmd) + address;
+       return ret;
 }
 
-extern inline void pmd_free_kernel(pmd_t *pmd)
-{ free_page((unsigned long) pmd); }
+extern __inline__ void free_pmd_fast(pgd_t *pmd)
+{
+       pmd_val(*pmd) = (unsigned long) pmd_quicklist;
+       pmd_quicklist = (unsigned long *) pmd;
+       (pgtable_cache_size)++;
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern __inline__ pte_t *get_pte_fast(void)
 {
-       address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-       if (pgd_none(*pgd)) {
-               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (pgd_none(*pgd)) {
-                       if (page) {
-                               __init_pmd(page);
-                               pgd_set(pgd, page);
-                               return page + address;
-                       }
-                       pgd_set(pgd, BAD_PMD);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-#ifdef PGTABLE_SANITY_CHECKS
-       if (pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-               pgd_set(pgd, BAD_PMD);
-               return NULL;
+       pte_t *ret;
+
+       if((ret = (pte_t *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)pte_val(*ret);
+               pte_val(ret[0]) = pte_val(ret[1]);
+               (pgtable_cache_size)--;
        }
-#endif
-       return (pmd_t *) pgd_page(*pgd) + address;
+       return ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+       pte_val(*pte) = (unsigned long) pte_quicklist;
+       pte_quicklist = (unsigned long *) pte;
+       (pgtable_cache_size)++;
 }
 
-extern inline void pte_free(pte_t * pte)
-{ free_page((unsigned long)pte); }
+#define pte_free_kernel(pte)   free_pte_fast(pte)
+#define pte_free(pte)          free_pte_fast(pte)
+#define pmd_free_kernel(pmd)   free_pmd_fast(pmd)
+#define pmd_free(pmd)          free_pmd_fast(pmd)
+#define pgd_free(pgd)          free_pgd_fast(pgd)
+#define pgd_alloc()            get_pgd_fast()
 
 extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
        if (pmd_none(*pmd)) {
-               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_set(pmd, page);
-                               return page + address;
-                       }
-                       pmd_set(pmd, BAD_PTE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-#ifdef PGTABLE_SANITY_CHECKS
-       if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, BAD_PTE);
-               return NULL;
+               pte_t *page = get_pte_fast();
+
+               if (!page)
+                       return get_pte_slow(pmd, address);
+               pmd_set(pmd, page);
+               return page + address;
        }
-#endif
        return (pte_t *) pmd_page(*pmd) + address;
 }
 
-extern inline void pmd_free(pmd_t * pmd)
-{ free_page((unsigned long) pmd); }
-
 extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
 {
        address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
        if (pgd_none(*pgd)) {
-               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (pgd_none(*pgd)) {
-                       if (page) {
-                               __init_pmd(page);
-                               pgd_set(pgd, page);
-                               return page + address;
-                       }
-                       pgd_set(pgd, BAD_PMD);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-#ifdef PGTABLE_SANITY_CHECKS
-       if (pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-               pgd_set(pgd, BAD_PMD);
-               return NULL;
+               pmd_t *page = get_pmd_fast();
+
+               if (!page)
+                       return get_pmd_slow(pgd, address);
+               pgd_set(pgd, page);
+               return page + address;
        }
-#endif
        return (pmd_t *) pgd_page(*pgd) + address;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{ free_page((unsigned long)pgd); }
-
-extern inline pgd_t * pgd_alloc(void)
-{
-       extern void __bfill64(void *, unsigned long *);
-       pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
-       
-       if (pgd)
-               __bfill64((void *)pgd, &null_pmd_table);
-       return pgd;
-}
+#define pte_alloc_kernel(pmd, addr)    pte_alloc(pmd, addr)
+#define pmd_alloc_kernel(pgd, addr)    pmd_alloc(pgd, addr)
 
 extern pgd_t swapper_pg_dir[1024];
 
@@ -505,22 +488,18 @@ struct mmu_sglist {
 extern __u32 mmu_get_scsi_one(char *, unsigned long, struct linux_sbus *sbus);
 extern void  mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus);
 
+extern void mmu_release_scsi_one(u32 vaddr, unsigned long len,
+                                struct linux_sbus *sbus);
+extern void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus);
+
+#define NEED_DMA_SYNCHRONIZATION
+#define mmu_sync_dma(dma_addr, len, sbus_instance)     \
+       mmu_release_scsi_one((dma_addr), (len), (sbus_instance))
+
 /* These do nothing with the way I have things setup. */
-#define mmu_release_scsi_one(vaddr, len, sbus) do { } while(0)
-#define mmu_release_scsi_sgl(sg, sz, sbus)     do { } while(0)
 #define mmu_lockarea(vaddr, len)               (vaddr)
 #define mmu_unlockarea(vaddr, len)             do { } while(0)
-
-extern void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address,
-                              pte_t pte);
-
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
-       unsigned long address, pte_t pte)
-{
-       /* Find and fix bad virutal cache aliases. */
-       if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
-               fixup_dcache_alias(vma, address, pte);
-}
+#define update_mmu_cache(vma, address, pte)    do { } while(0)
 
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
diff --git a/include/asm-sparc64/psycho.h b/include/asm-sparc64/psycho.h
new file mode 100644 (file)
index 0000000..46bcd46
--- /dev/null
@@ -0,0 +1,350 @@
+/* $Id: psycho.h,v 1.2 1997/08/11 14:35:40 davem Exp $
+ * psycho.h: UltraSparc AX specific PCI definitions.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_PSYCHO_H
+#define __SPARC64_PSYCHO_H
+
+#include <linux/types.h>
+
+/* Ultra AX PSYCHO Register Set, one per controller probed. */
+struct psycho_regs {
+/*0x0000*/     u64     upa_id;         /* PSYCHO UPA Port ID Register  */
+/*0x0008*/     u64     upa_cfg;        /* PSYCHO UPA Config Register   */
+/*0x0010*/     u64     control;        /* PSYCHO Control Register      */
+/*0x0018*/     u64     __pad0;
+/*0x0020*/     u64     ecc_control;    /* ECC Control Register         */
+/*0x0028*/     u64     __pad1;
+
+               /* Uncorrectable Error Fault Registers */
+/*0x0030*/     u64     ue_afsr;        /* UE Async Fault Status        */
+/*0x0038*/     u64     ue_afar;        /* UE Async Fault Address       */
+
+               /* Correctable Error Fault Registers */
+/*0x0040*/     u64     ce_afsr;        /* CE Async Fault Status        */
+/*0x0048*/     u64     ce_afar;        /* CE Async Fault Address       */
+
+               u64     __pad2[0x16];
+
+               /* Performance Monitoring Registers */
+/*0x0100*/     u64     pmon_control;
+/*0x0108*/     u64     pmon_counter;
+
+               u64     __pad3[0x1e];
+
+               /* PCI Bus IOMMU lives here */
+/*0x0200*/     u64     iommu_control;  /* IOMMU Control                */
+/*0x0208*/     u64     iommu_tsbbase;  /* IOMMU TSB Base               */
+/*0x0210*/     u64     iommu_flush;    /* IOMMU Flush Register         */
+
+               u64     __pad4[0x13d];
+
+               /* Interrupt mapping/control registers */
+/*0x0c00*/     u64     imap_a_slot0;   /* PCI A Slot 0 Int Mapping */
+/*0x0c08*/     u64     imap_a_slot1;   /* PCI A Slot 1 Int Mapping */
+
+               u64     __pad5[0x2];
+
+/*0x0c20*/     u64     imap_b_slot0;   /* PCI B Slot 0 Int Mapping */
+/*0x0c28*/     u64     imap_b_slot1;   /* PCI B Slot 1 Int Mapping */
+/*0x0c30*/     u64     imap_b_slot2;   /* PCI B Slot 2 Int Mapping */
+/*0x0c38*/     u64     imap_b_slot3;   /* PCI B Slot 3 Int Mapping */
+
+               u64     __pad6[0x78];
+
+/*0x1000*/     u64     imap_scsi;      /* SCSI Int Mapping     */
+/*0x1008*/     u64     imap_eth;       /* Ethernet Int Mapping */
+/*0x1010*/     u64     imap_bpp;       /* Parallel Port Int Mapping */
+/*0x1018*/     u64     imap_au_rec;    /* Audio Record Int Mapping */
+/*0x1020*/     u64     imap_au_play;   /* Audio Playback Int Mapping */
+/*0x1028*/     u64     imap_pfail;     /* Power Fail Int Mapping */
+/*0x1030*/     u64     imap_kms;       /* Kbd/Mouse/Ser Int Mapping */
+/*0x1038*/     u64     imap_flpy;      /* Floppy Int Mapping    */
+/*0x1040*/     u64     imap_shw;       /* Spare HW Int Mapping */
+/*0x1048*/     u64     imap_kbd;       /* Kbd Only Int Mapping */
+/*0x1050*/     u64     imap_ms;        /* Mouse Only Int Mapping */
+/*0x1058*/     u64     imap_ser;       /* Serial Only Int Mapping */
+/*0x1060*/     u64     imap_tim0;      /* Timer 0 Int Mapping  */
+/*0x1068*/     u64     imap_tim1;      /* Timer 1 Int Mapping  */
+/*0x1070*/     u64     imap_ue;        /* UE Int Mapping       */
+/*0x1078*/     u64     imap_ce;        /* CE Int Mapping       */
+/*0x1080*/     u64     imap_a_err;     /* PCI A Err Int Mapping */
+/*0x1088*/     u64     imap_b_err;     /* PCI B Err Int Mapping */
+/*0x1090*/     u64     imap_pmgmt;     /* Power Mgmt Int Mapping */
+/*0x1098*/     u64     imap_gfx;       /* OB Graphics Int Mapping */
+/*0x10a0*/     u64     imap_eupa;      /* UPA Expansion Int Mapping */
+
+               u64     __pad7[0x6b];
+
+               /* Interrupt Clear Registers */
+/*0x1400*/     u64     iclr_a_slot0[4];        /* PCI A Slot 0 Clear Int Reg */
+/*0x1420*/     u64     iclr_a_slot1[4];        /* PCI A Slot 1 Clear Int Reg */
+
+               u64     __pad8[0x8];
+
+/*0x1480*/     u64     iclr_b_slot0[4];        /* PCI B Slot 0 Clear Int Reg */
+/*0x14a0*/     u64     iclr_b_slot1[4];        /* PCI B Slot 1 Clear Int Reg */
+/*0x14c0*/     u64     iclr_b_slot2[4];        /* PCI B Slot 2 Clear Int Reg */
+/*0x14e0*/     u64     iclr_b_slot3[4];        /* PCI B Slot 3 Clear Int Reg */
+
+               u64     __pad9[0x60];
+
+/*0x1800*/     u64     iclr_scsi;
+/*0x1808*/     u64     iclr_eth;
+/*0x1810*/     u64     iclr_bpp;
+/*0x1818*/     u64     iclr_au_rec;
+/*0x1820*/     u64     iclr_au_play;
+/*0x1828*/     u64     iclr_pfail;
+/*0x1830*/     u64     iclr_kms;
+/*0x1838*/     u64     iclr_flpy;
+/*0x1840*/     u64     iclr_shw;
+/*0x1848*/     u64     iclr_kbd;
+/*0x1850*/     u64     iclr_ms;
+/*0x1858*/     u64     iclr_ser;
+/*0x1860*/     u64     iclr_tim0;
+/*0x1868*/     u64     iclr_tim1;
+/*0x1870*/     u64     iclr_ue;
+/*0x1878*/     u64     iclr_ce;
+/*0x1880*/     u64     iclr_a_err;
+/*0x1888*/     u64     iclr_b_err;
+/*0x1890*/     u64     iclr_pmgmt;
+
+               u64     __pad10[0x2d];
+
+               /* Interrupt Retry Timer. */
+/*0x1a00*/     u64     irq_retry;
+
+               u64     __pad11[0x3f];
+
+               /* Counters/Timers */
+/*0x1c00*/     u64     tim0_cnt;
+/*0x1c08*/     u64     tim0_lim;
+/*0x1c10*/     u64     tim1_cnt;
+/*0x1c18*/     u64     tim1_lim;
+
+               u64     __pad12[0x7c];
+
+               /* PCI Bus A Registers */
+/*0x2000*/     u64     pci_a_control;  /* PCI Bus A Control Register   */
+/*0x2008*/     u64     __pad13;
+/*0x2010*/     u64     pci_a_afsr;     /* PCI Bus A Async Fault Status */
+/*0x2018*/     u64     pci_a_afar;     /* PCI Bus A Async Fault Address*/
+/*0x2020*/     u64     pci_a_diag;     /* PCI Bus A Diag Register      */
+
+               u64     __pad14[0xfb];
+
+               /* PCI Bus A/IOMMU Streaming Buffer Registers */
+/*0x2800*/     u64     sbuf_a_control; /* StrBuffer Control            */
+/*0x2808*/     u64     sbuf_a_pflush;  /* StrBuffer Page Flush         */
+/*0x2810*/     u64     sbuf_a_fsync;   /* StrBuffer Flush Sync Reg     */
+
+               u64     __pad15[0x2fd];
+
+               /* PCI Bus B Registers */
+/*0x4000*/     u64     pci_b_control;  /* PCI Bus B Control Register   */
+/*0x4008*/     u64     __pad16;
+/*0x4010*/     u64     pci_b_afsr;     /* PCI Bus B Async Fault Status */
+/*0x4018*/     u64     pci_b_afar;     /* PCI Bus B Async Fault Address*/
+/*0x4020*/     u64     pci_b_diag;     /* PCI Bus B Diag Register      */
+
+               u64     __pad17[0x7b];
+
+               /* IOMMU diagnostic things */
+/*0x4400*/     u64     iommu_vdiag;    /* VADDR Diagnostic Register    */
+/*0x4408*/     u64     iommu_tcompare; /* IOMMU TLB Tag Compare        */
+
+               u64     __pad18[0x7e];
+
+               /* PCI Bus B/IOMMU Streaming Buffer Registers */
+/*0x4800*/     u64     sbuf_b_control; /* StrBuffer Control            */
+/*0x4808*/     u64     sbuf_b_pflush;  /* StrBuffer Page Flush         */
+/*0x4810*/     u64     sbuf_b_fsync;   /* StrBuffer Flush Sync Reg     */
+
+               u64     __pad19[0xafd];
+
+               /* DMA Scoreboard Diagnostic Registers */
+/*0xa000*/     u64     dscore_reg0;    /* DMA Scoreboard Diag Reg 0    */
+/*0xa008*/     u64     dscore_reg1;    /* DMA Scoreboard Diag Reg 1    */
+
+               u64     __pad20[0x9e];
+
+               /* More IOMMU diagnostic things */
+/*0xa500*/     u64     iommu_lru[16];  /* IOMMU LRU Queue Diag         */
+/*0xa580*/     u64     iommu_tag[16];  /* IOMMU TLB Tag Diag           */
+/*0xa600*/     u64     iommu_data[16]; /* IOMMU TLB Data RAM Diag      */
+
+               u64     __pad21[0x30];
+
+               /* Interrupt State Diagnostics */
+/*0xa800*/     u64     pci_istate;
+/*0xa808*/     u64     obio_istate;
+
+               u64     __pad22[0xfe];
+
+               /* Streaming Buffer A Diagnostic Area */
+/*0xb000*/     u64     sbuf_a_data[128]; /* StrBuffer Data Ram Diag    */
+/*0xb400*/     u64     sbuf_a_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xb800*/     u64     sbuf_a_ptag[16]; /* StrBuffer Page Tag Diag     */
+/*0xb880*/     u64     __pad23[16];
+/*0xb900*/     u64     sbuf_a_ltag[16]; /* StrBuffer Line Tag Diag     */
+
+               u64     __pad24[0xd0];
+
+               /* Streaming Buffer B Diagnostic Area */
+/*0xc000*/     u64     sbuf_b_data[128]; /* StrBuffer Data Ram Diag    */
+/*0xc400*/     u64     sbuf_b_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xc800*/     u64     sbuf_b_ptag[16]; /* StrBuffer Page Tag Diag     */
+/*0xc880*/     u64     __pad25[16];
+/*0xc900*/     u64     sbuf_b_ltag[16]; /* StrBuffer Line Tag Diag     */
+};
+
+/* PSYCHO UPA Port ID */
+#define PSYCHO_UPPID_FESC      0xff00000000000000 /* FCode escape, 0xfc           */
+#define PSYCHO_UPPID_RESV1     0x00fffff800000000 /* Reserved                     */
+#define PSYCHO_UPPID_ENV       0x0000000400000000 /* Cannot generate ECC          */
+#define PSYCHO_UPPID_ORD       0x0000000200000000 /* One Outstanding Read         */
+#define PSYCHO_UPPID_RESV2     0x0000000180000000 /* Reserved                     */
+#define PSYCHO_UPPID_PDQ       0x000000007e000000 /* Data Queue size              */
+#define PSYCHO_UPPID_PRQ       0x0000000001e00000 /* Request Queue size           */
+#define PSYCHO_UPPID_UCAP      0x00000000001f0000 /* UPA Capabilities             */
+#define PSYCHO_UPPID_JEDEC     0x000000000000ffff /* JEDEC ID for PSYCHO          */
+
+/* PSYCHO UPA Configuration Register */
+#define PSYCHO_UPCFG_RESV      0xffffffffffffff00 /* Reserved                     */
+#define PSYCHO_UPCFG_SCIQ1     0x00000000000000f0 /* Unused, always zero          */
+#define PSYCHO_UPCFG_SCIQ2     0x000000000000000f /* Requests Queue size 0x2      */
+
+/* PSYCHO Control Register */
+#define PSYCHO_CONTROL_IMPL    0xf000000000000000 /* Implementation of this PSYCHO*/
+#define PSYCHO_CONTROL_VER     0x0f00000000000000 /* Version of this PSYCHO       */
+#define PSYCHO_CONTROL_MID     0x00f8000000000000 /* UPA Module ID of PSYCHO      */
+#define PSYCHO_CONTROL_IGN     0x0007c00000000000 /* Interrupt Group Number       */
+#define PSYCHO_CONTROL_RESV     0x00003ffffffffff0 /* Reserved                     */
+#define PSYCHO_CONTROL_APCKEN  0x0000000000000008 /* Address Parity Check Enable  */
+#define PSYCHO_CONTROL_APERR   0x0000000000000004 /* Incoming System Addr Parerr  */
+#define PSYCHO_CONTROL_IAP     0x0000000000000002 /* Invert UPA Parity            */
+#define PSYCHO_CONTROL_MODE    0x0000000000000001 /* PSYCHO clock mode            */
+
+/* PSYCHO ECC Control Register */
+#define PSYCHO_ECNTRL_ECCEN    0x8000000000000000 /* Enable ECC Checking          */
+#define PSYCHO_ECNTRL_UEEN     0x4000000000000000 /* Enable UE Interrupts         */
+#define PSYCHO_ECNTRL_CEEN     0x2000000000000000 /* Enable CE Interrupts         */
+
+/* Uncorrectable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_UEAFSR_PPIO     0x8000000000000000 /* Primary PIO is cause         */
+#define PSYCHO_UEAFSR_PDRD     0x4000000000000000 /* Primary DVMA read is cause   */
+#define PSYCHO_UEAFSR_PDWR     0x2000000000000000 /* Primary DVMA write is cause  */
+#define PSYCHO_UEAFSR_SPIO     0x1000000000000000 /* Secondary PIO is cause       */
+#define PSYCHO_UEAFSR_SDRD     0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_UEAFSR_SDWR     0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_UEAFSR_RESV1    0x03ff000000000000 /* Reserved                     */
+#define PSYCHO_UEAFSR_BMSK     0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_UEAFSR_DOFF     0x00000000e0000000 /* Doubleword Offset            */
+#define PSYCHO_UEAFSR_MID      0x000000001f000000 /* UPA MID causing the fault    */
+#define PSYCHO_UEAFSR_BLK      0x0000000000800000 /* Trans was block operation    */
+#define PSYCHO_UEAFSR_RESV2    0x00000000007fffff /* Reserved                     */
+
+/* Correctable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_CEAFSR_PPIO     0x8000000000000000 /* Primary PIO is cause         */
+#define PSYCHO_CEAFSR_PDRD     0x4000000000000000 /* Primary DVMA read is cause   */
+#define PSYCHO_CEAFSR_PDWR     0x2000000000000000 /* Primary DVMA write is cause  */
+#define PSYCHO_CEAFSR_SPIO     0x1000000000000000 /* Secondary PIO is cause       */
+#define PSYCHO_CEAFSR_SDRD     0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_CEAFSR_SDWR     0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_CEAFSR_RESV1    0x0300000000000000 /* Reserved                     */
+#define PSYCHO_CEAFSR_ESYND    0x00ff000000000000 /* Syndrome Bits                */
+#define PSYCHO_UEAFSR_SIZE     0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_CEAFSR_DOFF     0x00000000e0000000 /* Double Offset                */
+#define PSYCHO_CEAFSR_MID      0x000000001f000000 /* UPA MID causing the fault    */
+#define PSYCHO_CEAFSR_BLK      0x0000000000800000 /* Trans was block operation    */
+#define PSYCHO_CEAFSR_RESV2    0x00000000007fffff /* Reserved                     */
+
+/* DMA Scoreboard Diagnostic Register(s) */
+#define PSYCHO_DSCORE_VALID    0x8000000000000000 /* Entry is valid               */
+#define PSYCHO_DSCORE_C                0x4000000000000000 /* Transaction cacheable        */
+#define PSYCHO_DSCORE_READ     0x2000000000000000 /* Transaction was a read       */
+#define PSYCHO_DSCORE_TAG      0x1f00000000000000 /* Transaction ID               */
+#define PSYCHO_DSCORE_ADDR     0x00fffffffff80000 /* Transaction PADDR            */
+#define PSYCHO_DSCORE_BMSK     0x000000000007fff8 /* Bytemask of pending transfer */
+#define PSYCHO_DSCORE_SRC      0x0000000000000007 /* Transaction source           */
+
+/* PSYCHO PCI Control Register */
+#define PSYCHO_PCICTRL_RESV1   0xfffffff000000000 /* Reserved                     */
+#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error    */
+#define PSYCHO_PCICTRL_SERR    0x0000000400000000 /* SERR signal asserted         */
+#define PSYCHO_PCICTRL_SPEED   0x0000000200000000 /* PCI speed (1 is U2P clock)   */
+#define PSYCHO_PCICTRL_RESV2   0x00000001ffc00000 /* Reserved                     */
+#define PSYCHO_PCICTRL_ARB_PARK        0x0000000000200000 /* PCI arbitration parking      */
+#define PSYCHO_PCICTRL_RESV3   0x00000000001ff800 /* Reserved                     */
+#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */
+#define PSYCHO_PCICTRL_WEN     0x0000000000000200 /* Power Mgmt Wake Enable       */
+#define PSYCHO_PCICTRL_EEN     0x0000000000000100 /* PCI Error Interrupt Enable   */
+#define PSYCHO_PCICTRL_RESV4   0x00000000000000c0 /* Reserved                     */
+#define PSYCHO_PCICTRL_AEN     0x000000000000003f /* PCI DVMA Arbitration Enable  */
+
+/* PSYCHO PCI AFSR, AFAR holds low 40 bits of physical address causing the fault. */
+#define PSYCHO_PCIAFSR_PMA     0x8000000000000000 /* Primary Master Abort Error   */
+#define PSYCHO_PCIAFSR_PTA     0x4000000000000000 /* Primary Target Abort Error   */
+#define PSYCHO_PCIAFSR_PRTRY   0x2000000000000000 /* Primary Excessive Retries    */
+#define PSYCHO_PCIAFSR_PPERR   0x1000000000000000 /* Primary Parity Error         */
+#define PSYCHO_PCIAFSR_SMA     0x0800000000000000 /* Secondary Master Abort Error */
+#define PSYCHO_PCIAFSR_STA     0x0400000000000000 /* Secondary Target Abort Error */
+#define PSYCHO_PCIAFSR_SRTRY   0x0200000000000000 /* Secondary Excessive Retries  */
+#define PSYCHO_PCIAFSR_SPERR   0x0100000000000000 /* Secondary Parity Error       */
+#define PSYCHO_PCIAFSR_RESV1   0x00ff000000000000 /* Reserved                     */
+#define PSYCHO_PCIAFSR_SIZE    0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_PCIAFSR_BLK     0x0000000080000000 /* Trans was block operation    */
+#define PSYCHO_PCIAFSR_RESV2   0x0000000040000000 /* Reserved                     */
+#define PSYCHO_PCIAFSR_MID     0x000000003e000000 /* MID causing the error        */
+#define PSYCHO_PCIAFSR_RESV3   0x0000000001ffffff /* Reserved                     */
+
+/* IOMMU things defined fully in asm-sparc64/iommu.h */
+
+/* Streaming Buffer Control Register */
+#define PSYCHO_SBUFCTRL_RESV   0xffffffffffffff80 /* Reserved                     */
+#define PSYCHO_SBUFCTRL_LRU_LP 0x0000000000000070 /* LRU Lock Pointer             */
+#define PSYCHO_SBUFCTRL_LRU_LE 0x0000000000000008 /* LRU Lock Enable              */
+#define PSYCHO_SBUFCTRL_RR_DIS 0x0000000000000004 /* Rerun Disable                */
+#define PSYCHO_SBUFCTRL_DE     0x0000000000000002 /* Diag Mode Enable             */
+#define PSYCHO_SBUFCTRL_SB_EN  0x0000000000000001 /* Streaming Buffer Enable      */
+
+/* Streaming Buffer Page Invalidate/Flush Register */
+#define PSYCHO_SBUFFLUSH_ADDR  0x00000000ffffe000 /* DVMA Page to be flushed      */
+#define PSYCHO_SBUFFLUSH_RESV  0x0000000000001fff /* Ignored bits                 */
+
+/* Streaming Buffer Flush Synchronization Register */
+#define PSYCHO_SBUFSYNC_ADDR   0x000001ffffffffc0 /* Physical address to update   */
+#define PSYCHO_SBUFSYNC_RESV   0x000000000000003f /* Ignored bits                 */
+
+/* PSYCHO Interrupt mapping register(s). */
+#define PSYCHO_IMAP_RESV1      0xffffffff00000000 /* Reserved                     */
+#define PSYCHO_IMAP_VALID      0x0000000080000000 /* This enables delivery.       */
+#define PSYCHO_IMAP_TID                0x000000007c000000 /* Target ID (MID to send it to)*/
+#define PSYCHO_IMAP_RESV2      0x0000000003fff800 /* Reserved                     */
+#define PSYCHO_IMAP_IGN                0x00000000000007c0 /* Interrupt Group Number.      */
+#define PSYCHO_IMAP_INO                0x000000000000003f /* Interrupt Number Offset.     */
+#define PSYCHO_IMAP_INR                0x00000000000007ff /* Interrupt # (Gfx/UPA_slave)  */
+
+/* PSYCHO Interrupt clear pseudo register(s). */
+#define PSYCHO_ICLR_RESV1      0xfffffffffffffff0 /* Reserved                     */
+#define PSYCHO_ICLR_IDLE       0x0000000000000000 /* Transition to idle state.    */
+#define PSYCHO_ICLR_TRANSMIT   0x0000000000000001 /* Transition to transmit state */
+#define PSYCHO_ICLR_RESV2      0x0000000000000002 /* Reserved.                    */
+#define PSYCHO_ICLR_PENDING    0x0000000000000003 /* Transition to pending state. */
+
+/* PSYCHO Interrupt Retry Timer register. */
+#define PSYCHO_IRETRY_LIMIT    0x00000000000fffff /* The retry interval.          */
+
+/* PSYCHO Interrupt State registers. XXX fields to be documented later */
+
+/* PSYCHO Counter register. XXX fields to be documented later */
+
+/* PSYCHO Limit register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Control register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Counter register. XXX fields to be documented later */
+
+#endif /* !(__SPARC64_PSYCHO_H) */
diff --git a/include/asm-sparc64/sab82532.h b/include/asm-sparc64/sab82532.h
new file mode 100644 (file)
index 0000000..81a1ac1
--- /dev/null
@@ -0,0 +1,371 @@
+/* $Id: sab82532.h,v 1.2 1997/08/12 04:13:15 ecd Exp $
+ * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _SPARC64_SAB82532_H
+#define _SPARC64_SAB82532_H
+
+#include <linux/types.h>
+#include <linux/serial.h>
+
+struct sab82532_async_rd_regs {
+       u8      rfifo[0x20];    /* Receive FIFO                         */
+       u8      star;           /* Status Register                      */
+       u8      __pad1;
+       u8      mode;           /* Mode Register                        */
+       u8      timr;           /* Timer Register                       */
+       u8      xon;            /* XON Character                        */
+       u8      xoff;           /* XOFF Character                       */
+       u8      tcr;            /* Termination Character Register       */
+       u8      dafo;           /* Data Format                          */
+       u8      rfc;            /* RFIFO Control Register               */
+       u8      __pad2;
+       u8      rbcl;           /* Receive Byte Count Low               */
+       u8      rbch;           /* Receive Byte Count High              */
+       u8      ccr0;           /* Channel Configuration Register 0     */
+       u8      ccr1;           /* Channel Configuration Register 1     */
+       u8      ccr2;           /* Channel Configuration Register 2     */
+       u8      ccr3;           /* Channel Configuration Register 3     */
+       u8      __pad3[4];
+       u8      vstr;           /* Version Status Register              */
+       u8      __pad4[3];
+       u8      gis;            /* Global Interrupt Status              */
+       u8      ipc;            /* Interrupt Port Configuration         */
+       u8      isr0;           /* Interrupt Status 0                   */
+       u8      isr1;           /* Interrupt Status 1                   */
+       u8      pvr;            /* Port Value Register                  */
+       u8      pis;            /* Port Interrupt Status                */
+       u8      pcr;            /* Port Configuration Register          */
+       u8      ccr4;           /* Channel Configuration Register 4     */
+};
+
+struct sab82532_async_wr_regs {
+       u8      xfifo[0x20];    /* Transmit FIFO                        */
+       u8      cmdr;           /* Command Register                     */
+       u8      __pad1;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad2;
+       u8      xbcl;           /* Transmit Byte Count Low              */
+       u8      xbch;           /* Transmit Byte Count High             */
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      tsax;           /* Time-Slot Assignment Reg. Transmit   */
+       u8      tsar;           /* Time-Slot Assignment Reg. Receive    */
+       u8      xccr;           /* Transmit Channel Capacity Register   */
+       u8      rccr;           /* Receive Channel Capacity Register    */
+       u8      bgr;            /* Baud Rate Generator Register         */
+       u8      tic;            /* Transmit Immediate Character         */
+       u8      mxn;            /* Mask XON Character                   */
+       u8      mxf;            /* Mask XOFF Character                  */
+       u8      iva;            /* Interrupt Vector Address             */
+       u8      ipc;
+       u8      imr0;           /* Interrupt Mask Register 0            */
+       u8      imr1;           /* Interrupt Mask Register 1            */
+       u8      pvr;
+       u8      pim;            /* Port Interrupt Mask                  */
+       u8      pcr;
+       u8      ccr4;
+};
+
+struct sab82532_async_rw_regs {        /* Read/Write registers                 */
+       u8      __pad1[0x20];
+       u8      __pad2;
+       u8      __pad3;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad4;
+       u8      __pad5;
+       u8      __pad6;
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      __pad7;
+       u8      __pad8;
+       u8      __pad9;
+       u8      __pad10;
+       u8      __pad11;
+       u8      __pad12;
+       u8      __pad13;
+       u8      __pad14;
+       u8      __pad15;
+       u8      ipc;
+       u8      __pad16;
+       u8      __pad17;
+       u8      pvr;
+       u8      __pad18;
+       u8      pcr;
+       u8      ccr4;
+};
+
+union sab82532_async_regs {
+       __volatile__ struct sab82532_async_rd_regs      r;
+       __volatile__ struct sab82532_async_wr_regs      w;
+       __volatile__ struct sab82532_async_rw_regs      rw;
+};
+
+#define NR_PORTS                        2
+
+union sab82532_irq_status {
+       unsigned long                    stat;
+       struct {
+               unsigned char            isr0;
+               unsigned char            isr1;
+               unsigned char            ddsr;
+       } sreg;
+};
+
+struct sab82532 {
+       int                              magic;
+       int                              baud_base;
+       union sab82532_async_regs       *regs;
+       int                              irq;
+       int                              flags;         /* defined in tty.h */
+       int                              type;          /* SAB82532 version */
+       struct tty_struct               *tty;
+       int                              read_status_mask;
+       int                              ignore_status_mask;
+       int                              timeout;
+       int                              xmit_fifo_size;
+       int                              custom_divisor;
+       int                              quot;
+       int                              x_char;
+       int                              close_delay;
+       unsigned short                   closing_wait;
+       unsigned short                   closing_wait2;
+       int                              all_sent;
+       int                              is_console;
+       unsigned char                    interrupt_mask0;
+       unsigned char                    interrupt_mask1;
+       unsigned char                    pvr_dtr_bit;
+       unsigned char                    pvr_dsr_bit;
+       unsigned long                    event;
+       unsigned long                    last_active;
+       int                              line;
+       int                              count;
+       int                              blocked_open;
+       long                             session;
+       long                             pgrp;
+       unsigned char                   *xmit_buf;
+       int                              xmit_head;
+       int                              xmit_tail;
+       int                              xmit_cnt;
+       struct tq_struct                 tqueue;
+       struct tq_struct                 tqueue_hangup;
+       struct async_icount              icount;
+       struct termios                   normal_termios;
+       struct termios                   callout_termios;
+       struct wait_queue               *open_wait;
+       struct wait_queue               *close_wait;
+       struct wait_queue               *delta_msr_wait;
+       struct sab82532                 *next;
+       struct sab82532                 *prev;
+};
+
+
+/* RFIFO Status Byte */
+#define SAB82532_RSTAT_PE              0x80
+#define SAB82532_RSTAT_FE              0x40
+#define SAB82532_RSTAT_PARITY          0x01
+
+/* Status Register (STAR) */
+#define SAB82532_STAR_XDOV             0x80
+#define SAB82532_STAR_XFW              0x40
+#define SAB82532_STAR_RFNE             0x20
+#define SAB82532_STAR_FCS              0x10
+#define SAB82532_STAR_TEC              0x08
+#define SAB82532_STAR_CEC              0x04
+#define SAB82532_STAR_CTS              0x02
+
+/* Command Register (CMDR) */
+#define SAB82532_CMDR_RMC              0x80
+#define SAB82532_CMDR_RRES             0x40
+#define SAB82532_CMDR_RFRD             0x20
+#define SAB82532_CMDR_STI              0x10
+#define SAB82532_CMDR_XF               0x08
+#define SAB82532_CMDR_XRES             0x01
+
+/* Mode Register (MODE) */
+#define SAB82532_MODE_FRTS             0x40
+#define SAB82532_MODE_FCTS             0x20
+#define SAB82532_MODE_FLON             0x10
+#define SAB82532_MODE_RAC              0x08
+#define SAB82532_MODE_RTS              0x04
+#define SAB82532_MODE_TRS              0x02
+#define SAB82532_MODE_TLP              0x01
+
+/* Timer Register (TIMR) */
+#define SAB82532_TIMR_CNT_MASK         0xe0
+#define SAB82532_TIMR_VALUE_MASK       0x1f
+
+/* Data Format (DAFO) */
+#define SAB82532_DAFO_XBRK             0x40
+#define SAB82532_DAFO_STOP             0x20
+#define SAB82532_DAFO_PAR_SPACE                0x00
+#define SAB82532_DAFO_PAR_ODD          0x08
+#define SAB82532_DAFO_PAR_EVEN         0x10
+#define SAB82532_DAFO_PAR_MARK         0x18
+#define SAB82532_DAFO_PARE             0x04
+#define SAB82532_DAFO_CHL8             0x00
+#define SAB82532_DAFO_CHL7             0x01
+#define SAB82532_DAFO_CHL6             0x02
+#define SAB82532_DAFO_CHL5             0x03
+
+/* RFIFO Control Register (RFC) */
+#define SAB82532_RFC_DPS               0x40
+#define SAB82532_RFC_DXS               0x20
+#define SAB82532_RFC_RFDF              0x10
+#define SAB82532_RFC_RFTH_1            0x00
+#define SAB82532_RFC_RFTH_4            0x04
+#define SAB82532_RFC_RFTH_16           0x08
+#define SAB82532_RFC_RFTH_32           0x0c
+#define SAB82532_RFC_TCDE              0x01
+
+/* Received Byte Count High (RBCH) */
+#define SAB82532_RBCH_DMA              0x80
+#define SAB82532_RBCH_CAS              0x20
+
+/* Transmit Byte Count High (XBCH) */
+#define SAB82532_XBCH_DMA              0x80
+#define SAB82532_XBCH_CAS              0x20
+#define SAB82532_XBCH_XC               0x10
+
+/* Channel Configuration Register 0 (CCR0) */
+#define SAB82532_CCR0_PU               0x80
+#define SAB82532_CCR0_MCE              0x40
+#define SAB82532_CCR0_SC_NRZ           0x00
+#define SAB82532_CCR0_SC_NRZI          0x08
+#define SAB82532_CCR0_SC_FM0           0x10
+#define SAB82532_CCR0_SC_FM1           0x14
+#define SAB82532_CCR0_SC_MANCH         0x18
+#define SAB82532_CCR0_SM_HDLC          0x00
+#define SAB82532_CCR0_SM_SDLC_LOOP     0x01
+#define SAB82532_CCR0_SM_BISYNC                0x02
+#define SAB82532_CCR0_SM_ASYNC         0x03
+
+/* Channel Configuration Register 1 (CCR1) */
+#define SAB82532_CCR1_ODS              0x10
+#define SAB82532_CCR1_BCR              0x08
+#define SAB82532_CCR1_CM_MASK          0x07
+
+/* Channel Configuration Register 2 (CCR2) */
+#define SAB82532_CCR2_SOC1             0x80
+#define SAB82532_CCR2_SOC0             0x40
+#define SAB82532_CCR2_BR9              0x80
+#define SAB82532_CCR2_BR8              0x40
+#define SAB82532_CCR2_BDF              0x20
+#define SAB82532_CCR2_SSEL             0x10
+#define SAB82532_CCR2_XCS0             0x20
+#define SAB82532_CCR2_RCS0             0x10
+#define SAB82532_CCR2_TOE              0x08
+#define SAB82532_CCR2_RWX              0x04
+#define SAB82532_CCR2_DIV              0x01
+
+/* Channel Configuration Register 3 (CCR3) */
+#define SAB82532_CCR3_PSD              0x01
+
+/* Time Slot Assignment Register Transmit (TSAX) */
+#define SAB82532_TSAX_TSNX_MASK                0xfc
+#define SAB82532_TSAX_XCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAX_XCS1             0x01
+
+/* Time Slot Assignment Register Receive (TSAR) */
+#define SAB82532_TSAR_TSNR_MASK                0xfc
+#define SAB82532_TSAR_RCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAR_RCS1             0x01
+
+/* Version Status Register (VSTR) */
+#define SAB82532_VSTR_CD               0x80
+#define SAB82532_VSTR_DPLA             0x40
+#define SAB82532_VSTR_VN_MASK          0x0f
+#define SAB82532_VSTR_VN_1             0x00
+#define SAB82532_VSTR_VN_2             0x01
+#define SAB82532_VSTR_VN_3_2           0x02
+
+/* Global Interrupt Status Register (GIS) */
+#define SAB82532_GIS_PI                        0x80
+#define SAB82532_GIS_ISA1              0x08
+#define SAB82532_GIS_ISA0              0x04
+#define SAB82532_GIS_ISB1              0x02
+#define SAB82532_GIS_ISB0              0x01
+
+/* Interrupt Vector Address (IVA) */
+#define SAB82532_IVA_MASK              0xf1
+
+/* Interrupt Port Configuration (IPC) */
+#define SAB82532_IPC_VIS               0x80
+#define SAB82532_IPC_SLA1              0x10
+#define SAB82532_IPC_SLA0              0x08
+#define SAB82532_IPC_CASM              0x04
+#define SAB82532_IPC_IC_OPEN_DRAIN     0x00
+#define SAB82532_IPC_IC_ACT_LOW                0x01
+#define SAB82532_IPC_IC_ACT_HIGH       0x03
+
+/* Interrupt Status Register 0 (ISR0) */
+#define SAB82532_ISR0_TCD              0x80
+#define SAB82532_ISR0_TIME             0x40
+#define SAB82532_ISR0_PERR             0x20
+#define SAB82532_ISR0_FERR             0x10
+#define SAB82532_ISR0_PLLA             0x08
+#define SAB82532_ISR0_CDSC             0x04
+#define SAB82532_ISR0_RFO              0x02
+#define SAB82532_ISR0_RPF              0x01
+
+/* Interrupt Status Register 1 (ISR1) */
+#define SAB82532_ISR1_BRK              0x80
+#define SAB82532_ISR1_BRKT             0x40
+#define SAB82532_ISR1_ALLS             0x20
+#define SAB82532_ISR1_XOFF             0x10
+#define SAB82532_ISR1_TIN              0x08
+#define SAB82532_ISR1_CSC              0x04
+#define SAB82532_ISR1_XON              0x02
+#define SAB82532_ISR1_XPR              0x01
+
+/* Interrupt Mask Register 0 (IMR0) */
+#define SAB82532_IMR0_TCD              0x80
+#define SAB82532_IMR0_PERR             0x20
+#define SAB82532_IMR0_SCD              0x10
+#define SAB82532_IMR0_PLLA             0x08
+#define SAB82532_IMR0_CDSC             0x04
+#define SAB82532_IMR0_RFO              0x02
+#define SAB82532_IMR0_RPF              0x01
+#define SAB82532_IMR0_OR_ME_IN         0x40
+
+/* Interrupt Mask Register 1 (IMR1) */
+#define SAB82532_IMR1_ALLS             0x20
+#define SAB82532_IMR1_XDU              0x10
+#define SAB82532_IMR1_TIN              0x08
+#define SAB82532_IMR1_CSC              0x04
+#define SAB82532_IMR1_XMR              0x02
+#define SAB82532_IMR1_XPR              0x01
+#define SAB82532_IMR1_OR_ME_IN         0xc0
+
+/* Port Interrupt Status Register (PIS) */
+#define SAB82532_PIS_SYNC_B            0x08
+#define SAB82532_PIS_DTR_B             0x04
+#define SAB82532_PIS_DTR_A             0x02
+#define SAB82532_PIS_SYNC_A            0x01
+
+/* Channel Configuration Register 4 (CCR4) */
+#define SAB82532_CCR4_MCK4             0x80
+#define SAB82532_CCR4_EBRG             0x40
+#define SAB82532_CCR4_TST1             0x20
+#define SAB82532_CCR4_ICD              0x10
+
+
+#endif /* !(_SPARC64_SAB82532_H) */
index 3fb21e06eee1dcb52f8ab87298e7385f068e39f5..2c89a84ba5d909b9a1bc9c953c7cfc4cca7178bb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.3 1997/03/21 17:57:24 jj Exp $
+/* $Id: sbus.h,v 1.5 1997/08/12 04:13:16 ecd Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -87,9 +87,7 @@ extern struct linux_sbus *SBus_chain;
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-       for((bus) = SBus_chain, (device) = (bus)->devices; (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
-
-/* XXX This is promlib stuff, what is it doing here? XXX */
+       for((bus) = SBus_chain, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
 
 /* Apply promlib probed SBUS ranges to registers. */
 extern void prom_apply_sbus_ranges(struct linux_sbus *sbus, 
index 297173a89528a35ffeb6d6f4a9e63fee0f321804..4a5912bb9ff0e7caf54e2d31cf407ac24587020c 100644 (file)
@@ -38,20 +38,28 @@ extern void __up(struct semaphore * sem);
 
 extern __inline__ void down(struct semaphore * sem)
 {
-       if (atomic_dec_return(&sem->count) < 0)
+       int result;
+
+       result = atomic_dec_return(&sem->count);
+       membar("#StoreLoad | #StoreStore");
+       if (result < 0)
                __down(sem);
 }
 
 extern __inline__ int down_interruptible(struct semaphore *sem)
 {
-       int ret = 0;
-       if (atomic_dec_return(&sem->count) < 0)
+       int result, ret = 0;
+
+       result = atomic_dec_return(&sem->count);
+       membar("#StoreLoad | #StoreStore");
+       if (result < 0)
                ret = __down_interruptible(sem);
        return ret;
 }
 
 extern __inline__ void up(struct semaphore * sem)
 {
+       membar("#StoreStore | #LoadStore");
        if (atomic_inc_return(&sem->count) <= 0)
                __up(sem);
 }      
index ded0406b4ac58835e18e9ebc3e398a362d5edd7b..3b90c34b1ed7dca6faab87aa8583c7081cf88332 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.1 1996/12/26 14:22:36 davem Exp $ */
+/* $Id: shmparam.h,v 1.2 1997/08/04 16:16:55 davem Exp $ */
 #ifndef _ASMSPARC64_SHMPARAM_H
 #define _ASMSPARC64_SHMPARAM_H
 
@@ -41,7 +41,7 @@
 #define SHMMNI (1<<_SHM_ID_BITS)       /* max num of segs system wide */
 #define SHMALL                         /* max shm system wide (pages) */ \
        (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
-#define        SHMLBA PAGE_SIZE                /* attach addr a multiple of this */
+#define        SHMLBA (PAGE_SIZE<<1)           /* attach addr a multiple of this */
 #define SHMSEG SHMMNI                  /* max shared segs per process */
 
 #endif /* _ASMSPARC64_SHMPARAM_H */
index 116f83237c52a2eb12e4a3bb8a224c30342c5e89..363be0fe9715ee08c02ec97df9a8192b59eb1b4b 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef _SPARC64_SMP_H
 #define _SPARC64_SMP_H
 
+#include <linux/tasks.h>
 #include <asm/asi.h>
 
 #ifndef __ASSEMBLY__
@@ -29,8 +30,20 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 
 /* Per processor Sparc parameters we need. */
 
+/* Keep this a multiple of 64-bytes for cache reasons. */
 struct cpuinfo_sparc {
-       unsigned long udelay_val; /* that's it */
+       /* Dcache line 1 */
+       unsigned long   irq_count;
+       unsigned int    multiplier;
+       unsigned int    counter;
+       unsigned long   last_tlbversion_seen;
+       unsigned long   pgcache_size;
+
+       /* Dcache line 2 */
+       unsigned long   *pgd_cache;
+       unsigned long   *pmd_cache;
+       unsigned long   *pte_cache;
+       unsigned long   udelay_val;
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
@@ -49,21 +62,8 @@ extern struct klock_info klock_info;
  *     Private routines/data
  */
  
-extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
-extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned char active_kernel_processor;
-extern void smp_message_irq(void);
-extern unsigned long ipi_count;
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned long syscall_count;
-
-extern void print_lock_state(void);
-
-typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
-                      unsigned long, unsigned long);
 
 /*
  *     General functions that each host system must provide.
@@ -88,30 +88,12 @@ extern __inline__ int hard_smp_processor_id(void)
 
 #define smp_processor_id() (current->processor)
 
-extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
 #endif /* !(__ASSEMBLY__) */
 
-/* Sparc specific messages. */
-#define MSG_CROSS_CALL         0x0005       /* run func on cpus */
-
-/* Empirical PROM processor mailbox constants.  If the per-cpu mailbox
- * contains something other than one of these then the ipi is from
- * Linux's active_kernel_processor.  This facility exists so that
- * the boot monitor can capture all the other cpus when one catches
- * a watchdog reset or the user enters the monitor using L1-A keys.
- */
-#define MBOX_STOPCPU          0xFB
-#define MBOX_IDLECPU          0xFC
-#define MBOX_IDLECPU2         0xFD
-#define MBOX_STOPCPU2         0xFE
-
-#define PROC_CHANGE_PENALTY     20
-
-#define SMP_FROM_INT           1
-#define SMP_FROM_SYSCALL       2
+#define PROC_CHANGE_PENALTY    20
 
 #endif /* !(__SMP__) */
 
-#define NO_PROC_ID            0xFF
+#define NO_PROC_ID             0xFF
 
 #endif /* !(_SPARC64_SMP_H) */
index 3012ed6bb5ee406165f15db49f03930883ae815a..a01d9ec353a4fc114824ed60619253452a9b9f81 100644 (file)
@@ -28,6 +28,7 @@ do {                                                  \
                __cli();                                \
                (task)->lock_depth = 0;                 \
                klock_info.akp = NO_PROC_ID;            \
+               membar("#LoadStore | #StoreStore");     \
                klock_info.kernel_flag = 0;             \
        }                                               \
        release_irqlock(cpu);                           \
@@ -45,7 +46,7 @@ do {                                                                          \
                                     " mov      %1, %%g2"                       \
                                     : /* No outputs. */                        \
                                     : "r" (klip), "r" (depth)                  \
-                                    : "g2", "g3", "g5", "g7", "memory", "cc"); \
+                                    : "g2", "g3", "g5", "memory", "cc");       \
        }                                                                       \
 } while(0)
 
@@ -63,9 +64,9 @@ extern __inline__ void lock_kernel(void)
        __asm__ __volatile__("
        mov     %%o7, %%g5
        call    ___lock_kernel
-        ld     [%%g6 + %0], %%g2
+        lduw   [%%g6 + %0], %%g2
 "      : : "i" (AOFF_task_lock_depth), "r" (klip)
-       : "g2", "g3", "g5", "g7", "memory", "cc");
+       : "g2", "g3", "g5", "memory", "cc");
 }
 
 /* Release kernel global lock. */
@@ -76,7 +77,7 @@ extern __inline__ void unlock_kernel(void)
        __asm__ __volatile__("
        mov     %%o7, %%g5
        call    ___unlock_kernel
-        ld     [%%g6 + %0], %%g2
+        lduw   [%%g6 + %0], %%g2
 "      : : "i" (AOFF_task_lock_depth), "r" (klip)
        : "g2", "g3", "g5", "memory", "cc");
 }
index cf2e51c710bb9ee646fc585820519565c3b924cc..65880b033816f5b6f9f72eb780d1d2a83c44714b 100644 (file)
@@ -68,33 +68,35 @@ typedef struct { } rwlock_t;
 
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED     0
-#define spin_lock_init(lock)   (*(lock) = 0)
-#define spin_unlock_wait(lock) do { barrier(); } while(*(volatile spinlock_t *)lock)
+
+#define spin_lock_init(lock)   (*((unsigned char *)(lock)) = 0)
+
+#define spin_unlock_wait(lock) \
+do {   membar("#LoadLoad");    \
+} while(*((volatile unsigned char *)lock))
 
 extern __inline__ void spin_lock(spinlock_t *lock)
 {
        __asm__ __volatile__("
-1:     ldstub          [%0], %%g2
-       brz,pt          %%g2, 2f
-        membar         #LoadLoad | #LoadStore
-       b,a             %%xcc, 3f
-2:
-       .text           2
-3:     ldub            [%0], %%g2
-4:     brnz,a,pt       %%g2, 4b
-        ldub           [%0], %%g2
-       b,a             1b
+1:     ldstub          [%0], %%g7
+       brnz,pn         %%g7, 2f
+        membar         #StoreLoad | #StoreStore
+       .subsection     2
+2:     ldub            [%0], %%g7
+       brnz,pt         %%g7, 2b
+        membar         #LoadLoad
+       b,a,pt          %%xcc, 1b
        .previous
 "      : /* no outputs */
        : "r" (lock)
-       : "g2", "memory");
+       : "g7", "memory");
 }
 
 extern __inline__ int spin_trylock(spinlock_t *lock)
 {
        unsigned int result;
        __asm__ __volatile__("ldstub [%1], %0\n\t"
-                            "membar #LoadLoad | #LoadStore"
+                            "membar #StoreLoad | #StoreStore"
                             : "=r" (result)
                             : "r" (lock)
                             : "memory");
@@ -104,7 +106,7 @@ extern __inline__ int spin_trylock(spinlock_t *lock)
 extern __inline__ void spin_unlock(spinlock_t *lock)
 {
        __asm__ __volatile__("membar    #StoreStore | #LoadStore\n\t"
-                            "stb       %%g0, [%0]"
+                            "stb       %%g0, [%0]\n\t"
                             : /* No outputs */
                             : "r" (lock)
                             : "memory");
@@ -114,20 +116,18 @@ extern __inline__ void spin_lock_irq(spinlock_t *lock)
 {
        __asm__ __volatile__("
        wrpr            %%g0, 15, %%pil
-1:     ldstub          [%0], %%g2
-       brz,pt          %%g2, 2f
-        membar         #LoadLoad | #LoadStore
-       b,a             3f
-2:
-       .text           2
-3:     ldub            [%0], %%g2
-4:     brnz,a,pt       %%g2, 4b
-        ldub           [%0], %%g2
-       b,a             1b
+1:     ldstub          [%0], %%g7
+       brnz,pn         %%g7, 2f
+        membar         #StoreLoad | #StoreStore
+       .subsection     2
+2:     ldub            [%0], %%g7
+       brnz,pt         %%g7, 2b
+        membar         #LoadLoad
+       b,a,pt          %%xcc, 1b
        .previous
 "      : /* no outputs */
        : "r" (lock)
-       : "g2", "memory");
+       : "g7", "memory");
 }
 
 extern __inline__ void spin_unlock_irq(spinlock_t *lock)
@@ -147,20 +147,18 @@ do {      register spinlock_t *lp asm("g1");                      \
        __asm__ __volatile__(                                   \
        "\n     rdpr            %%pil, %0\n"                    \
        "       wrpr            %%g0, 15, %%pil\n"              \
-       "1:     ldstub          [%1], %%g2\n"                   \
-       "       brz,pt          %%g2, 2f\n"                     \
-       "        membar         #LoadLoad | #LoadStore\n"       \
-       "       b,a             3f\n"                           \
-       "2:\n"                                                  \
-       "       .text           2\n"                            \
-       "3:     ldub            [%1], %%g2\n"                   \
-       "4:     brnz,a,pt       %%g2, 4b\n"                     \
-       "        ldub           [%1], %%g2\n"                   \
-       "       b,a             1b\n"                           \
+       "1:     ldstub          [%1], %%g7\n"                   \
+       "       brnz,pn         %%g7, 2f\n"                     \
+       "        membar         #StoreLoad | #StoreStore\n"     \
+       "       .subsection     2\n"                            \
+       "2:     ldub            [%1], %%g7\n"                   \
+       "       brnz,pt         %%g7, 2b\n"                     \
+       "        membar         #LoadLoad\n"                    \
+       "       b,a,pt          %%xcc, 1b\n"                    \
        "       .previous\n"                                    \
        : "=&r" (flags)                                         \
        : "r" (lp)                                              \
-       : "g2", "memory");                                      \
+       : "g7", "memory");                                      \
 } while(0)
 
 extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
@@ -182,94 +180,83 @@ typedef unsigned long rwlock_t;
 extern __inline__ void read_lock(rwlock_t *rw)
 {
        __asm__ __volatile__("
-       ldx             [%0], %%g2
-1:     brgez,pt        %%g2, 4f
-        add            %%g2, 1, %%g3
-       b,a             2f
-4:     casx            [%0], %%g2, %%g3
-       cmp             %%g2, %%g3
-       bne,a,pn        %%xcc, 1b
-        ldx            [%0], %%g2
-       membar          #LoadLoad | #LoadStore
-       .text           2
-2:     ldx             [%0], %%g2
-3:     brlz,a,pt       %%g2, 3b
-        ldx            [%0], %%g2
-       b               4b
-        add            %%g2, 1, %%g3
+1:     ldx             [%0], %%g5
+       brlz,pn         %%g5, 2f
+4:      add            %%g5, 1, %%g7
+       casx            [%0], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%xcc, 1b
+        membar         #StoreLoad | #StoreStore
+       .subsection     2
+2:     ldx             [%0], %%g5
+       brlz,pt         %%g5, 2b
+        membar         #LoadLoad
+       b,a,pt          %%xcc, 4b
        .previous
 "      : /* no outputs */
        : "r" (rw)
-       : "g2", "g3", "cc", "memory");
+       : "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ void read_unlock(rwlock_t *rw)
 {
        __asm__ __volatile__("
-       membar          #StoreStore | #LoadStore
-       ldx             [%0], %%g2
-1:     sub             %%g2, 1, %%g3
-       casx            [%0], %%g2, %%g3
-       cmp             %%g2, %%g3
-       bne,a,pn        %%xcc, 1b
-        ldx            [%0], %%g2
+1:     ldx             [%0], %%g5
+       sub             %%g5, 1, %%g7
+       casx            [%0], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%xcc, 1b
+        membar         #StoreLoad | #StoreStore
 "      : /* no outputs */
        : "r" (rw)
-       : "g2", "g3", "cc", "memory");
+       : "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ void write_lock(rwlock_t *rw)
 {
        __asm__ __volatile__("
-       sethi           %%uhi(0x8000000000000000), %%g5
-       ldx             [%0], %%g2
-       sllx            %%g5, 32, %%g5
-1:     brgez,pt        %%g2, 4f
-        or             %%g2, %%g5, %%g3
-       b,a             5f
-4:     casx            [%0], %%g2, %%g3
-       cmp             %%g2, %%g3
-       bne,a,pn        %%xcc, 1b
-        ldx            [%0], %%g2
-       andncc          %%g3, %%g5, %%g0
-       be,pt           %%xcc, 2f
-        membar         #LoadLoad | #LoadStore
-       b,a             7f
-2:
-       .text           2
-7:     ldx             [%0], %%g2
-3:     andn            %%g2, %%g5, %%g3
-       casx            [%0], %%g2, %%g3
-       cmp             %%g2, %%g3
-       bne,a,pn        %%xcc, 3b
-        ldx            [%0], %%g2
-       membar          #LoadLoad | #LoadStore
-5:     ldx             [%0], %%g2
-6:     brlz,a,pt       %%g2, 6b
-        ldx            [%0], %%g2
-       b               4b
-        or             %%g2, %%g5, %%g3
+       sethi           %%uhi(0x8000000000000000), %%g3
+       sllx            %%g3, 32, %%g3
+1:     ldx             [%0], %%g5
+       brlz,pn         %%g5, 5f
+4:      or             %%g5, %%g3, %%g7
+       casx            [%0], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%xcc, 1b
+        andncc         %%g7, %%g3, %%g0
+       bne,pn          %%xcc, 7f
+        membar         #StoreLoad | #StoreStore
+       .subsection     2
+7:     ldx             [%0], %%g5
+       andn            %%g5, %%g3, %%g7
+       casx            [%0], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%xcc, 7b
+        membar         #StoreLoad | #StoreStore
+5:     ldx             [%0], %%g5
+       brnz,pt         %%g5, 5b
+        membar         #LoadLoad
+       b,a,pt          %%xcc, 4b
        .previous
 "      : /* no outputs */
        : "r" (rw)
-       : "g2", "g3", "g5", "memory", "cc");
+       : "g3", "g5", "g7", "memory", "cc");
 }
 
 extern __inline__ void write_unlock(rwlock_t *rw)
 {
        __asm__ __volatile__("
-       membar          #StoreStore | #LoadStore
-       sethi           %%uhi(0x8000000000000000), %%g5
-       ldx             [%0], %%g2
-       sllx            %%g5, 32, %%g5
-1:     andn            %%g2, %%g5, %%g3
-       casx            [%0], %%g2, %%g3
-       cmp             %%g2, %%g3
-       bne,a,pn        %%xcc, 1b
-        ldx            [%0], %%g2
+       sethi           %%uhi(0x8000000000000000), %%g3
+       sllx            %%g3, 32, %%g3
+1:     ldx             [%0], %%g5
+       andn            %%g5, %%g3, %%g7
+       casx            [%0], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%xcc, 1b
+        membar         #StoreLoad | #StoreStore
 "      : /* no outputs */
        : "r" (rw)
-       : "g2", "g3", "g5", "memory", "cc");
+       : "g3", "g5", "g7", "memory", "cc");
 }
 
 #define read_lock_irq(lock)    do { __cli(); read_lock(lock); } while (0)
index 05d72706d81a1ee23100926fbd04ae1708cad5c4..5e8fb9414642aa32f017b76124d635702676c178 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sysio.h,v 1.2 1997/04/03 12:26:45 davem Exp $
+/* $Id: sysio.h,v 1.6 1997/08/15 06:44:53 davem Exp $
  * sysio.h: UltraSparc sun5 specific SBUS definitions.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,7 @@ struct sysio_regs {
                 *      slot 5) MACIO
                 *      slot 6) SLAVIO
                 *
-                * On Sunfire/Wildfire enterprise boxen these upper slots
+                * On Sunfire/Starfire/Wildfire enterprise boxen these upper slots
                 * are unused.
                 */
 /*0x2020*/     u64     sbus_s0cfg;     /* SBUS Slot 0 Config                   */
@@ -72,83 +72,83 @@ struct sysio_regs {
                /* SBUS/IOMMU Streaming Buffer Registers */
 /*0x2800*/     u64     sbuf_control;   /* StrBuffer Control                    */
 /*0x2808*/     u64     sbuf_pflush;    /* StrBuffer Page Flush                 */
-/*0x2810*/     u64     sbus_fsync;     /* StrBuffer Flush Synchronization Reg  */
+/*0x2810*/     u64     sbuf_fsync;     /* StrBuffer Flush Synchronization Reg  */
 
                u64     __pad4[0x7d];
 
                /* Interrupt mapping/control registers */
-/*0x2c00*/     u32     imap_slot0, _uim0;      /* SBUS Slot 0 Int Mapping      */
-/*0x2c08*/     u32     imap_slot1, _uim1;      /* SBUS Slot 1 Int Mapping      */
-/*0x2c10*/     u32     imap_slot2, _uim2;      /* SBUS Slot 2 Int Mapping      */
-/*0x2c18*/     u32     imap_slot3, _uim3;      /* SBUS Slot 3 Int Mapping      */
+/*0x2c00*/     u32     _uim0, imap_slot0;      /* SBUS Slot 0 Int Mapping      */
+/*0x2c08*/     u32     _uim1, imap_slot1;      /* SBUS Slot 1 Int Mapping      */
+/*0x2c10*/     u32     _uim2, imap_slot2;      /* SBUS Slot 2 Int Mapping      */
+/*0x2c18*/     u32     _uim3, imap_slot3;      /* SBUS Slot 3 Int Mapping      */
 
                /* Interrupt Retry Timer. */
-/*0x2c20*/     u32     irq_retry,  _irpad;
+/*0x2c20*/     u32     _irpad, irq_retry;
 
                u64     __pad5[0x7b];
 
                /* The following are only used on Fusion/Electron/Pulsar
-                * desktop systems, they mean nothing on Sunfire/Wildfire
+                * desktop systems, they mean nothing on Sunfire/Starfire/Wildfire
                 */
-/*0x3000*/     u32     imap_scsi,  _uis;       /* SCSI Int Mapping             */
-/*0x3008*/     u32     imap_eth,   _uie;       /* Ethernet Int Mapping         */
-/*0x3010*/     u32     imap_bpp,   _uip;       /* Parallel Port Int Mapping    */
-/*0x3018*/     u32     imap_audio, _uia;       /* Audio Int Mapping            */
-/*0x3020*/     u32     imap_pfail, _uipf;      /* Power Fail Int Mapping       */
-/*0x3028*/     u32     imap_kms,   _uik;       /* Kbd/Mouse/Serial Int Mapping */
-/*0x3030*/     u32     imap_flpy,  _uif;       /* Floppy Int Mapping           */
-/*0x3038*/     u32     imap_shw,   _uishw;     /* Spare HW Int Mapping         */
-/*0x3040*/     u32     imap_kbd,   _uikbd;     /* Kbd Only Int Mapping         */
-/*0x3048*/     u32     imap_ms,    _uims;      /* Mouse Only Int Mapping       */
-/*0x3050*/     u32     imap_ser,   _uiser;     /* Serial Only Int Mapping      */
+/*0x3000*/     u32     _uis, imap_scsi;        /* SCSI Int Mapping             */
+/*0x3008*/     u32     _uie, imap_eth;         /* Ethernet Int Mapping         */
+/*0x3010*/     u32     _uip, imap_bpp;         /* Parallel Port Int Mapping    */
+/*0x3018*/     u32     _uia, imap_audio;       /* Audio Int Mapping            */
+/*0x3020*/     u32     _uipf, imap_pfail;      /* Power Fail Int Mapping       */
+/*0x3028*/     u32     _uik, imap_kms;         /* Kbd/Mouse/Serial Int Mapping */
+/*0x3030*/     u32     _uif, imap_flpy;        /* Floppy Int Mapping           */
+/*0x3038*/     u32     _uishw, imap_shw;       /* Spare HW Int Mapping         */
+/*0x3040*/     u32     _uikbd, imap_kbd;       /* Kbd Only Int Mapping         */
+/*0x3048*/     u32     _uims, imap_ms;         /* Mouse Only Int Mapping       */
+/*0x3050*/     u32     _uiser, imap_ser;       /* Serial Only Int Mapping      */
 /*0x3058*/     u64     _imap_unused;
-/*0x3060*/     u32     imap_tim0,  _uit0;      /* Timer 0 Int Mapping          */
-/*0x3068*/     u32     imap_tim1,  _uit1;      /* Timer 1 Int Mapping          */
-/*0x3070*/     u32     imap_ue,    _uiue;      /* UE Int Mapping               */
-/*0x3078*/     u32     imap_ce,    _uice;      /* CE Int Mapping               */
-/*0x3080*/     u32     imap_sberr, _uisbe;     /* SBUS Err Int Mapping         */
-/*0x3088*/     u32     imap_pmgmt, _uipm;      /* Power Mgmt Int Mapping       */
-/*0x3090*/     u32     imap_gfx,   _uigfx;     /* OB Graphics Int Mapping      */
-/*0x3098*/     u32     imap_eupa,  _uieupa;    /* UPA Expansion Int Mapping    */
+/*0x3060*/     u32     _uit0, imap_tim0;       /* Timer 0 Int Mapping          */
+/*0x3068*/     u32     _uit1, imap_tim1;       /* Timer 1 Int Mapping          */
+/*0x3070*/     u32     _uiue, imap_ue;         /* UE Int Mapping               */
+/*0x3078*/     u32     _uice, imap_ce;         /* CE Int Mapping               */
+/*0x3080*/     u32     _uisbe, imap_sberr;     /* SBUS Err Int Mapping         */
+/*0x3088*/     u32     _uipm, imap_pmgmt;      /* Power Mgmt Int Mapping       */
+/*0x3090*/     u32     _uigfx, imap_gfx;       /* OB Graphics Int Mapping      */
+/*0x3098*/     u32     _uieupa, imap_eupa;     /* UPA Expansion Int Mapping    */
 
                u64     __pad6[0x6c];
 
                /* Interrupt Clear Registers */
-/*0x3400*/     u64     iclr_unused0;
-/*0x3408*/     u32     iclr_slot0, _ucs0;
+/*0x3400*/     u32     __ucu0, iclr_unused0;
+/*0x3408*/     u32     _ucs0, iclr_slot0;
                u64     __pad7[0x7];
-/*0x3448*/     u32     iclr_slot1, _ucs1;
+/*0x3448*/     u32     _ucs1, iclr_slot1;
                u64     __pad8[0x7];
-/*0x3488*/     u32     iclr_slot2, _ucs2;
+/*0x3488*/     u32     _ucs2, iclr_slot2;
                u64     __pad9[0x7];
-/*0x34c8*/     u32     iclr_slot3, _ucs3;
+/*0x34c8*/     u32     _ucs3, iclr_slot3;
                u64     __pad10[0x66];
-/*0x3800*/     u32     iclr_scsi,  _ucscsi;
-/*0x3808*/     u32     iclr_eth,   _uceth;
-/*0x3810*/     u32     iclr_bpp,   _ucbpp;
-/*0x3818*/     u32     iclr_audio, _ucaudio;
-/*0x3820*/     u32     iclr_pfail, _ucpfail;
-/*0x3828*/     u32     iclr_kms,   _uckms;
-/*0x3830*/     u32     iclr_flpt,  _ucflpy;
-/*0x3838*/     u32     iclr_shw,   _ucshw;
-/*0x3840*/     u32     iclr_kbd,   _uckbd;
-/*0x3848*/     u32     iclr_ms,    _ucms;
-/*0x3850*/     u32     iclr_ser,   _ucser;
+/*0x3800*/     u32     _ucscsi, iclr_scsi;
+/*0x3808*/     u32     _uceth, iclr_eth;
+/*0x3810*/     u32     _ucbpp, iclr_bpp;
+/*0x3818*/     u32     _ucaudio, iclr_audio;
+/*0x3820*/     u32     _ucpfail, iclr_pfail;
+/*0x3828*/     u32     _uckms, iclr_kms;
+/*0x3830*/     u32     _ucflpy, iclr_flpt;
+/*0x3838*/     u32     _ucshw, iclr_shw;
+/*0x3840*/     u32     _uckbd, iclr_kbd;
+/*0x3848*/     u32     _ucms, iclr_ms;
+/*0x3850*/     u32     _ucser, iclr_ser;
 /*0x3858*/     u64     iclr_unused1;
-/*0x3860*/     u32     iclr_tim0,  _uctim0;
-/*0x3868*/     u32     iclr_tim1,  _uctim1;
-/*0x3870*/     u32     iclr_ue,    _ucue;
-/*0x3878*/     u32     iclr_ce,    _ucce;
-/*0x3880*/     u32     iclr_serr,  _ucserr;
-/*0x3888*/     u32     iclr_pmgmt, _ucpmgmt;
+/*0x3860*/     u32     _uctim0, iclr_tim0;
+/*0x3868*/     u32     _uctim1, iclr_tim1;
+/*0x3870*/     u32     _ucue, iclr_ue;
+/*0x3878*/     u32     _ucce, iclr_ce;
+/*0x3880*/     u32     _ucserr, iclr_serr;
+/*0x3888*/     u32     _ucpmgmt, iclr_pmgmt;
 
                u64     __pad11[0x6e];
 
                /* Counters/Timers */
-/*0x3c00*/     u32     tim0_cnt, _tim0_u0;
-/*0x3c08*/     u32     tim0_lim, _tim0_u1;
-/*0x3c10*/     u32     tim1_cnt, _tim1_u0;
-/*0x3c18*/     u32     tim1_lim, _tim1_u1;
+/*0x3c00*/     u64     tim0_cnt;
+/*0x3c08*/     u64     tim0_lim;
+/*0x3c10*/     u64     tim1_cnt;
+/*0x3c18*/     u64     tim1_lim;
 
                u64     __pad12[0x7c];
 
@@ -169,11 +169,13 @@ struct sysio_regs {
 /*0x4580*/     u64     iommu_tag[16];  /* IOMMU TLB Tag Diagnostic Access      */
 /*0x4600*/     u64     iommu_data[32]; /* IOMMU TLB Data RAM Diagnostic Access */
 
+               u64     __pad15[0x20];
+
                /* Interrupt State Diagnostics */
 /*0x4800*/     u64     sbus_istate;
 /*0x4808*/     u64     obio_istate;
 
-               u64     __pad15[0xfe];
+               u64     __pad16[0xfe];
 
                /* Streaming Buffer Diagnostic Area */
 /*0x5000*/     u64     sbuf_data[128]; /* StrBuffer Data Ram Diagnostic        */
index ab05190e9ae676ed64e269760eb0c3c101e19a00..d1d1b91363d0968cb2ebfbd83fcf8fae13ddcffb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
+/* $Id: system.h,v 1.35 1997/08/07 03:53:00 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -6,8 +6,6 @@
 #include <asm/processor.h>
 #include <asm/asm_offsets.h>
 
-#define NCPUS  4       /* No SMP yet */
-
 #ifndef __ASSEMBLY__
 /*
  * Sparc (general) CPU types
@@ -103,7 +101,7 @@ extern void __global_restore_flags(unsigned long flags);
 
 #define membar(type)   __asm__ __volatile__ ("membar " type : : : "memory");
 
-#define flushi(addr)   __asm__ __volatile__ ("flush %0" : : "r" (addr))
+#define flushi(addr)   __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
 
 #define flushw_all()   __asm__ __volatile__("flushw")
 
@@ -131,6 +129,16 @@ extern __inline__ void flushw_user(void)
         * I do not clobber it, when in fact I do.  Please,
         * when modifying this code inspect output of sched.s very
         * carefully to make sure things still work.  -DaveM
+        *
+        * SMP NOTE: At first glance it looks like there is a tiny
+        *           race window here at the end.  The possible problem
+        *           would be if a tlbcachesync MONDO vector got delivered
+        *           to us right before we set the final %g6 thread reg
+        *           value.  But that is impossible since only the holder
+        *           of scheduler_lock can send a tlbcachesync MONDO and
+        *           by definition we hold it right now.  Normal tlb
+        *           flush xcalls can come in, but those are safe and do
+        *           not reference %g6.
         */
 #define switch_to(prev, next)                                                  \
 do {   __label__ switch_continue;                                              \
@@ -142,7 +150,6 @@ do {        __label__ switch_continue;                                              \
        "rdpr   %%pstate, %%g2\n\t"                                             \
        "wrpr   %%g2, 0x3, %%pstate\n\t"                                        \
        "flushw\n\t"                                                            \
-/*XXX*/        "wr     %%g0, 0, %%fprs\n\t"                                            \
        "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                 \
        "stx    %%i7, [%%sp + 2047 + 0x78]\n\t"                                 \
        "rdpr   %%wstate, %%o5\n\t"                                             \
@@ -151,6 +158,7 @@ do {        __label__ switch_continue;                                              \
        "rdpr   %%cwp, %%o5\n\t"                                                \
        "stx    %%o7, [%%g6 + %4]\n\t"                                          \
        "st     %%o5, [%%g6 + %5]\n\t"                                          \
+       "membar #Sync\n\t"                                                      \
        "mov    %0, %%g6\n\t"                                                   \
        "ld     [%0 + %5], %%g1\n\t"                                            \
        "wrpr   %%g1, %%cwp\n\t"                                                \
@@ -176,30 +184,35 @@ do {      __label__ switch_continue;                                              \
          "o0", "o1", "o2", "o3", "o4", "o5");                                  \
 switch_continue: } while(0)
 
-/* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
-extern __inline__ unsigned long xchg_u32(__volatile__ unsigned int *m, unsigned int val)
+extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
 {
-       __asm__ __volatile__("swap      [%2], %0"
-                            : "=&r" (val)
-                            : "0" (val), "r" (m));
+       __asm__ __volatile__("
+       mov             %0, %%g5
+1:     lduw            [%2], %%g7
+       cas             [%2], %%g7, %0
+       cmp             %%g7, %0
+       bne,a,pn        %%icc, 1b
+        mov            %%g5, %0
+       membar          #StoreLoad | #StoreStore
+"      : "=&r" (val)
+       : "0" (val), "r" (m)
+       : "g5", "g7", "cc", "memory");
        return val;
 }
 
-/* Bolix, must use casx for 64-bit values. */
-extern __inline__ unsigned long xchg_u64(__volatile__ unsigned long *m,
-                                        unsigned long val)
+extern __inline__ unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
 {
-       unsigned long temp;
        __asm__ __volatile__("
-       mov             %0, %%g1
-1:     ldx             [%3], %1
-       casx            [%3], %1, %0
-       cmp             %1, %0
+       mov             %0, %%g5
+1:     ldx             [%2], %%g7
+       casx            [%2], %%g7, %0
+       cmp             %%g7, %0
        bne,a,pn        %%xcc, 1b
-        mov            %%g1, %0
-"      : "=&r" (val), "=&r" (temp)
+        mov            %%g5, %0
+       membar          #StoreLoad | #StoreStore
+"      : "=&r" (val)
        : "0" (val), "r" (m)
-       : "g1", "cc");
+       : "g5", "g7", "cc", "memory");
        return val;
 }
 
@@ -213,9 +226,9 @@ static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
 {
        switch (size) {
        case 4:
-               return xchg_u32(ptr, x);
+               return xchg32(ptr, x);
        case 8:
-               return xchg_u64(ptr, x);
+               return xchg64(ptr, x);
        };
        __xchg_called_with_bad_pointer();
        return x;
index 01e8364c66ab18e98114792033541946edccd494..aa227e7b30c10f47c9da89ba516908899204892b 100644 (file)
@@ -148,13 +148,18 @@ struct termios {
 #define HUPCL    0x00000400
 #define CLOCAL   0x00000800
 #define CBAUDEX   0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
 #define  B57600   0x00001001
 #define  B115200  0x00001002
 #define  B230400  0x00001003
 #define  B460800  0x00001004
 /* This is what we can do with the Zilogs. */
 #define  B76800   0x00001005
+/* This is what we can do with the SAB82532. */
+#define  B153600  0x00001006
+#define  B307200  0x00001007
+#define  B614400  0x00001008
+#define  B921600  0x00001009
+#define  B1843200 0x0000100a
 #define CIBAUD   0x100f0000  /* input baud rate (not used) */
 #define CMSPAR    0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS          0x80000000  /* flow control */
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
new file mode 100644 (file)
index 0000000..f6710ed
--- /dev/null
@@ -0,0 +1,320 @@
+/* $Id: ttable.h,v 1.2 1997/08/09 09:03:36 davem Exp $ */
+#ifndef _SPARC64_TTABLE_H
+#define _SPARC64_TTABLE_H
+
+#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
+
+/* We need a "cleaned" instruction... */
+#define CLEAN_WINDOW                                                   \
+       rdpr    %cleanwin, %l0;         add     %l0, 1, %l0;            \
+       wrpr    %l0, 0x0, %cleanwin;                                    \
+       clr     %o0;    clr     %o1;    clr     %o2;    clr     %o3;    \
+       clr     %o4;    clr     %o5;    clr     %o6;    clr     %o7;    \
+       clr     %l0;    clr     %l1;    clr     %l2;    clr     %l3;    \
+       clr     %l4;    clr     %l5;    clr     %l6;    clr     %l7;    \
+       retry;                                                          \
+       nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
+
+#define TRAP(routine)                                  \
+       sethi   %hi(109f), %g7;                         \
+       ba,pt   %xcc, etrap;                            \
+109:    or     %g7, %lo(109b), %g7;                    \
+       call    routine;                                \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;                                    \
+       nop;
+
+#define TRAP_NOSAVE(routine)                           \
+       ba,pt   %xcc, routine;                          \
+        nop;                                           \
+       nop; nop; nop; nop; nop; nop;
+
+#define TRAPTL1(routine)                               \
+       sethi   %hi(109f), %g7;                         \
+       ba,pt   %xcc, etraptl1;                         \
+109:    or     %g7, %lo(109b), %g7;                    \
+       call    routine;                                \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;                                    \
+       nop;
+       
+#define TRAP_ARG(routine, arg)                         \
+       sethi   %hi(109f), %g7;                         \
+       ba,pt   %xcc, etrap;                            \
+109:    or     %g7, %lo(109b), %g7;                    \
+       add     %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       call    routine;                                \
+        mov    arg, %o1;                               \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;
+       
+#define TRAPTL1_ARG(routine, arg)                      \
+       sethi   %hi(109f), %g7;                         \
+       ba,pt   %xcc, etraptl1;                         \
+109:    or     %g7, %lo(109b), %g7;                    \
+       add     %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       call    routine;                                \
+        mov    arg, %o1;                               \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;
+       
+#define SYSCALL_TRAP(routine, systbl)                  \
+       sethi   %hi(109f), %g7;                         \
+       ba,pt   %xcc, etrap;                            \
+109:    or     %g7, %lo(109b), %g7;                    \
+       call    routine;                                \
+        sethi  %hi(systbl), %l7;                       \
+       nop; nop; nop;
+       
+#define ACCESS_EXCEPTION_TRAP(routine)                 \
+       rdpr    %pstate, %g1;                           \
+       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
+       ba,pt   %xcc, etrap;                            \
+        rd     %pc, %g7;                               \
+       call    routine;                                \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;
+
+#define ACCESS_EXCEPTION_TRAPTL1(routine)              \
+       rdpr    %pstate, %g1;                           \
+       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
+       ba,pt   %xcc, etraptl1;                         \
+        rd     %pc, %g7;                               \
+       call    routine;                                \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       ba,pt   %xcc, rtrap;                            \
+        clr    %l6;
+
+#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
+#define        LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
+#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
+#define GETCC_TRAP TRAP(getcc)
+#define SETCC_TRAP TRAP(setcc)
+/* FIXME: Write these actually */      
+#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
+#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
+#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
+#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
+
+#define TRAP_IRQ(routine, level)                       \
+       rdpr    %pil, %g2;                              \
+       wrpr    %g0, 15, %pil;                          \
+       b,pt    %xcc, etrap_irq;                        \
+        rd     %pc, %g7;                               \
+       mov     level, %o0;                             \
+       call    routine;                                \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o1;       \
+       ba,a,pt %xcc, rtrap_clr_l6;
+
+#ifdef __SMP__
+#define TRAP_TICK                                      \
+       rdpr    %pil, %g2;                              \
+       wrpr    %g0, 15, %pil;                          \
+       b,pt    %xcc, etrap_irq;                        \
+        rd     %pc, %g7;                               \
+       call    smp_percpu_timer_interrupt;             \
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
+       b,pt    %xcc, rtrap;                            \
+        clr    %l6;
+#else
+#define TRAP_TICK      TRAP_IRQ(handler_irq, 14)
+#endif
+
+#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
+
+#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
+
+#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
+
+#define FLUSH_WINDOW_TRAP                                              \
+       ba,pt   %xcc, etrap;                                            \
+        rd     %pc, %g7;                                               \
+       flushw;                                                         \
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;       \
+       add     %l1, 4, %l2;                                            \
+       stx     %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];        \
+       ba,pt   %xcc, rtrap_clr_l6;                                     \
+        stx    %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
+               
+/* Before touching these macros, you owe it to yourself to go and
+ * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ */
+
+/* Normal kernel spill */
+#define SPILL_0_NORMAL                                 \
+       stx     %l0, [%sp + STACK_BIAS + 0x00];         \
+       stx     %l1, [%sp + STACK_BIAS + 0x08];         \
+       stx     %l2, [%sp + STACK_BIAS + 0x10];         \
+       stx     %l3, [%sp + STACK_BIAS + 0x18];         \
+       stx     %l4, [%sp + STACK_BIAS + 0x20];         \
+       stx     %l5, [%sp + STACK_BIAS + 0x28];         \
+       stx     %l6, [%sp + STACK_BIAS + 0x30];         \
+       stx     %l7, [%sp + STACK_BIAS + 0x38];         \
+       stx     %i0, [%sp + STACK_BIAS + 0x40];         \
+       stx     %i1, [%sp + STACK_BIAS + 0x48];         \
+       stx     %i2, [%sp + STACK_BIAS + 0x50];         \
+       stx     %i3, [%sp + STACK_BIAS + 0x58];         \
+       stx     %i4, [%sp + STACK_BIAS + 0x60];         \
+       stx     %i5, [%sp + STACK_BIAS + 0x68];         \
+       stx     %i6, [%sp + STACK_BIAS + 0x70];         \
+       stx     %i7, [%sp + STACK_BIAS + 0x78];         \
+       saved; retry; nop; nop; nop; nop; nop; nop;     \
+       nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit spill */
+#define SPILL_1_GENERIC(xxx)                           \
+       wr      %g0, xxx, %asi;                         \
+       stxa    %l0, [%sp + STACK_BIAS + 0x00] %asi;    \
+       stxa    %l1, [%sp + STACK_BIAS + 0x08] %asi;    \
+       stxa    %l2, [%sp + STACK_BIAS + 0x10] %asi;    \
+       stxa    %l3, [%sp + STACK_BIAS + 0x18] %asi;    \
+       stxa    %l4, [%sp + STACK_BIAS + 0x20] %asi;    \
+       stxa    %l5, [%sp + STACK_BIAS + 0x28] %asi;    \
+       stxa    %l6, [%sp + STACK_BIAS + 0x30] %asi;    \
+       stxa    %l7, [%sp + STACK_BIAS + 0x38] %asi;    \
+       stxa    %i0, [%sp + STACK_BIAS + 0x40] %asi;    \
+       stxa    %i1, [%sp + STACK_BIAS + 0x48] %asi;    \
+       stxa    %i2, [%sp + STACK_BIAS + 0x50] %asi;    \
+       stxa    %i3, [%sp + STACK_BIAS + 0x58] %asi;    \
+       stxa    %i4, [%sp + STACK_BIAS + 0x60] %asi;    \
+       stxa    %i5, [%sp + STACK_BIAS + 0x68] %asi;    \
+       stxa    %i6, [%sp + STACK_BIAS + 0x70] %asi;    \
+       stxa    %i7, [%sp + STACK_BIAS + 0x78] %asi;    \
+       saved; retry; nop; nop; nop; nop; nop; nop;     \
+       nop; nop; nop; nop; nop;                        \
+       b,a,pt  %xcc, spill_fixup_mna;                  \
+       b,a,pt  %xcc, spill_fixup;
+
+/* Normal 32bit spill */
+#define SPILL_2_GENERIC(xxx)                           \
+       wr      %g0, xxx, %asi;                         \
+       srl     %sp, 0, %sp;                            \
+       stwa    %l0, [%sp + 0x00] %asi;                 \
+       stwa    %l1, [%sp + 0x04] %asi;                 \
+       stwa    %l2, [%sp + 0x08] %asi;                 \
+       stwa    %l3, [%sp + 0x0c] %asi;                 \
+       stwa    %l4, [%sp + 0x10] %asi;                 \
+       stwa    %l5, [%sp + 0x14] %asi;                 \
+       stwa    %l6, [%sp + 0x18] %asi;                 \
+       stwa    %l7, [%sp + 0x1c] %asi;                 \
+       stwa    %i0, [%sp + 0x20] %asi;                 \
+       stwa    %i1, [%sp + 0x24] %asi;                 \
+       stwa    %i2, [%sp + 0x28] %asi;                 \
+       stwa    %i3, [%sp + 0x2c] %asi;                 \
+       stwa    %i4, [%sp + 0x30] %asi;                 \
+       stwa    %i5, [%sp + 0x34] %asi;                 \
+       stwa    %i6, [%sp + 0x38] %asi;                 \
+       stwa    %i7, [%sp + 0x3c] %asi;                 \
+       saved; retry; nop; nop; nop; nop;               \
+       nop; nop; nop; nop; nop; nop;                   \
+       b,a,pt  %xcc, spill_fixup_mna;                  \
+       b,a,pt  %xcc, spill_fixup;
+
+#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
+#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
+#define SPILL_3_NORMAL SPILL_0_NORMAL
+#define SPILL_4_NORMAL SPILL_0_NORMAL
+#define SPILL_5_NORMAL SPILL_0_NORMAL
+#define SPILL_6_NORMAL SPILL_0_NORMAL
+#define SPILL_7_NORMAL SPILL_0_NORMAL
+
+#define SPILL_0_OTHER SPILL_0_NORMAL
+#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
+#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
+#define SPILL_3_OTHER SPILL_3_NORMAL
+#define SPILL_4_OTHER SPILL_4_NORMAL
+#define SPILL_5_OTHER SPILL_5_NORMAL
+#define SPILL_6_OTHER SPILL_6_NORMAL
+#define SPILL_7_OTHER SPILL_7_NORMAL
+
+/* Normal kernel fill */
+#define FILL_0_NORMAL                                  \
+       ldx     [%sp + STACK_BIAS + 0x00], %l0;         \
+       ldx     [%sp + STACK_BIAS + 0x08], %l1;         \
+       ldx     [%sp + STACK_BIAS + 0x10], %l2;         \
+       ldx     [%sp + STACK_BIAS + 0x18], %l3;         \
+       ldx     [%sp + STACK_BIAS + 0x20], %l4;         \
+       ldx     [%sp + STACK_BIAS + 0x28], %l5;         \
+       ldx     [%sp + STACK_BIAS + 0x30], %l6;         \
+       ldx     [%sp + STACK_BIAS + 0x38], %l7;         \
+       ldx     [%sp + STACK_BIAS + 0x40], %i0;         \
+       ldx     [%sp + STACK_BIAS + 0x48], %i1;         \
+       ldx     [%sp + STACK_BIAS + 0x50], %i2;         \
+       ldx     [%sp + STACK_BIAS + 0x58], %i3;         \
+       ldx     [%sp + STACK_BIAS + 0x60], %i4;         \
+       ldx     [%sp + STACK_BIAS + 0x68], %i5;         \
+       ldx     [%sp + STACK_BIAS + 0x70], %i6;         \
+       ldx     [%sp + STACK_BIAS + 0x78], %i7;         \
+       restored; retry; nop; nop; nop; nop; nop; nop;  \
+       nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit fill */
+#define FILL_1_GENERIC(xxx)                            \
+       wr      %g0, xxx, %asi;                         \
+       ldxa    [%sp + STACK_BIAS + 0x00] %asi, %l0;    \
+       ldxa    [%sp + STACK_BIAS + 0x08] %asi, %l1;    \
+       ldxa    [%sp + STACK_BIAS + 0x10] %asi, %l2;    \
+       ldxa    [%sp + STACK_BIAS + 0x18] %asi, %l3;    \
+       ldxa    [%sp + STACK_BIAS + 0x20] %asi, %l4;    \
+       ldxa    [%sp + STACK_BIAS + 0x28] %asi, %l5;    \
+       ldxa    [%sp + STACK_BIAS + 0x30] %asi, %l6;    \
+       ldxa    [%sp + STACK_BIAS + 0x38] %asi, %l7;    \
+       ldxa    [%sp + STACK_BIAS + 0x40] %asi, %i0;    \
+       ldxa    [%sp + STACK_BIAS + 0x48] %asi, %i1;    \
+       ldxa    [%sp + STACK_BIAS + 0x50] %asi, %i2;    \
+       ldxa    [%sp + STACK_BIAS + 0x58] %asi, %i3;    \
+       ldxa    [%sp + STACK_BIAS + 0x60] %asi, %i4;    \
+       ldxa    [%sp + STACK_BIAS + 0x68] %asi, %i5;    \
+       ldxa    [%sp + STACK_BIAS + 0x70] %asi, %i6;    \
+       ldxa    [%sp + STACK_BIAS + 0x78] %asi, %i7;    \
+       restored; retry; nop; nop; nop; nop; nop; nop;  \
+       nop; nop; nop; nop; nop;                        \
+       b,a,pt  %xcc, fill_fixup_mna;                   \
+       b,a,pt  %xcc, fill_fixup;
+
+/* Normal 32bit fill */
+#define FILL_2_GENERIC(xxx)                            \
+       wr      %g0, xxx, %asi;                         \
+       srl     %sp, 0, %sp;                            \
+       lduwa   [%sp + 0x00] %asi, %l0;                 \
+       lduwa   [%sp + 0x04] %asi, %l1;                 \
+       lduwa   [%sp + 0x08] %asi, %l2;                 \
+       lduwa   [%sp + 0x0c] %asi, %l3;                 \
+       lduwa   [%sp + 0x10] %asi, %l4;                 \
+       lduwa   [%sp + 0x14] %asi, %l5;                 \
+       lduwa   [%sp + 0x18] %asi, %l6;                 \
+       lduwa   [%sp + 0x1c] %asi, %l7;                 \
+       lduwa   [%sp + 0x20] %asi, %i0;                 \
+       lduwa   [%sp + 0x24] %asi, %i1;                 \
+       lduwa   [%sp + 0x28] %asi, %i2;                 \
+       lduwa   [%sp + 0x2c] %asi, %i3;                 \
+       lduwa   [%sp + 0x30] %asi, %i4;                 \
+       lduwa   [%sp + 0x34] %asi, %i5;                 \
+       lduwa   [%sp + 0x38] %asi, %i6;                 \
+       lduwa   [%sp + 0x3c] %asi, %i7;                 \
+       restored; retry; nop; nop; nop; nop;            \
+       nop; nop; nop; nop; nop; nop;                   \
+       b,a,pt  %xcc, fill_fixup_mna;                   \
+       b,a,pt  %xcc, fill_fixup;
+
+#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
+#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
+#define FILL_3_NORMAL FILL_0_NORMAL
+#define FILL_4_NORMAL FILL_0_NORMAL
+#define FILL_5_NORMAL FILL_0_NORMAL
+#define FILL_6_NORMAL FILL_0_NORMAL
+#define FILL_7_NORMAL FILL_0_NORMAL
+
+#define FILL_0_OTHER FILL_0_NORMAL
+#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
+#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
+#define FILL_3_OTHER FILL_3_NORMAL
+#define FILL_4_OTHER FILL_4_NORMAL
+#define FILL_5_OTHER FILL_5_NORMAL
+#define FILL_6_OTHER FILL_6_NORMAL
+#define FILL_7_OTHER FILL_7_NORMAL
+
+#endif /* !(_SPARC64_TTABLE_H) */
index c0668e3f23c757abc8722d3251dd1e50852a6f9e..d75beb5b6df6441a3775fd6e4554cb7f1d94a8a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.20 1997/07/13 18:23:45 davem Exp $ */
+/* $Id: uaccess.h,v 1.21 1997/07/31 07:37:25 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
 
 #define get_fs() (current->tss.current_ds)
 #define get_ds() (KERNEL_DS)
+
+extern spinlock_t scheduler_lock;
+
 #define set_fs(val)                            \
-do {                                           \
+do {   spin_lock(&scheduler_lock);             \
        current->tss.current_ds = (val);        \
        if ((val) == KERNEL_DS) {               \
                flushw_user ();                 \
@@ -41,6 +44,7 @@ do {                                          \
        }                                       \
        spitfire_set_secondary_context(current->tss.ctx); \
        __asm__ __volatile__("flush %g6");      \
+       spin_unlock(&scheduler_lock);           \
 } while(0)
 
 #define __user_ok(addr,size) 1
index 412f0c1c3a799ba1d883071244e3be680674792e..66ef4b47efd0b4bc77968c1df6f9762abd19018b 100644 (file)
@@ -97,6 +97,9 @@ extern int ddv_init(void);
 #ifdef CONFIG_AMIGA_Z2RAM
 extern int z2_init(void);
 #endif
+#ifdef CONFIG_MAC_FLOPPY
+extern int swim3_init(void);
+#endif
 
 extern void set_device_ro(kdev_t dev,int flag);
 void add_blkdev_randomness(int major);
index 6ba47f2e2ba57cde9427d464cc21eff3cf232386..0114f7052652af63154089c73828e80b3cc0977d 100644 (file)
@@ -97,7 +97,6 @@ extern void d_instantiate(struct dentry *, struct inode *);
 extern void d_delete(struct dentry *);
 
 /* allocate/de-allocate */
-extern void d_free(struct dentry *);
 extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
 extern void shrink_dcache(void);
 extern int d_invalidate(struct dentry *);
index ad6893bd2765e7bda344701d535f1bf4c2ade2a4..86f374c4c3d972b9a56d735bc005d242c7f9389c 100644 (file)
@@ -51,7 +51,8 @@ enum root_directory_inos {
        PROC_HARDWARE,
        PROC_SLABINFO,
        PROC_PARPORT,
-       PROC_OMIRR /* whether enabled or not */
+       PROC_OMIRR, /* whether enabled or not */
+       PROC_PPC_HTAB
 };
 
 enum pid_directory_inos {
@@ -181,6 +182,8 @@ enum scsi_directory_inos {
        PROC_SCSI_GVP11,
        PROC_SCSI_ATARI,
        PROC_SCSI_IDESCSI,
+       PROC_SCSI_MESH,
+       PROC_SCSI_53C94,
        PROC_SCSI_SCSI_DEBUG,   
        PROC_SCSI_NOT_PRESENT,
        PROC_SCSI_FILE,                        /* I'm assuming here that we */
@@ -362,6 +365,7 @@ extern struct inode_operations proc_fd_inode_operations;
 extern struct inode_operations proc_ringbuf_inode_operations;
 #endif
 extern struct inode_operations proc_omirr_inode_operations;
+extern struct inode_operations proc_ppc_htab_inode_operations;
 
 #endif
 
@@ -378,3 +382,8 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
 extern void proc_tty_init(void);
 extern void proc_tty_register_driver(struct tty_driver *driver);
 extern void proc_tty_unregister_driver(struct tty_driver *driver);
+
+/*
+ * proc_devtree.c
+ */
+extern void proc_device_tree_init(void);
index 2d9bb6e196c575aa2110fc78ae2745a7187247d9..926575eb481dfeb3aae916a1aff6bea9de5ea1c1 100644 (file)
@@ -74,6 +74,8 @@ extern struct screen_info screen_info;
 
 #define VIDEO_TYPE_SUN          0x50    /* Sun frame buffer. */
 
+#define VIDEO_TYPE_PMAC                0x60    /* PowerMacintosh frame buffer. */
+
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
  * a c_cc[] character, but indicates that a particular special character
index d2025c5301172b8b3c0e18d9fc36c4e63fa1135c..e75cfcc5eef3f2a209385cdf287caa07896f864d 100644 (file)
@@ -67,7 +67,6 @@ extern unsigned char aux_device_present, kbd_read_mask;
 #include <asm/irq.h>
 #ifdef __SMP__
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #endif
 
 extern char *get_options(char *str, int *ints);
@@ -282,7 +281,6 @@ EXPORT_SYMBOL(timer_table);
 /* Various random spinlocks we want to export */
 EXPORT_SYMBOL(tqueue_lock);
 EXPORT_SYMBOL(waitqueue_lock);
-EXPORT_SYMBOL(lk_lockmsg);
 #endif
 
 /* autoirq from  drivers/net/auto_irq.c */
index 6dc90b0ab5365357dcdb4e67fada324e0306fb81..f444718a7cb33a3041a25a2521b9f86c5ce00827 100644 (file)
@@ -2039,7 +2039,7 @@ __initfunc(void ip_fib_init(void))
                fib_class_get_info
        });
        proc_net_register(&(struct proc_dir_entry) {
-               PROC_NET_RTRULES, 8, "rt_local",
+               PROC_NET_RTLOCAL, 8, "rt_local",
                S_IFREG | S_IRUGO, 1, 0, 0,
                0, &proc_net_inode_operations,
                fib_local_get_info
index 4b722e127042be01c608bb9e1ca45a965e74a656..e359abd30cd2fefc25244e80a330e13a8cc9a36e 100644 (file)
@@ -648,28 +648,25 @@ int sock_create(int family, int type, int protocol, struct socket **res)
 
 asmlinkage int sys_socket(int family, int type, int protocol)
 {
-       int fd, err;
+       int retval;
        struct socket *sock;
 
        lock_kernel();
 
-       if ((err = sock_create(family, type, protocol, &sock)) < 0)
+       retval = sock_create(family, type, protocol, &sock);
+       if (retval < 0)
                goto out;
 
-       if ((fd = get_fd(sock->inode)) < 0) 
-       {
+       retval = get_fd(sock->inode);
+       if (retval < 0) {
                sock_release(sock);
-               err = -EINVAL;
-       }
-       else
-       {
-               sock->file = current->files->fd[fd];
-               err = fd;
+               goto out;
        }
 
+       sock->file = current->files->fd[retval];
 out:
        unlock_kernel();
-       return err;
+       return retval;
 }
 
 /*