]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.4 1.3.4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:03 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:03 +0000 (15:10 -0500)
239 files changed:
CREDITS
Makefile
arch/alpha/kernel/entry.S
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/setup.c
arch/i386/config.in
arch/i386/ibcs/binfmt_elf.c
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/process.c
arch/i386/kernel/sys_i386.c
arch/mips/kernel/traps.c
arch/sparc/Makefile
arch/sparc/boot/Makefile [new file with mode: 0644]
arch/sparc/boot/README [new file with mode: 0644]
arch/sparc/boot/bare.S [new file with mode: 0644]
arch/sparc/boot/bare.h [new file with mode: 0644]
arch/sparc/boot/imperical.h [new file with mode: 0644]
arch/sparc/boot/init_me.c [new file with mode: 0644]
arch/sparc/config.in
arch/sparc/kernel/Makefile
arch/sparc/kernel/V9head.S [new file with mode: 0644]
arch/sparc/kernel/c_mp.c [new file with mode: 0644]
arch/sparc/kernel/entry.S
arch/sparc/kernel/head.S
arch/sparc/kernel/idprom.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/mp.S [new file with mode: 0644]
arch/sparc/kernel/probe.c
arch/sparc/kernel/process.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/traps.c
arch/sparc/mm/Makefile
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/loadmmu.c [new file with mode: 0644]
arch/sparc/mm/srmmu.c [new file with mode: 0644]
arch/sparc/mm/srmmuinv.c [new file with mode: 0644]
arch/sparc/mm/sun4c.c [new file with mode: 0644]
arch/sparc/prom/Makefile [new file with mode: 0644]
arch/sparc/prom/bootstr.c [new file with mode: 0644]
arch/sparc/prom/console.c [new file with mode: 0644]
arch/sparc/prom/devmap.c [new file with mode: 0644]
arch/sparc/prom/devops.c [new file with mode: 0644]
arch/sparc/prom/init.c [new file with mode: 0644]
arch/sparc/prom/memory.c [new file with mode: 0644]
arch/sparc/prom/misc.c [new file with mode: 0644]
arch/sparc/prom/mp.c [new file with mode: 0644]
arch/sparc/prom/palloc.c [new file with mode: 0644]
arch/sparc/prom/printf.c [new file with mode: 0644]
arch/sparc/prom/ranges.c [new file with mode: 0644]
arch/sparc/prom/segment.c [new file with mode: 0644]
arch/sparc/prom/tree.c [new file with mode: 0644]
drivers/block/Makefile
drivers/block/aztcd.c
drivers/block/blk.h
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/ide.c
drivers/block/ll_rw_blk.c
drivers/block/xd.c
drivers/char/atixlmouse.c
drivers/char/busmouse.c
drivers/char/console.c
drivers/char/consolemap.c
drivers/char/cyclades.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/msbusmouse.c
drivers/char/n_tty.c
drivers/char/psaux.c
drivers/char/scc.c
drivers/char/selection.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/vc_screen.c
drivers/char/vesa_blank.c
drivers/char/vt.c
drivers/net/Makefile
drivers/net/Space.c
drivers/net/arcnet.c
drivers/net/eepro.c [new file with mode: 0644]
drivers/net/eql.c
drivers/net/ne.c
drivers/net/ppp.c
drivers/net/sk_g16.c
drivers/net/slip.c
drivers/scsi/53c7,8xx.c
drivers/scsi/53c7,8xx.h
drivers/scsi/53c7,8xx.scr
drivers/scsi/53c8xx_d.h
drivers/scsi/Makefile
drivers/scsi/README-FIRST.aic7xxx [new file with mode: 0644]
drivers/scsi/README.aha274x [deleted file]
drivers/scsi/README.aic7xxx [new file with mode: 0644]
drivers/scsi/aha274x.c [deleted file]
drivers/scsi/aha274x.h [deleted file]
drivers/scsi/aha274x.seq [deleted file]
drivers/scsi/aha274x_seq.h [deleted file]
drivers/scsi/aic7770.c
drivers/scsi/aic7xxx.c [new file with mode: 0644]
drivers/scsi/aic7xxx.h [new file with mode: 0644]
drivers/scsi/aic7xxx.seq [new file with mode: 0644]
drivers/scsi/fdomain.c
drivers/scsi/hosts.c
drivers/scsi/script_asm.pl
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_ioctl.c
drivers/scsi/sd_ioctl.c
drivers/scsi/sg.c
drivers/scsi/sr_ioctl.c
fs/binfmt_elf.c
fs/block_dev.c
fs/buffer.c
fs/exec.c
fs/ext/file.c
fs/ext/symlink.c
fs/ext2/file.c
fs/ext2/symlink.c
fs/hpfs/hpfs_fs.c
fs/isofs/file.c
fs/isofs/symlink.c
fs/minix/file.c
fs/minix/symlink.c
fs/msdos/dir.c
fs/msdos/file.c
fs/namei.c
fs/nfs/symlink.c
fs/open.c
fs/pipe.c
fs/proc/array.c
fs/proc/inode.c
fs/proc/link.c
fs/read_write.c
fs/readdir.c
fs/select.c
fs/sysv/file.c
fs/sysv/symlink.c
fs/umsdos/dir.c
fs/umsdos/emd.c
fs/umsdos/ioctl.c
fs/umsdos/rdir.c
fs/xiafs/file.c
fs/xiafs/symlink.c
include/asm-alpha/dma.h
include/asm-alpha/pal.h [new file with mode: 0644]
include/asm-alpha/segment.h
include/asm-alpha/system.h
include/asm-alpha/termios.h
include/asm-i386/bitops.h
include/asm-i386/io.h
include/asm-i386/segment.h
include/asm-i386/string.h
include/asm-i386/types.h
include/asm-sparc/asi.h
include/asm-sparc/auxio.h [new file with mode: 0644]
include/asm-sparc/bitops.h
include/asm-sparc/bugs.h
include/asm-sparc/cache.h [new file with mode: 0644]
include/asm-sparc/clock.h
include/asm-sparc/contregs.h
include/asm-sparc/cypress.h [new file with mode: 0644]
include/asm-sparc/delay.h
include/asm-sparc/dma.h
include/asm-sparc/ecc.h [new file with mode: 0644]
include/asm-sparc/eeprom.h [new file with mode: 0644]
include/asm-sparc/head.h
include/asm-sparc/idprom.h
include/asm-sparc/io.h
include/asm-sparc/ipsum.h [new file with mode: 0644]
include/asm-sparc/irq.h
include/asm-sparc/kdebug.h [new file with mode: 0644]
include/asm-sparc/machines.h [new file with mode: 0644]
include/asm-sparc/mbus.h [new file with mode: 0644]
include/asm-sparc/memerr.h
include/asm-sparc/memreg.h [new file with mode: 0644]
include/asm-sparc/mostek.h [new file with mode: 0644]
include/asm-sparc/mp.h [new file with mode: 0644]
include/asm-sparc/mpmbox.h [new file with mode: 0644]
include/asm-sparc/mxcc.h [new file with mode: 0644]
include/asm-sparc/openprom.h
include/asm-sparc/oplib.h [new file with mode: 0644]
include/asm-sparc/page.h
include/asm-sparc/pgtable.h
include/asm-sparc/pgtsfmmu.h [new file with mode: 0644]
include/asm-sparc/pgtsrmmu.h [new file with mode: 0644]
include/asm-sparc/pgtsun4.h [new file with mode: 0644]
include/asm-sparc/pgtsun4c.h [new file with mode: 0644]
include/asm-sparc/processor.h
include/asm-sparc/psr.h
include/asm-sparc/ptrace.h
include/asm-sparc/ross.h [new file with mode: 0644]
include/asm-sparc/sbus.h [new file with mode: 0644]
include/asm-sparc/segment.h
include/asm-sparc/smpprim.h [new file with mode: 0644]
include/asm-sparc/string.h
include/asm-sparc/sysen.h
include/asm-sparc/system.h
include/asm-sparc/timer.h [new file with mode: 0644]
include/asm-sparc/traps.h [new file with mode: 0644]
include/asm-sparc/tsunami.h [new file with mode: 0644]
include/asm-sparc/ultra.h [new file with mode: 0644]
include/asm-sparc/unistd.h
include/asm-sparc/vac-ops.h
include/asm-sparc/vaddrs.h
include/asm-sparc/viking.h [new file with mode: 0644]
include/linux/fd.h
include/linux/fs.h
include/linux/mm.h
include/linux/module.h
include/linux/mtio.h
include/linux/sbpcd.h
include/linux/umsdos_fs.p
include/net/sock.h
include/net/tcp.h
init/main.c
ipc/msg.c
ipc/shm.c
ipc/util.c
kernel/exit.c
kernel/ksyms.c
kernel/module.c
kernel/printk.c
kernel/signal.c
kernel/sys.c
kernel/time.c
mm/kmalloc.c
mm/mmap.c
mm/swap.c
mm/vmalloc.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/udp.c
net/socket.c

diff --git a/CREDITS b/CREDITS
index 2bda0cf13f264157db6413354b8cd5a2a0a2a26b..deccebc3a75b2639184c2245cf9f0f98760b69cf 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -807,6 +807,13 @@ S: 1 Laurie Court
 S: Kanata, Ontario
 S: CANADA K2L 1S2
 
+N: Andrew Tridgell
+E: Andrew.Tridgell@anu.edu.au
+D: dosemu, networking, samba
+S: 3 Ballow Crescent
+S: MacGregor A.C.T
+S: 2615 Australia
+
 N: Theodore Ts'o
 E: tytso@mit.edu
 D: Random Linux hacker
index 32465bce239ba2de5c45171aa78b3c2d47da1a46..b53b427c349f35c6bd6f63a53dbc51d192ae704f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 3
+SUBLEVEL = 4
 
 ARCH = i386
 
index f0a5b05f6b7724d7177113e0a285506660caa6fb..43f6120bc99b24f70142305510ae9e331b6cbafd 100644 (file)
@@ -504,23 +504,23 @@ sys_call_table:
        .quad sys_umask, do_entSys, do_entSys, sys_getpgrp, sys_getpagesize
        .quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys
        .quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect
-       .quad sys_madvise, do_entSys, do_entSys, do_entSys, sys_getgroups
+       .quad sys_madvise, sys_vhangup, do_entSys, do_entSys, sys_getgroups
        /* map BSD's setpgrp to sys_setpgid for binary compatibility: */
        .quad sys_setgroups, do_entSys, sys_setpgid, sys_setitimer, do_entSys
        .quad do_entSys, sys_getitimer, sys_gethostname, sys_sethostname, sys_getdtablesize
        .quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, do_entSys
-       .quad sys_fsync, sys_setpriority, sys_socket, do_entSys, do_entSys
-/*100*/        .quad do_entSys, do_entSys, do_entSys, sys_sigreturn, sys_bind
-       .quad do_entSys, sys_listen, do_entSys, do_entSys, do_entSys
+       .quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/        .quad sys_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind
+       .quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys
        .quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys
-       .quad do_entSys, sys_gettimeofday, sys_getrusage, do_entSys, do_entSys
+       .quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys
        .quad do_entSys, do_entSys, sys_settimeofday, sys_fchown, sys_fchmod
-       .quad do_entSys, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-       .quad sys_ftruncate, do_entSys, sys_setgid, do_entSys, do_entSys
-       .quad do_entSys, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
-       .quad do_entSys, do_entSys, do_entSys, do_entSys, sys_getrlimit
+       .quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+       .quad sys_ftruncate, do_entSys, sys_setgid, sys_sendto, sys_shutdown
+       .quad sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
+       .quad do_entSys, sys_getpeername, do_entSys, do_entSys, sys_getrlimit
        .quad sys_setrlimit, do_entSys, sys_setsid, do_entSys, do_entSys
-/*150*/        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+/*150*/        .quad sys_getsockname, do_entSys, do_entSys, do_entSys, do_entSys
        .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries
        .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys
        .quad osf_getdomainname, do_entSys, do_entSys, do_entSys, do_entSys
@@ -538,7 +538,7 @@ sys_call_table:
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
-       .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+       .quad do_entSys, do_entSys, do_entSys, do_entSys, osf_proplist_syscall
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 /*250*/        .quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, do_entSys
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
@@ -552,4 +552,4 @@ sys_call_table:
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 /* linux-specific system calls start at 300 */
 /*300*/        .quad sys_bdflush, sys_sethae, sys_mount, sys_adjtimex, sys_swapoff
-       .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+       .quad sys_getdents, sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms
index 447a2a6acd73159cfe863e312010004b007e2a45..48d68918cb5e8cc79c5279bf9ad83d6658ab71fc 100644 (file)
@@ -68,7 +68,7 @@ struct osf_dirent_callback {
        int error;
 };
 
-static int osf_filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int osf_filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
        struct osf_dirent * dirent;
        struct osf_dirent_callback * buf = (struct osf_dirent_callback *) __buf;
@@ -509,3 +509,124 @@ asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
         */
        return raddr;
 }
+
+
+/*
+ * The following stuff should move into a header file should it ever
+ * be labeled "officially supported."  Right now, there is just enough
+ * support to avoid applications (such as tar) printing error
+ * messages.  The attributes are not really implemented.
+ */
+
+/*
+ * Values for Property list entry flag
+ */
+#define PLE_PROPAGATE_ON_COPY          0x1     /* cp(1) will copy entry
+                                                  by default */
+#define PLE_FLAG_MASK                  0x1     /* Valid flag values */
+#define PLE_FLAG_ALL                   -1      /* All flag value */
+
+struct proplistname_args {
+       unsigned int    pl_mask;
+       unsigned int    pl_numnames;
+       char            **pl_names;
+};
+
+union pl_args {
+       struct setargs {
+               char *path;
+               long follow;
+               long nbytes;
+               char *buf;
+       } set;
+       struct fsetargs {
+               long fd;
+               long nbytes;
+               char *buf;
+       } fset;
+       struct getargs {
+               char *path;
+               long follow;
+               struct proplistname_args *name_args;
+               long nbytes;
+               char *buf;
+               int *min_buf_size;
+       } get;
+       struct fgetargs {
+               long fd;
+               struct proplistname_args *name_args;
+               long nbytes;
+               char *buf;
+               int *min_buf_size;
+       } fget;
+       struct delargs {
+               char *path;
+               long follow;
+               struct proplistname_args *name_args;
+       } del;
+       struct fdelargs {
+               long fd;
+               struct proplistname_args *name_args;
+       } fdel;
+};
+
+enum pl_code {
+       PL_SET  = 1,    PL_FSET = 2,
+       PL_GET  = 3,    PL_FGET = 4,
+       PL_DEL  = 5,    PL_FDEL = 6
+};
+
+asmlinkage long osf_proplist_syscall (enum pl_code code, union pl_args *args)
+{
+       long error;
+       int *min_buf_size_ptr;
+
+       switch (code) {
+             case PL_SET:
+               error = verify_area(VERIFY_READ, &args->set.nbytes,
+                                   sizeof(args->set.nbytes));
+               if (error)
+                 return error;
+               return args->set.nbytes;
+
+             case PL_FSET:
+               error = verify_area(VERIFY_READ, &args->fset.nbytes,
+                                   sizeof(args->fset.nbytes));
+               if (error)
+                 return error;
+               return args->fset.nbytes;
+
+             case PL_GET:
+               error = verify_area(VERIFY_READ, &args->get.min_buf_size,
+                                   sizeof(args->get.min_buf_size));
+               if (error)
+                 return error;
+               min_buf_size_ptr = get_user(&args->get.min_buf_size);
+               error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
+                                   sizeof(*min_buf_size_ptr));
+               if (error)
+                 return error;
+               put_user(0, min_buf_size_ptr);
+               return 0;
+
+             case PL_FGET:
+               error = verify_area(VERIFY_READ, &args->fget.min_buf_size,
+                                   sizeof(args->fget.min_buf_size));
+               if (error)
+                 return error;
+               min_buf_size_ptr = get_user(&args->fget.min_buf_size);
+               error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
+                                   sizeof(*min_buf_size_ptr));
+               if (error)
+                 return error;
+               put_user(0, min_buf_size_ptr);
+               return 0;
+
+             case PL_DEL:
+             case PL_FDEL:
+               return 0;
+
+             default:
+               return -EOPNOTSUPP;
+       }
+}
index 0245d0cb05961553c0b9ff4c9ba2f3fe255503ca..344eefa683bb0b1c488d0cc45663a1f966840c53 100644 (file)
@@ -35,7 +35,7 @@ struct hae hae = {
 
 struct hwrpb_struct *hwrpb;
 
-unsigned char aux_device_present;
+unsigned char aux_device_present = 0xaa;
 
 /*
  * This is setup by the secondary bootstrap loader.  Because
@@ -52,7 +52,7 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
 /*
  * 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.
+ * code think we're on a VGA color display.
  */
 struct screen_info screen_info = {
        0, 0,                   /* orig-x, orig-y */
@@ -62,6 +62,7 @@ struct screen_info screen_info = {
        80,                     /* orig-video-cols */
        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
        25,                     /* orig-video-lines */
+       1,                      /* orig-video-isVGA */
        16                      /* orig-video-points */
 };
 
@@ -95,7 +96,6 @@ void setup_arch(char **cmdline_p,
        set_hae(hae.cache);             /* sync HAE register w/hae_cache */
 
        ROOT_DEV = 0x0802;              /* sda2 */
-       aux_device_present = 0xaa;
        command_line[COMMAND_LINE_SIZE - 1] = '\0';
        strcpy(command_line, COMMAND_LINE);
 
index bfbf42acb3fc7487df9a83cab343eeb388a68f8e..1cdf3e6617c2d137b5455b46c791b8d604259e3c 100644 (file)
@@ -92,7 +92,9 @@ comment 'SCSI low-level drivers'
 bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+if [ "$CONFIG_PCI" = "y" ]; then
+  bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
+fi
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
 bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
@@ -163,7 +165,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
        bool 'EtherWorks 3 support' CONFIG_EWRK3 n
        if [ "$CONFIG_NET_ALPHA" = "y" ]; then
                bool 'AT1700 support' CONFIG_AT1700 n
-#              bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
+               bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
                bool 'EtherExpress support' CONFIG_EEXPRESS n
                bool 'NI5210 support' CONFIG_NI52 n
                bool 'NI6510 support' CONFIG_NI65 n
@@ -230,8 +232,7 @@ bool 'Second extended fs support' CONFIG_EXT2_FS y
 bool 'xiafs filesystem support' CONFIG_XIA_FS n
 bool 'msdos fs support' CONFIG_MSDOS_FS y
 if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-#bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
-comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1'
+bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
 fi
 bool '/proc filesystem support' CONFIG_PROC_FS y
 if [ "$CONFIG_INET" = "y" ]; then
index ab6d36915787ae1e4c3f547eac03759b97e22d85..d38634219cd063e3b56215f13c81f4e6a6d796ae 100644 (file)
@@ -482,7 +482,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                                        elf_ppnt->p_offset & 0xfffff000);
                        
 #ifdef LOW_ELF_STACK
-                       if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack) 
+                       if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack) 
                                elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
 #endif
                        
@@ -635,7 +635,7 @@ static int load_elf_library(int fd){
        if(k > elf_bss) elf_bss = k;
        
        sys_close(fd);
-       if (error != elf_phdata->p_vaddr & 0xfffff000) {
+       if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
                kfree(elf_phdata);
                return error;
        }
index 1bdf062c8a0fd29397e331399d3c919ab095b926..a700c6ec674791ecb0d6602f886bf2fe0b06e044 100644 (file)
@@ -490,7 +490,7 @@ _sys_call_table:
        .long _sys_swapon
        .long _sys_reboot
        .long _old_readdir
-       .long _sys_mmap                 /* 90 */
+       .long _old_mmap                 /* 90 */
        .long _sys_munmap
        .long _sys_truncate
        .long _sys_ftruncate
@@ -544,4 +544,4 @@ _sys_call_table:
        .long _sys_getdents
        .long _sys_select
        .long _sys_flock
-       .space (NR_syscalls-140)*4
+       .space (NR_syscalls-143)*4
index a3e0df2132c0a2bd9e5374cf8a4474d23342e822..b3ebdfed1c39ffdbce495f4c9366d5e80e28450f 100644 (file)
@@ -14,7 +14,6 @@
 .globl _empty_bad_page
 .globl _empty_bad_page_table
 .globl _empty_zero_page
-.globl _floppy_track_buffer
 
 #define __ASSEMBLY__
 #include <linux/tasks.h>
@@ -288,15 +287,7 @@ _empty_bad_page_table:
 _empty_zero_page:
 
 .org 0x6000
-/*
- * floppy_track_buffer is used to buffer one track of floppy data: it
- * has to be separate from the tmp_floppy area, as otherwise a single-
- * sector read/write can mess it up. It can contain one full cylinder (sic) of
- * data (36*2*512 bytes).
- */
-_floppy_track_buffer:
-       .fill 512*2*MAX_BUFFER_SECTORS,1,0
-       
+
 stack_start:
        .long _init_user_stack+4096
        .long KERNEL_DS
index a5e8777bf34f3118ebfb2635bed223fc09721b5f..77254751b7ace5e5fb5d50e80bc6f4c46d2bf162 100644 (file)
@@ -39,22 +39,6 @@ void enable_hlt(void)
        hlt_counter--;
 }
 
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
-       int fd[2];
-       int error;
-
-       error = verify_area(VERIFY_WRITE,fildes,8);
-       if (error)
-               return error;
-       error = do_pipe(fd);
-       if (error)
-               return error;
-       put_fs_long(fd[0],0+fildes);
-       put_fs_long(fd[1],1+fildes);
-       return 0;
-}
-
 /*
  * The idle loop on a i386..
  */
index 8eec88a8f9fb89ddaa573882acac061e0467b4d8..c1276730922469883ee4ab44c605eb649e14ed79 100644 (file)
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/mman.h>
 
 #include <asm/segment.h>
 
 /*
- * Perform the select(nd, in, out, ex, tv) system call.
- * Linux/i386 didn't use to be able to handle 5 system call
- * parameters, so the old select used a memory block for
- * parameter passing..
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix tranditionally does this, though.
  */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+       int fd[2];
+       int error;
+
+       error = verify_area(VERIFY_WRITE,fildes,8);
+       if (error)
+               return error;
+       error = do_pipe(fd);
+       if (error)
+               return error;
+       put_fs_long(fd[0],0+fildes);
+       put_fs_long(fd[1],1+fildes);
+       return 0;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+asmlinkage int old_mmap(unsigned long *buffer)
+{
+       int error;
+       unsigned long flags;
+       struct file * file = NULL;
+
+       error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
+       if (error)
+               return error;
+       flags = get_user(buffer+3);
+       if (!(flags & MAP_ANONYMOUS)) {
+               unsigned long fd = get_user(buffer+4);
+               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+                       return -EBADF;
+       }
+       return do_mmap(file, get_user(buffer), get_user(buffer+1),
+                      get_user(buffer+2), flags, get_user(buffer+5));
+}
+
+
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 
 asmlinkage int old_select(unsigned long *buffer)
index a958670df80ced992dbd8cbf45eca8be10777d98..c38d824599ebc556fd3420e6b5fd7daf6956684f 100644 (file)
@@ -82,7 +82,7 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err)
        unsigned long *stack, addr, module_start, module_end;
        extern char start_kernel, etext;
 
-       if (regs->cp0_status & (ST0_ERL|ST0_EXL) == 0)
+       if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
                return;
 
        sp = (unsigned long *)regs->reg29;
index 88bcd6578b491c31226a191b61f7d3ba2e8ba9f2..ebf518eef3182a1db866af2400ef89c4d9df8ec3 100644 (file)
@@ -19,15 +19,25 @@ SHELL  =/bin/bash
 # I ignore it and eliminate those mappings during vm initialization and
 # just leave the low mapping.
 #
-LINKFLAGS = -N -Ttext 0x00004000
+LINKFLAGS = -N -Ttext 0xf0004000
 CFLAGS := $(CFLAGS) -pipe
 
 HEAD := arch/sparc/kernel/head.o
 
-SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm
+SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
+       arch/sparc/prom
+
 ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES)
-LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a
+
+aoutimage: vmlinux
+       elftoaout -o aoutimage vmlinux
+
+
+LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a \
+       $(TOPDIR)/arch/sparc/prom/promlib.a
+
 
 archclean:
+       rm -f $(TOPDIR)/arch/sparc/boot/boot
 
 archdep:
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
new file mode 100644 (file)
index 0000000..51f46ad
--- /dev/null
@@ -0,0 +1,35 @@
+# Makefile for the Sparc low level /boot module.
+#
+# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+
+OBJS   =bare.o init_me.o ../kernel/promops.o ../lib/lib.a
+BOOTLINKFLAGS = -N -Ttext 0x200000 -e _first_adr_in_text
+
+.c.s:
+       $(CC) $(CFLAGS) -S -o $*.s $<
+.s.o:
+       $(AS) -o $*.o $<
+.c.o:
+       $(CC) $(CFLAGS) -c -o $*.o $<
+.S.s:
+       $(CC) -D__ASSEMBLY__ -D__KERNEL__ -ansi -E -o $*.o $<
+.S.o:
+       $(CC) -D__ASSEMBLY__ -D__KERNEL__ -ansi -c -o $*.o $<
+
+all: boot
+
+boot: $(OBJS)
+       $(LD) $(BOOTLINKFLAGS) $(OBJS) -o boot
+
+dep:
+       $(CPP) -M *.c > .depend
+       $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/sparc/boot/README b/arch/sparc/boot/README
new file mode 100644 (file)
index 0000000..77f34da
--- /dev/null
@@ -0,0 +1,21 @@
+This directory will contain the code necessary to compile and link the
+/boot program which is necessary to boot on the Sparc.  This program
+is real ugly and it knows too much.  It must be able to not only boot
+off of the root partition but also be able to netboot.  This means
+that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it
+can remote mount the root directory to fetch the kernel.  Also it must
+be able to ARP for it's IP address and who it's boot server is.  I
+think I'm getting sick.
+
+Regardless for now I will concentrate on the low-level stuff necessary
+to get the thing going.  This means the low-level entry code, etc.
+The prom knows how to get "us" if we have the proper boot blocks,
+actually the boot blocks live in our logical partition on a hard drive
+whereas over NFS this isn't applicable.  We have the boot blocks in
+our data area either way because we can be dual purpose.
+
+More will come....
+
+Hopefully I can write this such that it will work on almost all SUN
+machines in existance.  We'll see ;(
+
diff --git a/arch/sparc/boot/bare.S b/arch/sparc/boot/bare.S
new file mode 100644 (file)
index 0000000..8cd8df9
--- /dev/null
@@ -0,0 +1,158 @@
+/* base.S:      Ugly low-level boot program entry code.  The job of this
+ *              module is to parse the boot flags, try to mount the remote
+ *              root filesystem and load the kernel into virtual memory.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include "bare.h"
+
+       .data
+       .globl C_LABEL(romvec)
+       .globl C_LABEL(idp_ptr)
+
+C_LABEL(romvec):
+       .word 0
+C_LABEL(idp_ptr):
+       .word 0
+
+       .text
+       .align 8
+       .globl C_LABEL(first_adr_in_text)
+
+C_LABEL(first_adr_in_text):
+
+       /* Grrr, boot block, scratching my head... */
+       .globl C_LABEL(b_block)       /* Start of actual boot block */
+       .globl C_LABEL(b_block_size)  /* In bytes */
+       .globl C_LABEL(b_block_cksum) /* Checksum of boot block bytes */
+
+       b       start_of_execution    /* XXX Hack */
+       nop
+
+       .align  8
+C_LABEL(b_block):      
+       .skip   (BOOTBLOCK_NENTRIES * BOOTBLOCK_ENTSIZE)
+
+C_LABEL(b_block_size):
+       .word   0
+
+C_LABEL(b_block_cksum):
+       .word   0
+
+/* Ok, the prom has left in %o0 the PROM pointer.  We leave it here
+ * for when we jump into the kernel.  So save out of this window before
+ * you dick with %o0.  As far as I know we could be loaded *anywhere*, so
+ * we relocate ourselves to the "linked" location.  Self modifying code rules.
+ */
+
+start_of_execution:
+       sethi   %hi(C_LABEL(first_adr_in_text)), %o1            ! This is our top
+       or      %o1, %lo(C_LABEL(first_adr_in_text)), %o1       ! of stack too.
+       sub     %o1, C_STACK, %o1
+       add     %o1, 0x7, %o1
+       andn    %o1, 0x7, %o1
+       save    %o1, 0x0, %sp                                   ! save is an add
+here:
+       call    there
+       sethi   %hi(here), %o4
+there: 
+       sub     %o7, here-C_LABEL(first_adr_in_text), %o5
+       or      %o4, %lo(here), %o4
+       cmp     %o4, %o7
+       be      loaded_ok
+       nop
+
+       /* Gotta relocate, compute our size sans bss segment. */
+       set     C_LABEL(edata)+4, %o3
+       set     C_LABEL(first_adr_in_text), %o2
+       sub     %o3, %o2, %o3
+rel_loop:
+       ld      [%o5], %o4
+       add     %o5, 0x4, %o5
+       st      %o4, [%o2]
+       subcc   %o3, 0x4, %o3
+       bg      rel_loop
+       add     %o2, 0x4, %o2
+
+       /* Pray that we are now in a sane place in memory */
+       sethi   %hi(loaded_ok), %o2
+       or      %o2, %lo(loaded_ok), %o2
+       jmp     %o2
+       nop
+
+loaded_ok:
+       /* Save the PROM pointer */
+       sethi   %hi(C_LABEL(romvec)), %o1
+       or      %o1, %lo(C_LABEL(romvec)), %o1
+       st      %i0, [%o1]
+
+       /* Build a PSR we can live with */
+       rd      %psr, %o1
+
+#if 0
+       andn    %o1, PSR_PIL, %o1
+       sethi   %hi(SANE_PSR), %g4
+       or      %g4, %lo(SANE_PSR), %g4
+       or      %o1, %g4, %o1
+#endif
+
+       /* V8 book says this works to calculate num_windows */
+       sethi   %hi(0xffffffff), %g2
+       rd      %wim, %g3
+       or      %g2, %lo(0xffffffff), %g2
+       wr      %g2, 0x0, %wim
+       WRITE_PAUSE
+
+       rd      %wim, %g4
+       WRITE_PAUSE
+
+       wr      %g3, 0x0, %wim
+       WRITE_PAUSE
+
+       /* Restore old %psr */
+       wr      %o1, 0x0, %psr
+       WRITE_PAUSE
+
+       or      %g0, 0x0, %g3
+1:
+       srl     %g4, 0x1, %g4
+       subcc   %g4, 0x0, %g0
+       bne     1b
+       add     %g3, 0x1, %g3
+       
+       /* %g3 now contains nwindows */
+       sethi   %hi(C_LABEL(nwindows)), %o4
+       st      %g3, [%o4 + %lo(C_LABEL(nwindows))]
+
+       /* Now zero out our bss segment, lord knows the nasty prom monster
+        * didn't do it for us.
+        */
+       sethi   %hi(C_LABEL(end)), %g1
+       or      %g1, %lo(C_LABEL(end)), %g1
+       add     %g1, 0x4, %g1
+       sethi   %hi(C_LABEL(edata)), %g2
+       or      %g2, %lo(C_LABEL(edata)), %g2
+
+       /* Slow, inefficient, who cares, this is messy boot code */
+bzero_bss_loop:
+       st      %g0, [%g2]
+       add     %g2, 0x4, %g2
+       cmp     %g2, %g1
+       bl      bzero_bss_loop
+       nop
+
+       call    C_LABEL(init_me)        ! Fun with imperical constants and prom
+       nop
+
+       /* Dump back into the prom */
+get_me_out_of_here:
+       set     C_LABEL(romvec), %g2
+       ld      [%g2], %g2
+       ld      [%g2 + 0x74], %g2
+       restore
+       call    %g2
+       nop
+
+
+
diff --git a/arch/sparc/boot/bare.h b/arch/sparc/boot/bare.h
new file mode 100644 (file)
index 0000000..86c01e7
--- /dev/null
@@ -0,0 +1,17 @@
+/* bare.h:  Defines for the low level entry code of the BOOT program.
+ *          We include in the head.h stuff that the real kernel uses
+ *          and this saves a lot of repetition here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/cprefix.h>
+
+#define     SANE_PIL  (0xd00)    /* No interrupts except clock and unmaskable NMI's */
+#define     SANE_PSR  (SANE_PIL|PSR_S|PSR_ET)
+
+#define     BOOTBLOCK_NENTRIES   0x40      /* Number of entries in the boot block */
+#define     BOOTBLOCK_ENTSIZE    0x04      /* Size in bytes of each boot block entry */
+
diff --git a/arch/sparc/boot/imperical.h b/arch/sparc/boot/imperical.h
new file mode 100644 (file)
index 0000000..f5f7727
--- /dev/null
@@ -0,0 +1,7 @@
+/* imperical.h:  Nasty hacks....
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#define DEF_BOGO     25
+
diff --git a/arch/sparc/boot/init_me.c b/arch/sparc/boot/init_me.c
new file mode 100644 (file)
index 0000000..2c4cc2b
--- /dev/null
@@ -0,0 +1,68 @@
+/* init_me.c:  Initialize imperical constants and gather some info from
+ *             the boot prom.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>  /* For property declarations and the prom structs */
+#include <asm/oplib.h>
+#include <asm/vac-ops.h>
+
+#include "imperical.h"   /* Don't ask... */
+
+#define DEBUG_INIT_ME    /* Tell me whats goin on */
+
+unsigned int nwindows;   /* Set in bare.S */
+unsigned int nwindowsm1;
+unsigned int pac_or_vac; /* 0 means "dunno" 1 means "VAC" 2 means "PAC" */
+unsigned int pvac_size;  /* Use the same two variables for a PAC and VAC */
+unsigned int pvac_linesize;
+unsigned int pac_size;
+int num_segmaps;
+int num_contexts;
+unsigned int BOGOMIPS;        /* bogosity without the VAC cache on */
+unsigned int BOGOMIPS_WCACHE; /* bogosity with the VAC cache */
+unsigned int delay_factor;
+
+extern int prom_node_root;
+void (*printk)(const char *str, ...);
+
+void init_me(void)
+{
+       unsigned int grrr;
+
+       printk = romvec->pv_printf;
+       prom_node_root = prom_nextnode(0);
+       prom_getprop(prom_node_root, "mmu-npmg", &num_segmaps,
+                    sizeof(unsigned int));
+
+       pvac_size = prom_getint_default(prom_node_root, "vac-size", 65536);
+
+       pvac_linesize = prom_getint_default(prom_node_root, "vac-linesize", 16);
+       
+       grrr = prom_getint_default(prom_node_root, "mips-on", 0);
+       if(!grrr) {
+               grrr = prom_getint_default(prom_node_root, "clock-frequency", 0);
+               if(grrr > 15000000 && grrr < 100000000) {
+                       BOGOMIPS = 3;
+                       BOGOMIPS_WCACHE = grrr / 1000000;
+               } else {
+                       BOGOMIPS = DEF_BOGO;
+                       BOGOMIPS_WCACHE = DEF_BOGO;
+               }
+       } else (BOGOMIPS_WCACHE = grrr, 
+               BOGOMIPS = prom_getint(prom_node_root, "mips-off"));
+
+#ifdef DEBUG_INIT_ME
+       (*(romvec->pv_printf))("\nBOGOMIPS        %d\n", (int) BOGOMIPS);
+       (*(romvec->pv_printf))("BOGOMIPS_WCACHE %d\n", (int) BOGOMIPS_WCACHE);
+       (*(romvec->pv_printf))("pvac_size        %d\n", (int) pvac_size);
+       (*(romvec->pv_printf))("pvac_linesize    %d\n", (int) pvac_linesize);
+       (*(romvec->pv_printf))("num_segmaps     %d\n", (int) num_segmaps);
+#endif
+
+       delay_factor = (BOGOMIPS > 3) ? ((BOGOMIPS - 2) >> 1) : 11;
+
+       (*(romvec->pv_printf))("\nLILO: \n");
+       return;
+}
index be9336eedd00f44c13ddbb0df6f22ff761cefcd1..6fab6963db180519c331bae20f9e5a0f8cf9ee74 100644 (file)
@@ -9,12 +9,12 @@
 # see the Configure script.
 #
 
+echo "#define CONFIG_SPARCDEVS 1" >> $CONFIG_H
+echo "CONFIG_SPARCDEVS=y" >> $CONFIG
+
 comment 'Sparc Kernel setup'
 
-bool 'Sparc V8 kernel' CONFIG_SPARC_V8 y
-bool 'Sparc SMP support' CONFIG_LINUX_SMP n
-bool 'Sparc SUN4M support' CONFIG_SUN4M n
-bool 'Sparc Reference MMU' CONFIG_SRMMU n
+bool 'Sun floppy controller support' CONFIG_BLK_DEV_SUNFD n
 bool 'Networking support' CONFIG_NET n
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'System V IPC' CONFIG_SYSVIPC y
@@ -57,26 +57,8 @@ bool 'SCSI generic support' CONFIG_CHR_DEV_SG n
 
 comment 'SCSI low-level drivers'
 
-bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
-bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
-bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
-bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
-if [ "$CONFIG_PCI" = "y" ]; then
-  bool 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx n
-fi
-bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
-bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
-bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
-bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
-bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
-bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
-bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
-bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
-#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+bool 'Sun ESP Scsi support' CONFIG_SCSI_SUN_ESP n
+
 fi
 
 
@@ -100,143 +82,42 @@ fi
 bool 'PPP (point-to-point) support' CONFIG_PPP n
 bool 'PLIP (parallel port) support' CONFIG_PLIP n
 bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
-bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
-bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
-if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-       bool 'WD80*3 support' CONFIG_WD80x3 n
-       bool 'SMC Ultra support' CONFIG_ULTRA n
-fi
-bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
-bool '3COM cards' CONFIG_NET_VENDOR_3COM y
-if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
-       bool '3c501 support' CONFIG_EL1 n
-       bool '3c503 support' CONFIG_EL2 n
-       if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-               bool '3c505 support' CONFIG_ELPLUS n
-               bool '3c507 support' CONFIG_EL16 n
-       fi
-       bool '3c509/3c579 support' CONFIG_EL3 y
-fi
-bool 'Other ISA cards' CONFIG_NET_ISA n
-if [ "$CONFIG_NET_ISA" = "y" ]; then
-       bool 'Cabletron E21xx support' CONFIG_E2100 n
-       bool 'DEPCA support' CONFIG_DEPCA n
-       bool 'EtherWorks 3 support' CONFIG_EWRK3 n
-       if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-#              bool 'Arcnet support' CONFIG_ARCNET n
-               bool 'AT1700 support' CONFIG_AT1700 n
-#              bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
-               bool 'EtherExpress support' CONFIG_EEXPRESS n
-               bool 'NI5210 support' CONFIG_NI52 n
-               bool 'NI6510 support' CONFIG_NI65 n
-       fi
-       bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
-       bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
-       bool 'NE2000/NE1000 support' CONFIG_NE2000 y
-       bool 'SK_G16 support' CONFIG_SK_G16 n
-fi
-bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
-if [ "$CONFIG_NET_EISA" = "y" ]; then
-       if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-               bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
-       fi
-       bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
-#      bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
-#      bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
-#      bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
-       bool 'Zenith Z-Note support' CONFIG_ZNET y
+bool 'Sun LANCE Ethernet support' CONFIG_SUN_LANCE n
+bool 'Sun Intel Ethernet support' CONFIG_SUN_INTEL n
 fi
-bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
-if [ "$CONFIG_NET_POCKET" = "y" ]; then
-       bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
-       bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
-       bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
-#      bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
-#      bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
-#      bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
 fi
-fi
-fi
-
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
-bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
-bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n
-bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
-if [ "$CONFIG_SBPCD" = "y" ]; then
-  bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
-  if [ "$CONFIG_SBPCD2" = "y" ]; then
-    bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
-    if [ "$CONFIG_SBPCD3" = "y" ]; then
-      bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
-    fi
-  fi
-fi
-bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
 
 comment 'Filesystems'
 
-bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
-bool 'Extended fs support' CONFIG_EXT_FS y
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
+bool 'Extended fs support' CONFIG_EXT_FS n
 bool 'Second extended fs support' CONFIG_EXT2_FS y
-bool 'xiafs filesystem support' CONFIG_XIA_FS y
-bool 'msdos fs support' CONFIG_MSDOS_FS y
-if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
-fi
+bool 'xiafs filesystem support' CONFIG_XIA_FS n
+bool 'msdos fs support' CONFIG_MSDOS_FS n
 bool '/proc filesystem support' CONFIG_PROC_FS n
 if [ "$CONFIG_INET" = "y" ]; then
 bool 'NFS filesystem support' CONFIG_NFS_FS n
 fi
 if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
-       bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
+       bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
 else
        bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
 fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
-bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS y
+bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 
 
 comment 'character devices'
 
-bool 'Cyclades async mux support' CONFIG_CYCLADES n
-bool 'Parallel printer support' CONFIG_PRINTER n
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
-bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
-if [ "$CONFIG_PSMOUSE" = "y" ]; then
-bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
-fi
-bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
-bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-
-
-bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
-if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
-bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF y
-if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
-
-comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
-
-else
-
-comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
-comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
-
-fi
-fi
-
-bool 'QIC-117 tape support' CONFIG_FTAPE n
-if [ "$CONFIG_FTAPE" = "y" ]; then
-int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
-fi
+bool 'Zilog serial support' CONFIG_SUN_ZS n
 
 comment 'Sound'
 
-bool 'Sound card support' CONFIG_SOUND n
+bool 'Sun Audio support' CONFIG_SUN_AUDIO n
 
 comment 'Kernel hacking'
 
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
 bool 'Kernel profiling support' CONFIG_PROFILE n
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
index b5151d77edded5bece75ee7aa3dcfd044da47811..6ff07429fb17657757129b2df26b11d66a243405 100644 (file)
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-OBJS  = entry.o traps.o irq.o process.o promops.o signal.o ioport.o setup.o \
-       idprom.o probe.o
+OBJS  = entry.o traps.o irq.o process.o signal.o ioport.o setup.o \
+       idprom.o probe.o mp.o c_mp.o
 
 all: kernel.o head.o
 
 head.o: head.s
 
-head.s: head.S $(TOPDIR)/include/asm-sparc/head.h
-       $(CPP) -D__ASSEMBLY__ -ansi -o $*.s $<
+head.s: head.S
+       $(CPP) -D__KERNEL__ -D__ASSEMBLY__ -ansi -o $*.s $<
 
 kernel.o: $(OBJS)
        $(LD) -r -o kernel.o $(OBJS)
@@ -34,6 +34,7 @@ kernel.o: $(OBJS)
 
 dep:
        $(CPP) -M *.c > .depend
+       $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
 
 dummy:
 
diff --git a/arch/sparc/kernel/V9head.S b/arch/sparc/kernel/V9head.S
new file mode 100644 (file)
index 0000000..f8e0912
--- /dev/null
@@ -0,0 +1,16 @@
+/* V9head.S: Initial boot code for the V9 Sparc under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ */
+
+#include <asm/cprefix.h>
+
+       .text
+
+       .globl  start
+       .globl  _start
+       .globl  C_LABEL(trapbase)
+_start:
+start:
+C_LABEL(trapbase):
diff --git a/arch/sparc/kernel/c_mp.c b/arch/sparc/kernel/c_mp.c
new file mode 100644 (file)
index 0000000..59747fc
--- /dev/null
@@ -0,0 +1,47 @@
+/* mp.c:  SMP cpu idling and dispatch on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller
+ */
+
+#include <asm/mp.h>
+#include <asm/mbus.h>
+
+struct sparc_percpu *percpu_table;
+
+void
+sparc_cpu_init(void)
+{
+       /* We now have our per-cpu mappings ok, and we should
+        * be good to go.
+        */
+
+       /* Do cache crap here. */
+
+       /* CPU initted, idle the puppy. */
+
+       return;
+}
+
+extern thiscpus_mid;
+
+void
+sparc_cpu_idle(void)
+{
+       int cpuid;
+
+/*     cpuid = get_cpuid(); */
+       cpuid = (thiscpus_mid&(~8));
+/*     printk("SMP: cpu%d has entered idle loop", cpuid); */
+
+       /* Say that we exist and set up. */
+       percpu_table[cpuid].cpuid = cpuid;
+       percpu_table[cpuid].cpu_is_alive = 0x1;
+       percpu_table[cpuid].cpu_is_idling = 0x1;
+
+       /* Let other cpus catch up. */
+       while(linux_smp_still_initting) ;
+       printk("cpu%d done spinning\n", get_cpuid());
+       for(;;) ;  /* Do something useful here... */
+
+       return;
+}      
index 21548015ef22ac9e013f442251fcc368479e9477..d5282a6b16ba1495acece7d3fa3da80b9a8e41ff 100644 (file)
@@ -5,18 +5,52 @@
  * the trap table and how it works, this will show you how we get
  * to these routines.
  *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+
 #include <asm/head.h>
 #include <asm/asi.h>
+#include <asm/contregs.h>
 #include <asm/psr.h>
 #include <asm/cprefix.h>
 #include <asm/vaddrs.h>
+#include <asm/memreg.h>
+#include <asm/page.h>
+
+#define NR_SYSCALLS 255      /* Each OS is different... */
+
+/* A debugging macro, it just prints a dot on the screen.  For now
+ * it is only used in the context switch code since it is so delicate
+ * I need to use the prom putchar() routines and reload the pointers
+ * every time.  This clobbers %l7 and %o0.
+ */
+#define DO_SPARC_DOT \
+       sethi   %hi(C_LABEL(romvec)), %l7; \
+       ld      [%l7 + %lo(C_LABEL(romvec))], %l7; \
+       ld      [%l7 + 0x54], %l7; \
+       or      %g0, '.', %o0; \
+       call    %l7; \
+       nop; \
+       nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
+
+/* Another macro, the name speaks for itself. */
+#define DROP_THE_BOMB \
+       sethi   %hi(C_LABEL(romvec)), %l7;  \
+       ld      [%l7 + %lo(C_LABEL(romvec))], %l7;  \
+       ld      [%l7 + 0x74], %l7;  \
+       call    %l7;  \
+       nop;  \
+
+/* Turn off interrupts while we change contexts. Clobbers %l7 */
+#define TRAPS_OFF \
+       rd      %psr, %l7; \
+       andn    %l7, (PSR_ET), %l7; \
+       wr      %l7, 0x0, %psr; \
 
 /* Here are macros for routines we do often, this allows me to inline this
- * without making the code look real ugly. Well, the macro looks ugly too but
- * makes the trap entry code easier to understand.
+ * without making the code look real ugly.  Well, the macro looks ugly too
+ * but makes the trap entry code easier to understand.
  */
 
 /* I really don't like synthetic instructions. So I avoid them like the
  * have to check that the pages of memory that I am going to throw the window(s)
  * onto are valid and are writable by the user (this is %sp to %sp + 64) before
  * I start dumping stuff there. We always assume that kernels stack is ok.
+ * XXX Will change on MP's XXX
  *
  * If we have to save a kernel window, only one branch is taken. This should
  * make trap handlers quicker in this scenario.
  *
  * Once 'current' is loaded into %g6, it stays there until we leave
  * this macro.
- *
- * XXX must do some checking on the assumption that kernel stack is always ok
  */
 
 /* I will document how this works real soon. TODO */
@@ -62,6 +95,8 @@
        sll     %g5, %g7, %g5; \
        wr      %g5, 0x0, %wim;                 /* update %wim to 'now' invalid */ \
        and     %g7, 0x1f, %g7; \
+       sethi   %hi( C_LABEL(current) ), %g6; \
+       ld      [%g6 + %lo( C_LABEL(current) )], %g6; \
        st      %g7, [%g6 + THREAD_WIM];        /* save 'this' threads mask */ \
        restore %g0, %g0, %g0; \
        or      %g0, %l5, %g5;                  /* restore the globals we used */ \
        b       8f;                             /* we are done */ \
        or      %g0, %l7, %g7; \
 2:     sub     %g7, 0x1, %g7; \
+       sethi   %hi( C_LABEL(current) ), %g6; \
+       ld      [%g6 + %lo( C_LABEL(current) )], %g6; \
        st      %g7, [%g6 + THREAD_UWINDOWS];   /* There are user windows if we */ \
        andcc   %sp, 0x7, %g0;                  /* get here. Check for stack alignment. */ \
        bne     5f;                             /* Stack is unaligned, yuck. */ \
  * upon entry to most traps and interrupts. This is save away the current window
  * if it is the trap window, clean it, and adjust the stack for the handler c-code
  * to work.
+ *
+ * See asm-sparc/cprefix.h to see how the CONCAT macros work.
+ */
+/* NOTE: The system call entry code ASSUMES that the ENTER_TRAP macro
+ *       does NOT touch register %l7 and leaves the same contents after
+ *       the macro is done. Keep in mind if you change this code.
  */
 
-#define ENTER_TRAP \
+#define ENTER_TRAP(label) \
        rd      %wim, %l4; \
        or      %g0, 0x1, %l5; \
        sll     %l5, %l0, %l5; \
-       andcc   %l0, 0x40, %g0; \
-       bz      1f; \
+       andcc   %l0, PSR_PS, %g0; \
+       bz      CONCAT1(label, 1); \
        andcc   %l4, %l5, %g0; \
-       bz,a    3f; \
+       bz,a    CONCAT1(label, 3); \
        sub     %fp, 0xb0, %sp; \
        TRAP_WIN_CLEAN \
-       b       3f; \
+       b       CONCAT1(label, 3); \
        sub     %fp, 0xb0, %sp; \
-1:     sethi   %hi( C_LABEL(current) ), %l6; \
+CONCAT1(label, 1): \
+       sethi   %hi( C_LABEL(current) ), %l6; \
        ld      [%l6 + %lo( C_LABEL(current) )], %l6; \
        ld      [%l6 + THREAD_WIM], %l5; \
        and     %l0, 0x1f, %l4; \
        cmp     %l5, %l3; \
-       ble,a   4f; \
+       ble,a   CONCAT1(label, 4); \
        sethi   %hi( C_LABEL(nwindowsm1) ), %l4; \
        sub     %l5, %l3, %l3; \
-       b       5f; \
+       b       CONCAT1(label, 5); \
        sub     %l3, 0x1, %l5; \
-4:     ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+CONCAT1(label, 4): \
+       ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
        sub     %l4, %l3, %l4; \
        add     %l5, %l4, %l5; \
-5:     st      %l5, [%l6 + THREAD_UWINDOWS]; \
-       bz,a    2f; \
-       sethi   %hi(TASK_SIZE-176), %l5; \
-       TRAP_WIN_CLEAN; \
-       sethi   %hi( C_LABEL(current) ), %l6; \
-       ld      [%l6 + %lo( C_LABEL(current) )], %l6; \
-       sethi   %hi(TASK_SIZE-176), %l5; \
-2:     or      %l5, %lo(TASK_SIZE-176), %l5; \
-       add     %l6, %l5, %sp; \
-3: \
+CONCAT1(label, 5): \
+       st      %l5, [%l6 + THREAD_UWINDOWS]; \
+       bz,a    CONCAT1(label, 2); \
+       sethi   %hi(C_LABEL(current)), %l6; \
+       TRAP_WIN_CLEAN \
+       sethi   %hi(C_LABEL(current)), %l6; \
+CONCAT1(label, 2): \
+       ld      [%l6 + %lo(C_LABEL(current))], %l6; \
+       ld      [%l6 + TASK_KSTACK_PG], %l6; \
+       add     %l6, (PAGE_SIZE - 96 - 80), %l6; \
+       andn    %l6, 0x7, %l6; \
+       or      %g0, %l6, %sp; \
+CONCAT1(label, 3):
 
-#define ENTER_IRQ \
+/* What needs to be executed upon entry to an interrupt.
+ *
+ * See asm-sparc/cprefix.h to see how the CONCAT macros work.
+ */
+
+#define ENTER_IRQ(label) \
        rd      %wim, %l4; \
        or      %g0, 0x1, %l5; \
        sll     %l5, %l0, %l5; \
-       andcc   %l0, 0x40, %g0; \
-       bz      1f; \
+       andcc   %l0, PSR_PS, %g0; \
+       bz      CONCAT1(label, 1); \
        andcc   %l4, %l5, %g0; \
+       bz,a    CONCAT1(label, 0); \
        sethi   %hi( C_LABEL(eintstack) ), %l7; \
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7; \
-       bz      0f; \
-       nop; \
        TRAP_WIN_CLEAN \
        sethi   %hi( C_LABEL(eintstack) ), %l7; \
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7; \
-0:     subcc   %fp, %l7, %g0; \
-       bg,a    3f; \
+CONCAT1(label, 0): \
+       subcc   %fp, %l7, %g0; \
+       bge,a   CONCAT1(label, 3); \
        sub     %l7, 0xb0, %sp; \
-       b       3f; \
+       b       CONCAT1(label, 3); \
        sub     %fp, 0xb0, %sp; \
-1:     sethi   %hi( C_LABEL(current) ), %l6; \
+CONCAT1(label, 1): \
+       sethi   %hi( C_LABEL(current) ), %l6; \
        ld      [%l6 + %lo( C_LABEL(current) )], %l6; \
        ld      [%l6 + THREAD_WIM], %l5; \
        and     %l0, 0x1f, %l7; \
        cmp     %l5, %l7; \
-       ble,a   4f; \
+       ble,a   CONCAT1(label, 4); \
        sethi   %hi( C_LABEL(nwindowsm1) ), %l4; \
        sub     %l5, %l7, %l7; \
-       b       5f; \
+       b       CONCAT1(label, 5); \
        sub     %l7, 0x1, %l5; \
-4:     ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+CONCAT1(label, 4): \
+       ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
        sub     %l4, %l7, %l4; \
        add     %l5, %l4, %l5; \
-5:     st      %l5, [%l6 + THREAD_UWINDOWS]; \
-       bz,a    2f; \
+CONCAT1(label, 5): \
+       st      %l5, [%l6 + THREAD_UWINDOWS]; \
+       bz,a    CONCAT1(label, 2); \
        sethi   %hi( C_LABEL(eintstack) ), %l7; \
        TRAP_WIN_CLEAN \
        sethi   %hi( C_LABEL(eintstack) ), %l7; \
-2: \
+CONCAT1(label, 2): \
        sub     %l7, 0xb0, %sp; \
-3:
+CONCAT1(label, 3):
 
 
        .text
        .align 4
 
-/* Default trap handler */
-       .globl my_trap_handler
-my_trap_handler:
-#if 1
-               jmp     %l1
-               rett    %l2
-               nop
-#else
-               rd %wim, %l4
-               or %g0, 0x1, %l5
-               sll %l5, %l0, %l5
-               cmp %l4, %l5        ! are we in the invalid window?
-       
-               TRAP_WIN_CLEAN
-
-               nop
-               or %g0, %l3, %o0
-               call C_LABEL(do_hw_interrupt)
-               or %g0, %g0, %o1
-               wr %l0, 0x20, %psr  ! re-enable traps and reset the condition codes
-               nop
-               nop
-               nop                 ! click our heels three times, "no place like home"
-               jmp %l1
-               rett %l2
-#endif /* bogon */
+/* Bad trap handler */
+       .globl bad_trap_handler
+bad_trap_handler:
+       ENTER_TRAP(bad_trap_handler)
+
+       or      %g0, %l3, %o0
+       or      %g0, %l0, %o1
+       call    C_LABEL(do_hw_interrupt)
+       or      %g0, %l1, %o2
+
+       jmp     %l1
+       rett %  l2
        
        .align 4
        .globl sparc_timer
 sparc_timer:
-       sethi   %hi(TIMER_VADDR), %l4
-       or      %l4, %lo(TIMER_VADDR), %l4      ! read the limit register
-       ld      [%l4 + 0xc], %l4                ! to clear the interrupt
-       rd      %wim, %l4
-       or      %g0, 0x1, %l5
-       sll     %l5, %l0, %l5
-       andcc   %l0, 0x40, %g0
-       bz      st1
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       andcc   %l4, %l5, %g0
-       bz      st0
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-       TRAP_WIN_CLEAN
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-st0:   subcc   %fp, %l7, %g0
-       bg,a    st3
-       sub     %l7, 0xb0, %sp
-       b       st3
-       sub     %fp, 0xb0, %sp
-st1:   sethi   %hi( C_LABEL(current) ), %l6
-       ld      [%l6 + %lo( C_LABEL(current) )], %l6
-       ld      [%l6 + THREAD_WIM], %l5
-       and     %l0, 0x1f, %l7
-       cmp     %l5, %l7
-       ble,a   st4
-       sethi   %hi( C_LABEL(nwindowsm1) ), %l4
-       sub     %l5, %l7, %l7
-       b       st5
-       sub     %l7, 0x1, %l5
-st4:   ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
-       sub     %l4, %l7, %l4
-       add     %l5, %l4, %l5
-st5:   st      %l5, [%l6 + THREAD_UWINDOWS]
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       bz,a    st2
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-       TRAP_WIN_CLEAN
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-st2:   sub     %l7, 0xb0, %sp
-
-st3:   std     %g2, [%sp + 96 + 24]
+       ENTER_IRQ(sparc_timer)
+
+       sethi   %hi(C_LABEL(master_l10_limit)), %l4
+       ld      [%l4 + %lo(C_LABEL(master_l10_limit))], %l4
+       ld      [%l4], %g0                      ! read the limit register
+
+       std     %g2, [%sp + C_STACK + PT_G2]
        or      %g0, %g1, %l7
        rd      %y, %l6
-       std     %g4, [%sp + 96 + 32]
+       std     %g4, [%sp + C_STACK + PT_G4]
        andn    %l0, PSR_PIL, %l4
-       sll     %l3, 0x8, %l5
-       std     %g6, [%sp + 96 + 40]
-       or      %l5, %l4, %l4
+/*     sll     %l3, 0x8, %l5 */
+       std     %g6, [%sp + C_STACK + PT_G6]
+/*     or      %l5, %l4, %l4 */
 
-       wr      %l4, 0x0, %psr
+       /* Magic, we can't increase PIL and set ET at the same
+        * time or the chip calls prom_panic().
+        */
+/*     wr      %l4, 0x0, %psr */
        wr      %l4, PSR_ET, %psr
 
-       std     %l0, [%sp + 96 + 0]
-       std     %l2, [%sp + 96 + 8]
-       st      %fp, [%sp + 96 + 16]
-       
-       or      %g0, 14, %o0    
-       or      %g0, %g0, %o1
-       call    C_LABEL(do_sparc_timer)
+       or      %g0, 10, %o0
+       add     %sp, C_STACK, %o1
+       call    C_LABEL(do_IRQ)
        nop
 
        or      %g0, %l7, %g1
        wr      %l6, 0x0, %y
-       ldd     [%sp + 96 + 24], %g2
-       ldd     [%sp + 96 + 32], %g4
-       ldd     [%sp + 96 + 40], %g6
-       wr      %l0, 0x0, %psr
-       nop
-       nop
-       nop
-
-       and     %l0, 31, %l5
-       sethi   %hi(lnx_winmask), %l6
-       or      %l6, %lo(lnx_winmask), %l6
-       ldub    [%l6 + %l5], %l5
-       andcc   %l0, PSR_PS, %g0
-       bnz     1f
-       rd      %wim, %l4
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
 
-1:     andcc   %l5, %l4, %g0
-       bnz     2f
+       b       ret_trap_entry
        wr      %l0, 0x0, %psr
-       nop
-       nop
-       nop
-
-       jmp     %l1
-       rett    %l2
 
-2:     wr      %g0, 0x0, %wim
-       nop
-       nop
-       nop
-
-       restore
-       restore %g0, 0x1, %l1
-       rd      %psr, %l0
-       and     %l0, 31, %l0
-       sll     %l1, %l0, %l1
-       wr      %l1, 0x0, %wim
-       sethi   %hi( C_LABEL(current) ), %l1
-       ld      [%l1 + %lo( C_LABEL(current) ) ], %l1
-       st      %l0, [%l1 + THREAD_WIM]
-       save    %g0, %g0, %g0
-       
-       ldd     [%sp], %l0
-       ldd     [%sp + 0x8], %l2
-       ldd     [%sp + 0x10], %l4
-       ldd     [%sp + 0x18], %l6
-       ldd     [%sp + 0x20], %i0
-       ldd     [%sp + 0x28], %i2
-       ldd     [%sp + 0x30], %i4
-       ldd     [%sp + 0x38], %i6
-       
-       save    %g0, %g0, %g0
-       
-       jmp     %l1
-       rett    %l2
-
-
-/* For now all IRQ's not registered get sent here so I can see
- * what is poking the chip.
+/* For now all IRQ's not registered get sent here. handler_irq() will
+ * see if a routine is registered to handle this interrupt and if not
+ * it will say so on the console.
  */
 
        .align 4
-       .globl stray_irq_entry
-stray_irq_entry:
-       rd      %wim, %l4
-       or      %g0, 0x1, %l5
-       sll     %l5, %l0, %l5
-       andcc   %l0, 0x40, %g0
-       bz      tt1
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       andcc   %l4, %l5, %g0
-       bz      tt0
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-       TRAP_WIN_CLEAN
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-tt0:   subcc   %fp, %l7, %g0
-       bg,a    tt3
-       sub     %l7, 0xb0, %sp
-       b       tt3
-       sub     %fp, 0xb0, %sp
-tt1:   sethi   %hi( C_LABEL(current) ), %l6
-       ld      [%l6 + %lo( C_LABEL(current) )], %l6
-       ld      [%l6 + THREAD_WIM], %l5
-       and     %l0, 0x1f, %l7
-       cmp     %l5, %l7
-       ble,a   tt4
-       sethi   %hi( C_LABEL(nwindowsm1) ), %l4
-       sub     %l5, %l7, %l7
-       b       tt5
-       sub     %l7, 0x1, %l5
-tt4:   ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
-       sub     %l4, %l7, %l4
-       add     %l5, %l4, %l5
-tt5:   st      %l5, [%l6 + THREAD_UWINDOWS]
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       bz,a    tt2
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-       TRAP_WIN_CLEAN
-       sethi   %hi( C_LABEL(eintstack) ), %l7
-       or      %l7, %lo( C_LABEL(eintstack) ), %l7
-tt2:   sub     %l7, 0xb0, %sp
-
-tt3:   std     %g2, [%sp + 96 + 24]
+       .globl real_irq_entry
+real_irq_entry:
+       ENTER_IRQ(real_irq_entry)
+       std     %g2, [%sp + C_STACK + PT_G2]
        or      %g0, %g1, %l7
        rd      %y, %l6
-       std     %g4, [%sp + 96 + 32]
+       std     %g4, [%sp + C_STACK + PT_G4]
        andn    %l0, PSR_PIL, %l4
        sll     %l3, 0x8, %l5
-       std     %g6, [%sp + 96 + 40]
+       std     %g6, [%sp + C_STACK + PT_G6]
        or      %l5, %l4, %l4
 
        wr      %l4, 0x0, %psr
        wr      %l4, PSR_ET, %psr
 
-       std     %l0, [%sp + 96 + 0]
-       std     %l2, [%sp + 96 + 8]
-       st      %fp, [%sp + 96 + 16]
+       std     %l0, [%sp + C_STACK + PT_PSR]
+       std     %l2, [%sp + C_STACK + PT_NPC]
        
        or      %g0, %l3, %o0   
-       or      %g0, %g0, %o1
-       call    C_LABEL(unexpected_irq)
+       add     %sp, C_STACK, %o1
+       call    C_LABEL(handler_irq)
        nop
 
        or      %g0, %l7, %g1
        wr      %l6, 0x0, %y
-       ldd     [%sp + 96 + 24], %g2
-       ldd     [%sp + 96 + 32], %g4
-       ldd     [%sp + 96 + 40], %g6
-       wr      %l0, 0x0, %psr
-       nop
-       nop
-       nop
-
-       and     %l0, 31, %l5
-       sethi   %hi(lnx_winmask), %l6
-       or      %l6, %lo(lnx_winmask), %l6
-       ldub    [%l6 + %l5], %l5
-       andcc   %l0, PSR_PS, %g0
-       bnz     1f
-       rd      %wim, %l4
-
-1:     andcc   %l5, %l4, %g0
-       bnz     2f
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
        wr      %l0, 0x0, %psr
-       nop
-       nop
-       nop
-
-       jmp     %l1
-       rett    %l2
-
-2:     wr      %g0, 0x0, %wim
-       nop
-       nop
-       nop
-
-       restore
-       restore %g0, 0x1, %l1
-       rd      %psr, %l0
-       and     %l0, 31, %l0
-       sll     %l1, %l0, %l1
-       wr      %l1, 0x0, %wim
-       sethi   %hi( C_LABEL(current) ), %l1
-       ld      [%l1 + %lo( C_LABEL(current) ) ], %l1
-       st      %l0, [%l1 + THREAD_WIM]
-       save    %g0, %g0, %g0
-       
-       ldd     [%sp], %l0
-       ldd     [%sp + 0x8], %l2
-       ldd     [%sp + 0x10], %l4
-       ldd     [%sp + 0x18], %l6
-       ldd     [%sp + 0x20], %i0
-       ldd     [%sp + 0x28], %i2
-       ldd     [%sp + 0x30], %i4
-       ldd     [%sp + 0x38], %i6
-       
-       save    %g0, %g0, %g0
-       
-       jmp     %l1
-       rett    %l2
-
 
 
 /* This routine is optimized for kernel window fills. User fills take about two
@@ -503,14 +367,14 @@ tt3:      std     %g2, [%sp + 96 + 24]
  */
 
 /* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
- * full of them! If you think this routine is hairy, window spills are worse,
+ * full of them! If you think this routine is hairy, window fills are worse,
  * see below.
  */
 
        .align 4
        .globl spill_window_entry
 spill_window_entry:
-       andcc   %l0, 0x40, %g0          ! see if this is a user window fill
+       andcc   %l0, PSR_PS, %g0        ! see if this is a user window fill
        bz,a    spill_from_user
        nop
 
@@ -535,10 +399,12 @@ spill_from_user:
        sub     %l5, %l3, %l3
        b       2f
        sub     %l3, 0x1, %l5
-1:     ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+1:
+       ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
        sub     %l4, %l3, %l4
        add     %l5, %l4, %l5
-2:     st      %l5, [%l6 + THREAD_UWINDOWS]
+2:
+       st      %l5, [%l6 + THREAD_UWINDOWS]
 
        TRAP_WIN_CLEAN             /* danger, danger... */
        sethi   %hi( C_LABEL(current) ), %l6
@@ -607,7 +473,8 @@ fill_from_user:
        cmp     %l7, -1
        bne     fill_bad_stack
        andn    %sp, 0xfff, %l7
-1:     lda     [%l7] ASI_PTE, %l7
+1:
+       lda     [%l7] ASI_PTE, %l7
        srl     %l7, 0x1d, %l7
        andn    %l7, 0x2, %l7
        cmp     %l7, 0x4
@@ -624,7 +491,8 @@ fill_from_user:
        cmp     %l7, -1
        bne     fill_bad_stack
        andn    %sp, 0xfff, %l7
-1:     lda     [%l7] ASI_PTE, %l7
+1:
+       lda     [%l7] ASI_PTE, %l7
        srl     %l7, 0x1d, %l7
        andn    %l7, 0x2, %l7
        cmp     %l7, 0x4
@@ -641,8 +509,8 @@ fill_bad_stack:
        sll     %l4, %l5, %l4
        wr      %l4, 0x0, %wim
        ld      [%l6 + THREAD_KSP], %sp         ! set to kernel stack pointer
-       wr      %l0, 0x20, %psr                 ! turn off traps
-       std     %l0, [%sp + C_STACK]            ! set up thread_frame on stack
+       wr      %l0, PSR_ET, %psr               ! turn off traps
+       std     %l0, [%sp + C_STACK]            ! set up thread_frame XXX
        rd      %y, %l3
        std     %l2, [%sp + C_STACK + 0x8]
        or      %g0, 0x6, %o0                   ! so _sparc_trap knows what to do
@@ -656,7 +524,7 @@ fill_bad_stack:
        std     %i0, [%sp + C_STACK + 0x30]
        std     %i2, [%sp + C_STACK + 0x38]
        std     %i4, [%sp + C_STACK + 0x40]
-       call    sparc_trap
+       nop                                     /* SHould trap here */
        std     %i6, [%sp + C_STACK + 0x48]
        
        ldd     [%sp + C_STACK], %l0
@@ -677,9 +545,10 @@ fill_bad_stack:
        cmp     %l7, 0x0
        bl,a    1f
        wr      %g0, 0x0, %wim
-       b,a     leave_trap
+       /* Should trap here */
 
-1:     or      %g0, %g6, %l3
+1:
+       or      %g0, %g6, %l3
        or      %g0, %l6, %g6
        st      %g0, [%g6 + THREAD_W_SAVED]
        restore %g0, %g0, %g0
@@ -739,46 +608,1120 @@ fill_stack_ok:
        jmp     %l1
        rett    %l2
 
+       /* This routine handles illegal isntructions and privileged
+        * instruction attempts from user code.
+        */
        .align 4
-       .globl trap_entry
-trap_entry:
-       TRAP_WIN_CLEAN
-       jmp     %l1
-       rett    %l2
+       .globl bad_instruction
+bad_instruction:
+       ENTER_TRAP(bad_instruction)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       cmp     %l3, 0x2
+       bne     1f
+       call    C_LABEL(do_illegal_instruction)
+       mov     %l0, %o3
+       b       2f
+       ld      [%sp + C_STACK + PT_G1], %g1
+
+1:
+       call    C_LABEL(do_priv_instruction)
+       mov     %l0, %o3
+       ld      [%sp + C_STACK + PT_G1], %g1
+2:
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles unaligned data accesses.
+        */
+       .align 4
+       .globl mna_handler
+mna_handler:
+       ENTER_TRAP(mna_handler)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(do_memaccess_unaligned)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles floating point disabled traps.
+        */
+       .align 4
+       .globl fpd_trap_handler
+fpd_trap_handler:
+       ENTER_TRAP(fpd_trap_handler)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(do_fpd_trap)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Floating Point Exceptions.
+        */
+       .align 4
+       .globl fpe_trap_handler
+fpe_trap_handler:
+       ENTER_TRAP(fpe_trap_handler)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(do_fpe_trap)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Tag Overflow Exceptions.
+        */
+       .align 4
+       .globl do_tag_overflow
+do_tag_overflow:
+       ENTER_TRAP(do_tag_overflow)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_tag_overflow)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Watchpoint Exceptions.
+        */
+       .align 4
+       .globl do_watchpoint
+do_watchpoint:
+       ENTER_TRAP(do_watchpoint)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_watchpoint)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Register Access Exceptions.
+        */
+       .align 4
+       .globl do_reg_access
+do_reg_access:
+       ENTER_TRAP(do_reg_access)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_reg_access)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Instruction Access Errors.
+        */
+       .align 4
+       .globl do_iacc_error
+do_iacc_error:
+       ENTER_TRAP(do_iacc_error)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_iacc_error)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Co-Processor Disabled Exceptions.
+        */
+       .align 4
+       .globl do_cp_disabled
+do_cp_disabled:
+       ENTER_TRAP(do_cp_disabled)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_cp_disabled)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Unimplemented FLUSH Exceptions.
+        */
+       .align 4
+       .globl do_bad_flush
+do_bad_flush:
+       ENTER_TRAP(do_bad_flush)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_bad_flush)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Co-Processor Exceptions.
+        */
+       .align 4
+       .globl do_cp_exception
+do_cp_exception:
+       ENTER_TRAP(do_cp_exception)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_cp_exception)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Data Access Errors.
+        */
+       .align 4
+       .globl do_dacc_error
+do_dacc_error:
+       ENTER_TRAP(do_dacc_error)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_dacc_error)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Hardware Divide By Zero Exceptions.
+        */
+       .align 4
+       .globl do_hw_divzero
+do_hw_divzero:
+       ENTER_TRAP(do_hw_divzero)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_hw_divzero)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Data Store Errors.
+        */
+       .align 4
+       .globl do_dstore_err
+do_dstore_err:
+       ENTER_TRAP(do_dstore_err)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_dstore_error)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Data Access MMU-Miss Exceptions.
+        */
+       .align 4
+       .globl do_dacc_mmu_miss
+do_dacc_mmu_miss:
+       ENTER_TRAP(do_dacc_mmu_miss)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_dacc_mmu_miss)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* This routine handles Instruction Access MMU-Miss Exceptions.
+        */
+       .align 4
+       .globl do_iacc_mmu_miss
+do_iacc_mmu_miss:
+       ENTER_TRAP(do_iacc_mmu_miss)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       rd      %y, %l4
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       wr      %l0, PSR_ET, %psr               ! re-enable traps
+       add     %sp, C_STACK, %o0
+       mov     %l1, %o1
+       mov     %l2, %o2
+       call    C_LABEL(handle_iacc_mmu_miss)
+       mov     %l0, %o3
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+       /* The getcc software trap.  The user wants the condition codes from
+        * the %psr in register %g1.
+        */
+
+       .align 4
+       .globl getcc_trap_handler
+getcc_trap_handler:
+       /* Shit, one more instruction and I could do this inline. */
+       sll     %l0, 0x8, %g1
+       srl     %g1, 28, %g1
+       jmp     %l2
+       rett    %l2+0x4
+
+       /* The setcc software trap.  The user has condition codes in %g1
+        * that it would like placed in the %psr.  Be careful not to flip
+        * any unintention bits!
+        */
+
+       .align 4
+       .globl setcc_trap_handler
+setcc_trap_handler:
+       sll     %g1, 0x14, %l4
+       set     PSR_ICC, %l5
+       andn    %l0, %l5, %l0
+       or      %l4, %l0, %l4
+       wr      %l4, 0x0, %psr
+       WRITE_PAUSE
+       jmp     %l2
+       rett    %l2+0x4
+
+       .align 4
+NMI_STRING:    .asciz  "NMI received, dazed and confused, halting...\n"
 
        .align 4
        .globl linux_trap_nmi
+       .globl C_LABEL(interrupt_enable)
 linux_trap_nmi:
-       TRAP_WIN_CLEAN
+       sethi   %hi(C_LABEL(prom_vector_p)), %o0
+       ld      [%o0 + %lo(C_LABEL(prom_vector_p))], %o0
+       ld      [%o0 + 0x74], %o0
+       /* Ugh, until I figure out how to clear the IRQ line ;( */
+       call    %o0
+       nop
+
+       .align 4
+       .globl sparc_text_fault
+sparc_text_fault:
+       ENTER_TRAP(sparc_text_fault)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       rd      %y, %l4
+       sethi   %hi(AC_SYNC_ERR), %o0
+       lda     [%o0] ASI_CONTROL, %o1
+       add     %o0, 0x4, %o0           ! go to sync vaddr
+       lda     [%o0] ASI_CONTROL, %o2
+       andcc   %o1, SUN4C_SYNC_NOMEM, %g0
+       bz,a    normal_page_fault
+       wr      %l0, PSR_ET, %psr       ! re-enable traps
+
+       add     %o0, 0x4, %o0           ! go to async error register
+       lda     [%o0] ASI_CONTROL, %o3
+       add     %o0, 0x4, %o0           ! go to async vaddr
+       subcc   %o4, %o2, %g0
+       be,a    is_sync_fault           ! not an async fault
+       wr      %l0, PSR_ET, %psr
+
+       /* crap, an asynchronous error has occurred */
+       sethi   %hi(C_LABEL(interrupt_enable)), %l5
+       ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o0
+       andn    %o0, INTS_ENAB, %o0
+       stb     %o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
+       wr      %l0, PSR_ET, %psr               ! enable traps
+       call    C_LABEL(sparc_txtmem_error)     ! call high level c-code
+       or      %g0, FAULT_ASYNC, %o0
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o1
+       or      %o1, INTS_ENAB, %o1
+       stb     %o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+is_sync_fault:
+       call    C_LABEL(sparc_txtmem_error)     ! call high level c-code
+       or      %g0, FAULT_SYNC, %o0
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ld      [%sp + C_STACK + PT_G2], %g2
+       ld      [%sp + C_STACK + PT_G4], %g4
+       ld      [%sp + C_STACK + PT_G6], %g6
+       wr      %l4, 0x0, %y
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+normal_page_fault:
+       std     %l0, [%sp + C_STACK + PT_PSR]
+       or      %g0, %l3, %o0
+       st      %l2, [%sp + C_STACK + PT_NPC]
+       st      %l4, [%sp + C_STACK + PT_Y]
+       or      %g0, %l1, %o3
+       std     %i0, [%sp + C_STACK + PT_I0]
+       std     %i2, [%sp + C_STACK + PT_I2]
+       or      %g0, %l0, %o4
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+       call    C_LABEL(sparc_text_access_fault)
+       add     %sp, C_STACK, %o5
+
+       ldd     [%sp + C_STACK + PT_PSR], %l0
+       ldd     [%sp + C_STACK + PT_NPC], %l2
+       wr      %l3, 0x0, %y
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldd     [%sp + C_STACK + PT_I0], %i0
+       ldd     [%sp + C_STACK + PT_I2], %i2
+       ldd     [%sp + C_STACK + PT_I4], %i4
+       ldd     [%sp + C_STACK + PT_I6], %i6
+
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+       .align 4
+       .globl sparc_data_fault
+sparc_data_fault:
+       ENTER_TRAP(sparc_data_fault)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       rd      %y, %l4
+       sethi   %hi(AC_SYNC_ERR), %o0
+       lda     [%o0] ASI_CONTROL, %o1
+       add     %o0, 0x4, %o0           ! go to sync vaddr
+       lda     [%o0] ASI_CONTROL, %o2
+       andcc   %o1, SUN4C_SYNC_NOMEM, %g0
+       bz,a    normal_data_page_fault
+       wr      %l0, PSR_ET, %psr
+
+       add     %o0, 0x4, %o0           ! go to async error register
+       lda     [%o0] ASI_CONTROL, %o3
+       add     %o0, 0x4, %o0           ! go to async vaddr
+       subcc   %o4, %o2, %g0
+       be,a    is_data_sync_fault      ! not an async fault
+       wr      %l0, PSR_ET, %psr
+
+       /* crap, an asynchronous error has occurred */
+       sethi   %hi(C_LABEL(interrupt_enable)), %l5
+       ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o0
+       andn    %o0, INTS_ENAB, %o0
+       stb     %o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
+       wr      %l0, PSR_ET, %psr
+       call    C_LABEL(sparc_datamem_error)    ! call high level c-code
+       or      %g0, FAULT_ASYNC, %o0
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       wr      %l0, 0x0, %psr
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o1
+       or      %o1, INTS_ENAB, %o1
+       stb     %o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
+       b       ret_trap_entry
+       wr      %l4, 0, %y
+
+is_data_sync_fault:
+       call    C_LABEL(sparc_datamem_error)    ! call high level c-code
+       or      %g0, FAULT_SYNC, %o0
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       wr      %l4, 0x0, %y
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+normal_data_page_fault:
+       std     %l0, [%sp + C_STACK + PT_PSR]   ! store %psr and pc
+       or      %g0, %l3, %o0
+       st      %l2, [%sp + C_STACK + PT_NPC]   ! store npc
+       st      %l4, [%sp + C_STACK + PT_Y]     ! store %y
+       or      %g0, %l1, %o3
+
+       /* The globals have already been placed on the stack */
+       std     %i0, [%sp + C_STACK + PT_I0]    ! store ins
+       std     %i2, [%sp + C_STACK + PT_I2]
+       or      %g0, %l0, %o4
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+       call    C_LABEL(sparc_data_access_fault)
+       add     %sp, C_STACK, %o5
+
+       ldd     [%sp + C_STACK + PT_PSR], %l0
+       ldd     [%sp + C_STACK + PT_NPC], %l2
+       wr      %l3, 0x0, %y
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldd     [%sp + C_STACK + PT_I0], %i0
+       ldd     [%sp + C_STACK + PT_I2], %i2
+       ldd     [%sp + C_STACK + PT_I4], %i4
+       ldd     [%sp + C_STACK + PT_I6], %i6
+
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+
+       .align 4
+       .globl C_LABEL(srmmu_text_fault)
+C_LABEL(srmmu_text_fault):
+       ENTER_TRAP(srmmu_text_fault)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       rd      %y, %l4
+       set     0x300, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o1        ! fault status
+       set     0x400, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o2        ! fault address
+       wr      %l0, PSR_ET, %psr               ! traps back on
+       WRITE_PAUSE
+       std     %l0, [%sp + C_STACK + PT_PSR]
+       or      %g0, %l3, %o0
+       st      %l2, [%sp + C_STACK + PT_NPC]
+       st      %l4, [%sp + C_STACK + PT_Y]
+       or      %g0, %l1, %o3
+       std     %i0, [%sp + C_STACK + PT_I0]
+       std     %i2, [%sp + C_STACK + PT_I2]
+       or      %g0, %l0, %o4
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+       call    C_LABEL(srmmu_text_access_fault)
+       add     %sp, C_STACK, %o5
+
+       ldd     [%sp + C_STACK + PT_PSR], %l0
+       ldd     [%sp + C_STACK + PT_NPC], %l2
+       wr      %l3, 0x0, %y
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldd     [%sp + C_STACK + PT_I0], %i0
+       ldd     [%sp + C_STACK + PT_I2], %i2
+       ldd     [%sp + C_STACK + PT_I4], %i4
+       ldd     [%sp + C_STACK + PT_I6], %i6
+
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+       .align 4
+       .globl C_LABEL(srmmu_data_fault)
+C_LABEL(srmmu_data_fault):
+       ENTER_TRAP(srmmu_data_fault)
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       rd      %y, %l4
+
+       set     AC_M_SFSR, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o1        ! fault status
+       set     AC_M_SFAR, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o2        ! fault address
+       set     AC_M_AFSR, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o3
+       set     AC_M_AFAR, %o0
+       lda     [%o0] ASI_M_MMUREGS, %o4
+       wr      %l0, PSR_ET, %psr               ! traps back on
+       WRITE_PAUSE
+       std     %l0, [%sp + C_STACK + PT_PSR]
+       or      %g0, %l3, %o0
+       st      %l2, [%sp + C_STACK + PT_NPC]
+       st      %l4, [%sp + C_STACK + PT_Y]
+       std     %i0, [%sp + C_STACK + PT_I0]
+       std     %i2, [%sp + C_STACK + PT_I2]
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+       call    C_LABEL(srmmu_data_access_fault)
+       add     %sp, C_STACK, %o5
+
+       ldd     [%sp + C_STACK + PT_PSR], %l0
+       ldd     [%sp + C_STACK + PT_NPC], %l2
+       wr      %l3, 0x0, %y
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldd     [%sp + C_STACK + PT_I0], %i0
+       ldd     [%sp + C_STACK + PT_I2], %i2
+       ldd     [%sp + C_STACK + PT_I4], %i4
+       ldd     [%sp + C_STACK + PT_I6], %i6
+
+       b       ret_trap_entry
+       wr      %l0, 0x0, %psr
+
+/* Normal Linux system calls enter here... */
+/* Trying to make this as generic and simple as possible. */
+
+       .align 4
+       .globl linux_sparc_syscall
+linux_sparc_syscall:
+       /* Don't dork with %l7, it holds the pointer to the
+        * system call vector table.  ENTER_TRAP does not
+        * modify its value.
+        */
+       ENTER_TRAP(linux_sparc_syscall)
+
+       /* setup pt_regs stack frame, leave ints off...
+        * First save all but the current window onto the stack.
+        * This means nwindows-2 saves and nwindows-2 restores.
+        */
+       andn    %l0, PSR_PIL, %l5
+       wr      %l5, 0xf00, %psr
+       wr      %l5, 0xf20, %psr        ! no ints, traps on
+       WRITE_PAUSE
+       
+       .globl nop7
+       /* Flush windows */
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+nop7:  save    %sp, -C_STACK, %sp
+       restore
+       restore
+       restore
+       restore
+       restore
+       restore
+
+       rd      %psr, %l6
+       and     %l6, PSR_CWP, %l6               ! only care about CWP
+       andn    %l0, PSR_CWP, %l0
+       or      %l0, %l6, %l0                   ! %l0 is now the new %psr
+       
+       std     %l0, [%sp + C_STACK + PT_PSR]   ! save it away
+       rd      %y, %l3
+       std     %l2, [%sp + C_STACK + PT_NPC]
+
+       /* Put %wim in %g0 slot, a hack.  This way we ensure that %wim
+        * sits right behind the current window in %psr, which is what
+        * we want.
+        */
+       rd      %wim, %l4
+       st      %l4, [%sp + C_STACK + PT_G0]
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       std     %i0, [%sp + C_STACK + PT_I0]
+       std     %i2, [%sp + C_STACK + PT_I2]
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+
+       wr      %l0, PSR_ET, %psr /* Turn on traps + interrupts */
+       WRITE_PAUSE
+
+       cmp     %i0, NR_SYSCALLS
+       bgu,a   C_LABEL(ret_sys_call)
+       or      %g0, -1, %i0
+
+       cmp     %i0, 0x2                ! fork? Same number for all OSs
+       bne     not_fork
+       nop
+       call    C_LABEL(sys_fork)       ! yep, load pt_regs into first arg
+       add     %sp, C_STACK, %o0
+       b       C_LABEL(ret_sys_call)
+       nop
+not_fork:
+       /* Remember, trap table entry loaded syscall table ptr in %l7 */
+       sll     %i0, 0x2, %o0
+       add     %l7, %o0, %l7
+       ld      [%l7], %o5              ! load up ptr to syscall handler
+
+       mov     %i1, %o0                ! load up arguments
+       mov     %i2, %o1
+       mov     %i3, %o2
+       mov     %i4, %o3
+       jmpl    %o5, %o7                ! Make syscall
+       mov     %i5, %o4
+
+       .globl C_LABEL(ret_sys_call)  /* exported for copy_process() */
+C_LABEL(ret_sys_call):  /* Child of a fork returns here */
+       /* dump the pt_regs back into their rightful places */
+       ldd     [%sp + C_STACK + PT_PSR], %l0
+       ldd     [%sp + C_STACK + PT_NPC], %l2
+       wr      %l3, 0x0, %y
+
+       ld      [%sp + C_STACK + PT_G1], %g1
+       ldd     [%sp + C_STACK + PT_G2], %g2
+       ldd     [%sp + C_STACK + PT_G4], %g4
+       ldd     [%sp + C_STACK + PT_G6], %g6
+       ldd     [%sp + C_STACK + PT_I0], %i0
+       ldd     [%sp + C_STACK + PT_I2], %i2
+       ldd     [%sp + C_STACK + PT_I4], %i4
+       ldd     [%sp + C_STACK + PT_I6], %i6
+
+       /* %i6 is our frame pointer, the restore done by the rett
+        * instruction will automatically put us back on the users
+        * stack.
+        * Advance the pc and npc past the trap instruction, the copy_process()
+        * code for fork() depends on this being done right before trap return.
+        */
+       or      %l2, 0x0, %l5
+
+       or      %l5, 0x0, %l1    /* pc = npc */
+       add     %l5, 0x4, %l2    /* npc= npc+4 */
+
+       wr      %l0, 0x0, %psr
+       WRITE_PAUSE     
+
+       /* Fall through to ret_trap_entry */
+
+/* Return from trap code.  I realized that I was duplicating a lot
+ * of logic in the various trap handlers. Traps are off upon entry.
+ */
+
+ret_trap_entry:
+       and     %l0, 0x1f, %l5
+       sethi   %hi(lnx_winmask), %l6
+       or      %l6, %lo(lnx_winmask), %l6
+       ldub    [%l6 + %l5], %l5
+       andcc   %l0, PSR_PS, %g0
+       bnz     ret_trap_kernel
+       rd      %wim, %l4
+
+       sethi   %hi(C_LABEL(current)), %l6
+       ld      [%l6 + %lo(C_LABEL(current))], %l6
+       ld      [%l6 + THREAD_W_SAVED], %l7
+       subcc   %g0, %l7, %g0
+       bz,a    ret_trap_user
+       nop
+
+       wr      %g0, 0, %wim
+       or      %g0, %g6, %l3
+       or      %g0, %l6, %g6
+       st      %g0, [%g6 + THREAD_W_SAVED]
+       restore
+       restore %g0, 1, %l1
+       rd      %psr, %l0
+       sll     %l1, %l0, %l1
+       wr      %l1, 0x0, %wim
+       and     %l0, 0x1f, %l0
+       st      %l0, [%g6 + THREAD_WIM]
+       nop
+       save    %g0, %g0, %g0
+       add     %g6, THREAD_REG_WINDOW, %g6
+       ldd     [%g6], %l0
+       ldd     [%g6 + 0x8], %l2
+       ldd     [%g6 + 0x10], %l4
+       ldd     [%g6 + 0x18], %l6
+       ldd     [%g6 + 0x20], %i0
+       ldd     [%g6 + 0x28], %i2
+       ldd     [%g6 + 0x30], %i4
+       ldd     [%g6 + 0x38], %i6
+
+       save    %g0, %g0, %g0
+       wr      %l0, 0x0, %psr
+       or      %g0, %l3, %g6
        jmp     %l1
        rett    %l2
 
-       .align 4
-       .globl sparc_trap
-sparc_trap:
-       TRAP_WIN_CLEAN
+ret_trap_kernel:
+       andcc   %l4, %l5, %g0
+       bnz     1f
+       wr      %l0, 0x0, %psr       ! reset condition codes
+       nop
        jmp     %l1
        rett    %l2
 
-       .align 4
-       .globl leave_trap
-leave_trap:
+1:
+       wr      %g0, 0x0, %wim
+       WRITE_PAUSE
+       restore
+       restore %g0, 0x1, %l1
+       rd      %psr, %l0
+       and     %l0, 0x1f, %l0
+       sll     %l1, %l0, %l1
+       wr      %l1, 0x0, %wim
+       sethi   %hi(C_LABEL(current)), %l1
+       ld      [%l1 + %lo(C_LABEL(current))], %l1
+       st      %l0, [%l1 + THREAD_WIM]
+       save    %g0, %g0, %g0
+       ldd     [%sp], %l0
+       ldd     [%sp + 0x8], %l2
+       ldd     [%sp + 0x10], %l4
+       ldd     [%sp + 0x18], %l6
+       ldd     [%sp + 0x20], %i0
+       ldd     [%sp + 0x28], %i2
+       ldd     [%sp + 0x30], %i4
+       ldd     [%sp + 0x38], %i6
+
+       save    %g0, %g0, %g0
        jmp     %l1
        rett    %l2
 
+ret_trap_user:
+       andcc   %l4, %l5, %g0
+       bnz     1f
+       wr      %l0, 0x0, %psr
+       nop
+       jmp     %l1
+       rett    %l2
+
+1:
+       wr      %g0, 0x0, %wim
+       wr      %l0, 0x0, %psr
+       WRITE_PAUSE
+       restore
+       restore %g0, 0x1, %l1
+       rd      %psr, %l0
+       sll     %l1, %l0, %l1
+       wr      %l1, 0x0, %wim
+       sethi   %hi(C_LABEL(current)), %l1
+       ld      [%l1 + %lo(C_LABEL(current))], %l1
+       and     %l0, 0x1f, %l0
+       st      %l0, [%l1 + THREAD_WIM]
+       save    %g0, %g0, %g0
+       ldd     [%sp], %l0
+       ldd     [%sp + 0x8], %l2
+       ldd     [%sp + 0x10], %l4
+       ldd     [%sp + 0x18], %l6
+       ldd     [%sp + 0x20], %i0
+       ldd     [%sp + 0x28], %i2
+       ldd     [%sp + 0x30], %i4
+       ldd     [%sp + 0x38], %i6
+       save    %g0, %g0, %g0
+       jmp     %l1
+       rett    %l2
+
+/* Context switch code.  I don't feel like playing around with
+ * inline gcc-assembly to do this right, so here it is.  The new
+ * process's task_struct ptr is passed in %o0.
+ *
+ * This is still work in progress.
+ * ONLY MAKE PROM CALLS FOR DIAGNOSTICS WHEN TRAPS ARE ON!!!!!
+ *
+ * First successful task switch 05/13/95 21:52:37
+ *
+ */
+       .align 4
+       .globl C_LABEL(sparc_switch_to)
+C_LABEL(sparc_switch_to):
+       or      %g0, %o0, %l5
+       sethi   %hi(C_LABEL(current)), %l6
+       ld      [%l6 + %lo(C_LABEL(current))], %l6
+       rd      %psr, %l0
+
+       or      %g0, %l0, %l4
+       andn    %l0, PSR_PIL, %l0   /* turn off IRQ level bits leave PSR_ET on */
+
+       wr      %l0, 0xf00, %psr    /* NO interrupts */
+       WRITE_PAUSE
+
+       /* Save state of old process */
+       .globl rnop7
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+       save    %sp, -C_STACK, %sp
+rnop7: save    %sp, -C_STACK, %sp
+       restore
+       restore
+       restore
+       restore
+       restore
+       restore
+
+       rd      %psr, %l3
+       and     %l3, PSR_CWP, %l3               ! only care about CWP bits now
+       andn    %l0, PSR_CWP, %l0               ! integrate with old %psr
+       or      %l3, %l0, %l0
+       
+       st      %l0, [%sp + C_STACK + PT_PSR]   ! save new %psr
+       /* ??? We backtrack the PC two instructions due to retl's semantics ??? */
+       /*sub   %o7, 0x8, %o7 */
+       st      %o7, [%sp + C_STACK + PT_PC]    ! save return PC
+       add     %o7, 0x4, %l3
+       st      %l3, [%sp + C_STACK + PT_NPC]   ! and NPC
+
+       rd      %y, %l3
+       st      %l3, [%sp + C_STACK + PT_Y]     ! save %y
+
+       /* Save the %wim into %g0 slot, ensures that it sits behind CWP */
+       rd      %wim, %l3
+       st      %l3, [%sp + C_STACK + PT_G0]    ! save new %wim
+       st      %g1, [%sp + C_STACK + PT_G1]
+       std     %g2, [%sp + C_STACK + PT_G2]
+       std     %g4, [%sp + C_STACK + PT_G4]
+       std     %g6, [%sp + C_STACK + PT_G6]
+       std     %i0, [%sp + C_STACK + PT_I0]
+       std     %i2, [%sp + C_STACK + PT_I2]
+       std     %i4, [%sp + C_STACK + PT_I4]
+       std     %i6, [%sp + C_STACK + PT_I6]
+
+       wr      %l0, (0xf20), %psr              ! no traps, no intrs
+       WRITE_PAUSE
+
+       /* TRAPS ARE OFF, NO PROM CALLS WHATSOEVER FOR DEBUGGING!!! */
+       /* SO what we do is we put an imperical constant in %g2 and
+        * a 'counter' in %g1 which we increment after every instruction
+        * so we can figure out where the thing prom panics.  Then at the
+        * prom prompt we print out the saved registers.  To drop into the
+        * prom and look at the registers just execute 7 saves since that
+        * will induce a window trap before the last one and traps are off,
+        * thus a watchdog reset will occur.
+        */
+
+       /* Grrr, this is hairy... be careful, again NO PROM CALLS YET! */
+       /* Load up the new 'current' */
+       sethi   %hi(C_LABEL(current)), %g1
+       st      %l5, [%g1 + %lo(C_LABEL(current))]
+       
+       /* Load up new processes stack, we always switch onto the kernel stack */
+       /* Be CAREFUL, use globals for temporaries, because after we change the
+        * %psr the window could change and you will most likely be accessing
+        * different outs, ins, and locals than you origionally were.
+        */
+       or      %g0, %l5, %g6
+       ld      [%l5 + THREAD_KSP], %g3
+
+       /* New procs %psr */
+       ld      [%g3 + C_STACK + PT_PSR], %g4
+       wr      %g4, 0xf00, %psr         /* No ints, no traps */
+       WRITE_PAUSE
+
+       /* We could be in a different window NOW. Assume nothing about the
+        * current set of in, out and local registers.
+        */
+
+       /* New procs %wim */
+       ld      [%g3 + C_STACK + PT_G0], %l4 /* %wim is here */
+       st      %l4, [%g6 + THREAD_WIM]      /* Update tss */
+       wr      %l4, 0x0, %wim               /* Use it */
+       WRITE_PAUSE
+
+       /* Finally, load the stack */
+       or      %g0, %g3, %sp
+
+       /* We are now sane, we have a good stack and our state is reflected
+        * properly in 'current'.  Let it rip.
+        */
+       /* Remember, you can't increase PIL and turn on traps at the
+        * same time.
+        */
+       wr      %g4, 0xf00, %psr  /* Traps on, no interrupts. */
+       wr      %g4, 0xf20, %psr
+       WRITE_PAUSE
+       
+       sethi   %hi(C_LABEL(current)), %o0
+       ld      [%o0 + %lo(C_LABEL(current))], %o0
+       ld      [%o0 + THREAD_PC], %o7 /* Setup return address */
+
+       /* cross fingers */
+       retl
+       nop
+
 /* The following two things point to window management tables. The first
-   one is used to quickly look up how many user windows there are from
-   trap-land. The second is used in a trap handler to determine if a rett
-   instruction will land us smack inside the invalid window that possibly
-   the trap was called to fix-up.
-*/
+ * one is used to quickly look up how many user windows there are from
+ * trap-land. The second is used in a trap handler to determine if a rett
+ * instruction will land us smack inside the invalid window that possibly
+ * the trap was called to fix-up.
+ */
+
+/* For now these are static tables geared for a 7 window sparc.
+ * But in head.S after we calculate this table based upon the
+ * nwindows value.  This table is big enough for a 16 window sparc.
+ */
 
-/* For now these are static tables geared for a 7 window sparc. */
 
                .data
                .align 4
-lnx_winmask:   .byte   2, 4, 8, 16, 32, 64, 128, 1  ! lnx_winmask[0..7]
-
+               .globl lnx_winmask
+lnx_winmask:
+               .byte   2, 4, 8, 16, 32, 64, 1, 0
+               .byte   0, 0, 0, 0, 0, 0, 0, 0
        
                .align 4
                .globl C_LABEL(sys_call_table)
@@ -918,10 +1861,90 @@ C_LABEL(sys_call_table):
        .long C_LABEL(sys_getpgid)
        .long C_LABEL(sys_fchdir)
        .long C_LABEL(sys_bdflush)
-       .long C_LABEL(sys_sysfs)        /* 135 */
+       .long C_LABEL(sys_sysfs)                /* 135 */
        .long C_LABEL(sys_personality)
-       .long 0                         /* for afs_syscall */
+       .long C_LABEL(sys_ni_syscall)           /* for afs_syscall */
        .long C_LABEL(sys_setfsuid)
        .long C_LABEL(sys_setfsgid)
        .long C_LABEL(sys_llseek)               /* 140 */
+       .long C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 150 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 160 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 170 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 180 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 190 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 200 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 210 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 220 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 230 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 240 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+       /* 250 */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall)           /* 255 */
        .align 4
index c3a5453e795d2e3465d2d0f1463acfc46e31a08c..241422e390f28ad51c4ac4a241287ef8963106cb 100644 (file)
@@ -1,52 +1,53 @@
-/* boot.S: The initial boot code for the Sparc port of Linux.
-
  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-
          This file has to serve three purposes.
-
         1) determine the prom-version and cpu/architecture
         2) print enough useful info before we start to execute
            c-code that I can possibly begin to debug things
         3) Hold the vector of trap entry points
-
-   The Sparc offers many challenges to kernel design. Here I will
  document those I have come across thus far. Upon bootup the boot
  prom loads your a.out image into memory. This memory the prom has
  already mapped for you in two places, however as far as I can tell
  the virtual address cache is not turned on although the MMU is
  translating things. You get loaded at 0x4000 exactly and you are
  aliased to 0xf8004000 with the appropriate mmu entries. So, when
-   you link a boot-loadable object you want to do something like:
-
       ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o ....
-
  to produce a proper image.
-
  At boot time you are given (as far as I can tell at this time)
  one key to figure out what machine you are one and what devices
  are available. The prom when it loads you leaves a pointer to
  the 'rom vector' in register %o0 right before it jumps to your
  starting address. This is a pointer to a struct that is full of
  pointer to functions (ie. printf, halt, reboot), pointers to
  linked lists (ie. memory mappings), and pointer to empirical
  constants (ie. stdin and stdout magic cookies + rom version).
  Starting with this piece of information you can figure out 
  just about anything you want about the machine you are on.
-
  Although I don't use it now, if you are on a Multiprocessor and
  therefore a v3 or above prom, register %o2 at boot contains a
  function pointer you must call before you proceed to invoke the
  other cpu's on the machine. I have no idea what kind of magic this
  is, give me time.
-*/
+/* head.S: The initial boot code for the Sparc port of Linux.
+ *
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
*         This file has to serve three purposes.
+ *
*        1) determine the prom-version and cpu/architecture
*        2) print enough useful info before we start to execute
*           c-code that I can possibly begin to debug things
*        3) Hold the vector of trap entry points
+ *
*  The Sparc offers many challenges to kernel design. Here I will
* document those I have come across thus far. Upon bootup the boot
* prom loads your a.out image into memory. This memory the prom has
* already mapped for you in two places, however as far as I can tell
* the virtual address cache is not turned on although the MMU is
* translating things. You get loaded at 0x4000 exactly and you are
* aliased to 0xf8004000 with the appropriate mmu entries. So, when
+ * you link a boot-loadable object you want to do something like
+ *
*      ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o ....
+ *
* to produce a proper image.
+ *
* At boot time you are given (as far as I can tell at this time)
* one key to figure out what machine you are one and what devices
* are available. The prom when it loads you leaves a pointer to
* the 'rom vector' in register %o0 right before it jumps to your
* starting address. This is a pointer to a struct that is full of
* pointer to functions (ie. printf, halt, reboot), pointers to
* linked lists (ie. memory mappings), and pointer to empirical
* constants (ie. stdin and stdout magic cookies + rom version).
* Starting with this piece of information you can figure out 
* just about anything you want about the machine you are on.
+ *
* Although I don't use it now, if you are on a Multiprocessor and
* therefore a v3 or above prom, register %o2 at boot contains a
* function pointer you must call before you proceed to invoke the
* other cpu's on the machine. I have no idea what kind of magic this
* is, give me time.
+ */
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
-#include <asm/version.h>
+#include <linux/version.h>
 #include <asm/asi.h>
 #include <asm/contregs.h>
 #include <asm/psr.h>
 #include <asm/page.h>
+#include <asm/kdebug.h>
 
        .data
 
@@ -54,6 +55,7 @@
 
         .globl  C_LABEL(intstack)
         .globl  C_LABEL(eintstack)
+       .align 4
 C_LABEL(intstack):
         .skip   4 * PAGE_SIZE                ! 16k = 128 128-byte stack frames
 C_LABEL(eintstack):
@@ -61,19 +63,24 @@ C_LABEL(eintstack):
 
 
 /* 
  The following are used with the prom_vector node-ops to figure out
  the cpu-type 
-*/
* The following are used with the prom_vector node-ops to figure out
* the cpu-type 
+ */
 
+       .align 4
         .globl  C_LABEL(cputyp)
-
 C_LABEL(cputyp):
         .word   1
 
+       .align 4
+       .globl C_LABEL(cputypval)
 C_LABEL(cputypval):
        .asciz "sun4c"
        .ascii "     "
 
+C_LABEL(cputypvalend):
+C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
+
        .align 4
 /*
  * Sun people can't spell worth damn. "compatability" indeed.
@@ -86,501 +93,740 @@ C_LABEL(cputypval):
 C_LABEL(cputypvar):
        .asciz "compatability"
 
-C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
-
-/* This hold the prom-interface-version number for either v0 or v2. */
-
+/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. --P3 */
        .align 4
-       .globl  C_LABEL(prom_iface_vers)
-
-C_LABEL(prom_iface_vers):      .skip 4
+C_LABEL(cputypvar_sun4m):
+       .asciz "compatible"
 
 /* WARNING: evil messages follow */
 
        .align 4
 
 sun4_notsup:
-       .asciz  "Sparc-Linux: sun4 support not implemented yet\n\n"
-       .align 4
-
-sun4m_notsup:
-        .asciz  "Sparc-Linux: sun4m support does not exist\n\n"
+       .asciz  "Sparc-Linux sun4 support not implemented yet\n\n"
        .align 4
 
 sun4d_notsup:
-        .asciz  "Sparc-Linux: sun4d support does not exist\n\n"
+        .asciz  "Sparc-Linux sun4d support does not exist\n\n"
        .align 4
 
-you_lose:
-       .asciz  "You lose..... Thanks for playing...\n"
+sun4e_notsup:
+        .asciz  "Sparc-Linux sun4e support does not exist\n\n"
        .align 4
 
-
-       .globl boot_msg
-
-/* memory descriptor property strings, v2 = yuk yuk yuk  */
-/* XXX how to figure out vm mapped by prom? May have to scan magic addresses */
-
-mem_prop_physavail:    .asciz "available"
-       
-                       .align 4
-mem_prop_phystot:      .asciz "reg"
-
-/* v2_memory descriptor struct kludged here for assembly, if it ain't broke */
-
-               .align 4
-v2_mem_struct:         .skip 0xff
-
-                       .align 4
-v2_printf_physavail:   .asciz "Physical Memory Available: 0x%x bytes"
-       
-                       .align 4
-v2_printf_phystot:     .asciz "Physical Memory: 0x%x bytes"
-
-/* A place to store property strings returned from the prom 'node' funcs */
-
-                       .align 4
-prop_string_buf:       .skip 32
-
-               .align 4
-prop_name:     .asciz "name"
-       
-               .align 4
-current_node:  .skip 4
-
-
-/* nice little boot message */
-
-               .align 4
-boot_msg:      
-       .ascii "Booting Sparc-Linux V0.00PRE-ALPHA "
-       .ascii WHO_COMPILED_ME 
-       .ascii "\r\n"
-       .align 4
-
-       .globl boot_msg2
-
-boot_msg2:
-       .asciz "Booting Sparclinux V0.00 PRE-ALPHA on a (SUN4C)\r\n\n"
-
+sun4u_notsup:
+        .asciz  "Sparc-Linux sun4u support does not exist\n\n"
        .align 4
 
-pstring1:
-       .asciz "Prom Magic Cookie: 0x%x  \n"
-       .align 4
+/* Ok, things start to get interesting. We get linked such that 'start'
+ * is the entry symbol. However, it is real low in kernel address space
+ * and as such a nifty place to place the trap table. We achieve this goal
+ * by just jumping to 'gokernel' for the first trap's entry as the sparc
+ * never receives the zero trap as it is real special (hw reset).
+ *
+ * Each trap entry point is the size of 4 sparc instructions (or 4 bytes
+ * * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
+ * or unimplemented) and 128 software traps (sys-calls, etc.).
+ *
+ * One of the instructions must be a branch. More often than not this
+ * will be to a trap handler entry point because it is completely
+ * impossible to handle any trap in 4 insns. I welcome anyone to 
+ * challenge this theory. :-)
+ *
+ * On entry into this table the hardware has loaded the program counter
+ * at which the trap occurred into register %l1 and the next program
+ * counter into %l2, this way we can return from the trap with a simple
+ *
+ *         jmp %l1; rett %l2  ! poof...
+ *
+ * after properly servicing the trap. It wouldn't be a bad idea to load
+ * some more information into the local regs since we have technically
+ * 2 or 3 instructions to play with besides the jmp to the 'real' trap
+ * handler (one can even go in the delay slot). For now I am going to put
+ * the %psr (processor status register) and the trap-type value in %l0
+ * and %l3 respectively. Also, for IRQ's I'll put the level in %l4.
+ */
 
-pstring2:
-       .asciz "Interface Version: v%d\n"
-       .align 4
+       .text
 
-pstring3:
-       .asciz "Prom Revision: V%d\n\n"
-       .align 4
+       .globl  start
+       .globl  _start  /* warning, solaris hack */
+       .globl  C_LABEL(trapbase)
+_start:   /* danger danger */
+start:
+C_LABEL(trapbase):
+/* XXX Grrr, this table is basically sun4c specific, sort of... XXX */
+/* We get control passed to us here at t_zero. */
+t_zero:        b gokernel; nop; nop; nop;
+
+t_tflt:        TRAP_ENTRY(0x1, sparc_text_fault)    /* Inst. Access Exception        */
+t_bins:        TRAP_ENTRY(0x2, bad_instruction)     /* Illegal Instruction           */
+t_pins:        TRAP_ENTRY(0x3, bad_instruction)     /* Privileged Instruction        */
+t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler)    /* Floating Point Disabled       */
+t_wovf:        TRAP_ENTRY(0x5, spill_window_entry)  /* Window Overflow               */
+t_wunf:        TRAP_ENTRY(0x6, fill_window_entry)   /* Window Underflow              */
+t_mna: TRAP_ENTRY(0x7, mna_handler)         /* Memory Address Not Aligned    */
+t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler)    /* Floating Point Exception      */
+t_dflt:        TRAP_ENTRY(0x9, sparc_data_fault)    /* Data Miss Exception           */
+t_tio: TRAP_ENTRY(0xa, do_tag_overflow)     /* Tagged Instruction Ovrflw     */
+t_wpt: TRAP_ENTRY(0xb, do_watchpoint)       /* Watchpoint Detected           */
+t_badc:        TRAP_ENTRY(0xc, bad_trap_handler)    /* Undefined...                  */
+t_badd:        TRAP_ENTRY(0xd, bad_trap_handler)    /* Undefined...                  */
+t_bade:        TRAP_ENTRY(0xe, bad_trap_handler)    /* Undefined...                  */
+t_badf:        TRAP_ENTRY(0xf, bad_trap_handler)    /* Undefined...                  */
+t_bad10:TRAP_ENTRY(0x10, bad_trap_handler)   /* Undefined...                  */
+t_irq1:        TRAP_ENTRY_INTERRUPT(1)              /* IRQ Software/SBUS Level 1     */
+t_irq2:        TRAP_ENTRY_INTERRUPT(2)              /* IRQ SBUS Level 2              */
+t_irq3:        TRAP_ENTRY_INTERRUPT(3)              /* IRQ SCSI/DMA/SBUS Level 3     */
+t_irq4:        TRAP_ENTRY_INTERRUPT(4)              /* IRQ Software Level 4          */
+t_irq5:        TRAP_ENTRY_INTERRUPT(5)              /* IRQ SBUS/Ethernet Level 5     */
+t_irq6:        TRAP_ENTRY_INTERRUPT(6)              /* IRQ Software Level 6          */
+t_irq7:        TRAP_ENTRY_INTERRUPT(7)              /* IRQ Video/SBUS Level 5        */
+t_irq8:        TRAP_ENTRY_INTERRUPT(8)              /* IRQ SBUS Level 6              */
+t_irq9:        TRAP_ENTRY_INTERRUPT(9)              /* IRQ SBUS Level 7              */
+t_irq10:TRAP_ENTRY_TIMER                     /* IRQ Timer #1 (one we use)     */
+t_irq11:TRAP_ENTRY_INTERRUPT(11)             /* IRQ Floppy Intr.              */
+t_irq12:TRAP_ENTRY_INTERRUPT(12)             /* IRQ Zilog serial chip         */
+t_irq13:TRAP_ENTRY_INTERRUPT(13)             /* IRQ Audio Intr.               */
+t_irq14:TRAP_ENTRY_INTERRUPT(14)             /* IRQ Timer #2                  */
+t_nmi: NMI_TRAP                             /* Level 15 (NMI)                */
+t_racc:        TRAP_ENTRY(0x20, do_reg_access)      /* General Register Access Error */
+t_iacce:TRAP_ENTRY(0x21, do_iacc_error)      /* Instruction Access Error      */
+t_bad22:TRAP_ENTRY(0x22, bad_trap_handler)   /* Undefined...                  */
+t_bad23:TRAP_ENTRY(0x23, bad_trap_handler)   /* Undefined...                  */
+t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)     /* Co-Processor Disabled         */
+t_uflsh:TRAP_ENTRY(0x25, do_bad_flush)       /* Unimplemented FLUSH inst.     */
+t_bad26:TRAP_ENTRY(0x26, bad_trap_handler)   /* Undefined...                  */
+t_bad27:TRAP_ENTRY(0x27, bad_trap_handler)   /* Undefined...                  */
+t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)    /* Co-Processor Exception        */
+t_dacce:TRAP_ENTRY(0x29, do_dacc_error)      /* Data Access Error             */
+t_hwdz:        TRAP_ENTRY(0x2a, do_hw_divzero)      /* Division by zero, you lose... */
+t_dserr:TRAP_ENTRY(0x2b, do_dstore_err)      /* Data Store Error              */
+t_daccm:TRAP_ENTRY(0x2c, do_dacc_mmu_miss)   /* Data Access MMU-Miss          */
+t_bad2d:TRAP_ENTRY(0x2d, bad_trap_handler)   /* Undefined...                  */
+t_bad2e:TRAP_ENTRY(0x2e, bad_trap_handler)   /* Undefined...                  */
+t_bad2f:TRAP_ENTRY(0x2f, bad_trap_handler)   /* Undefined...                  */
+t_bad30:TRAP_ENTRY(0x30, bad_trap_handler)   /* Undefined...                  */
+t_bad31:TRAP_ENTRY(0x31, bad_trap_handler)   /* Undefined...                  */
+t_bad32:TRAP_ENTRY(0x32, bad_trap_handler)   /* Undefined...                  */
+t_bad33:TRAP_ENTRY(0x33, bad_trap_handler)   /* Undefined...                  */
+t_bad34:TRAP_ENTRY(0x34, bad_trap_handler)   /* Undefined...                  */
+t_bad35:TRAP_ENTRY(0x35, bad_trap_handler)   /* Undefined...                  */
+t_bad36:TRAP_ENTRY(0x36, bad_trap_handler)   /* Undefined...                  */
+t_bad37:TRAP_ENTRY(0x37, bad_trap_handler)   /* Undefined...                  */
+t_bad38:TRAP_ENTRY(0x38, bad_trap_handler)   /* Undefined...                  */
+t_bad39:TRAP_ENTRY(0x39, bad_trap_handler)   /* Undefined...                  */
+t_bad3a:TRAP_ENTRY(0x3a, bad_trap_handler)   /* Undefined...                  */
+t_bad3b:TRAP_ENTRY(0x3b, bad_trap_handler)   /* Undefined...                  */
+t_iaccm:TRAP_ENTRY(0x3c, do_iacc_mmu_miss)   /* Instruction Access MMU-Miss   */
+t_bad3d:TRAP_ENTRY(0x3d, bad_trap_handler)   /* Undefined...                  */
+t_bad3e:TRAP_ENTRY(0x3e, bad_trap_handler)   /* Undefined...                  */
+t_bad3f:TRAP_ENTRY(0x3f, bad_trap_handler)   /* Undefined...                  */
+t_bad40:TRAP_ENTRY(0x40, bad_trap_handler)   /* Undefined...                  */
+t_bad41:TRAP_ENTRY(0x41, bad_trap_handler)   /* Undefined...                  */
+t_bad42:TRAP_ENTRY(0x42, bad_trap_handler)   /* Undefined...                  */
+t_bad43:TRAP_ENTRY(0x43, bad_trap_handler)   /* Undefined...                  */
+t_bad44:TRAP_ENTRY(0x44, bad_trap_handler)   /* Undefined...                  */
+t_bad45:TRAP_ENTRY(0x45, bad_trap_handler)   /* Undefined...                  */
+t_bad46:TRAP_ENTRY(0x46, bad_trap_handler)   /* Undefined...                  */
+t_bad47:TRAP_ENTRY(0x47, bad_trap_handler)   /* Undefined...                  */
+t_bad48:TRAP_ENTRY(0x48, bad_trap_handler)   /* Undefined...                  */
+t_bad49:TRAP_ENTRY(0x49, bad_trap_handler)   /* Undefined...                  */
+t_bad4a:TRAP_ENTRY(0x4a, bad_trap_handler)   /* Undefined...                  */
+t_bad4b:TRAP_ENTRY(0x4b, bad_trap_handler)   /* Undefined...                  */
+t_bad4c:TRAP_ENTRY(0x4c, bad_trap_handler)   /* Undefined...                  */
+t_bad4d:TRAP_ENTRY(0x4d, bad_trap_handler)   /* Undefined...                  */
+t_bad4e:TRAP_ENTRY(0x4e, bad_trap_handler)   /* Undefined...                  */
+t_bad4f:TRAP_ENTRY(0x4f, bad_trap_handler)   /* Undefined...                  */
+t_bad50:TRAP_ENTRY(0x50, bad_trap_handler)   /* Undefined...                  */
+t_bad51:TRAP_ENTRY(0x51, bad_trap_handler)   /* Undefined...                  */
+t_bad52:TRAP_ENTRY(0x52, bad_trap_handler)   /* Undefined...                  */
+t_bad53:TRAP_ENTRY(0x53, bad_trap_handler)   /* Undefined...                  */
+t_bad54:TRAP_ENTRY(0x54, bad_trap_handler)   /* Undefined...                  */
+t_bad55:TRAP_ENTRY(0x55, bad_trap_handler)   /* Undefined...                  */
+t_bad56:TRAP_ENTRY(0x56, bad_trap_handler)   /* Undefined...                  */
+t_bad57:TRAP_ENTRY(0x57, bad_trap_handler)   /* Undefined...                  */
+t_bad58:TRAP_ENTRY(0x58, bad_trap_handler)   /* Undefined...                  */
+t_bad59:TRAP_ENTRY(0x59, bad_trap_handler)   /* Undefined...                  */
+t_bad5a:TRAP_ENTRY(0x5a, bad_trap_handler)   /* Undefined...                  */
+t_bad5b:TRAP_ENTRY(0x5b, bad_trap_handler)   /* Undefined...                  */
+t_bad5c:TRAP_ENTRY(0x5c, bad_trap_handler)   /* Undefined...                  */
+t_bad5d:TRAP_ENTRY(0x5d, bad_trap_handler)   /* Undefined...                  */
+t_bad5e:TRAP_ENTRY(0x5e, bad_trap_handler)   /* Undefined...                  */
+t_bad5f:TRAP_ENTRY(0x5f, bad_trap_handler)   /* Undefined...                  */
+t_bad60:TRAP_ENTRY(0x60, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad61:TRAP_ENTRY(0x61, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad62:TRAP_ENTRY(0x62, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad63:TRAP_ENTRY(0x63, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad64:TRAP_ENTRY(0x64, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad65:TRAP_ENTRY(0x65, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad66:TRAP_ENTRY(0x66, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad67:TRAP_ENTRY(0x67, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad68:TRAP_ENTRY(0x68, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad69:TRAP_ENTRY(0x69, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6a:TRAP_ENTRY(0x6a, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6b:TRAP_ENTRY(0x6b, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6c:TRAP_ENTRY(0x6c, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6d:TRAP_ENTRY(0x6d, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6e:TRAP_ENTRY(0x6e, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6f:TRAP_ENTRY(0x6f, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad70:TRAP_ENTRY(0x70, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad71:TRAP_ENTRY(0x71, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad72:TRAP_ENTRY(0x72, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad73:TRAP_ENTRY(0x73, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad74:TRAP_ENTRY(0x74, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad75:TRAP_ENTRY(0x75, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad76:TRAP_ENTRY(0x76, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad77:TRAP_ENTRY(0x77, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad78:TRAP_ENTRY(0x78, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad79:TRAP_ENTRY(0x79, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7a:TRAP_ENTRY(0x7a, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7b:TRAP_ENTRY(0x7b, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7c:TRAP_ENTRY(0x7c, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7d:TRAP_ENTRY(0x7d, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7e:TRAP_ENTRY(0x7e, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7f:TRAP_ENTRY(0x7f, bad_trap_handler)   /* Impl-Dep Exception            */
+t_sunos:SUNOS_SYSCALL_TRAP                   /* SunOS System Call             */
+t_sbkpt:TRAP_ENTRY(0x81, bad_trap_handler)   /* Software Breakpoint           */
+t_divz:        TRAP_ENTRY(0x82, bad_trap_handler)   /* Divide by zero trap           */
+t_flwin:TRAP_ENTRY(0x83, bad_trap_handler)   /* Flush Windows Trap            */
+t_clwin:TRAP_ENTRY(0x84, bad_trap_handler)   /* Clean Windows Trap            */
+t_rchk:        TRAP_ENTRY(0x85, bad_trap_handler)   /* Range Check                   */
+t_funal:TRAP_ENTRY(0x86, bad_trap_handler)   /* Fix Unaligned Access Trap     */
+t_iovf:        TRAP_ENTRY(0x87, bad_trap_handler)   /* Integer Overflow Trap         */
+t_slowl:SOLARIS_SYSCALL_TRAP                 /* Slowaris System Call          */
+t_netbs:NETBSD_SYSCALL_TRAP                  /* Net-B.S. System Call          */
+t_bad8a:TRAP_ENTRY(0x8a, bad_trap_handler)   /* Software Trap                 */
+t_bad8b:TRAP_ENTRY(0x8b, bad_trap_handler)   /* Software Trap                 */
+t_bad8c:TRAP_ENTRY(0x8c, bad_trap_handler)   /* Software Trap                 */
+t_bad8d:TRAP_ENTRY(0x8d, bad_trap_handler)   /* Software Trap                 */
+t_bad8e:TRAP_ENTRY(0x8e, bad_trap_handler)   /* Software Trap                 */
+t_bad8f:TRAP_ENTRY(0x8f, bad_trap_handler)   /* Software Trap                 */
+t_linux:LINUX_SYSCALL_TRAP                   /* Linux System Call             */
+t_bad91:TRAP_ENTRY(0x91, bad_trap_handler)   /* Software Trap                 */
+t_bad92:TRAP_ENTRY(0x92, bad_trap_handler)   /* Software Trap                 */
+t_bad93:TRAP_ENTRY(0x93, bad_trap_handler)   /* Software Trap                 */
+t_bad94:TRAP_ENTRY(0x94, bad_trap_handler)   /* Software Trap                 */
+t_bad95:TRAP_ENTRY(0x95, bad_trap_handler)   /* Software Trap                 */
+t_bad96:TRAP_ENTRY(0x96, bad_trap_handler)   /* Software Trap                 */
+t_bad97:TRAP_ENTRY(0x97, bad_trap_handler)   /* Software Trap                 */
+t_bad98:TRAP_ENTRY(0x98, bad_trap_handler)   /* Software Trap                 */
+t_bad99:TRAP_ENTRY(0x99, bad_trap_handler)   /* Software Trap                 */
+t_bad9a:TRAP_ENTRY(0x9a, bad_trap_handler)   /* Software Trap                 */
+t_bad9b:TRAP_ENTRY(0x9b, bad_trap_handler)   /* Software Trap                 */
+t_bad9c:TRAP_ENTRY(0x9c, bad_trap_handler)   /* Software Trap                 */
+t_bad9d:TRAP_ENTRY(0x9d, bad_trap_handler)   /* Software Trap                 */
+t_bad9e:TRAP_ENTRY(0x9e, bad_trap_handler)   /* Software Trap                 */
+t_bad9f:TRAP_ENTRY(0x9f, bad_trap_handler)   /* Software Trap                 */
+t_getcc:GETCC_TRAP                           /* Get Condition Codes           */
+t_setcc:SETCC_TRAP                           /* Set Condition Codes           */
+t_bada2:TRAP_ENTRY(0xa2, bad_trap_handler)   /* Software Trap                 */
+t_bada3:TRAP_ENTRY(0xa3, bad_trap_handler)   /* Software Trap                 */
+t_bada4:TRAP_ENTRY(0xa4, bad_trap_handler)   /* Software Trap                 */
+t_bada5:TRAP_ENTRY(0xa5, bad_trap_handler)   /* Software Trap                 */
+t_bada6:TRAP_ENTRY(0xa6, bad_trap_handler)   /* Software Trap                 */
+t_bada7:TRAP_ENTRY(0xa7, bad_trap_handler)   /* Software Trap                 */
+t_bada8:TRAP_ENTRY(0xa8, bad_trap_handler)   /* Software Trap                 */
+t_bada9:TRAP_ENTRY(0xa9, bad_trap_handler)   /* Software Trap                 */
+t_badaa:TRAP_ENTRY(0xaa, bad_trap_handler)   /* Software Trap                 */
+t_badab:TRAP_ENTRY(0xab, bad_trap_handler)   /* Software Trap                 */
+t_badac:TRAP_ENTRY(0xac, bad_trap_handler)   /* Software Trap                 */
+t_badad:TRAP_ENTRY(0xad, bad_trap_handler)   /* Software Trap                 */
+t_badae:TRAP_ENTRY(0xae, bad_trap_handler)   /* Software Trap                 */
+t_badaf:TRAP_ENTRY(0xaf, bad_trap_handler)   /* Software Trap                 */
+t_badb0:TRAP_ENTRY(0xb0, bad_trap_handler)   /* Software Trap                 */
+t_badb1:TRAP_ENTRY(0xb1, bad_trap_handler)   /* Software Trap                 */
+t_badb2:TRAP_ENTRY(0xb2, bad_trap_handler)   /* Software Trap                 */
+t_badb3:TRAP_ENTRY(0xb3, bad_trap_handler)   /* Software Trap                 */
+t_badb4:TRAP_ENTRY(0xb4, bad_trap_handler)   /* Software Trap                 */
+t_badb5:TRAP_ENTRY(0xb5, bad_trap_handler)   /* Software Trap                 */
+t_badb6:TRAP_ENTRY(0xb6, bad_trap_handler)   /* Software Trap                 */
+t_badb7:TRAP_ENTRY(0xb7, bad_trap_handler)   /* Software Trap                 */
+t_badb8:TRAP_ENTRY(0xb8, bad_trap_handler)   /* Software Trap                 */
+t_badb9:TRAP_ENTRY(0xb9, bad_trap_handler)   /* Software Trap                 */
+t_badba:TRAP_ENTRY(0xba, bad_trap_handler)   /* Software Trap                 */
+t_badbb:TRAP_ENTRY(0xbb, bad_trap_handler)   /* Software Trap                 */
+t_badbc:TRAP_ENTRY(0xbc, bad_trap_handler)   /* Software Trap                 */
+t_badbd:TRAP_ENTRY(0xbd, bad_trap_handler)   /* Software Trap                 */
+t_badbe:TRAP_ENTRY(0xbe, bad_trap_handler)   /* Software Trap                 */
+t_badbf:TRAP_ENTRY(0xbf, bad_trap_handler)   /* Software Trap                 */
+t_badc0:TRAP_ENTRY(0xc0, bad_trap_handler)   /* Software Trap                 */
+t_badc1:TRAP_ENTRY(0xc1, bad_trap_handler)   /* Software Trap                 */
+t_badc2:TRAP_ENTRY(0xc2, bad_trap_handler)   /* Software Trap                 */
+t_badc3:TRAP_ENTRY(0xc3, bad_trap_handler)   /* Software Trap                 */
+t_badc4:TRAP_ENTRY(0xc4, bad_trap_handler)   /* Software Trap                 */
+t_badc5:TRAP_ENTRY(0xc5, bad_trap_handler)   /* Software Trap                 */
+t_badc6:TRAP_ENTRY(0xc6, bad_trap_handler)   /* Software Trap                 */
+t_badc7:TRAP_ENTRY(0xc7, bad_trap_handler)   /* Software Trap                 */
+t_badc8:TRAP_ENTRY(0xc8, bad_trap_handler)   /* Software Trap                 */
+t_badc9:TRAP_ENTRY(0xc9, bad_trap_handler)   /* Software Trap                 */
+t_badca:TRAP_ENTRY(0xca, bad_trap_handler)   /* Software Trap                 */
+t_badcb:TRAP_ENTRY(0xcb, bad_trap_handler)   /* Software Trap                 */
+t_badcc:TRAP_ENTRY(0xcc, bad_trap_handler)   /* Software Trap                 */
+t_badcd:TRAP_ENTRY(0xcd, bad_trap_handler)   /* Software Trap                 */
+t_badce:TRAP_ENTRY(0xce, bad_trap_handler)   /* Software Trap                 */
+t_badcf:TRAP_ENTRY(0xcf, bad_trap_handler)   /* Software Trap                 */
+t_badd0:TRAP_ENTRY(0xd0, bad_trap_handler)   /* Software Trap                 */
+t_badd1:TRAP_ENTRY(0xd1, bad_trap_handler)   /* Software Trap                 */
+t_badd2:TRAP_ENTRY(0xd2, bad_trap_handler)   /* Software Trap                 */
+t_badd3:TRAP_ENTRY(0xd3, bad_trap_handler)   /* Software Trap                 */
+t_badd4:TRAP_ENTRY(0xd4, bad_trap_handler)   /* Software Trap                 */
+t_badd5:TRAP_ENTRY(0xd5, bad_trap_handler)   /* Software Trap                 */
+t_badd6:TRAP_ENTRY(0xd6, bad_trap_handler)   /* Software Trap                 */
+t_badd7:TRAP_ENTRY(0xd7, bad_trap_handler)   /* Software Trap                 */
+t_badd8:TRAP_ENTRY(0xd8, bad_trap_handler)   /* Software Trap                 */
+t_badd9:TRAP_ENTRY(0xd9, bad_trap_handler)   /* Software Trap                 */
+t_badda:TRAP_ENTRY(0xda, bad_trap_handler)   /* Software Trap                 */
+t_baddb:TRAP_ENTRY(0xdb, bad_trap_handler)   /* Software Trap                 */
+t_baddc:TRAP_ENTRY(0xdc, bad_trap_handler)   /* Software Trap                 */
+t_baddd:TRAP_ENTRY(0xdd, bad_trap_handler)   /* Software Trap                 */
+t_badde:TRAP_ENTRY(0xde, bad_trap_handler)   /* Software Trap                 */
+t_baddf:TRAP_ENTRY(0xdf, bad_trap_handler)   /* Software Trap                 */
+t_bade0:TRAP_ENTRY(0xe0, bad_trap_handler)   /* Software Trap                 */
+t_bade1:TRAP_ENTRY(0xe1, bad_trap_handler)   /* Software Trap                 */
+t_bade2:TRAP_ENTRY(0xe2, bad_trap_handler)   /* Software Trap                 */
+t_bade3:TRAP_ENTRY(0xe3, bad_trap_handler)   /* Software Trap                 */
+t_bade4:TRAP_ENTRY(0xe4, bad_trap_handler)   /* Software Trap                 */
+t_bade5:TRAP_ENTRY(0xe5, bad_trap_handler)   /* Software Trap                 */
+t_bade6:TRAP_ENTRY(0xe6, bad_trap_handler)   /* Software Trap                 */
+t_bade7:TRAP_ENTRY(0xe7, bad_trap_handler)   /* Software Trap                 */
+t_bade8:TRAP_ENTRY(0xe8, bad_trap_handler)   /* Software Trap                 */
+t_bade9:TRAP_ENTRY(0xe9, bad_trap_handler)   /* Software Trap                 */
+t_badea:TRAP_ENTRY(0xea, bad_trap_handler)   /* Software Trap                 */
+t_badeb:TRAP_ENTRY(0xeb, bad_trap_handler)   /* Software Trap                 */
+t_badec:TRAP_ENTRY(0xec, bad_trap_handler)   /* Software Trap                 */
+t_baded:TRAP_ENTRY(0xed, bad_trap_handler)   /* Software Trap                 */
+t_badee:TRAP_ENTRY(0xee, bad_trap_handler)   /* Software Trap                 */
+t_badef:TRAP_ENTRY(0xef, bad_trap_handler)   /* Software Trap                 */
+t_badf0:TRAP_ENTRY(0xf0, bad_trap_handler)   /* Software Trap                 */
+t_badf1:TRAP_ENTRY(0xf1, bad_trap_handler)   /* Software Trap                 */
+t_badf2:TRAP_ENTRY(0xf2, bad_trap_handler)   /* Software Trap                 */
+t_badf3:TRAP_ENTRY(0xf3, bad_trap_handler)   /* Software Trap                 */
+t_badf4:TRAP_ENTRY(0xf4, bad_trap_handler)   /* Software Trap                 */
+t_badf5:TRAP_ENTRY(0xf5, bad_trap_handler)   /* Software Trap                 */
+t_badf6:TRAP_ENTRY(0xf6, bad_trap_handler)   /* Software Trap                 */
+t_badf7:TRAP_ENTRY(0xf7, bad_trap_handler)   /* Software Trap                 */
+t_badf8:TRAP_ENTRY(0xf8, bad_trap_handler)   /* Software Trap                 */
+t_badf9:TRAP_ENTRY(0xf9, bad_trap_handler)   /* Software Trap                 */
+t_badfa:TRAP_ENTRY(0xfa, bad_trap_handler)   /* Software Trap                 */
+t_badfb:TRAP_ENTRY(0xfb, bad_trap_handler)   /* Software Trap                 */
+t_badfc:TRAP_ENTRY(0xfc, bad_trap_handler)   /* Software Trap                 */
+t_badfd:TRAP_ENTRY(0xfd, bad_trap_handler)   /* Software Trap                 */
+dbtrap:        TRAP_ENTRY(0xfe, bad_trap_handler)   /* Debugger/PROM breakpoint #1   */
+dbtrap2:TRAP_ENTRY(0xff, bad_trap_handler)   /* Debugger/PROM breakpoint #2   */       
+
+       .globl  C_LABEL(end_traptable)
+C_LABEL(end_traptable):
 
-pstring4:
-       .ascii "Total Physical Memory: %d bytes\nVM mapped by Prom: %d bytes\n"
-       .asciz "Available Physical Memory: %d bytes\n"
-       .align 4
+       .skip 4096
 
+/* This was the only reasonable way I could think of to properly align
+ * these page-table data structures.
+ *
+ * XXX swapper_pg_dir is going to have to be 'per-CPU' for SMP support
+ */
 
-       .text
+       .globl C_LABEL(auxio_reg_addr)
+C_LABEL(auxio_reg_addr):       .skip   (PAGE_SIZE)
 
-        .globl  C_LABEL(msgbuf)
-msgbufsize = PAGE_SIZE                       ! 1 page for msg buffer
-C_LABEL(msgbuf) =  PAGE_SIZE
+       .globl C_LABEL(clock_reg_addr)
+C_LABEL(clock_reg_addr):       .skip   (PAGE_SIZE*5)
 
+       .globl C_LABEL(int_reg_addr)
+C_LABEL(int_reg_addr):         .skip   (PAGE_SIZE*5)
 
-IE_reg_addr = C_LABEL(msgbuf) + msgbufsize   ! this page not used; points to IEreg
+       .globl C_LABEL(pg0)
+       .globl C_LABEL(empty_bad_page)
+       .globl C_LABEL(empty_bad_page_table)
+       .globl C_LABEL(empty_zero_page)
+       .globl C_LABEL(swapper_pg_dir)
+C_LABEL(swapper_pg_dir):               .skip 0x1000
+C_LABEL(pg0):                          .skip 0x1000
+C_LABEL(empty_bad_page):               .skip 0x1000
+C_LABEL(empty_bad_page_table):         .skip 0x1000
+C_LABEL(empty_zero_page):              .skip 0x1000
 
-       
-/* Ok, things start to get interesting. We get linked such that 'start'
-   is the entry symbol. However, it is real low in kernel address space
-   and as such a nifty place to place the trap table. We achieve this goal
-   by just jumping to 'gokernel' for the first trap's entry as the sparc
-   never receives the zero trap as it is real special (hw reset).
 
-   Each trap entry point is the size of 4 sparc instructions (or 4 bytes
-   * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
-   or unimplemented) and 128 software traps (sys-calls, etc.).
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+ * %g7 and at prom_vector_p. And also quickly check whether we are on
+ * a v0, v2, or v3 prom.  We also get a debug structure of some sort from
+ * the boot loader (or is it the prom?) in %o1.  Finally a call back vector
+ * is passed in %o2.  I think this is how you register yourself with a
+ * debugger.  I do know that it wants my %o7 (return PC - 8) as it's
+ * first argument.  I will poke around and figure out what the debug
+ * vector is, it could contain useful stuff.
+ */
 
-   One of the instructions must be a branch. More often than not this
-   will be to a trap handler entry point because it is completely
-   impossible to handle any trap in 4 insns. I welcome anyone to 
-   challenge this theory. :-)
+/* Grrr, in order to be Sparc ABI complient, the kernel has to live in
+ * an address space above 0xe0000000  ;(  Must remain position independant
+ * until we 'remap' ourselves from low to high addresses.  We only map the
+ * first 3MB of addresses into upper ram as that is how much the PROM
+ * promises to set up for us.
+ */
+gokernel:
+               /* Ok, it's nice to know, as early as possible, if we
+                * are already mapped where we expect to be in virtual
+                * memory.  The Solaris /boot elf format bootloader
+                * will peek into our elf header and load us where
+                * we want to be, otherwise we have to re-map.
+                *
+                * Some boot loaders don't place the jmp'rs address
+                * in %o7, so we do a pc-relative call to a local
+                * label, then see what %o7 has.
+                */
+
+               /* XXX Sparc V9 detection goes here XXX */
+
+               or      %g0, %o7, %g4           ! Save %o7
+
+               /* Jump to it, and pray... */
+current_pc:
+               call    1f
+               nop
 
-   On entry into this table the hardware has loaded the program counter
-   at which the trap occurred into register %l1 and the next program
-   counter into %l2, this way we can return from the trap with a simple
+1:
+               or      %g0, %o7, %g3
 
-           jmp %l1; rett %l2  ! poof...
+got_pc:
+               or      %g0, %g4, %o7   /* Previous %o7. */
+       
+               or      %g0, %o0, %l0           ! stash away romvec
+               or      %g0, %o0, %g7           ! put it here too
+               or      %g0, %o1, %l1           ! stash away debug_vec too
+               rd      %psr, %l2               ! Save psr
+               rd      %wim, %l3               ! wim
+               rd      %tbr, %l4               ! tbr
+               or      %g0, %o2, %l5           ! and the possible magic func
+
+               /* Ok, let's check out our run time program counter. */
+               set     current_pc, %g5
+               cmp     %g3, %g5
+               be      already_mapped
+
+               /* %l6 will hold the offset we have to subtract
+                * from absolute symbols in order to access areas
+                * in our own image.  If already mapped this is
+                * just plain zero, else it is PAGE_OFFSET which is
+                * also KERNBASE.
+                */
+               set     PAGE_OFFSET, %l6
+               b       copy_prom_lvl14
+               nop
 
-   after properly servicing the trap. It wouldn't be a bad idea to load
-   some more information into the local regs since we have technically
-   2 or 3 instructions to play with besides the jmp to the 'real' trap
-   handler (one can even go in the delay slot). For now I am going to put
-   the %psr (processor status register) and the trap-type value in %l0
-   and %l3 respectively. Also, for IRQ's I'll put the level in %l4.
+already_mapped:
+               or      %g0, %g0, %l6
+
+               /* Copy over the Prom's level 14 clock handler. */
+copy_prom_lvl14:
+               rd      %tbr, %g1
+               andn    %g1, 0xfff, %g1         ! proms trap table base
+               or      %g0, (0x1e<<4), %g2     ! offset to lvl14 intr
+               or      %g1, %g2, %g2
+               set     t_irq14, %g3
+               sub     %g3, %l6, %g3
+               ldd     [%g2], %g4
+               std     %g4, [%g3]
+               ldd     [%g2 + 0x8], %g4
+               std     %g4, [%g3 + 0x8]        ! Copy proms handler
+
+               /* Copy over the Prom/debugger's trap entry points. */
+copy_prom_bpoint:
+               or      %g0, (0xfe<<4), %g2
+               or      %g1, %g2, %g2
+               set     dbtrap, %g3
+               sub     %g3, %l6, %g3
+               ldd     [%g2], %g4
+               std     %g4, [%g3]
+               ldd     [%g2 + 0x8], %g4
+               std     %g4, [%g3 + 0x8]
+               ldd     [%g2 + 0x10], %g4
+               std     %g4, [%g3 + 0x10]
+               ldd     [%g2 + 0x18], %g4
+               std     %g4, [%g3 + 0x18]
+
+copy_prom_done:
+               ld      [%o0 + 0x4], %g1
+               and     %g1, 0x3, %g1
+               subcc   %g1, 0x0, %g0
+               be      set_sane_psr            ! Not on v0 proms
+               nop
 
-*/
+               subcc   %o2, 0x0, %g0           ! check for boot routine pointer
+               bz      set_sane_psr
+               nop
+               jmpl    %o2, %o7                ! call boot setup func
+               add     %o7, 0x8, %o0
+
+set_sane_psr:
+               /* Traps are on, kadb can be tracing through here.  But
+                * we have no clue what the PIL is. So we set up a sane
+                * %psr, but preserve CWP or our locals could disappear!
+                */
+               rd      %psr, %g2
+               and     %g2, 0x1f, %g2                  ! %g2 has CWP now
+               set     (PSR_S|PSR_PIL), %g1            ! Supervisor + PIL high
+               or      %g1, %g2, %g1                   ! mix mix mix
+               wr      %g1, 0x0, %psr                  ! let PIL set in
+               wr      %g1, PSR_ET, %psr               ! now turn on traps
+
+               /* A note about the last two instructions...
+                * If you are going to increase PIL and turn on
+                * traps at the same time you are asking for trouble.
+                * You MUST set a %psr with traps off containing
+                * your new PIL, then turn on the ET bit with the
+                * next write.  On certain buggy Sparc chips if you
+                * set both at the same time you can get a Watchdog
+                * Reset under certain conditions.  This is no fun.
+                * Basically the PIL bits get there before the
+                * EnableTrap bit does or something like that.
+                */
+
+               /* Insane asylum... */
+               WRITE_PAUSE
 
-       .globl  start
-       .globl  _start  /* warning, solaris hack */
-       .globl  C_LABEL(trapbase)
-_start:   /* danger danger */
-start:
-C_LABEL(trapbase):
-       b gokernel; nop; nop; nop;      ! we never get trap #0 it is special 
-
-       TRAP_ENTRY(0x1, my_trap_handler) /* Instruction Access Exception */
-       TRAP_ENTRY(0x2, my_trap_handler) /* Illegal Instruction */
-       TRAP_ENTRY(0x3, my_trap_handler) /* Privileged Instruction */
-       TRAP_ENTRY(0x4, my_trap_handler) /* Floating Point Disabled */
-       TRAP_ENTRY(0x5, spill_window_entry)   /* Window Overflow */
-       TRAP_ENTRY(0x6, fill_window_entry)  /* Window Underflow */
-       TRAP_ENTRY(0x7, my_trap_handler) /* Memory Address Not Aligned */
-       TRAP_ENTRY(0x8, my_trap_handler) /* Floating Point Exception */
-       TRAP_ENTRY(0x9, my_trap_handler) /* Data Miss Exception */
-       TRAP_ENTRY(0xa, my_trap_handler) /* Tagged Instruction Overflow */
-       TRAP_ENTRY(0xb, my_trap_handler) /* Watchpoint Detected */
-       TRAP_ENTRY(0xc, my_trap_handler) /* Undefined... */
-       TRAP_ENTRY(0xd, my_trap_handler) /* Undefined... */
-       TRAP_ENTRY(0xe, my_trap_handler) /* Undefined... */
-       TRAP_ENTRY(0xf, my_trap_handler) /* Undefined... */
-       TRAP_ENTRY(0x10, my_trap_handler) /* Undefined... */
-
-/* Level'd interrupt entry points, see macro defs above */
-
-        TRAP_ENTRY_INTERRUPT_SOFT(1, 0x101) /* IRQ Software/SBUS Level 1  */
-        TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2           */
-        TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3  */
-        TRAP_ENTRY_INTERRUPT_SOFT(4, 0x104) /* IRQ Software Level 4       */
-        TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5  */
-        TRAP_ENTRY_INTERRUPT_SOFT(6, 0x106) /* IRQ Software Level 6       */
-        TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5     */
-        TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6           */
-        TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7           */
-        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1               */
-        TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.           */
-        TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip      */
-        TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.            */
-        TRAP_ENTRY_TIMER                    /* IRQ Timer #2 (one we use)  */
-        TRAP_ENTRY_INTERRUPT_NMI(15, linux_trap_nmi) /* Level 15 (nmi) */
-
-       TRAP_ENTRY(0x20, my_trap_handler)   /* General Register Access Error */
-       TRAP_ENTRY(0x21, my_trap_handler)   /* Instruction Access Error      */
-       TRAP_ENTRY(0x22, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x23, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x24, my_trap_handler)   /* Co-Processor Disabled         */
-       TRAP_ENTRY(0x25, my_trap_handler)   /* Unimplemented FLUSH inst.     */
-       TRAP_ENTRY(0x26, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x27, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x28, my_trap_handler)   /* Co-Processor Exception        */
-       TRAP_ENTRY(0x29, my_trap_handler)   /* Data Access Error             */
-       TRAP_ENTRY(0x2a, my_trap_handler)   /* Division by zero, you lose... */
-       TRAP_ENTRY(0x2b, my_trap_handler)   /* Data Store Error              */
-       TRAP_ENTRY(0x2c, my_trap_handler)   /* Data Access MMU-Miss          */
-       TRAP_ENTRY(0x2d, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x2e, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x2f, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x30, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x31, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x32, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x33, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x34, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x35, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x36, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x37, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x38, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x39, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x3a, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x3b, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x3c, my_trap_handler)   /* Instruction Access MMU-Miss   */
-       TRAP_ENTRY(0x3d, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x3e, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x3f, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x40, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x41, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x42, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x43, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x44, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x45, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x46, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x47, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x48, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x49, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4a, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4b, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4c, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4d, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4e, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x4f, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x50, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x51, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x52, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x53, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x54, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x55, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x56, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x57, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x58, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x59, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5a, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5b, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5c, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5d, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5e, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x5f, my_trap_handler)   /* Undefined...                  */
-       TRAP_ENTRY(0x60, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x61, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x62, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x63, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x64, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x65, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x66, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x67, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x68, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x69, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6a, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6b, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6c, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6d, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6e, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x6f, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x70, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x71, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x72, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x73, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x74, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x75, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x76, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x77, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x78, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x79, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7a, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7b, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7c, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7d, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7e, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x7f, my_trap_handler)   /* Impl-Dep Exception            */
-       TRAP_ENTRY(0x80, my_trap_handler)   /* SunOS System Call             */
-       TRAP_ENTRY(0x81, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x82, my_trap_handler)   /* Divide by zero trap XXX       */
-       TRAP_ENTRY(0x83, my_trap_handler)   /* Flush Windows Trap XXX        */
-       TRAP_ENTRY(0x84, my_trap_handler)   /* Clean Windows Trap XXX        */
-       TRAP_ENTRY(0x85, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x86, my_trap_handler)   /* Fix Unaligned Access Trap XXX */
-       TRAP_ENTRY(0x87, my_trap_handler)   /* Integer Overflow Trap XXX     */
-       TRAP_ENTRY(0x88, my_trap_handler)   /* Slowaris System Call          */
-       TRAP_ENTRY(0x89, my_trap_handler)   /* NetBSD System Call            */
-       TRAP_ENTRY(0x8a, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x8b, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x8c, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x8d, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x8e, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x8f, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x90, my_trap_handler)   /* SparcLinux System Call        */
-       TRAP_ENTRY(0x91, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x92, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x93, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x94, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x95, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x96, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x97, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x98, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x99, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9a, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9b, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9c, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9d, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9e, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0x9f, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xa9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xaa, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xab, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xac, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xad, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xae, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xaf, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xb9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xba, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xbb, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xbc, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xbd, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xbe, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xbf, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xc9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xca, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xcb, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xcc, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xcd, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xce, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xcf, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xd9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xda, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xdb, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xdc, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xdd, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xde, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xdf, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xe9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xea, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xeb, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xec, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xed, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xee, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xef, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf0, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf1, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf2, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf3, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf4, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf5, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf6, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf7, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf8, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xf9, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xfa, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xfb, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xfc, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xfd, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xfe, my_trap_handler)   /* Software Trap                 */
-       TRAP_ENTRY(0xff, my_trap_handler)   /* Software Trap                 */ 
+/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
+ * MMU so we can remap ourselves properly.  DONT TOUCH %l0 thru %l5 in these
+ * remapping routines, we need their values afterwards!
+ *
+ * XXX UGH, need to write some sun4u SpitFire remapping V9 code RSN... XXX
+ */
+               /* Now check whether we are already mapped, if we
+                * are we can skip all this garbage coming up.
+                */
+               subcc   %l6, 0x0, %g0
+               bz      go_to_highmem           ! this will be a nop then
+               nop
 
-       .skip 4096
+               sethi   %hi(LOAD_ADDR), %g6
+               subcc   %g7, %g6, %g0
+               bne     remap_not_a_sun4        ! This is not a Sun4
+               nop
 
-C_LABEL(msgbufmapped):
-        .word   1
+               or      %g0, 0x1, %g1
+               lduba   [%g1] ASI_CONTROL, %g1  ! Only safe to try on Sun4.
+               subcc   %g1, 0x24, %g0          ! Is this a mutant Sun4/400???
+               be      sun4_mutant_remap       ! Ugh, it is...
+               nop
 
+remap_not_a_sun4:
+               lda     [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c
+               and     %g1, 0x1, %g1           ! Test SRMMU Enable bit ;-)
+               subcc   %g1, 0x0, %g0
+               bz      sun4c_remap             ! A sun4c MMU or normal Sun4
+               nop
+srmmu_remap:
+               /* First, check for a viking (TI) module. */
+               set     0x40000000, %g2
+               rd      %psr, %g3
+               and     %g2, %g3, %g3
+               subcc   %g3, 0x0, %g0
+               bz      srmmu_nviking
+               nop
 
+               /* Figure out what kind of viking we are on.
+                * We need to know if we have to play with the
+                * AC bit and disable traps or not.
+                */
+
+               /* I've only seen MicroSparc's on SparcClassics with this
+                * bit set.
+                */
+               set     0x800, %g2
+               lda     [%g0] ASI_M_MMUREGS, %g3        ! peek in the control reg
+               and     %g2, %g3, %g3
+               subcc   %g3, 0x0, %g0
+               bnz     srmmu_nviking                   ! is in mbus mode
+               nop
+               
+               rd      %psr, %g3                       ! DONT TOUCH %g3
+               andn    %g3, PSR_ET, %g2
+               wr      %g2, 0x0, %psr
+               WRITE_PAUSE
+               
+               /* Get context table pointer, then convert to
+                * a physical address, which is 36 bits.
+                */
+               set     AC_M_CTPR, %g4
+               lda     [%g4] ASI_M_MMUREGS, %g4
+               sll     %g4, 0x4, %g4                   ! We use this below
+                                                       ! DONT TOUCH %g4
+
+               /* Set the AC bit in the Viking's MMU control reg. */
+               lda     [%g0] ASI_M_MMUREGS, %g5        ! DONT TOUCH %g5
+               set     0x8000, %g6                     ! AC bit mask
+               or      %g5, %g6, %g6                   ! Or it in...
+               sta     %g6, [%g0] ASI_M_MMUREGS        ! Close your eyes...
+
+               /* Grrr, why does it seem like every other load/store
+                * on the sun4m is in some ASI space...
+                * Fine with me, let's get the pointer to the level 1
+                * page table directory and fetch it's entry.
+                */
+               lda     [%g4] ASI_M_BYPASS, %o1         ! This is a level 1 ptr
+               srl     %o1, 0x4, %o1                   ! Clear low 4 bits
+               sll     %o1, 0x8, %o1                   ! Make physical
+               
+               /* Ok, pull in the PTD. */
+               lda     [%o1] ASI_M_BYPASS, %o2         ! This is the 0x0 16MB pgd
+
+               /* Calculate to KERNBASE entry.
+                *
+                * XXX Should not use imperical constant, but Gas gets an  XXX
+                * XXX upset stomach with the bitshift I would have to use XXX
+                */
+               add     %o1, 0x3c0, %o3         
+
+               /* Poke the entry into the calculated address. */
+               sta     %o2, [%o3] ASI_M_BYPASS
+
+               /* I don't get it Sun, if you engineered all these
+                * boot loaders and the PROM (thank you for the debugging
+                * features btw) why did you not have them load kernel
+                * images up in high address space, since this is necessary
+                * for ABI compliance anyways?  Does this low-mapping provide
+                * enhanced interoperability?
+                *
+                * "The PROM is the computer."
+                */
+
+               /* Ok, restore the MMU control register we saved in %g5 */
+               sta     %g5, [%g0] ASI_M_MMUREGS        ! POW... ouch
+
+               /* Turn traps back on.  We saved it in %g3 earlier. */
+               wr      %g3, 0x0, %psr                  ! tick tock, tick tock
+
+               /* Now we burn precious CPU cycles due to bad engineering. */
+               WRITE_PAUSE
 
-/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
-   %g7 and at _prom_vector_p. And also quickly check whether we are on
-   a v0 or v2 prom.
-*/
+               /* Wow, all that just to move a 32-bit value from one
+                * place to another...  Jump to high memory.
+                */
+               b       go_to_highmem
+               nop
 
-gokernel:      or      %g0, %o0, %g7
-               sethi   %hi( C_LABEL(prom_vector_p) ), %g1
-               st      %o0, [%g1 + %lo( C_LABEL(prom_vector_p) )]   ! we will need it later
-               rd      %psr, %l2
-               rd      %wim, %l3
-               rd      %tbr, %l4
-               or      %g0, %o2, %l5           ! could be prom magic value...
-       
-#if 0 /* You think I'm nutz? */
-               subcc   %l5, 0x0, %g0           ! check for magic SMP pointer
-               bne     nosmp   
+               /* This works on viking's in Mbus mode and all
+                * other MBUS modules.  It is virtually the same as
+                * the above madness sans turning traps off and flipping
+                * the AC bit.
+                */
+srmmu_nviking:
+               set     AC_M_CTPR, %g1
+               lda     [%g1] ASI_M_MMUREGS, %g1        ! get ctx table ptr
+               sll     %g1, 0x4, %g1                   ! make physical addr
+               lda     [%g1] ASI_M_BYPASS, %g1         ! ptr to level 1 pg_table
+               srl     %g1, 0x4, %g1
+               sll     %g1, 0x8, %g1                   ! make phys addr for l1 tbl
+
+               lda     [%g1] ASI_M_BYPASS, %g2         ! get level1 entry for 0x0
+               add     %g1, 0x3c0, %g3                 ! XXX AWAY WITH IMPERICALS
+               sta     %g2, [%g3] ASI_M_BYPASS         ! place at KERNBASE entry
+               b       go_to_highmem
+               nop                                     ! wheee....
+
+               /* This remaps the kernel on Sun4/4xx machines
+                * that have the Sun Mutant Three Level MMU.
+                * It's like a platypus, Sun didn't have the
+                * SRMMU in conception so they kludged the three
+                * level logic in the regular Sun4 MMU probably.
+                *
+                * Basically, you take each entry in the top level
+                * directory that maps the low 3MB starting at
+                * address zero and put the mapping in the KERNBASE
+                * slots.  These top level pgd's are called regmaps.
+                */
+sun4_mutant_remap:
+               or      %g0, %g0, %g3           ! source base
+               sethi   %hi(KERNBASE), %g4      ! destination base
+               or      %g4, %lo(KERNBASE), %g4
+               sethi   %hi(0x300000), %g5
+               or      %g5, %lo(0x300000), %g5 ! upper bound 3MB
+               or      %g0, 0x1, %l6
+               sll     %l6, 24, %l6            ! Regmap mapping size
+               add     %g3, 0x2, %g3           ! Base magic
+               add     %g4, 0x2, %g4           ! Base magic
+
+               /* Main remapping loop on Sun4-Mutant-MMU.
+                * "I am not an animal..." -Famous Mutant Person
+                */
+sun4_mutant_loop:
+               lduha   [%g3] ASI_REGMAP, %g2   ! Get lower entry
+               stha    %g2, [%g4] ASI_REGMAP   ! Store in high entry
+               add     %g4, %l6, %g4           ! Move up high memory ptr
+               subcc   %g3, %g5, %g0           ! Reached our limit?
+               blu     sun4_mutant_loop        ! Nope, loop again
+               add     %g3, %l6, %g3           ! delay, Move up low ptr
+               b       go_to_highmem           ! Jump to high memory.
                nop
-               call    %o2                     ! call smp prom setup 
+
+/* The following works for normal (ie. non Sun4/400) Sun4 MMU's */
+sun4c_remap:
+               or      %g0, %g0, %g3           ! source base
+               sethi   %hi(KERNBASE), %g4      ! destination base
+               or      %g4, %lo(KERNBASE), %g4
+               sethi   %hi(0x300000), %g5
+               or      %g5, %lo(0x300000), %g5 ! upper bound 3MB
+               or      %g0, 0x1, %l6
+               sll     %l6, 18, %l6            ! sun4c mmu segmap size
+sun4c_remap_loop:
+               lda     [%g3] ASI_SEGMAP, %g6   ! load phys_seg
+               sta     %g6, [%g4] ASI_SEGMAP   ! store new virt mapping
+               add     %g3, %l6, %g3           ! Increment source ptr
+               subcc   %g3, %g5, %g0           ! Reached limit?
+               bl      sun4c_remap_loop        ! Nope, loop again
+               add     %g4, %l6, %g4           ! delay, Increment dest ptr
+
+/* Now do a non-relative jump so that PC is in high-memory */
+go_to_highmem:
+               set     execute_in_high_mem, %g1
+               jmp     %g1
                nop
-#endif /* I will be soon... */
 
 /* Acquire boot time privileged register values, this will help debugging.
- * I figure out and store nwindows later on.
+ * I figure out and store nwindows and nwindowsm1 later on.
  */
+execute_in_high_mem:
+               or      %g0, %l0, %o0           ! put back romvec
+               or      %g0, %l1, %o1           ! and debug_vec
 
-nosmp:         sethi   %hi( C_LABEL(boot_psr) ), %l1
-               st      %l2, [%l1 + %lo( C_LABEL(boot_psr) )]
-               sethi   %hi( C_LABEL(boot_wim) ), %l1
-               st      %l3, [%l1 + %lo( C_LABEL(boot_wim) )]
-               sethi   %hi( C_LABEL(boot_tbr) ), %l1
-               st      %l4, [%l1 + %lo( C_LABEL(boot_tbr) )]
-               sethi   %hi( C_LABEL(boot_smp_ptr) ), %l1
-               st      %l5, [%l1 + %lo( C_LABEL(boot_smp_ptr) )]
+               sethi   %hi( C_LABEL(prom_vector_p) ), %g1
+               st      %o0, [%g1 + %lo( C_LABEL(prom_vector_p) )]
 
-               or      %g0, %o0, %g7
-               sethi   %hi( C_LABEL(prom_vector_p) ), %g5
-               st      %o0, [%g5 + %lo( C_LABEL(prom_vector_p) )]   ! we will need it later
+               sethi   %hi( C_LABEL(linux_dbvec) ), %g1
+               st      %o1, [%g1 + %lo( C_LABEL(linux_dbvec) )]
+
+               ld      [%o0 + 0x4], %o3
+               and     %o3, 0x3, %o5                   ! get the version
 
-               ld      [%g7 + 0x4], %o3
                subcc   %o3, 0x2, %g0                   ! a v2 prom?
-               be      found_v2
+               be      found_version
                nop
 
                /* paul@sfe.com.au */
                subcc   %o3, 0x3, %g0                   ! a v3 prom?
-               or      %g0, 0x3, %o5
-               sethi   %hi(C_LABEL(prom_iface_vers) ), %g1
-               st      %o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-               be      not_v2
+               be      found_version
                nop
 
-
 /* Old sun4's pass our load address into %o0 instead of the prom
  pointer. On sun4's you have to hard code the romvec pointer into
  your code. Sun probably still does that because they don't even
  trust their own "OpenBoot" specifications.
-*/
* pointer. On sun4's you have to hard code the romvec pointer into
* your code. Sun probably still does that because they don't even
* trust their own "OpenBoot" specifications.
+ */
 
                sethi   %hi(LOAD_ADDR), %g6
                subcc   %o0, %g6, %g0           ! an old sun4?
                be      no_sun4_here
                nop
 
-               sethi   %hi( C_LABEL(prom_iface_vers) ), %g1
-               st      %g0, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-               b       not_v2
-               nop
-
-found_v2:
-               or      %g0, 0x2, %o5
-               sethi   %hi( C_LABEL(prom_iface_vers) ), %g1
-               st      %o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-
-not_v2:
+found_version:
 
 /* Get the machine type via the mysterious romvec node operations.
- * Here we can find out whether we are on a sun4 sun4c, sun4m, or
- * a sun4m. The "nodes" are set up as a bunch of n-ary trees which
- * you can traverse to get information about devices and such. The
- * information acquisition happens via the node-ops which are defined
- * in the linux_openprom.h header file. Of particular interest is the
- * 'nextnode(int node)' function as it does the smart thing when
- * presented with a value of '0', it gives you the first node in the
+ * Here we can find out whether we are on a sun4, sun4c, sun4m, 
+ * sun4d, or a sun4e. The "nodes" are set up as a bunch of n-ary trees 
+ * which you can traverse to get information about devices and such.
+ * The information acquisition happens via the node-ops which are
+ * defined in the openprom.h header file. Of particular interest
+ * is the 'nextnode(int node)' function as it does the smart thing when
+ * presented with a value of '0', it gives you the root node in the
  * tree. These node integers probably offset into some internal prom
  * pointer table the openboot has. It's completely undocumented, so
  * I'm not about to go sifting through the prom address space, but may
@@ -593,8 +839,9 @@ not_v2:
                ld      [%l0], %l0
                call    %l0
                or      %g0, %g0, %o0           ! next_node(0) = first_node
+               or      %o0, %g0, %g6
 
-               sethi   %hi( C_LABEL(cputypvar) ), %o1  ! first node has cpu-arch
+               sethi   %hi( C_LABEL(cputypvar) ), %o1  ! First node has cpu-arch
                or      %o1, %lo( C_LABEL(cputypvar) ), %o1
                sethi   %hi( C_LABEL(cputypval) ), %o2  ! information, the string
                or      %o2, %lo( C_LABEL(cputypval) ), %o2
@@ -605,235 +852,128 @@ not_v2:
                                                ! to a buf where above string
                                                ! will get stored by the prom.
 
-               sethi   %hi( C_LABEL(cputypval) ), %o2  ! better safe than sorry
-               or      %o2, %lo( C_LABEL(cputypval) ), %o2
-               ldub    [%o2 + 0x4], %o0
-               subcc   %o0, 'c', %g0           ! we already know we are not
-               be      is_sun4c                ! on a plain sun4 because of
-               nop                             ! the check for 0x4000 in %o0
-               subcc   %o0, 'm', %g0           ! at start:
-               be      is_sun4m
+               subcc   %o0, %g0, %g0
+               bpos    got_prop                ! Got the property
                nop
-               b       no_sun4d_here           ! god bless the person who
-               nop                             ! tried to run this on sun4d
-
-is_sun4m:
-is_sun4c:                                      ! OK, this is a sun4c, yippie
-               or      %g0, %g7, %g6           ! load up the promvec offsets
-               sethi   %hi(prom_magic), %g5    ! magic mushroom :>
-               st      %g6, [%g5 + %lo(prom_magic)]
-               add     %g7, 0x4, %g6
-               sethi   %hi(prom_rom_vers), %g5
-               st      %g6, [%g5 + %lo(prom_rom_vers)]
-               add     %g7, 0x8, %g6
-               sethi   %hi(prom_pluginvers), %g5
-               st      %g6, [%g5 + %lo(prom_pluginvers)]
-               add     %g7, 0xc, %g6
-               sethi   %hi(prom_revision), %g5
-               st      %g6, [%g5 + %lo(prom_revision)]
-               add     %g7, 0x10, %g6
-               sethi   %hi(prom_v0mem_desc), %g5
-               st      %g6, [%g5 + %lo(prom_v0mem_desc)]
-               add     %g7, 0x1c, %g6
-               sethi   %hi(prom_nodefuncs), %g5
-               st      %g6, [%g5 + %lo(prom_nodefuncs)]
-               add     %g7, 0x68, %g6
-               sethi   %hi(prom_printf), %g5
-               st      %g6, [%g5 + %lo(prom_printf)]
-               add     %g7, 0x6c, %g6
-               sethi   %hi(prom_abort), %g5
-               st      %g6, [%g5 + %lo(prom_abort)]
-               add     %g7, 0x74, %g6
-               sethi   %hi(prom_halt), %g5
-               st      %g6, [%g5 + %lo(prom_halt)]
-               add     %g7, 0x78, %g6
-               sethi   %hi(prom_sync), %g5
-               st      %g6, [%g5 + %lo(prom_sync)]
-               add     %g7, 0x7c, %g6
-               sethi   %hi(prom_eval), %g5
-               st      %g6, [%g5 + %lo(prom_eval)]
-               add     %g7, 0x80, %g6
-               sethi   %hi(prom_v0bootline), %g6
-               st      %g6, [%g5 + %lo(prom_v0bootline)]
-
-
-/* That was easy, now lets try to print some message on the screen.
- * We don't have to worry about bad address translations when the prom
- * addresses our pointers because our pointers are at 0x0-kern_size
- * as the prom expects.
- */
 
-/* paul@sfe.com.au */
-/* V3 doesn't have printf.. And I don't really feel like doing the formatting
- * myself.. So we miss out on some messages (for now).
- */
-               ld      [%g7 + 0x4], %o0
-               subcc   %o3, 0x3, %g0
-               be      v3_bootmsg
+               or      %g6, %g0, %o0
+               sethi   %hi( C_LABEL(cputypvar_sun4m) ), %o1
+               or      %o1, %lo( C_LABEL(cputypvar_sun4m) ), %o1
+               sethi   %hi( C_LABEL(cputypval) ), %o2
+               or      %o2, %lo( C_LABEL(cputypval) ), %o2
+               ld      [%l1], %l0
+               ld      [%l0 + 0xc], %l0
+               call    %l0
                nop
 
-               sethi   %hi(boot_msg), %o0      
-               or      %o0, %lo(boot_msg), %o0
-               sethi   %hi(prom_printf), %o1
-               ld      [%o1 + %lo(prom_printf)], %o1
-               ld      [%o1], %o1
-               call    %o1                     ! print boot message #1
-               nop
+got_prop:
+               sethi   %hi( C_LABEL(cputypval) ), %o2
+               or      %o2, %lo( C_LABEL(cputypval) ), %o2
 
-               sethi   %hi(pstring1), %o0
-               or      %o0, %lo(pstring1), %o0
-               sethi   %hi(prom_printf), %o2
-               ld      [%o2 + %lo(prom_printf)], %o2
-               ld      [%o2], %o2
-               sethi   %hi(prom_magic), %o1
-               ld      [%o1 + %lo(prom_magic)], %o1
-               ld      [%o1], %o1
-               call    %o2
+               ldub    [%o2 + 0x4], %l1
+               subcc   %l1, 'c', %g0           ! We already know we are not
+               be      1f                      ! on a plain sun4 because of
+               nop                             ! the check for 0x4000 in %o0
+               subcc   %l1, 'm', %g0           ! at start
+               be      1f
                nop
 
-               sethi   %hi(pstring2), %o0
-               or      %o0, %lo(pstring2), %o0
-               sethi   %hi(prom_printf), %o2
-               ld      [%o2 + %lo(prom_printf)], %o2
-               ld      [%o2], %o2
-               sethi   %hi( C_LABEL(prom_iface_vers) ), %o1
-               ld      [%o1 + %lo( C_LABEL(prom_iface_vers) )], %o1
-               ld      [%o1], %o1
-               call    %o2
+               subcc   %l1, 'd', %g0
+               be      no_sun4d_here           ! God bless the person who
+               nop                             ! tried to run this on sun4d.
+       
+               subcc   %l1, 'e', %g0
+               be      no_sun4e_here           ! Could be a sun4e.
                nop
 
-               b       rest_of_boot
+               b       no_sun4u_here           ! AIEEE, a V9 sun4u...
                nop
 
-v3_bootmsg:
-               ld      [%g7 + 0x94], %o0
-               ld      [%o0], %o0
-               sethi   %hi(boot_msg), %o1
-               or      %o1, %lo(boot_msg), %o1
-               mov     BOOT_MSG_LEN, %o2
-               ld      [%g7 + 0xb8], %o4
-               call    %o4
-               nop
-               ld      [%g7 + 0x94], %o0
-               ld      [%o0], %o0
-               sethi   %hi(boot_msg2), %o1
-               or      %o1, %lo(boot_msg2), %o1
-               mov     BOOT_MSG2_LEN, %o2
-               ld      [%g7 + 0xb8], %o4
-               call    %o4
-               nop
-               b       rest_of_boot
-               nop
 
+1:
+               or      %g0, PAGE_SHIFT, %g5
 
-no_sun4_here:
-               ld      [%g7 + 0x68], %o1
-               set     sun4_notsup, %o0
-               call    %o1
+               sethi   %hi( C_LABEL(cputypval) ), %l1
+               or      %l1, %lo( C_LABEL(cputypval) ), %l1
+               ldub    [%l1 + 0x4], %l1
+               subcc   %l1, 'm', %g0           ! Test for sun4d, sun4e ?
+               be      sun4m_init
                nop
 
-rest_of_boot:
-               or      %g0, PAGE_SHIFT, %g5
-
                sethi   %hi(AC_CONTEXT), %g1    ! kernel context, safe now
                                                ! the only valid context
                                                ! until we call paging_init()
                stba    %g0, [%g1] ASI_CONTROL
 
+               b       sun4c_continue_boot
+               nop
 
-/* I make the kernel image sit in memory relative to 0x0 with the text 
- * starting at 0x4000. Now it looks like the way memory is set in Linux
- * on an ix86.
+sun4m_init:
+/* P3: I just do not know what to do here. But I do know that ASI_CONTROL
+ * will not serve on sun4m. Also I do not want to smash the current MMU
+ * setup until we call paging_init().
  */
 
-/* Uh, oh, interrupt time. This crap is real confusing. What I want to do is
- * clear all interrupts, map the interrupt enable register which in effect
- * enables non-maskable interrupts (or NMI's). Actually we take no interrupts
- * until we frob with the %tbr (trap base register) which the prom has set 
- * to all its routines which allows some sanity during bootup.
+/* Ok, the PROM could have done funny things and apple cider could still
+ * be sitting in the fault status/address registers.  Read them all to
+ * clear them so we don't get magic faults later on.
  */
+/* This sucks, aparently this makes Vikings call prom panic, will fix later */
 
-               sethi   %hi(IE_reg_addr), %l0
-               or      %l0, %lo(IE_reg_addr), %l0
+               set     (0x40000000), %o1
+               rd      %psr, %o0
+               andcc   %o0, %o1, %g0
+               bne     sun4c_continue_boot     ! quick hack
+               nop
 
-               set     0xf4000000, %l3
-               sethi   %hi(INT_ENABLE_REG_PHYSADR), %l2
-               or      %l2, %lo(INT_ENABLE_REG_PHYSADR), %l2
-               srl     %l2, %g5, %l2
-               or      %l2, %l3, %l1           
+clr_srmmu_fregs:
+               set     AC_M_SFSR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               set     AC_M_SFAR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               set     AC_M_AFSR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               set     AC_M_AFAR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               nop
+
+
+sun4c_continue_boot:
 
-#ifndef CONFIG_SRMMU
-               sta     %l1, [%l0] ASI_PTE
-#endif
-       
-               or      %g0, 0x1, %l1
-               stb     %l1, [%l0]
-       
 
 /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
  * show-time!
  */
 
-               sethi   %hi(1f), %g1
-               or      %g1, %lo(1f), %g1
-               jmp     %g1
-               nop
-
-               .align 4
-1:             sethi   %hi( C_LABEL(cputyp) ), %o0
+               sethi   %hi( C_LABEL(cputyp) ), %o0
                st      %g4, [%o0 + %lo( C_LABEL(cputyp) )]
 
-               sethi   %hi( C_LABEL(pgshift) ), %o0
-               st      %g5, [%o0 + %lo( C_LABEL(pgshift) )]
-
-               mov     1, %o0
-               sll     %o0, %g5, %g5
-               sethi   %hi( C_LABEL(nbpg) ), %o0
-               st      %g5, [%o0 + %lo( C_LABEL(nbpg) )]
-
-               sub     %g5, 1, %g5
-               sethi   %hi( C_LABEL(pgofset) ), %o0
-               st      %g5, [%o0 + %lo( C_LABEL(pgofset) )]
-
-
-               rd      %psr, %g3
-               andn    %g3, PSR_ET, %g3
-               wr      %g3, 0x0, %psr          ! make sure traps are off
-                                               ! before we play around
-               WRITE_PAUSE                     ! no guarantees until 3 insns
-
-
-               wr      %g0, 0x0, %wim          ! magical invalid window reg
-               WRITE_PAUSE                     ! see above
-
-/* I keep the timer interrupt on so that BogoMIPS works and the prom
- * keeps updating its "jiffies" counter. 100HZ clock on sparcstations.
- */    
-
-/* If gas wasn't so dumb, I could use or'd macros in this next
- * write. ;-( like this (PSR_PS | PSR_S | PSR_PIL)...
- */
-
+               /* Turn on PreviousSupervisor, Supervisor, EnableFloating,
+                * and all the PIL bits.  Also puts us in register window
+                * zero.
+                */
                sethi   %hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
                or      %g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
                wr      %g2, 0x0, %psr
                WRITE_PAUSE
 
-               wr      %g0, 0x2, %wim          ! window 1 invalid
+               wr      %g0, 0x2, %wim          ! Make window 1 invalid.
                WRITE_PAUSE
 
+               /* Initialize the WIM value for init_task. */
                or      %g0, 0x1, %g1
                sethi   %hi( C_LABEL(current) + THREAD_WIM), %g2
                st      %g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)]
 
 /* I want a kernel stack NOW! */
+/* Grrr, gotta be real careful about alignment here */
 
-               set     ( C_LABEL(init_user_stack) + 4092 - 96 - 80), %fp       
-               set     ( C_LABEL(init_user_stack) + 4092), %sp
-
-/* now out stack is set up similarly to the way it is on the i386 */
+               set     ( C_LABEL(init_user_stack) + PAGE_SIZE - 96 - 96 - 80), %g1
+               andn    %g1, 0x7, %g1
+               or      %g1, 0x0, %fp
+               add     %fp, (96+80), %sp
 
+               /* Enable traps. */
                rd      %psr, %l0
                wr      %l0, PSR_ET, %psr
                WRITE_PAUSE
@@ -843,26 +983,14 @@ rest_of_boot:
  * don't know, do you?
  */
 
-               set     C_LABEL(edata) , %o0
-               set     C_LABEL(end) , %o1
-               sub     %o1, %o0, %g2
-               sethi   %hi( C_LABEL(kernel_bss_len) ), %g3
-               st      %g2, [%g3 + %lo( C_LABEL(kernel_bss_len) )]
-               sethi   %hi( C_LABEL(trapbase) ), %g3
-               or      %g3, %lo( C_LABEL(trapbase) ), %g3
-               sethi   %hi( C_LABEL(etext) ), %g4
-               or      %g4, %lo( C_LABEL(etext) ), %g4                 
-               sub     %g4, %g3, %g2
-               sethi   %hi( C_LABEL(kernel_text_len) ), %g3
-               st      %g2, [%g3 + %lo( C_LABEL(kernel_text_len) )]
-               sethi   %hi( C_LABEL(etext) ), %g4
-               or      %g4, %lo( C_LABEL(etext) ), %g4
-               sethi   %hi( C_LABEL(edata) ), %g3
-               or      %g3, %lo( C_LABEL(edata) ), %g3
-               sub     %g3, %g4, %g2
-               sethi   %hi( C_LABEL(kernel_data_len) ), %g3
-               st      %g2, [%g3 + %lo( C_LABEL(kernel_data_len) )]
-               or      %g0, %g0, %g1
+               set     C_LABEL(edata) , %o0    ! First address of BSS
+               set     C_LABEL(end) , %o1      ! Last address of BSS
+
+               /* Argh, ELF gets me again... */
+               andn    %o0, 0x3, %o0
+               andn    %o1, 0x3, %o1
+
+/* Friggin' bzero() kludge. */
 
 1:     
                st      %g0, [%o0]
@@ -872,55 +1000,102 @@ rest_of_boot:
                nop
 
 /* Compute NWINDOWS and stash it away. Now uses %wim trick explained
- * in the V8 manual. Ok, this method seems to work, sparc is cool...
+ * in the V8 manual. Ok, this method seems to work, Sparc is cool...
+ * No, it doesn't work, have to play the save/readCWP/restore trick.
  */
 
-               sethi   %hi(0xffffffff), %g1
-               rd      %wim, %g2                       ! save current value
-               or      %g1, %lo(0xffffffff), %g1
-               wr      %g1, 0x0, %wim
-               rd      %wim, %g1                       ! get remaining mask
-               wr      %g2, 0x0, %wim                  ! restore old value
+               rd      %wim, %g1
+               rd      %psr, %g2
+               wr      %g0, 0x0, %wim                  ! so we dont get a trap
+               andn    %g2, 0x1f, %g3
+               wr      %g3, 0x0, %psr
                WRITE_PAUSE
+               save
+               rd      %psr, %g3
+               restore
+               and     %g3, 0x1f, %g3
+               add     %g3, 0x1, %g3
+               wr      %g2, 0x0, %psr
+               wr      %g1, 0x0, %wim
 
-               or      %g0, 0x0, %g3
+               cmp     %g3, 0x7
+               bne,a   2f
+               sethi   %hi( C_LABEL(nwindows) ), %g4
+
+
+               /* Nop out one save and one restore in the save state code
+                * and system call entry if this is a seven window Sparc.
+                */
+               sethi   %hi(nop7), %g5
+               or      %g5, %lo(nop7), %g5
+               sethi   %hi(NOP_INSN), %g6
+               or      %g6, %lo(NOP_INSN), %g6
+               /* patch 1 */
+               st      %g6, [%g5]
+               st      %g6, [%g5 + 0x4]
+               sethi   %hi(rnop7), %g5
+               or      %g5, %lo(rnop7), %g5
+               /* patch 2 */
+               st      %g6, [%g5]
+               st      %g6, [%g5 + 0x4]
 
-1:             srl     %g1, 0x1, %g1                   ! shift until highest
-               subcc   %g1, 0x0, %g0                   ! bit set
-               bne     1b
-               add     %g3, 0x1, %g3
                sethi   %hi( C_LABEL(nwindows) ), %g4
+
+2:             
                st      %g3, [%g4 + %lo( C_LABEL(nwindows) )]   ! store final value
                sub     %g3, 0x1, %g3
                sethi   %hi( C_LABEL(nwindowsm1) ), %g4
                st      %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )]
 
-
-/* Here we go */
-
-#ifndef CONFIG_SUN4M
-               /* paul@sfe.com.au */
-               /* Look into traps later :( */
+               /* Initialize lnx_winmask. */
+               set     lnx_winmask, %g4
+               or      %g0, 0x2, %g5
+               or      %g0, 0x0, %g6
+msk_loop:
+               stb     %g5, [%g4 + %g6]
+               add     %g6, 0x1, %g6
+               cmp     %g6, %g3
+               bl,a    msk_loop
+               sll     %g5, 0x1, %g5
+               or      %g0, 0x1, %g5
+               stb     %g5, [%g4 + %g3]
+
+               /* Here we go */
                set     C_LABEL(trapbase), %g3
                wr      %g3, 0x0, %tbr
                WRITE_PAUSE
-#endif
 
 
-/* First we call init_prom() to set up romvec, then off to start_kernel() */
-/* XXX put this in arch_init() */
+/* First we call prom_init() to set up PROMLIB, then off to start_kernel() */
+/* XXX put this in setup_arch() */
 
                sethi   %hi( C_LABEL(prom_vector_p) ), %g5
-               call    C_LABEL(init_prom)
-               ld      [%g5 + %lo( C_LABEL(prom_vector_p) )], %o0   /* delay slot */
+               call    C_LABEL(prom_init)
+               ld      [%g5 + %lo( C_LABEL(prom_vector_p) )], %o0
+
+               subcc   %o0, 0x1, %g0
+               be      halt_me                 ! promlib init failed
+               nop
 
                call    C_LABEL(start_kernel)
                nop
        
+               /* We should not get here. */
                call    halt_me
                nop
 
-/* There, happy now adrian? */
+/* There, happy now Adrian? */
+
+               /* XXX Fix this... XXX */
+no_sun4_here:
+               sethi   %hi(SUN4_PROM_VECTOR+SUN4_PRINTF), %o1
+               ld      [%o1 + %lo(SUN4_PROM_VECTOR+SUN4_PRINTF)], %o1
+               set     sun4_notsup, %o0
+               call    %o1
+               nop
+1:
+               ba      1b                      ! Cannot exit into KMON
+               nop
 
 no_sun4d_here:
                ld      [%g7 + 0x68], %o1
@@ -930,10 +1105,26 @@ no_sun4d_here:
                b       halt_me
                nop
 
+no_sun4e_here:
+               ld      [%g7 + 0x68], %o1
+               set     sun4e_notsup, %o0
+               call    %o1
+               nop
+               b       halt_me
+               nop
+
+no_sun4u_here:
+               ld      [%g7 + 0x68], %o1
+               set     sun4u_notsup, %o0
+               call    %o1
+               nop
+               b       halt_me
+               nop
+
 halt_me:
                ld      [%g7 + 0x74], %o0
-               call    %o0                     ! get us out of here...
-               nop                             ! apparently solaris is better
+               call    %o0                     ! Get us out of here...
+               nop                             ! Apparently Solaris is better.
 
        .data
        .align 4
@@ -945,35 +1136,7 @@ halt_me:
  */
 
                        .globl C_LABEL(prom_vector_p)
-
 C_LABEL(prom_vector_p):        .skip 4
-prom_magic:            .skip 4                 ! magic mushroom, beware...
-prom_rom_vers:                 .skip 4                 ! interface version (v0 or v2)
-prom_pluginvers:       .skip 4                 ! XXX help help help ???
-prom_revision:         .skip 4                 ! PROM revision (ie. 1.4)
-prom_halt:             .skip 4                 ! void halt(void)  solaris friend
-prom_eval:             .skip 4                 ! void eval(int len, char* string)
-prom_v0bootline:       .skip 4                 ! boot command line
-prom_v0mem_desc:       .skip 4                 ! V0 memory descriptor list ptr.
-prom_nodefuncs:                .skip 4                 ! Magical Node functions
-prom_printf:           .skip 4                 ! minimal printf()
-
-/* The prom_abort pointer MUST be mapped in all contexts, because if you
- * don't then if a user process is running when you press the abort key
- * sequence, all sorts of bad things can happen
- */
-
-prom_abort:            .skip 4         ! L1-A magic cookie
-                                       ! must be mapped in ALL contexts
-
-/* prom_sync is a place where the kernel should place a pointer to a kernel
- * function that when called will sync all pending information to the drives
- * and then promptly return. If the kernel gets aborted with 'L1-A' one can
- * give the 'sync' command to the boot prompt and this magic cookie gets
- * executed. Nice feature eh?
- */
-
-prom_sync:             .skip 4                 ! hook in prom for sync func
 
        .align 4
 
@@ -987,59 +1150,15 @@ C_LABEL(nwindows):       .skip 4
 C_LABEL(nwindowsm1):   .skip 4
 
        .align 4
-/* Boot time privileged register values, plus magic %o2 value */
 
-       .globl C_LABEL(boot_wim)
-       .globl C_LABEL(boot_psr)
-       .globl C_LABEL(boot_tbr)
-       .globl C_LABEL(boot_smp_ptr)
-C_LABEL(boot_wim):             .skip 4
-C_LABEL(boot_psr):             .skip 4
-C_LABEL(boot_tbr):             .skip 4
-C_LABEL(boot_smp_ptr):         .skip 4
+/* Boot time debugger vector value.  We need this later on. */
 
+       .globl C_LABEL(linux_dbvec)
+C_LABEL(linux_dbvec):          .skip 4
 
        .align 4
-/* Miscellaneous pieces of information saved at kernel startup. */
-       .globl C_LABEL(kernel_text_len)
-       .globl C_LABEL(kernel_data_len)
-       .globl C_LABEL(kernel_bss_len)
-C_LABEL(kernel_text_len):      .word 0
-C_LABEL(kernel_data_len):      .word 0
-C_LABEL(kernel_bss_len):       .word 0
-
-/* These are for page alignment/offset information as they change from
-   machine to machine.
-*/
-
-        .globl  C_LABEL(pgshift)
-       .globl  C_LABEL(nbpg)
-       .globl  C_LABEL(pgofset)
-
-       .align 4
-C_LABEL(pgshift):
-        .word   1
-C_LABEL(nbpg):
-        .word   1
-C_LABEL(pgofset):
-        .word   1
 
 /* Just to get the kernel through the compiler for now */
-       .globl C_LABEL(swapper_pg_dir), C_LABEL(pg0)
-       .globl C_LABEL(empty_bad_page)
-       .globl C_LABEL(empty_bad_page_table)
-       .globl C_LABEL(empty_zero_page)
        .globl C_LABEL(floppy_track_buffer)
 C_LABEL(floppy_track_buffer):
        .fill 512*2*36,1,0
-
-       .align 4
-C_LABEL(swapper_pg_dir):               .skip 0x1000
-C_LABEL(pg0):                          .skip 0x1000
-C_LABEL(empty_bad_page):               .skip 0x1000
-C_LABEL(empty_bad_page_table):         .skip 0x1000
-C_LABEL(empty_zero_page):              .skip 0x1000
-
-               .align 4
-diagstr:       .asciz  "DIAG\n"
-               .align 4
index c12f7467b3d3e1247af037be24e972882270b849..7f424d4521f6e3ca88c25703bafca9632ea1459e 100644 (file)
@@ -1,31 +1,86 @@
 /* idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
+ * Because they use the IDPROM's machine type field, some of the
+ * virtual address cache probings on the sun4c are done here.
+ *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/kernel.h>
 
 #include <asm/types.h>
-#include <asm/openprom.h>
+#include <asm/oplib.h>
 #include <asm/idprom.h>
+#include <asm/machines.h>  /* Fun with Sun released architectures. */
+#include <asm/system.h>    /* For halt() macro */
+
+struct idp_struct *idprom;
+static struct idp_struct idprom_buff;
 
-struct idp_struct idprom;
-extern int num_segmaps, num_contexts;
+/* Here is the master table of Sun machines which use some implementation
+ * of the Sparc CPU and have a meaningful IDPROM machtype value that we
+ * know about.  See asm-sparc/machines.h for imperical constants.
+ */
+struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
+/* First, Sun4's */
+{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
+{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
+{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
+{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+/* Now, Sun4c's */
+{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
+{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
+{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
+{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
+{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
+{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
+{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+/* Finally, early Sun4m's */
+{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
+{ "Sun4m SparcStation10", (SM_SUN4M | SM_4M_SS50) },
+{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
+{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
 
-void get_idprom(void)
+void
+sparc_display_systype(unsigned char machtyp)
+{
+       char system_name[128];
+       int i;
+
+       for(i = 0; i<NUM_SUN_MACHINES; i++) {
+               if(Sun_Machines[i].id_machtype == machtyp) {
+                       if(machtyp!=(SM_SUN4M_OBP | 0x0)) {
+                               printk("TYPE: %s\n", Sun_Machines[i].name);
+                               break;
+                       } else {
+                               prom_getproperty(prom_root_node, "banner-name",
+                                                system_name, sizeof(system_name));
+                               printk("TYPE: %s\n", system_name);
+                               break;
+                       }
+               }
+       }
+       if(i == NUM_SUN_MACHINES)
+               printk("Uh oh, IDPROM had bogus id_machtype value <%x>\n", machtyp);
+       return;
+}
+
+void
+get_idprom(void)
 {
-  char* idp_addr;
-  char* knl_idp_addr;
-  int i;
+       prom_getidp((char *) &idprom_buff, sizeof(idprom_buff));
 
-  idp_addr = (char *)IDPROM_ADDR;
-  knl_idp_addr = (char *) &idprom;
+       idprom = &idprom_buff;
 
-  for(i = 0; i<IDPROM_SIZE; i++)
-      *knl_idp_addr++ = *idp_addr++;
+       sparc_display_systype(idprom->id_machtype);
 
-  return;
+       printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
+              idprom->id_eaddr[0], idprom->id_eaddr[1], idprom->id_eaddr[2],
+              idprom->id_eaddr[3], idprom->id_eaddr[4], idprom->id_eaddr[5]);
+
+       return;
 }
 
 /* find_vac_size() returns the number of bytes in the VAC (virtual
@@ -35,37 +90,30 @@ void get_idprom(void)
 int
 find_vac_size(void)
 {
-  int vac_prop_len;
-  int vacsize = 0;
-  int node_root;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-size");
-
-  if(vac_prop_len != -1)
-    {
-      (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-size", (char *) &vacsize);
-      return vacsize;
-    }
-  else
-    {
-
-  /* The prom node functions can't help, do it via idprom struct */
-      switch(idprom.id_machtype)
-       {
-       case 0x51:
-       case 0x52:
-       case 0x53:
-       case 0x54:
-       case 0x55:
-       case 0x56:
-       case 0x57:
-         return 65536;
-       default:
-         return -1;
-       }
-    };
+       int vac_prop_len;
+       int vacsize = 0;
+
+       vac_prop_len = prom_getproplen(prom_root_node, "vac-size");
+       if(vac_prop_len != -1) {
+               vacsize = prom_getint(prom_root_node, "vac-size");
+               return vacsize;
+       } else {
+               switch(idprom->id_machtype) {
+               case (SM_SUN4C | SM_4C_SS1):     /* SparcStation1 */
+               case (SM_SUN4C | SM_4C_IPC):     /* SparcStation IPX */
+               case (SM_SUN4C | SM_4C_SS1PLUS): /* SparcStation1+ */
+               case (SM_SUN4C | SM_4C_SLC):     /* SparcStation SLC */
+               case (SM_SUN4C | SM_4C_SS2):     /* SparcStation2 Cache-Chip BUG! */
+               case (SM_SUN4C | SM_4C_ELC):     /* SparcStation ELC */
+               case (SM_SUN4C | SM_4C_IPX):     /* SparcStation IPX */
+                       return 65536;
+               default:
+                       printk("find_vac_size: Can't determine size of VAC, bailing out...\n");
+                       halt();
+                       break;
+               };
+       };
+       return -1;
 }
 
 /* find_vac_linesize() returns the size in bytes of the VAC linesize */ 
@@ -73,111 +121,49 @@ find_vac_size(void)
 int
 find_vac_linesize(void)
 {
-  int vac_prop_len;
-  int vaclinesize = 0;
-  int node_root;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-linesize");
-
-  if(vac_prop_len != -1)
-    {
-      (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-linesize",
-                                     (char *) &vaclinesize);
-      return vaclinesize;
-    }
-  else
-    {
-
-  /* The prom node functions can't help, do it via idprom struct */
-      switch(idprom.id_machtype)
-       {
-       case 0x51:
-       case 0x52:
-       case 0x53:
-       case 0x54:
-         return 16;
-       case 0x55:
-       case 0x56:
-       case 0x57:
-         return 32;
-       default:
-         return -1;
-       }
-    };
+       int vac_prop_len;
+
+       vac_prop_len = prom_getproplen(prom_root_node, "vac-linesize");
+
+       if(vac_prop_len != -1)
+               return prom_getint(prom_root_node, "vac-linesize");
+       else {
+               switch(idprom->id_machtype) {
+               case (SM_SUN4C | SM_4C_SS1):     /* SparcStation1 */
+               case (SM_SUN4C | SM_4C_IPC):     /* SparcStation IPC */
+               case (SM_SUN4C | SM_4C_SS1PLUS): /* SparcStation1+ */
+               case (SM_SUN4C | SM_4C_SLC):     /* SparcStation SLC */
+                       return 16;
+               case (SM_SUN4C | SM_4C_SS2):     /* SparcStation2 Cache-Chip BUG! */
+               case (SM_SUN4C | SM_4C_ELC):     /* SparcStation ELC */
+               case (SM_SUN4C | SM_4C_IPX):     /* SparcStation IPX */
+                       return 32;
+               default:
+                       printk("find_vac_linesize: Can't determine VAC linesize, bailing out...\n");
+                       halt();
+                       break;
+               };
+       };
+       return -1;
 }
 
 int
 find_vac_hwflushes(void)
 {
-  register int len, node_root;
-  int tmp1, tmp2;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac_hwflush");
-
-#ifdef DEBUG_IDPROM
-  printf("DEBUG: find_vac_hwflushes: proplen vac_hwflush=0x%x\n", len);
-#endif
-
-  /* Sun 4/75 has typo in prom_node, it's a dash instead of an underscore
-   * in the property name. :-(
-   */
-  len |= (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-hwflush");
-
-#ifdef DEBUG_IDPROM
-  printf("DEBUG: find_vac_hwflushes: proplen vac-hwflush=0x%x\n", len);
-#endif
-
-  len = (*(romvec->pv_nodeops->no_getprop))(node_root,"vac_hwflush", 
-                                           (char *) &tmp1);
-  if(len != 4) tmp1=0;
-
-  len = (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-hwflush",
-                                           (char *) &tmp2);
-  if(len != 4) tmp2=0;
-
-
-  return (tmp1|tmp2);
-}
-
-void
-find_mmu_num_segmaps(void)
-{
-  register int root_node, len;
-
-  root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-npmg", 
-                                           (char *) &num_segmaps);
-
-#ifdef DEBUG_MMU
-  printf("find_mmu_num_segmaps: property length = %d\n", len);
-#endif
-
-  if(len != 4) num_segmaps = 128;
-
-  return;
-}
-
-void
-find_mmu_num_contexts(void)
-{
-  register int root_node, len;
-
-  root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-nctx", 
-                                           (char *) &num_contexts);
+       register int len;
+       int tmp1, tmp2;
 
-#ifdef DEBUG_MMU
-  printf("find_mmu_num_contexts: property length = %d\n", len);
-#endif
+       /* Sun 4/75 has typo in prom_node, it's a dash instead of an underscore
+        * in the property name. :-(
+        */
+       len = prom_getproperty(prom_root_node, "vac_hwflush",
+                              (char *) &tmp1, sizeof(int));
+       if(len != 4) tmp1=0;
 
-  if(len != 4) num_contexts = 8;
+       len = prom_getproperty(prom_root_node, "vac-hwflush",
+                              (char *) &tmp2, sizeof(int));
+       if(len != 4) tmp2=0;
 
-  return;
+       return (tmp1|tmp2);
 }
 
index effa6c25e09483aef0eae5d036bcd374799e7b94..44cfbcfc20b9e4e214e943342ece6bd6146def3c 100644 (file)
@@ -1,8 +1,15 @@
-/* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
- *            in this file are for the sole purpose of getting the kernel
- *            through the compiler. :-)
+/* ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * The routines in this file should be changed for a memory allocator
+ * that would be setup just like NetBSD does : you create regions that
+ * are administered by a general purpose allocator, and then you call
+ * that allocator with your handle and the block size instead of this
+ * weak stuff.
+ *
+ * XXX No joke, this needs to be rewritten badly. XXX
  */
 
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/vaddrs.h>
+#include <asm/oplib.h>
+
+/* This points to the next to use virtual memory for io mappings */
+static long next_free_region = IOBASE_VADDR;
+static long dvma_next_free   = DVMA_VADDR;
+
+/*
+ * sparc_alloc_dev:
+ * Map and allocates an obio device.
+ * Implements a simple linear allocator, you can force the function
+ * to use your own mapping, but in practice this should not be used.
+ *
+ * Input:
+ *  address: the obio address to map
+ *  virtual: if non zero, specifies a fixed virtual address where
+ *           the mapping should take place.
+ *  len:     the length of the mapping
+ *  bus_type: The bus on which this io area sits.
+ *
+ * Returns:
+ *  The virtual address where the mapping actually took place.
+ */
+
+void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
+                     int bus_type, int rdonly)
+{
+       unsigned long vaddr, base_address;
+       unsigned long addr = (unsigned long) address;
+
+
+       if (virtual){
+               vaddr = (unsigned long) virtual;
+       } else {
+               vaddr = next_free_region;
+       }
+       
+       if (((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)){
+               printk ("alloc_io: Mapping ouside IOBASE area\n");
+               prom_halt ();
+       }
+       if (check_region (vaddr, len)){
+               printk ("alloc_io: 0x%lx is already in use\n", vaddr);
+               prom_halt ();
+       }
+
+       /* Tell Linux resource manager about the mapping */
+       request_region (vaddr, len, name);
+
+       base_address = vaddr;
+       /* Do the actual mapping */
+       for (; len > 0; len -= PAGE_SIZE){
+               mapioaddr (addr, vaddr, bus_type, rdonly);
+               vaddr += PAGE_SIZE;
+               addr  += PAGE_SIZE;
+               if (!virtual)
+                       next_free_region += PAGE_SIZE;
+       }
+       return (void *) base_address;
+}
+
+/* Does DVMA allocations with PAGE_SIZE granulatity */
+void *sparc_dvma_malloc (int len, char *name)
+{
+       unsigned long vaddr, base_address;
+
+       vaddr = dvma_next_free;
+       if (check_region (vaddr, len)){
+               printk ("alloc_dma: 0x%lx is already in use\n", vaddr);
+               prom_halt ();
+       }
+       if (vaddr + len > (DVMA_VADDR + DVMA_LEN)){
+               printk ("alloc_dvma: out of dvma memory\n");
+               prom_halt ();
+       }
+
+       /* Tell Linux resource manager about the mapping */
+       request_region (vaddr, len, name);
+
+       base_address = vaddr;
+       /* Assign the memory area and remove the cache bit */
+       /* XXX EWWWWEE!!  Sun4c specific, fix now! XXX */
+       for (; len > 0; len -= PAGE_SIZE){
+               printk ("Len=%d\n", len);
+               put_pte (vaddr, get_pte (vaddr) | PTE_NC);
+               vaddr += PAGE_SIZE;
+               dvma_next_free += PAGE_SIZE;
+       }
+       return (void *) base_address;
+}
index 5dcaf197162e67bfadcfd9d0bc8f00abe0a0235a..8e59431f791432059a5757abc9289ce632011738 100644 (file)
@@ -3,8 +3,9 @@
  *                            and you are supposed to probe the prom's device
  *                            node trees to find out who's got which IRQ.
  *
- *  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
- *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su)
  */
 
 /*
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+
 #include <asm/ptrace.h>
+#include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/psr.h>
 #include <asm/vaddrs.h>
-#include <asm/clock.h>
+#include <asm/timer.h>
 #include <asm/openprom.h>
-
-#define DEBUG_IRQ
-
-void disable_irq(unsigned int irq_nr)
+#include <asm/oplib.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/* Pointer to the interrupt enable byte */
+/* XXX Ugh, this is so sun4c specific it's driving me nuts. XXX */
+unsigned char *interrupt_enable = 0;
+struct sun4m_intregs *sun4m_interrupts;
+
+/* XXX Needs to handle Sun4m semantics XXX */
+void
+disable_irq(unsigned int irq_nr)
 {
-  unsigned long flags;
-  unsigned char *int_reg;
-  
-  save_flags(flags);
-  cli();
-
-  /* We have mapped the irq enable register in head.S and all we
-   * have to do here is frob the bits.
-   */
-
-  int_reg = (unsigned char *) IRQ_ENA_ADR;
-
-  switch(irq_nr)
-    {
-    case 1:
-      *int_reg = ((*int_reg) & (~(0x02)));
-      break;
-    case 4:
-      *int_reg = ((*int_reg) & (~(0x04)));
-      break;
-    case 6:
-      *int_reg = ((*int_reg) & (~(0x08)));
-      break;      
-    case 8:
-      *int_reg = ((*int_reg) & (~(0x10)));
-      break;      
-    case 10:
-      *int_reg = ((*int_reg) & (~(0x20)));
-      break;      
-    case 14:
-      *int_reg = ((*int_reg) & (~(0x80)));
-      break;      
-    default:
-      printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
-            (int) irq_nr);
-      break;
-    };
+       unsigned long flags;
+       unsigned char current_mask, new_mask;
+
+       if(sparc_cpu_model != sun4c) return;
+
+       save_flags(flags);
+       cli();
+
+       current_mask = *interrupt_enable;
+
+       switch(irq_nr) {
+       case 1:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
+               break;
+       case 4:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E4)));
+               break;
+       case 6:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E6)));
+               break;
+       case 8:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
+               break;
+       case 10:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E10)));
+               break;
+       case 14:
+               new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
+               break;
+       default:
+#if 0 /* Actually this is safe, as the floppy driver needs this */
+               printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
+                      (int) irq_nr);
+               prom_halt();
+#endif
+               break;
+       };
   
-  restore_flags(flags);
-  return;
+       restore_flags(flags);
+       return;
 }
 
-void enable_irq(unsigned int irq_nr)
+/* XXX Needs to handle sun4m semantics XXX */
+void
+enable_irq(unsigned int irq_nr)
 {
-  unsigned long flags;
-  unsigned char *int_reg;
-  
-  save_flags(flags);
-  cli();
+       unsigned long flags;
+       unsigned char current_mask, new_mask;
+
+       if(sparc_cpu_model != sun4c) return;
+
+       save_flags(flags);
+       cli();
+
+       current_mask = *interrupt_enable;
+
+       switch(irq_nr) {
+       case 1:
+               new_mask = ((current_mask) | SUN4C_INT_E1);
+               break;
+       case 4:
+               new_mask = ((current_mask) | SUN4C_INT_E4);
+               break;
+       case 6:
+               new_mask = ((current_mask) | SUN4C_INT_E6);
+               break;
+       case 8:
+               new_mask = ((current_mask) | SUN4C_INT_E8);
+               break;
+       case 10:
+               new_mask = ((current_mask) | SUN4C_INT_E10);
+               break;
+       case 14:
+               new_mask = ((current_mask) | SUN4C_INT_E14);
+               break;
+       default:
+#if 0  /* Floppy driver does this on sun4c's anyhow */
+               printk ("Interrupt does not need to enable IE\n");
+               return;
+#endif
+               restore_flags(flags);
+               return;
+       };
 
-  /* We have mapped the irq enable register in head.S and all we
-   * have to do here is frob the bits.
-   */
+       *interrupt_enable = new_mask;
 
-  int_reg = (unsigned char *) IRQ_ENA_ADR;
-  
-#ifdef DEBUG_IRQ
-  printk(" --- Enabling IRQ level %d ---\n", irq_nr);
-#endif
+       restore_flags(flags);
 
-  switch(irq_nr)
-    {
-    case 1:
-      *int_reg = ((*int_reg) | 0x02);
-      break;
-    case 4:
-      *int_reg = ((*int_reg) | 0x04);
-      break;
-    case 6:
-      *int_reg = ((*int_reg) | 0x08);
-      break;      
-    case 8:
-      *int_reg = ((*int_reg) | 0x10);
-      break;      
-    case 10:
-      *int_reg = ((*int_reg) | 0x20);
-      break;      
-    case 14:
-      *int_reg = ((*int_reg) | 0x80);
-      break;      
-    default:
-      printk("AIEEE, Illegal interrupt enable requested irq=%d\n", 
-            (int) irq_nr);
-      break;
-    };
-
-  restore_flags(flags);
-
-  return;
+       return;
 }
 
 /*
  * Initial irq handlers.
  */
 struct irqaction {
-  void (*handler)(int, struct pt_regs *);
-  unsigned long flags;
-  unsigned long mask;
-  const char *name;
+       void (*handler)(int, struct pt_regs *);
+       unsigned long flags;
+       unsigned long mask;
+       const char *name;
 };
 
 static struct irqaction irq_action[16] = {
@@ -151,29 +162,31 @@ static struct irqaction irq_action[16] = {
 };
 
 
-int get_irq_list(char *buf)
+int
+get_irq_list(char *buf)
 {
-  int i, len = 0;
-  struct irqaction * action = irq_action;
-  
-  for (i = 0 ; i < 16 ; i++, action++) {
-    if (!action->handler)
-      continue;
-    len += sprintf(buf+len, "%2d: %8d %c %s\n",
-                  i, kstat.interrupts[i],
-                  (action->flags & SA_INTERRUPT) ? '+' : ' ',
-                  action->name);
-  }
-  return len;
+       int i, len = 0;
+       struct irqaction * action = irq_action;
+
+       for (i = 0 ; i < 16 ; i++, action++) {
+               if (!action->handler)
+                       continue;
+               len += sprintf(buf+len, "%2d: %8d %c %s\n",
+                              i, kstat.interrupts[i],
+                              (action->flags & SA_INTERRUPT) ? '+' : ' ',
+                              action->name);
+       }
+       return len;
 }
 
-void free_irq(unsigned int irq)
+void
+free_irq(unsigned int irq)
 {
         struct irqaction * action = irq + irq_action;
         unsigned long flags;
 
         if (irq > 14) {  /* 14 irq levels on the sparc */
-                printk("Trying to free IRQ %d\n", irq);
+                printk("Trying to free bogus IRQ %d\n", irq);
                 return;
         }
         if (!action->handler) {
@@ -190,37 +203,33 @@ void free_irq(unsigned int irq)
         restore_flags(flags);
 }
 
-#if 0
-static void handle_nmi(struct pt_regs * regs)
-{
-  printk("NMI, probably due to bus-parity error.\n");
-  printk("PC=%08lx, SP=%08lx\n", regs->pc, regs->sp);
-}
-#endif
-
-void unexpected_irq(int irq, struct pt_regs * regs)
+void
+unexpected_irq(int irq, struct pt_regs * regs)
 {
         int i;
 
         printk("IO device interrupt, irq = %d\n", irq);
-        printk("PC = %08lx NPC = %08lx SP=%08lx\n", regs->pc, 
-              regs->npc, regs->sp);
+        printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
+              regs->npc, regs->u_regs[14]);
         printk("Expecting: ");
         for (i = 0; i < 16; i++)
                 if (irq_action[i].handler)
-                        printk("[%s:%d] ", irq_action[i].name, i);
+                        printk("[%s:%d:0x%x] ", irq_action[i].name, (int) i,
+                              (unsigned int) irq_action[i].handler);
         printk("AIEEE\n");
+       prom_halt();
 }
 
-static inline void handler_irq(int irq, struct pt_regs * regs)
+void
+handler_irq(int irq, struct pt_regs * regs)
 {
-  struct irqaction * action = irq + irq_action;
+       struct irqaction * action = irq_action + irq;
 
-  if (!action->handler) {
-    unexpected_irq(irq, regs);
-    return;
-  }
-  action->handler(irq, regs);
+       if (!action->handler) {
+               unexpected_irq(irq, regs);
+               return;
+       }
+       action->handler(irq, regs);
 }
 
 /*
@@ -230,35 +239,14 @@ static inline void handler_irq(int irq, struct pt_regs * regs)
  * IRQ's should use this format: notably the keyboard/timer
  * routines.
  */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
-{
-  struct irqaction *action = irq + irq_action;
-
-  kstat.interrupts[irq]++;
-  action->handler(irq, regs);
-  return;
-}
-
-/*
- * Since we need to special things to clear up the clock chip around
- * the do_timer() call we have a special version of do_IRQ for the
- * level 14 interrupt which does these things.
- */
-
-asmlinkage void do_sparc_timer(int irq, struct pt_regs * regs)
+asmlinkage void
+do_IRQ(int irq, struct pt_regs * regs)
 {
-  struct irqaction *action = irq + irq_action;
-  register volatile int clear;
-
-  kstat.interrupts[irq]++;
+       struct irqaction *action = irq + irq_action;
 
-  /* I do the following already in the entry code, better safe than
-   * sorry for now. Reading the limit register clears the interrupt.
-   */
-  clear = TIMER_STRUCT->timer_limit14;
-
-  action->handler(irq, regs);
-  return;
+       kstat.interrupts[irq]++;
+       action->handler(irq, regs);
+       return;
 }
 
 /*
@@ -266,70 +254,162 @@ asmlinkage void do_sparc_timer(int irq, struct pt_regs * regs)
  * stuff - the handler is also running with interrupts disabled unless
  * it explicitly enables them later.
  */
-asmlinkage void do_fast_IRQ(int irq)
+asmlinkage void
+do_fast_IRQ(int irq)
 {
-  kstat.interrupts[irq]++;
-  printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
-  return;
+       kstat.interrupts[irq]++;
+       printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
+       return;
 }
 
-extern int first_descent;
-extern void probe_clock(int);
+extern void probe_clock(void);
                
-int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-       unsigned long irqflags, const char * devname)
+int
+request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+           unsigned long irqflags, const char * devname)
 {
-  struct irqaction *action;
-  unsigned long flags;
+       struct irqaction *action;
+       unsigned long flags;
+
+       if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
+               return -EINVAL;
+
+       /* i386 keyboard interrupt request, just return */
+       if(irq == 1) return 0;
 
-  if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
-    return -EINVAL;
+       /* sched_init() requesting the timer IRQ */
+       if(irq == 0) {
+               irq = 10;
+       }
 
-  if(irq == 0)  /* sched_init() requesting the timer IRQ */
-    {
-      irq = 14;
-      probe_clock(first_descent);
-    }
+       action = irq + irq_action;
 
-  action = irq + irq_action;
+       if(action->handler)
+               return -EBUSY;
 
-  if(action->handler)
-    return -EBUSY;
+       if(!handler)
+               return -EINVAL;
 
-  if(!handler)
-    return -EINVAL;
+       save_flags(flags);
 
-  save_flags(flags);
+       cli();
 
-  cli();
+       action->handler = handler;
+       action->flags = irqflags;
+       action->mask = 0;
+       action->name = devname;
 
-  action->handler = handler;
-  action->flags = irqflags;
-  action->mask = 0;
-  action->name = devname;
+       enable_irq(irq);
 
-  enable_irq(irq);
+       /* Init the timer/clocks if necessary. */
+       if(irq == 10) probe_clock();
 
-  restore_flags(flags);
+       restore_flags(flags);
 
-  return 0;
+       return 0;
 }
 
-unsigned int probe_irq_on (void)
+void
+sun4c_init_IRQ(void)
 {
-  unsigned int irqs = 0;
-
-  return irqs;
+       struct linux_prom_registers int_regs[2];
+       int ie_node;
+
+       ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
+                                      "interrupt-enable");
+       if(ie_node == 0) {
+               printk("Cannot find /interrupt-enable node\n");
+               prom_halt();
+       }
+       /* Depending on the "address" property is bad news... */
+       prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
+       sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
+                      int_regs[0].reg_size, "sun4c_interrupts",
+                      int_regs[0].which_io, 0x0);
+
+       interrupt_enable = (char *) INTREG_VADDR;
+
+       /* Default value, accept interrupts, but no one is actually active */
+       /* We also turn on level14 interrupts so PROM can run the console. */
+       *interrupt_enable = (SUN4C_INT_ENABLE | SUN4C_INT_E14);
+       sti(); /* As of NOW, L1-A works.  Turn irq's on full-blast. */
+       return;
 }
 
-int probe_irq_off (unsigned int irqs)
+void
+sun4m_init_IRQ(void)
 {
-  unsigned int i = 0;
+       int ie_node, i;
+
+       struct linux_prom_registers int_regs[PROMREG_MAX];
+       int num_regs;
+
+       cli();
+
+       if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
+          (ie_node = prom_getchild (ie_node)) == 0 ||
+          (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
+       {
+               printk("Cannot find /obio/interrupt node\n");
+               prom_halt();
+       }
+       num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
+                                   sizeof(int_regs));
+       num_regs = (num_regs/sizeof(struct linux_prom_registers));
+
+       /* Apply the obio ranges to these registers. */
+       prom_apply_obio_ranges(int_regs, num_regs);
+
+       /* Map the interrupt registers for all possible cpus. */
+       sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
+                      PAGE_SIZE*NCPUS, "interrupts_percpu",
+                      int_regs[0].which_io, 0x0);
+
+       /* Map the system interrupt control registers. */
+       sparc_alloc_io(int_regs[num_regs-1].phys_addr,
+                      (void *) INTREG_VADDR+(NCPUS*PAGE_SIZE),
+                      int_regs[num_regs-1].reg_size, "interrupts_system",
+                      int_regs[num_regs-1].which_io, 0x0);
+
+       sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
+
+#if 0
+       printk("Interrupt register dump...\n");
+
+       for(i=0; i<NCPUS; i++)
+               printk("cpu%d: tbt %08x\n", i,
+                      sun4m_interrupts->cpu_intregs[i].tbt);
+
+       printk("Master tbt %08x\n", sun4m_interrupts->tbt);
+       printk("Master irqs %08x\n", sun4m_interrupts->irqs);
+       printk("Master set %08x\n", sun4m_interrupts->set);
+       printk("Master clear %08x\n", sun4m_interrupts->clear);
+       printk("Undirected ints taken by: %08x\n",
+              sun4m_interrupts->undirected_target);
+
+       prom_halt();
+#endif
+
+       sti();
 
-  return i;
+       return;
 }
 
-void init_IRQ(void)
+void
+init_IRQ(void)
 {
-  return;
+       switch(sparc_cpu_model) {
+       case sun4c:
+               sun4c_init_IRQ();
+               break;
+       case sun4m:
+               sun4m_init_IRQ();
+               break;
+       default:
+               printk("Cannot initialize IRQ's on this Sun machine...\n");
+               halt();
+               break;
+       };
+
+       return;
 }
diff --git a/arch/sparc/kernel/mp.S b/arch/sparc/kernel/mp.S
new file mode 100644 (file)
index 0000000..79163d1
--- /dev/null
@@ -0,0 +1,91 @@
+/* mp.S:  Multiprocessor low-level routines on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/vaddrs.h>
+#include <asm/contregs.h>
+
+
+       .text
+       .align 4
+
+/* When we start up a cpu for the first time it enters this routine.
+ * This initializes the chip from whatever state the prom left it
+ * in and sets PIL in %psr to 15, no irqs.
+ */
+
+       .globl C_LABEL(sparc_cpu_startup)
+C_LABEL(sparc_cpu_startup):
+       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+       set     (PSR_PIL | PSR_S | PSR_PS), %g1
+       wr      %g1, 0x0, %psr          ! traps off though
+       WRITE_PAUSE
+
+       /* Our %wim is one behind CWP */
+       wr      %g0, 0x2, %wim
+
+       rd      %tbr, %g4
+       or      %g0, 0x3, %g5
+       sll     %g5, 20, %g5
+       and     %g4, %g5, %g4           ! Mask cpu-id bits
+
+       /* Give ourselves a stack. */
+       set     PERCPU_VADDR, %g1
+       add     %g1, %g4, %g1
+       set     PERCPU_KSTACK_OFFSET, %g5
+       add     %g1, %g5, %g1
+       set     0x1000, %g5
+       add     %g1, %g5, %g1           ! end of stack
+       sub     %g1, (96+96+80), %g1    ! set up a frame
+       andn    %g1, 0x7, %g1
+       or      %g1, 0x0, %fp           ! bottom of frame
+       add     %fp, (96+80), %sp       ! top of frame
+
+       /* Set up per-cpu trap table pointer.  In actuality, the virtual
+        * address for the trap table on every cpu points to the same
+        * physical address, this virtual address is only used for cpu
+        * identification purposes.
+        */
+#if 0
+/*     set     PERCPU_VADDR, %g1 */
+/*     add     %g1, %g4, %g1 */
+/*     add     %g1, PERCPU_TBR_OFFSET, %g1 */
+       set     C_LABEL(thiscpus_tbr), %g1
+       ld      [%g1], %g1
+       wr      %g1, 0x0, %tbr
+       WRITE_PAUSE
+#else
+       set     C_LABEL(trapbase), %g3
+       wr      %g3, 0x0, %tbr
+       WRITE_PAUSE
+#endif
+
+       /* Turn on traps (PSR_ET). */
+       rd      %psr, %g1
+       wr      %g1, PSR_ET, %psr       ! traps on
+
+#if 0
+1:     nop
+       b       1b
+       nop
+#endif
+
+       /* Call C-code to do the rest of the real work. */
+       call    C_LABEL(sparc_cpu_init)
+       nop
+
+       /* Call cpu-idle routine so we can start it up later on. */
+       call    C_LABEL(sparc_cpu_idle)
+       nop
+
+       /* Done... This cpu should me spinning in a test loop.
+        * If execution gets here, something really bad happened.
+        */
+       call    C_LABEL(prom_halt)      ! Seems reasonable...
+       nop
+
index 462556164f90e04e388666575eede4d17de72695..87baf9b98aa88d6cb26a6d0ec0367830838e7216 100644 (file)
@@ -1,35 +1,41 @@
 /* probe.c: Preliminary device tree probing routines...
-
  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 #include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/string.h>
+
+#include <asm/oplib.h>
 #include <asm/vac-ops.h>
+#include <asm/idprom.h>
 #include <asm/io.h>
 #include <asm/vaddrs.h>
 #include <asm/param.h>
-#include <asm/clock.h>
+#include <asm/timer.h>
+#include <asm/mostek.h>
+#include <asm/auxio.h>
 #include <asm/system.h>
+#include <asm/mp.h>
+#include <asm/mbus.h>
 
 /* #define DEBUG_PROBING */
 
-char promstr_buf[64];         /* overkill */
-unsigned int promint_buf[1];
-
-extern int prom_node_root;
-extern int num_segmaps, num_contexts;
-
-extern int node_get_sibling(int node);
-extern int node_get_child(int node);
-extern char* get_str_from_prom(int node, char* name, char* value);
-extern unsigned int* get_int_from_prom(int node, char* name, unsigned int *value);
+/* XXX Grrr, this stuff should have it's own file, only generic stuff goes
+ * XXX here.  Possibly clock.c and timer.c?
+ */
+enum sparc_clock_type sp_clock_typ;
+struct mostek48t02 *mstk48t02_regs;
+struct mostek48t08 *mstk48t08_regs;
+volatile unsigned int *master_l10_limit = 0;
+struct sun4m_timer_regs *sun4m_timers;
 
-int first_descent;
+static char node_str[128];
 
 /* Cpu-type information and manufacturer strings */
 
-
 struct cpu_iu_info {
   int psr_impl;
   int psr_vers;
@@ -42,19 +48,24 @@ struct cpu_fp_info {
   char* fp_name;
 };
 
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
 struct cpu_fp_info linux_sparc_fpu[] = {
   { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
-  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5"},
+  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
   { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+  /* SparcStation SLC, SparcStation1 */
   { 0, 3, "Weitek WTL3170/2"},
-  { 0, 4, "Lsi Logic/Meiko L64804"},
+  /* SPARCstation-5 */
+  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
   { 0, 5, "reserved"},
   { 0, 6, "reserved"},
   { 0, 7, "No FPU"},
-  { 1, 0, "Lsi Logic L64812 or Texas Instruments ACT8847"},
+  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
   { 1, 1, "Lsi Logic L64814"},
   { 1, 2, "Texas Instruments TMS390-C602A"},
-  { 1, 3, "Weitek WTL3171"},
+  { 1, 3, "Cypress CY7C602 FPU"},
   { 1, 4, "reserved"},
   { 1, 5, "reserved"},
   { 1, 6, "reserved"},
@@ -63,10 +74,14 @@ struct cpu_fp_info linux_sparc_fpu[] = {
   { 2, 1, "reserved"},
   { 2, 2, "reserved"},
   { 2, 3, "reserved"},
-  { 2, 4,  "reserved"},
+  { 2, 4, "reserved"},
   { 2, 5, "reserved"},
   { 2, 6, "reserved"},
   { 2, 7, "No FPU"},
+  /* SuperSparc 50 module */
+  { 4, 0, "SuperSparc on-chip FPU"},
+  /* SparcClassic */
+  { 4, 4, "TI MicroSparc on chip FPU"},
   { 5, 0, "Matsushita MN10501"},
   { 5, 1, "reserved"},
   { 5, 2, "reserved"},
@@ -77,22 +92,37 @@ struct cpu_fp_info linux_sparc_fpu[] = {
   { 5, 7, "No FPU"},
 };
 
+#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
 struct cpu_iu_info linux_sparc_chips[] = {
-  { 0, 0, "Fujitsu Microelectronics, Inc. - MB86900/1A"},
-  { 1, 0, "Cypress CY7C601"},
-  { 1, 1, "LSI Logic Corporation - L64811"},
-  { 1, 3, "Cypress CY7C611"},
+  /* Sun4/100, 4/200, SLC */
+  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
+  /* borned STP1012PGA */
+  { 0, 4, "Fujitsu  MB86904"},
+  /* SparcStation2, SparcServer 490 & 690 */
+  { 1, 0, "LSI Logic Corporation - L64811"},
+  /* SparcStation2 */
+  { 1, 1, "Cypress/ROSS CY7C601"},
+  /* Embedded controller */
+  { 1, 3, "Cypress/ROSS CY7C611"},
+  /* Ross Technologies HyperSparc */
+  { 1, 0xf, "ROSS HyperSparc RT620"},
+  { 1, 0xe, "ROSS HyperSparc RT625"},
+  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+  /* Someone please write the code to support this beast! ;) */
   { 2, 0, "Bipolar Integrated Technology - B5010"},
   { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - unknown"},
-  { 4, 1, "Texas Instruments, Inc. - Sparc Classic"},
-  { 4, 2, "Texas Instruments, Inc. - unknown"},
-  { 4, 3, "Texas Instruments, Inc. - unknown"},
-  { 4, 4, "Texas Instruments, Inc. - unknown"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
+  /* SparcClassic  --  borned STP1010TAB-50*/
+  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
   { 4, 5, "Texas Instruments, Inc. - unknown"},
   { 5, 0, "Matsushita - MN10501"},
   { 6, 0, "Philips Corporation - unknown"},
   { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
   { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
   { 9, 0, "UNKNOWN CPU-VENDOR/TYPE"},
   { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
@@ -103,8 +133,10 @@ struct cpu_iu_info linux_sparc_chips[] = {
   { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
 };
 
-char *sparc_cpu_type = "cpu-oops";
-char *sparc_fpu_type = "fpu-oops";
+#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" };
 
 /* various Virtual Address Cache parameters we find at boot time... */
 
@@ -115,82 +147,72 @@ extern int vac_entries_per_page;
 extern int find_vac_size(void);
 extern int find_vac_linesize(void);
 extern int find_vac_hwflushes(void);
-extern void find_mmu_num_segmaps(void);
-extern void find_mmu_num_contexts(void);
+
+static inline int find_mmu_num_contexts(int cpu)
+{
+       return prom_getintdefault(cpu, "mmu-nctx", 0x8);
+}
+
+unsigned int fsr_storage;
 
 void
 probe_cpu(void)
 {
-  register int psr_impl=0;
-  register int psr_vers = 0;
-  register int fpu_vers = 0;
-  register int i = 0;
-  unsigned int tmp_fsr;
-
-  &tmp_fsr;   /* GCC grrr... */
-
-  __asm__("rd %%psr, %0\n\t"
-         "mov %0, %1\n\t"
-         "srl %0, 28, %0\n\t"
-         "srl %1, 24, %1\n\t"
-         "and %0, 0xf, %0\n\t"
-         "and %1, 0xf, %1\n\t" :
-         "=r" (psr_impl),
-         "=r" (psr_vers) :
-         "0" (psr_impl),
-         "1" (psr_vers));
-
-
-  __asm__("st %%fsr, %1\n\t"
-         "ld %1, %0\n\t"
-         "srl %0, 17, %0\n\t"
-         "and %0, 0x7, %0\n\t" :
-         "=r" (fpu_vers),
-         "=m" (tmp_fsr) :
-         "0" (fpu_vers),
-         "1" (tmp_fsr));
-
-  printk("fpu_vers: %d ", fpu_vers);
-  printk("psr_impl: %d ", psr_impl);
-  printk("psr_vers: %d \n\n", psr_vers);
-
-  for(i = 0; i<23; i++)
+  int psr_impl, psr_vers, fpu_vers;
+  int i, cpuid;
+
+  cpuid = get_cpuid();
+
+  psr_impl = ((get_psr()>>28)&0xf);
+  psr_vers = ((get_psr()>>24)&0xf);
+
+  fpu_vers = ((get_fsr()>>17)&0x7);
+
+  for(i = 0; i<NSPARCCHIPS; i++)
     {
       if(linux_sparc_chips[i].psr_impl == psr_impl)
        if(linux_sparc_chips[i].psr_vers == psr_vers)
          {
-           sparc_cpu_type = linux_sparc_chips[i].cpu_name;
+           sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
            break;
          }
     }
 
-  if(i==23)
+  if(i==NSPARCCHIPS)
     {
       printk("No CPU type! You lose\n");
       printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
             psr_vers);
-      return;
+      printk("Send this information and the type of SUN and CPU/FPU type you have\n");
+      printk("to davem@caip.rutgers.edu so that this can be fixed.\n");
+      printk("halting...\n\r\n");
+      /* If I don't know about this CPU, I don't want people running on it
+       * until I do.....
+       */
+      halt();
     }
 
-  for(i = 0; i<32; i++)
+  for(i = 0; i<NSPARCFPU; i++)
     {
       if(linux_sparc_fpu[i].psr_impl == psr_impl)
        if(linux_sparc_fpu[i].fp_vers == fpu_vers)
          {
-           sparc_fpu_type = linux_sparc_fpu[i].fp_name;
+           sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
            break;
          }
     }
 
-  if(i == 32)
+  if(i == NSPARCFPU)
     {
       printk("No FPU type! You don't completely lose though...\n");
       printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl, fpu_vers);
-      sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+      printk("Send this information and the type of SUN and CPU/FPU type you have\n");
+      printk("to davem@caip.rutgers.edu so that this can be fixed.\n");
+      sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
     }
 
-  printk("CPU: %s \n", sparc_cpu_type);
-  printk("FPU: %s \n", sparc_fpu_type);
+  printk("cpu%d CPU: %s \n", cpuid, sparc_cpu_type[cpuid]);
+  printk("cpu%d FPU: %s \n", cpuid, sparc_fpu_type[cpuid]);
 
   return;
 }
@@ -198,205 +220,295 @@ probe_cpu(void)
 void
 probe_vac(void)
 {
-  register unsigned int x,y;
-
-#ifndef CONFIG_SRMMU
-  vac_size = find_vac_size();
-  vac_linesize = find_vac_linesize();
-  vac_do_hw_vac_flushes = find_vac_hwflushes();
-
-  /* Calculate various constants that make the cache-flushing code
-   * mode speedy.
-   */
-
-  vac_entries_per_segment = vac_entries_per_context = vac_size >> 12;
-
-  for(x=0,y=vac_linesize; ((1<<x)<y); x++);
-  if((1<<x) != vac_linesize) printk("Warning BOGUS VAC linesize 0x%x",
-                                   vac_size);
-
-  vac_entries_per_page = x;
-
-  printk("Sparc VAC cache: Size=%d bytes  Line-Size=%d bytes ... ", vac_size,
-        vac_linesize);
-
-  /* Here we want to 'invalidate' all the software VAC "tags"
-   * just in case there is garbage in there. Then we enable it.
-   */
-
-  for(x=0x80000000, y=(x+vac_size); x<y; x+=vac_linesize)
-    __asm__("sta %0, [%1] %2" : : "r" (0), "r" (x), "n" (0x2));
-
-  x=enable_vac();
-  printk("ENABLED\n");
-#endif
-
-  return;
+       unsigned int x,y;
+
+       vac_size = find_vac_size();
+       vac_linesize = find_vac_linesize();
+       vac_do_hw_vac_flushes = find_vac_hwflushes();
+
+       /* Calculate various constants that make the cache-flushing code
+        * mode speedy.
+        */
+
+       vac_entries_per_segment = vac_entries_per_context = vac_size >> 12;
+       for(x=0,y=vac_linesize; ((1<<x)<y); x++);
+       if((1<<x) != vac_linesize) printk("Warning BOGUS VAC linesize 0x%x",
+                                         vac_size);
+       vac_entries_per_page = x;
+
+       /* Here we want to 'invalidate' all the software VAC "tags"
+        * just in case there is garbage in there. Then we enable it.
+        */
+
+       /* flush flush flush */
+       for(x=AC_CACHETAGS; x<(AC_CACHETAGS+vac_size); x+=vac_linesize)
+               __asm__("sta %%g0, [%0] %1" : : "r" (x), "i" (0x2));
+       x=enable_vac();
+       return;
 }
 
+extern int num_segmaps, num_contexts;
+
 void
-probe_mmu(void)
+probe_mmu(int prom_node_cpu)
 {
-  find_mmu_num_segmaps();
-  find_mmu_num_contexts();
-
-  printk("MMU segmaps: %d     MMU contexts: %d\n", num_segmaps, 
-        num_contexts);
-
-  return;
+       int cpuid;
+
+       /* who are we? */
+       cpuid = get_cpuid();
+       switch(sparc_cpu_model) {
+       case sun4:
+               break;
+       case sun4c:
+               /* A sun4, sun4c. */
+               num_segmaps = prom_getintdefault(prom_node_cpu, "mmu-npmg", 128);
+               num_contexts = find_mmu_num_contexts(prom_node_cpu);
+
+               printk("cpu%d MMU segmaps: %d     MMU contexts: %d\n", cpuid,
+                      num_segmaps, num_contexts);
+               break;
+       case sun4m:
+       case sun4d:
+       case sun4e:
+               /* Any Reference MMU derivate should be handled here, hopefuly. */
+               num_segmaps = 0;
+               num_contexts = find_mmu_num_contexts(prom_node_cpu);
+               vac_linesize = prom_getint(prom_node_cpu, "cache-line-size");
+               vac_size = (prom_getint(prom_node_cpu, "cache-nlines")*vac_linesize);
+               printk("cpu%d MMU contexts: %d\n", cpuid, num_contexts);
+               printk("cpu%d CACHE linesize %d total size %d\n", cpuid, vac_linesize,
+                      vac_size);
+               break;
+       default:
+               printk("cpu%d probe_mmu: sparc_cpu_model botch\n", cpuid);
+               break;
+       };
+
+       return;
 }
 
+/* Clock probing, we probe the timers here also. */
+/* #define DEBUG_PROBE_CLOCK */
+volatile unsigned int foo_limit;
+
 void
 probe_clock(int fchild)
 {
   register int node, type;
-  register char *node_str;
+  struct linux_prom_registers clk_reg[2];
 
   /* This will basically traverse the node-tree of the prom to see
    * which timer chip is on this machine.
    */
 
-  printk("Probing timer chip... ");
-
-  type = 0;
-  for(node = fchild ; ; )
-    {
-      node_str = get_str_from_prom(node, "model", promstr_buf);
-      if(strcmp(node_str, "mk48t02") == 0)
-       {
-         type = 2;
-         break;
-       }
-
-      if(strcmp(node_str, "mk48t08") == 0)
-       {
-         type = 8;
-         break;
-       }
-
-      node = node_get_sibling(node);
-      if(node == fchild)
-       {
-         printk("Aieee, could not find timer chip type\n");
+  node = 0;
+  if(sparc_cpu_model == sun4) {
+         printk("probe_clock: No SUN4 Clock/Timer support yet...\n");
          return;
-       }
-    }
-
-  printk("Mostek %s\n", node_str);
-  printk("At OBIO address: 0x%x Virtual address: 0x%x\n",
-        (unsigned int) TIMER_PHYSADDR, (unsigned int) TIMER_STRUCT);
-
-  mapioaddr((unsigned long) TIMER_PHYSADDR,
-           (unsigned long) TIMER_STRUCT);
-
-  TIMER_STRUCT->timer_limit14=(((1000000/HZ) << 10) | 0x80000000);
+  }
+  if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node);
+  else
+         if(sparc_cpu_model == sun4m)
+                 node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
+  type = 0;
+  sp_clock_typ = MSTK_INVALID;
+  for(;;) {
+         prom_getstring(node, "model", node_str, sizeof(node_str));
+         if(strcmp(node_str, "mk48t02") == 0) {
+                 sp_clock_typ = MSTK48T02;
+                 if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
+                         printk("probe_clock: FAILED!\n");
+                         halt();
+                 }
+                 prom_apply_obio_ranges(clk_reg, 1);
+                 /* Map the clock register io area read-only */
+                 mstk48t02_regs = (struct mostek48t02 *) 
+                         sparc_alloc_io((void *) clk_reg[0].phys_addr,
+                                        (void *) 0, sizeof(*mstk48t02_regs),
+                                        "clock", 0x0, 0x1);
+                 mstk48t08_regs = 0;  /* To catch weirdness */
+                 break;
+         }
 
-  return;
-}
+         if(strcmp(node_str, "mk48t08") == 0) {
+                 sp_clock_typ = MSTK48T08;
+                 if(prom_getproperty(node, "reg", (char *) clk_reg,
+                                     sizeof(clk_reg)) == -1) {
+                         printk("probe_clock: FAILED!\n");
+                         halt();
+                 }
+                 prom_apply_obio_ranges(clk_reg, 1);
+                 /* Map the clock register io area read-only */
+                 mstk48t08_regs = (struct mostek48t08 *)
+                         sparc_alloc_io((void *) clk_reg[0].phys_addr,
+                                        (void *) 0, sizeof(*mstk48t08_regs),
+                                        "clock", 0x0, 0x1);
+
+                 mstk48t02_regs = &mstk48t08_regs->regs;
+                 break;
+         }
 
+         node = prom_getsibling(node);
+         if(node == 0) {
+                 printk("Aieee, could not find timer chip type\n");
+                 return;
+         }
+  }
 
-void
-probe_esp(register int esp_node)
-{
-  register int nd;
-  register char* lbuf;
+  if(sparc_cpu_model == sun4c) {
 
-  nd = node_get_child(esp_node);
+  /* Map the Timer chip, this is implemented in hardware inside
+   * the cache chip on the sun4c.
+   */
+  sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR,
+                 sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0);
 
-  printk("\nProbing ESP:\n");
-  lbuf = get_str_from_prom(nd, "name", promstr_buf);
+  /* Have the level 10 timer tick at 100HZ.  We don't touch the
+   * level 14 timer limit since we are letting the prom handle
+   * them until we have a real console driver so L1-A works.
+   */
+  SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10);
+  master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10);
 
-  if(*get_int_from_prom(nd, "name", promint_buf) != 0)
-  printk("Node: 0x%x Name: %s\n", nd, lbuf);
+  } else {
+         int reg_count;
+         struct linux_prom_registers cnt_regs[PROMREG_MAX];
+         int obio_node, cnt_node;
+
+         cnt_node = 0;
+         if((obio_node =
+             prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
+            (obio_node = prom_getchild (obio_node)) == 0 ||
+            (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
+                 printk ("Cannot find /obio/counter node\n");
+                 prom_halt ();
+         }
+         reg_count = prom_getproperty(cnt_node, "reg",
+                                      (void *) cnt_regs, sizeof(cnt_regs));
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    lbuf = get_str_from_prom(nd, "name", promstr_buf);
-    printk("Node: 0x%x Name: %s\n", nd, lbuf);
-  }
+         reg_count = (reg_count/sizeof(struct linux_prom_registers));
 
-  printk("\n");
+         /* Apply the obio ranges to the timer registers. */
+         prom_apply_obio_ranges(cnt_regs, reg_count);
 
-  return;
-}
+         /* Map the per-cpu Counter registers. */
+         sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR,
+                        PAGE_SIZE*NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0);
 
-void
-probe_sbus(register int cpu_child_node)
-{
-  register int nd, savend;
-  register char* lbuf;
+         /* Map the system Counter register. */
+         sparc_alloc_io(cnt_regs[reg_count-1].phys_addr,
+                        (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE),
+                        cnt_regs[reg_count-1].reg_size,
+                        "counters_system", cnt_regs[reg_count-1].which_io, 0x0);
 
-  nd = cpu_child_node;
 
-  lbuf = (char *) 0;
+         sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR;
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    lbuf = get_str_from_prom(nd, "name", promstr_buf);
-    if(strcmp(lbuf, "sbus") == 0)
-      break;
-  };
+         foo_limit = (volatile) sun4m_timers->l10_timer_limit;
 
-  nd = node_get_child(nd);
+/*       printk("Timer register dump:\n"); */
+#if 0
+         printk("cpu0: l14limit %08x l14curcount %08x\n",
+                sun4m_timers->cpu_timers[0].l14_timer_limit,
+                sun4m_timers->cpu_timers[0].l14_cur_count);
+#endif
+#if 0
+         printk("sys: l10limit %08x l10curcount %08x\n",
+                sun4m_timers->l10_timer_limit,
+                sun4m_timers->l10_cur_count);
+#endif
 
-  printk("Node: 0x%x Name: %s\n", nd,
-        get_str_from_prom(nd, "name", promstr_buf));
+         /* Must set the master pointer first or we will lose badly. */
+         master_l10_limit =
+                 &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit);
 
-  if(strcmp(lbuf, "esp") == 0) {
-    probe_esp(nd);
-  };
+          ((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit =
+                 (((1000000/HZ) + 1) << 10);   /* 0x9c4000 */
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    printk("Node: 0x%x Name: %s\n", nd,
-          lbuf = get_str_from_prom(nd, "name", promstr_buf));
-    
-    if(strcmp(lbuf, "esp") == 0) {
-      savend = nd;
-      probe_esp(nd);
-      nd = savend;
-    };
-  };
+         /* We should be getting level 10 interrupts now. */
+  }
 
-  printk("\n");
   return;
 }
 
-extern unsigned long probe_memory(void);
-extern struct sparc_phys_banks sp_banks[14];
-unsigned int phys_bytes_of_ram, end_of_phys_memory;
-
+/* Probe and map in the Auxiliaary I/O register */
 void
-probe_devices(void)
+probe_auxio(void)
 {
-  register int nd, i;
-  register char* str;
+       int node, auxio_nd;
+       struct linux_prom_registers auxregs[1];
+
+       node = prom_getchild(prom_root_node);
+       auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+       if(!auxio_nd) {
+               node = prom_searchsiblings(node, "obio");
+               node = prom_getchild(node);
+               auxio_nd = prom_searchsiblings(node, "auxio");
+               if(!auxio_nd) {
+                       printk("Cannot find auxio node, cannot continue...\n");
+                       prom_halt();
+               }
+       }
+       prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
+       prom_apply_obio_ranges(auxregs, 0x1);
+       /* Map the register both read and write */
+       sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR,
+                      auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0);
+       printk("Mapped AUXIO at paddr %08lx vaddr %08lx\n",
+              (unsigned long) auxregs[0].phys_addr,
+              (unsigned long) AUXIO_VADDR);
+       return;
+}
 
-  nd = prom_node_root;
+extern unsigned long probe_memory(void);
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
+extern unsigned long probe_sbus(int, unsigned long);
+extern void probe_mbus(void);
 
-  printk("PROBING DEVICES:\n");
+/* #define DEBUG_PROBE_DEVICES */
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
 
-  str = get_str_from_prom(nd, "device_type", promstr_buf);
-  if(strcmp(str, "cpu") == 0) {
-    printk("Found CPU root prom device tree node.\n");
+unsigned long
+probe_devices(unsigned long mem_start)
+{
+  int nd, i, prom_node_cpu, thismid;
+  int cpu_nds[NCPUS];  /* One node for each cpu */
+  int cpu_ctr = 0;
+
+  prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+  if(strcmp(node_str, "cpu") == 0) {
+    cpu_nds[0] = prom_root_node;
+    cpu_ctr++;
   } else {
-    printk("Root node in device tree was not 'cpu' cannot continue.\n");
-    halt();
+    int scan;
+    scan = prom_getchild(prom_root_node);
+    nd = 0;
+    while((scan = prom_getsibling(scan)) != 0) {
+      prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+      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));
+             linux_cpus[cpu_ctr].mid = thismid;
+             cpu_ctr++;
+      }
+    };
+    if(cpu_ctr == 0) {
+      printk("No CPU nodes found, cannot continue.\n");
+      /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
+      halt();
+    }
+    printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
   };
+  prom_node_cpu = cpu_nds[0];
 
-#ifdef DEBUG_PROBING
-  printk("String address for d_type: 0x%x\n", (unsigned int) str);
-  printk("str[0] = %c  str[1] = %c  str[2] = %c \n", str[0], str[1], str[2]);
-#endif
-
-  str = get_str_from_prom(nd, "name", promstr_buf);
-
-#ifdef DEBUG_PROBING
-  printk("String address for name: 0x%x\n", (unsigned int) str);
-  printk("str[0] = %c  str[1] = %c  str[2] = %c \n", str[0], str[1], str[2]);
-#endif
-
-  printk("Name: %s \n", str);
-
-  first_descent = nd = node_get_child(nd);
-
+  linux_num_cpus = cpu_ctr;
+  for(i=0; i<cpu_ctr; i++) {
+         prom_getstring(cpu_nds[i], "name", node_str, sizeof(node_str));
+         printk("cpu%d: %s \n", i, node_str);
+  }
 
 /* Ok, here will go a call to each specific device probe. We can
  * call these now that we have the 'root' node and the child of
@@ -404,29 +516,11 @@ probe_devices(void)
  */
 
   probe_cpu();
-  probe_vac();
-  probe_mmu();
-  phys_bytes_of_ram = probe_memory();
-
-  printk("Physical Memory: %d bytes\n", (int) phys_bytes_of_ram);
-  for(i=0; sp_banks[i].num_bytes != 0; i++) {
-    printk("Bank %d:  base 0x%x  bytes %d\n", i,
-          (unsigned int) sp_banks[i].base_addr, 
-          (int) sp_banks[i].num_bytes);
-    end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes;
-  }
-
-  printk("PROM Root Child Node: 0x%x Name: %s \n", nd,
-        get_str_from_prom(nd, "name", promstr_buf));
+  probe_auxio();
+  if(sparc_cpu_model == sun4c) probe_vac();
+  if(sparc_cpu_model != sun4c) probe_mbus(); /* Are MBUS's relevant on sun4c's? */
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    printk("Node: 0x%x Name: %s", nd,
-          get_str_from_prom(nd, "name", promstr_buf));
-    printk("\n");
-  };
-
-  printk("\nProbing SBUS:\n");
-  probe_sbus(first_descent);
+  mem_start = probe_sbus(prom_getchild(prom_root_node), mem_start);
 
-  return;
+  return mem_start;
 }
index 679863ba32c75d423896068c2800fff99fb454c0..b522d6cbe46febc0ec5b8848ed7e0a3694e45117 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  linux/arch/i386/kernel/process.c
+ *  linux/arch/sparc/kernel/process.c
  *
- *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /*
 #include <linux/user.h>
 #include <linux/a.out.h>
 
+#include <asm/oplib.h>
 #include <asm/segment.h>
 #include <asm/system.h>
-
-void ret_from_sys_call(void) { __asm__("nop"); }
+#include <asm/processor.h>
 
 /*
- * The idle loop on a i386..
+ * The idle loop on a sparc... ;)
  */
 asmlinkage int sys_idle(void)
 {
+
        if (current->pid != 0)
                return -EPERM;
 
+       printk("in sys_idle...\n");
        /* Map out the low memory: it's no longer needed */
        /* Sparc version RSN */
 
        /* endless idle loop with no priority at all */
        current->counter = -100;
        for (;;) {
-               schedule();
+         printk("calling schedule() aieee!\n");
+         schedule();
+         printk("schedule() returned, halting...\n");
+         halt();
        }
 }
 
 void hard_reset_now(void)
 {
-       halt();
+       prom_reboot("boot vmlinux");
 }
 
 void show_regs(struct pt_regs * regs)
 {
-        printk("\nSP: %08lx PC: %08lx NPC: %08lx\n", regs->sp, regs->pc,
-              regs->npc);
-}
-
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-void start_thread(struct pt_regs * regs, unsigned long sp, unsigned long fp)
-{
-       regs->sp = sp;
-       regs->fp = fp;
+        printk("\nFP: %08lx PC: %08lx NPC: %08lx\n", regs->u_regs[14],
+              regs->pc, regs->npc);
 }
 
 /*
@@ -76,15 +72,60 @@ void flush_thread(void)
   halt();
 }
 
-void copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct * p, struct pt_regs * regs)
+extern void ret_sys_call(void);
+
+/*
+ * Copy a Sparc thread.  The context of a process on the Sparc is
+ * composed of the following:
+ *  1) status registers  %psr (for condition codes + CWP) and %wim
+ *  2) current register window (in's and global registers)
+ *  3) the current live stack frame, it contains the register
+ *     windows the child may 'restore' into, this is important
+ *  4) kernel stack pointer, user stack pointer (which is %i6)
+ *  5) The pc and npc the child returns to during a switch
+ */
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+                struct task_struct * p, struct pt_regs * regs)
 {
-       struct pt_regs * childregs;
+       struct pt_regs *childregs;
+       unsigned char *old_stack;
+       unsigned char *new_stack;
+       int i;
+
+       /* This process has no context yet. */
+       p->tss.context = -1;
+
+       /* Grrr, Sparc stack alignment restrictions make things difficult. */
+       childregs = ((struct pt_regs *) 
+                    ((p->kernel_stack_page + PAGE_SIZE - 80)&(~7)));
 
-       childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
-       p->tss.usp = (unsigned long) childregs;
        *childregs = *regs;
-       childregs->sp = sp;
-       p->tss.psr = regs->psr; /* for condition codes */
+
+       p->tss.usp = sp;    /* both processes have the same user stack */
+       /* See entry.S */
+
+       /* Allocate new processes kernel stack right under pt_regs.
+        * Hopefully this should align things the right way.
+        */
+       p->tss.ksp = (unsigned long) ((p->kernel_stack_page + PAGE_SIZE - 80 - 96)&(~7));
+       new_stack = (unsigned char *) (p->tss.ksp);
+       old_stack = (unsigned char *) (((unsigned long) regs) - 96);
+
+       /* Copy c-stack. */
+       for(i=0; i<96; i++) *new_stack++ = *old_stack++;
+
+       /* These pc values are only used when we switch to the child for
+        * the first time, it jumps the child to ret_sys_call in entry.S
+        * so that the child returns from the sys_call just like parent.
+        */
+       p->tss.pc = (((unsigned long) ret_sys_call) - 8);
+       p->tss.npc = p->tss.pc+4;
+
+       /* Set the return values for both the parent and the child */
+       regs->u_regs[8] = p->pid;
+       childregs->u_regs[8] = 0;
+
        return;
 }
 
@@ -96,9 +137,9 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
   return; /* solaris does this enough */
 }
 
-asmlinkage int sys_fork(struct pt_regs regs)
+asmlinkage int sys_fork(struct pt_regs *regs)
 {
-       return do_fork(COPYVM | SIGCHLD, regs.sp, &regs);
+  return do_fork(COPYVM | SIGCHLD, regs->u_regs[14], regs);
 }
 
 /*
@@ -106,6 +147,7 @@ asmlinkage int sys_fork(struct pt_regs regs)
  */
 asmlinkage int sys_execve(struct pt_regs regs)
 {
+  printk("sys_execve()... halting\n");
   halt();
   return 0;
 }
index 5ec5b56ba85b113e67523f45cc158c4e80afb8db..45e3804afd382853dfa55ec7c73f3d75a8c5667f 100644 (file)
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/openprom.h>   /* for console registration + cheese */
+#include <asm/processor.h>
+#include <asm/oplib.h>    /* The PROM is your friend... */
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/vaddrs.h>
+#include <asm/kdebug.h>
 
-extern void get_idprom(void);
-extern void probe_devices(void);
+extern unsigned long probe_devices(unsigned long);
 
 /*
  * Gcc is hard to keep happy ;-)
@@ -42,9 +47,7 @@ struct screen_info screen_info = {
        25                      /* orig-video-lines */
 };
 
-/* At least I hide the sneaky floppy_track_buffer in my dirty assembly
- * code. ;-)
- */
+char wp_works_ok = 0;
 
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 {
@@ -52,8 +55,8 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 }
 
 /* Lame prom console routines, gets registered below. Thanks for the
- * tip Linus.  First comes the V0 prom routine, then the V3 version
- * written by Paul Hatchman (paul@sfe.com.au).
+ * tip Linus.  We now use a generic putchar prom routine through the
+ * linux prom library.
  */
 
 void sparc_console_print(const char * p)
@@ -62,31 +65,66 @@ void sparc_console_print(const char * p)
 
        while ((c = *(p++)) != 0)
          {
-           if (c == '\n') romvec->pv_putchar('\r');
-           (*(romvec->pv_putchar))(c);
+           if (c == '\n')
+             prom_putchar('\r');
+           prom_putchar(c);
          }
 
   return;
 
 }
 
-/* paul@sfe.com.au */
-/* V3 prom console printing routines */
-void sparc_console_print_v3 (const char *p)
+/* Typing sync at the prom promptcalls the function pointed to by
+ * romvec->pv_synchook which I set to the following function.
+ * This should sync all filesystems and return, for now it just
+ * prints out pretty messages and returns.
+ */
+void prom_sync_me(void)
 {
-       unsigned char c;
+       printk("PROM SYNC COMMAND...\n");
+       show_free_areas();
+       printk("Returning to prom\n");
+       return;
+}
 
-       while ((c = *(p++)) != 0)
-       {
-               if (c == '\n') romvec->pv_v2devops.v2_dev_write 
-                       ((*romvec->pv_v2bootargs.fd_stdout), "\r", 1);
-               romvec->pv_v2devops.v2_dev_write 
-                       ((*romvec->pv_v2bootargs.fd_stdout), &c, 1);
-       }
+unsigned int boot_flags;
+#define BOOTME_DEBUG  0x1
+#define BOOTME_SINGLE 0x2
+#define BOOTME_KGDB   0x3
 
-       return;
-}
+/* This routine does no error checking, make sure your string is sane
+ * before calling this!
+ * XXX This is cheese, make generic and better.
+ */
+void
+boot_flags_init(char *commands)
+{
+       int i;
+       for(i=0; i<strlen(commands); i++)
+               if(commands[i]=='-')
+                       switch(commands[i+1]) {
+                       case 'd':
+                               boot_flags |= BOOTME_DEBUG;
+                               break;
+                       case 's':
+                               boot_flags |= BOOTME_SINGLE;
+                               break;
+                       case 'h':
+                               printk("boot_flags_init: Found halt flag, doing so now...\n");
+                               halt();
+                               break;
+                       case 'k':
+                               printk("Found KGDB boot flag...\n");
+                               boot_flags |= BOOTME_KGDB;
+                               break;
+                       default:
+                               printk("boot_flags_init: Unknown boot arg (-%c)\n",
+                                      commands[i+1]);
+                               break;
+                       };
 
+       return;
+}
 
 /* This routine will in the future do all the nasty prom stuff
  * to probe for the mmu type and its parameters, etc. This will
@@ -95,23 +133,133 @@ void sparc_console_print_v3 (const char *p)
  */
 
 extern void register_console(void (*proc)(const char *));
-extern unsigned int prom_iface_vers, end_of_phys_memory;
+extern void load_mmu(void);
+extern int prom_probe_memory(void);
+extern void probe_mmu(int node);
+extern void get_idprom(void);
+extern void srmmu_patch_fhandlers(void);
+extern unsigned int prom_iface_vers, end_of_phys_memory, phys_bytes_of_ram;
+extern char cputypval;
+extern unsigned long start;
+char sparc_command_line[256];  /* Should be enough */
+enum sparc_cpu sparc_cpu_model;
+
+struct tt_entry *sparc_ttable;
+
+/* #define DEBUG_CMDLINE */
 
 void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-       if(romvec->pv_romvers == 0) {
-         register_console(sparc_console_print);
-       } else {
-         register_console(sparc_console_print_v3);
-       };
+       int counter, total, i, node;
+       char devtype[64];
+
+       sparc_ttable = (struct tt_entry *) &start;
+
+       register_console(sparc_console_print);
+
+       /* Initialize PROM console and command line. */
+       *cmdline_p = prom_getbootargs();
+       boot_flags_init(*cmdline_p);
 
-       printk("Sparc PROM-Console registered...\n");
-       get_idprom();     /* probe_devices expects this to be done */
-       probe_devices();  /* cpu/fpu, mmu probes */
+       /* Synchronize with debugger if necessary.  Grrr, have to check
+        * the boot flags too. ;(
+        */
+       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
+          ((*(short *)linux_dbvec) != -1)) {
+               printk("Booted under debugger. Syncing up trap table.\n");
+               /* Sync us up... */
+               (*(linux_dbvec->teach_debugger))();
 
+               SP_ENTER_DEBUGGER;
+       }
+
+       /* Set sparc_cpu_model */
+       sparc_cpu_model = sun_unknown;
+       if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
+       if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
+       if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
+       if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
+       if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+       printk("ARCH: ");
+       switch(sparc_cpu_model)
+         {
+         case sun4c:
+                 memset(phys_seg_map, 0x0, sizeof(phys_seg_map[PSEG_ENTRIES]));
+                 put_segmap(IOBASE_VADDR, IOBASE_SUN4C_SEGMAP);
+                 phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV;
+                 node = prom_root_node;
+
+                 printk("SUN4C\n");
+                 break;
+          case sun4m:
+                 node = prom_getchild(prom_root_node);
+                 prom_getproperty(node, "device_type", devtype, sizeof(devtype));
+                 while(strcmp(devtype, "cpu") != 0) {
+                         node = prom_getsibling(node);
+                         prom_getproperty(node, "device_type", devtype,
+                                          sizeof(devtype));
+                 }
+                 /* Patch trap table. */
+                 srmmu_patch_fhandlers();
+                 printk("SUN4M\n");
+                 break;
+         case sun4d:
+                 printk("SUN4D\n");
+                 break;
+         case sun4e:
+                 printk("SUN4E\n");
+                 break;
+         case sun4u:
+                 printk("SUN4U\n");
+                 break;
+         default:
+                 printk("UNKNOWN!\n");
+                 break;
+         };
+
+       /* probe_devices() expects this to be done. */
+       get_idprom();
+
+       /* Probe the mmu constants. */
+       probe_mmu(node);
+
+       /* Set pointers to memory management routines. */
+       load_mmu();
+
+       /* Probe for memory. */
+       total = prom_probe_memory();
        *memory_start_p = (((unsigned long) &end));
-       *memory_end_p = (((unsigned long) end_of_phys_memory));
+
+       printk("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
+              (unsigned long) total);
+
+       for(i=0; sp_banks[i].num_bytes != 0; i++) {
+#if 0
+               printk("Bank %d:  base 0x%x  bytes %d\n", i,
+                      (unsigned int) sp_banks[i].base_addr, 
+                      (int) sp_banks[i].num_bytes);
+#endif
+               end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+       }
+
+       /* Set prom sync hook pointer */
+       prom_setsync(prom_sync_me);
+
+       init_task.mm->start_code = PAGE_OFFSET;
+       init_task.mm->end_code = PAGE_OFFSET + (unsigned long) &etext;
+       init_task.mm->end_data = PAGE_OFFSET + (unsigned long) &edata;
+       init_task.mm->brk = PAGE_OFFSET + (unsigned long) &end;
+       init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
+
+       /* Grrr, wish I knew why I have to do this ;-( */
+       for(counter=1; counter<NR_TASKS; counter++) {
+               task[counter] = NULL;
+       }
+
+       *memory_end_p = (((unsigned long) (total) + PAGE_OFFSET));
+
+       return;
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
index 9302191c789e89e5dd8d1465ec46f0cc7ef1bfe7..9149e8abf987d5e9bde904c4f48491172427b869 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/sparc/kernel/traps.c
  *
- * Copyright 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /*
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
 
-void do_hw_interrupt(unsigned long type, unsigned long vector)
-{
-  if (vector == 14) {
-    jiffies++;
-    return;
-  }
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mp.h>
+#include <asm/kdebug.h>
 
-  /* Just print garbage for everything else for now. */
+void
+do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+{
 
-  printk("Unimplemented Sparc TRAP, vector = %lx type = %lx\n", vector, type);
+  printk("Unimplemented Sparc TRAP, type = %02lx psr = %08lx pc = %08lx\n",
+        type, psr, pc);
+  halt();
 
   return;
 }
 
-extern unsigned long *trapbase;
+void
+do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Illegal instruction at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Privileged instruction at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Unaligned memory access at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Floating Point Disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Floating Point Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Tag overflow trap at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_iacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Instruction Access Error at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Co-Processor disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_dacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Data Access Error at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_dstore_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Data Store Error at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+void
+handle_dacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       printk("Data Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
 
-void trap_init(void)
+void
+handle_iacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
 {
+       printk("Instruction Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+       halt();
+       return;
+}
+
+/* Since we have our mappings set up, on multiprocessors we can spin them
+ * up here so that timer interrupts work during initialization.
+ */
+
+extern void sparc_cpu_startup(void);
 
-  /* load up the trap table */
+extern int linux_num_cpus;
+extern pgd_t *lnx_root;
 
-#if 0 /* not yet */
-  __asm__("wr %0, 0x0, %%tbr\n\t"
-         "nop; nop; nop\n\t" : :
-         "r" (trapbase));
+int linux_smp_still_initting;
+unsigned int thiscpus_tbr;
+int thiscpus_mid;
+
+/* #define SMP_TESTING */
+
+void
+trap_init(void)
+{
+       struct linux_prom_registers ctx_reg;
+       int i;
+
+       if(linux_num_cpus == 1) {
+               printk("trap_init: Uniprocessor detected.\n");
+               return;
+       }
+       if(sparc_cpu_model != sun4m) {
+               printk("trap_init: Multiprocessor on a non-sun4m! Aieee...\n");
+               printk("trap_init: Cannot continue, bailing out.\n");
+               prom_halt();
+       }
+       /* Ok, we are on a sun4m with multiple cpu's */
+       printk("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n",
+              linux_num_cpus);
+       linux_smp_still_initting = 1;
+       ctx_reg.which_io = 0x0;  /* real ram */
+       ctx_reg.phys_addr = (char *) (((unsigned long) lnx_root) - PAGE_OFFSET);
+       ctx_reg.reg_size = 0x0;
+       /* This basically takes every cpu, loads up our Linux context table
+        * into it's context table pointer register, inits it at the low level
+        * and then makes it spin in an endless loop...
+        */
+       for(i=0; i<linux_num_cpus; i++) {
+               if((linux_cpus[i].mid & (~8)) != 0x0) {
+                       static int cpuid = 0;
+                       cpuid = (linux_cpus[i].mid & (~8));
+                       percpu_table[cpuid].cpu_is_alive = 0;
+                       thiscpus_mid = linux_cpus[i].mid;
+                       thiscpus_tbr = (unsigned int)
+                               percpu_table[cpuid].trap_table;
+#ifdef SMP_TESTING
+                       printk("thiscpus_tbr = %08x\n", thiscpus_tbr);
+                       printk("About to fire up cpu %d mid %d cpuid %d\n", i,
+                              linux_cpus[i].mid, cpuid);
 #endif
+                       prom_startcpu(linux_cpus[i].prom_node, &ctx_reg, 0x0,
+                                     (char *) sparc_cpu_startup);
+                       printk("Waiting for cpu %d to start up...\n", i);
+                       while(percpu_table[cpuid].cpu_is_alive == 0) {
+                               static int counter = 0;
+                               counter++;
+                               if(counter>200) {
+#ifdef SMP_TESTING
+                                       printk("UGH, CPU would not start up ;-( \n");
+#endif
+                                       break;
+                               }
+                               __delay(200000);
+                       }
+               }
+       }
 
-  return;
+       linux_smp_still_initting = 1;
+
+       return;
 }
 
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
+void
+die_if_kernel(char * str, struct pt_regs * regs, long err)
 {
   return;
 }
index a4148d0136005082f0db5fd244841f9aa1e55d77..9192b768929bd14be241fd610ccb9d3468a62df2 100644 (file)
@@ -14,7 +14,7 @@
 .c.s:
        $(CC) $(CFLAGS) -S $<
 
-OBJS   = fault.o vac-flush.o init.o
+OBJS   = fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o
 
 mm.o: $(OBJS)
        $(LD) -r -o mm.o $(OBJS)
index 4c5fd0bc3bfa1a78a3d79598bb6ab140d6864e92..2ca8d55de95938a245cd8f8e6aaaf6833e5e73a2 100644 (file)
@@ -1,3 +1,8 @@
+/* fault.c:  Page fault handlers for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/openprom.h>
+#include <asm/idprom.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/memreg.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/kdebug.h>
 
-extern unsigned long pg0[1024];                /* page table for 0-4MB for everybody */
-extern struct sparc_phys_banks sp_banks[14];
+#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
+
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+extern int prom_node_root;
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
@@ -42,46 +54,37 @@ int vac_entries_per_page;
  */
 #undef CONFIG_TEST_VERIFY_AREA
 
-/* Traverse the memory lists in the prom to see how much physical we
- * have.
- */
-
-unsigned long
-probe_memory(void)
+/* Nice, simple, prom library does all the sweating for us. ;) */
+int prom_probe_memory (void)
 {
-  register struct linux_romvec *lprom;
   register struct linux_mlist_v0 *mlist;
   register unsigned long bytes, base_paddr, tally;
   register int i;
 
-  bytes = tally = 0;
-  base_paddr = 0;
-  i=0;
-  lprom = romvec;
-  switch(lprom->pv_romvers)
-    {
-    case 0:
-      mlist=(*(lprom->pv_v0mem.v0_totphys));
-      bytes = tally = mlist->num_bytes;
-      base_paddr = (unsigned long) mlist->start_adr;
-
-      sp_banks[0].base_addr = base_paddr;
-      sp_banks[0].num_bytes = bytes;
-
-      if(mlist->theres_more != (void *)0) {
-         i++;
-         mlist=mlist->theres_more;
-         bytes=mlist->num_bytes;
-         tally += bytes;
-         sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
-         sp_banks[i].num_bytes = mlist->num_bytes;
-       }
-      break;
-    case 2:
-      printk("no v2 memory probe support yet.\n");
-      (*(lprom->pv_halt))();
+  i = 0;
+  mlist= *prom_meminfo()->v0_available;
+  bytes = tally = mlist->num_bytes;
+  base_paddr = (unsigned long) mlist->start_adr;
+  
+  sp_banks[0].base_addr = base_paddr;
+  sp_banks[0].num_bytes = bytes;
+
+  while (mlist->theres_more != (void *) 0){
+    i++;
+    mlist = mlist->theres_more;
+    bytes = mlist->num_bytes;
+    tally += bytes;
+    if (i >= SPARC_PHYS_BANKS-1) {
+      printk ("The machine has more banks that this kernel can support\n"
+             "Increase the SPARC_PHYS_BANKS setting (currently %d)\n",
+             SPARC_PHYS_BANKS);
+      i = SPARC_PHYS_BANKS-1;
       break;
     }
+    
+    sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
+    sp_banks[i].num_bytes = mlist->num_bytes;
+  }
 
   i++;
   sp_banks[i].base_addr = 0xdeadbeef;
@@ -90,84 +93,464 @@ probe_memory(void)
   return tally;
 }
 
-/* Sparc routine to reserve the mapping of the open boot prom */
+/* Traverse the memory lists in the prom to see how much physical we
+ * have.
+ */
+unsigned long
+probe_memory(void)
+{
+       int total;
+
+       total = prom_probe_memory();
 
-/* uncomment this for FAME and FORTUNE! */
-/* #define DEBUG_MAP_PROM */
+       /* Oh man, much nicer, keep the dirt in promlib. */
+       return total;
+}
 
-int
-map_the_prom(int curr_num_segs)
+asmlinkage void sparc_txtmem_error(int type, unsigned long sync_err_reg,
+                                  unsigned long sync_vaddr,
+                                  unsigned long async_err_reg,
+                                  unsigned long async_vaddr)
 {
-  register unsigned long prom_va_begin;
-  register unsigned long prom_va_end;
-  register int segmap_entry, i;
+  printk("Aieee, sparc text page access error, halting\n");
+  printk("type = %d  sync_err_reg = 0x%x  sync_vaddr = 0x%x\n",
+        type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr);
+  printk("async_err_reg = 0x%x  async_vaddr = 0x%x\n",
+        (unsigned int) async_err_reg, (unsigned int) async_vaddr);
+  halt();
+}
 
-  prom_va_begin = LINUX_OPPROM_BEGVM;
-  prom_va_end   = LINUX_OPPROM_ENDVM;
+/* #define DEBUG_SPARC_TEXT_ACCESS_FAULT */
 
-#ifdef DEBUG_MAP_PROM
-  printk("\ncurr_num_segs = 0x%x\n", curr_num_segs);
+asmlinkage void sparc_text_access_fault(int type, unsigned long sync_err_reg,
+                                       unsigned long sync_vaddr,
+                                       unsigned long pc, unsigned long psr,
+                                       struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+
+  address = sync_vaddr;
+#ifdef DEBUG_SPARC_TEXT_ACCESS_FAULT
+  printk("Text FAULT: address = %08lx  code = %08lx\n",
+        (unsigned long) address, (unsigned long) sync_err_reg);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  SP_ENTER_DEBUGGER;
+  halt();
 #endif
+  vma = find_vma(current, address);
+  if(!vma) {
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+  goto bad_area;
 
-  while( prom_va_begin < prom_va_end)
-    {
-      segmap_entry=get_segmap(prom_va_begin);
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+  handle_mm_fault(vma, address, 0);
+  return;
 
-      curr_num_segs = ((segmap_entry<curr_num_segs) 
-                      ? segmap_entry : curr_num_segs);
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+        (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
 
-      for(i = num_contexts; --i > 0;)
-         (*romvec->pv_setctxt)(i, (char *) prom_va_begin,
-                               segmap_entry);
+asmlinkage void sparc_datamem_error(int type, unsigned long sync_err_reg,
+                                   unsigned long sync_vaddr,
+                                   unsigned long async_err_reg,
+                                   unsigned long async_vaddr)
+{
+  printk("Aieee, sparc data page access error, halting\n");
+  printk("type = %d  sync_err_reg = 0x%x  sync_vaddr = 0x%x\n",
+        type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr);
+  printk("async_err_reg = 0x%x  async_vaddr = 0x%x\n",
+        (unsigned int) async_err_reg, (unsigned int) async_vaddr);
+  printk("SYNC PAGE has MMU entry %08lx\n",
+        (unsigned long) get_pte(sync_vaddr));
+  halt();
+}
 
-      if(segmap_entry == invalid_segment)
-       {
+/* #define DEBUG_SPARC_DATA_ACCESS_FAULT */
 
-#ifdef DEBUG_MAP_PROM
-         printk("invalid_segments, virt_addr 0x%x\n", prom_va_begin);
+asmlinkage void sparc_data_access_fault(int type, unsigned long sync_err_reg,
+                                       unsigned long sync_vaddr,
+                                       unsigned long pc, unsigned long psr,
+                                       struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+  int error_code;
+
+  address = sync_vaddr;
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("Data FAULT: address = %08lx  code = %08lx\n",
+        (unsigned long) address, (unsigned long) sync_err_reg);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  printk("PTE = %08lx\n", (unsigned long) get_pte(address));
+#endif
+  vma = find_vma(current, address);
+  if(!vma) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+    printk("NULL VMA\n");
 #endif
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
 
-         prom_va_begin += 0x40000;  /* num bytes per segment entry */
-         continue;
-       }
+  if(!(vma->vm_flags & VM_GROWSDOWN)) {
+    goto bad_area;
+  }
+  if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) {
+    goto bad_area;
+  }
 
-      /* DUH, prom maps itself so that users can access it. This is
-       * broken.
-       */
+  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+  vma->vm_start = (address & PAGE_MASK);
 
-#ifdef DEBUG_MAP_PROM
-      printk("making segmap for prom privileged, va = 0x%x\n",
-            prom_va_begin);
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("Found good_area\n");
 #endif
-
-      for(i = 0x40; --i >= 0; prom_va_begin+=4096)
-       {
-         put_pte(prom_va_begin, get_pte(prom_va_begin) | 0x20000000);
-       }
-
+  if((sync_err_reg & SUN4C_SYNC_BADWRITE) &&
+     (sync_err_reg & SUN4C_SYNC_NPRESENT)) {
+    if(!(vma->vm_flags & VM_WRITE)) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("oops, vma not writable\n");
+#endif
+      goto bad_area;
     }
+  } else {
+    if(sync_err_reg & SUN4C_SYNC_PROT) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("PROT violation\n");
+#endif
+      goto bad_area;
+    }
+    if(!(vma->vm_flags & (VM_READ | VM_EXEC))) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("vma not readable nor executable\n");
+#endif
+      goto bad_area;
+    }
+  }
 
-  printk("Mapped the PROM in all contexts...\n");
+  if(sync_err_reg & SUN4C_SYNC_BADWRITE)
+    error_code = 0x2;
+  else
+    error_code = 0x0;
 
-#ifdef DEBUG_MAP_PROM
-  printk("curr_num_segs = 0x%x\n", curr_num_segs);
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("calling handle_mm_fault vma=%08lx addr=%08lx code=%d\n",
+        (unsigned long) vma, (unsigned long) address,
+        (int) error_code);
 #endif
+  handle_mm_fault(vma, address, error_code);
+  return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if (wp_works_ok < 0 && address == 0x0) {
+         wp_works_ok = 1;
+         pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_SHARED));
+         put_pte((unsigned long) 0x0, pg0[0]);
+         printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n");
+         return;
+  }
+
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+        (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
+
+/* Dump the contents of the SRMMU fsr in a human readable format. */
+void
+dump_srmmu_fsr(unsigned long fsr)
+{
+       unsigned long ebe, l, at, ft, fav, ow;
+
+       ebe = (fsr&SRMMU_FSR_EBE_MASK)>>10;
+       l = (fsr&SRMMU_FSR_L_MASK)>>8;
+       at = (fsr&SRMMU_FSR_AT_MASK)>>5;
+       ft = (fsr&SRMMU_FSR_FT_MASK)>>2;
+       fav = (fsr&SRMMU_FSR_FAV_MASK)>>1;
+       ow = (fsr&SRMMU_FSR_OW_MASK);
+
+       printk("FSR %08lx: ", fsr);
+
+       /* Ugh, the ebe is arch-dep, have to find out the meanings. */
+       printk("EBE<%s> ", (ebe == 0 ? "none" : (ebe == 1 ? "bus err" :
+                                                (ebe == 2 ? "bus timeout" :
+                                                 (ebe == 4 ? "uncorrectable err" :
+                                                  (ebe == 8 ? "undefined err" :
+                                                   (ebe == 16 ? "parity err" :
+                                                    (ebe == 24 ? "tsunami parity err" :
+                                                     (ebe == 32 ? "store buf err" :
+                                                      (ebe == 64 ? "control space err" :
+                                                       "VIKING emergency response team"))))))))));
+       printk("L<%s> ", (l == 0 ? "context table" : (l == 1 ? "level1" :
+                                                     (l == 2 ? "level2" :
+                                                      "level3"))));
+       printk("AT<%s> ", (at == 0 ? "user load" :
+                          (at == 1 ? "priv load" :
+                           (at == 2 ? "user rd/exec" :
+                            (at == 3 ? "priv rd/exec" :
+                             (at == 4 ? "user store data" :
+                              (at == 5 ? "priv store data" :
+                               (at == 6 ? "user store inst" :
+                                "priv store inst"))))))));
+
+       printk("FT<%s> ", (ft == 0 ? "none" :
+                          (ft == 1 ? "invalid address" :
+                           (ft == 2 ? "prot violation" :
+                            (ft == 3 ? "priv violation" :
+                             (ft == 4 ? "translation error" :
+                              (ft == 5 ? "bus acc error" :
+                               (ft == 6 ? "internal error" :
+                                "reserved"))))))));
+
+       printk("FAV<%s> ", (fav == 0 ? "faddr invalid" : "faddr valid"));
+       printk("OW<%s>\n", (ow == 0 ? "fsr not overwritten" : "fsr overwritten"));
+
+       return;
+}
 
-  return curr_num_segs;
+/* #define DEBUG_SRMMU_TEXT_ACCESS_FAULT */
 
+void
+really_bad_srmmu_fault(int type, unsigned long fstatus, unsigned long faddr)
+{
+       /* Learn how to handle these later... */
+       printk("REALLY BAD SRMMU FAULT DETECTED\n");
+       printk("Bailing out...\n");
+       dump_srmmu_fsr(fstatus);
+       prom_halt();
+       return;
 }
 
+asmlinkage void srmmu_text_access_fault(int type, unsigned long fstatus,
+                                       unsigned long faddr,
+                                       unsigned long pc, unsigned long psr,
+                                       struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+
+  /* Check for external bus errors and uncorrectable errors */
+  if(fstatus&SRMMU_FSR_EBE_MASK)
+         printk("External Bus Error detected during a text fault.\n");
+
+  /* Check for multiple faults... */
+  if(fstatus&SRMMU_FSR_OW_MASK && (fstatus&SRMMU_FSR_FT_TRANS)) {
+         printk("Multiple faults detected in text fault handler\n");
+         printk("Fault number one: Text fault at addr %08lx", faddr);
+         printk("Fault number two: Translation Error\n");
+         printk("Giving up...\n");
+         prom_halt();
+  }
+         
+  if(fstatus&(SRMMU_FSR_EBE_BERR | SRMMU_FSR_EBE_BTIMEO | SRMMU_FSR_EBE_UNCOR))
+         really_bad_srmmu_fault(type, fstatus, faddr);
+
+  /* Ok, we should be able to handle it at this point. */
+
+  address = faddr;
+#ifdef DEBUG_SRMMU_TEXT_ACCESS_FAULT
+  printk("Text FAULT: address = %08lx  code = %08lx\n",
+        (unsigned long) address, (unsigned long) fstatus);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  dump_srmmu_fsr(fstatus);
+  halt();
+#endif
+
+  /* Ugh, how often does this happen? ;-( */
+  if(!(fstatus&SRMMU_FSR_FAV_MASK)) {
+         printk("Fault address register is INVALID!  Since this is a text\n");
+         printk("fault I'll use the value of the trapped PC instead...\n");
+         address = regs->pc;
+  }
+
+  /* Ugh, I don't wanna know... */
+
+  vma = find_vma(current, address);
+  if(!vma) {
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+  goto bad_area;
+
 /*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-{
-       die_if_kernel("Oops", regs, error_code);
-       do_exit(SIGKILL);
+good_area:
+  do_no_page(vma, address, 0);
+  return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+        (unsigned long) current->tss.pgd_ptr);
+  halt();
 }
 
+/* #define DEBUG_SRMMU_DATA_ACCESS_FAULT */
+
+asmlinkage void srmmu_data_access_fault(int type, unsigned long fstatus,
+                                       unsigned long faddr,
+                                       unsigned long afstatus,
+                                       unsigned long afaddr,
+                                       struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address, pc, psr;
+  int error_code;
+
+  pc = regs->pc;
+  psr= regs->psr;
+  address = faddr;
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("Data FAULT: address = %08lx  code = %08lx\n",
+        (unsigned long) address, (unsigned long) fstatus);
+  printk("PC = %08lx\n", (unsigned long) pc);
+  printk("afsr = %08lx afaddr = %08lx\n", afstatus, afaddr);
+  dump_srmmu_fsr(fstatus);
+#endif
+
+  /* I figure if I make the panic's look like they came from SunOS or Solaris
+   * my life will be a lot easier ;-)
+   */
+  if(!(fstatus&SRMMU_FSR_FAV_MASK)) {
+         dump_srmmu_fsr(fstatus);
+         panic("hat_pteload: Fault address is invalid on a data fault, I'm confused...\n");
+  }
+
+#if 0 /* I see this all the time on supersparcs ;-( */
+  if(fstatus&SRMMU_FSR_OW_MASK) {
+         dump_srmmu_fsr(fstatus);
+         panic("hat_pteload: Multiple faults at once, giving up...\n");
+  }
+#endif
+
+  vma = find_vma(current, address);
+  if(!vma) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+    printk("NULL VMA\n");
+#endif
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+
+  if(!(vma->vm_flags & VM_GROWSDOWN)) {
+    goto bad_area;
+  }
+  if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) {
+    goto bad_area;
+  }
+
+  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+  vma->vm_start = (address & PAGE_MASK);
+
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("Found good_area\n");
+#endif
+  if((fstatus & SUN4C_SYNC_BADWRITE) &&
+     (fstatus & SUN4C_SYNC_NPRESENT)) {
+    if(!(vma->vm_flags & VM_WRITE)) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("oops, vma not writable\n");
+#endif
+      goto bad_area;
+    }
+  } else {
+    if(fstatus & SUN4C_SYNC_PROT) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("PROT violation\n");
+#endif
+      goto bad_area;
+    }
+    if(!(vma->vm_flags & (VM_READ | VM_EXEC))) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("vma not readable nor executable\n");
+#endif
+      goto bad_area;
+    }
+  }
 
+  if(fstatus & SUN4C_SYNC_BADWRITE)
+    error_code = 0x2;
+  else
+    error_code = 0x0;
 
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("calling do_no_page vma=%08lx addr=%08lx code=%d\n",
+        (unsigned long) vma, (unsigned long) address,
+        (int) error_code);
+#endif
+  do_no_page(vma, address, error_code);
+  return;
 
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if (wp_works_ok < 0 && address == 0x0) {
+         wp_works_ok = 1;
+         /* Advance the PC and NPC over the test store. */
+         regs->pc = regs->npc;
+         regs->npc += 4;
+         printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n");
+         return;
+  }
+
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+        (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
index a65e9e0949f2f9666219c6bca401e115d1804bc3..7ef59cd44d034a8f338ef9acbb28cad10ad6ec12 100644 (file)
 #include <asm/vac-ops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/vaddrs.h>
 
 extern void scsi_mem_init(unsigned long);
 extern void sound_mem_init(void);
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
-extern int map_the_prom(int);
+struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
+/* The following number keeps track of which page table is to
+ * next be allocated in a page.  This is necessary since there
+ * are 16 page tables per page on the space.
+ */
+unsigned long ptr_in_current_pgd;
+
+/* This keeps track of which physical segments are in use right now. */
+unsigned int phys_seg_map[PSEG_ENTRIES];
+unsigned int phys_seg_life[PSEG_ENTRIES];
+
+/* Context allocation. */
+struct task_struct *ctx_tasks[MAX_CTXS];
+int ctx_tasks_last_frd;
 
-struct sparc_phys_banks sp_banks[14];
-unsigned long *sun4c_mmu_table;
 extern int invalid_segment, num_segmaps, num_contexts;
 
 /*
@@ -61,7 +74,7 @@ pte_t __bad_page(void)
 unsigned long __zero_page(void)
 {
        memset((void *) ZERO_PGE, 0, PAGE_SIZE);
-       return ZERO_PGE;
+       return (unsigned long) ZERO_PGE;
 }
 
 void show_mem(void)
@@ -93,252 +106,140 @@ void show_mem(void)
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
+extern pgprot_t protection_map[16];
 
 /*
- * paging_init() sets up the page tables: in the alpha version this actually
- * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
+ * paging_init() sets up the page tables: We call the MMU specific
+ * init routine based upon the Sun model type on the Sparc.
  *
- * The bootup sequence put the virtual page table into high memory: that
- * means that we can change the L1 page table by just using VL1p below.
  */
+extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
+extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
+extern unsigned long probe_devices(unsigned long);
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-       unsigned long i, a, b, mask=0;
-       unsigned long curseg, curpte, num_inval;
-       unsigned long address;
-       pte_t *pg_table;
-
-       register int num_segs, num_ctx;
-       register char * c;
+       int i;
 
-       num_segs = num_segmaps;
-       num_ctx = num_contexts;
+       switch(sparc_cpu_model) {
+       case sun4c:
+               start_mem = sun4c_paging_init(start_mem, end_mem);
+               break;
+       case sun4m:
+       case sun4d:
+       case sun4e:
+               start_mem = srmmu_paging_init(start_mem, end_mem);
+               break;
+       default:
+               printk("paging_init: Cannot init paging on this Sparc\n");
+               printk("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+               printk("paging_init: Halting...\n");
+               halt();
+       };
+
+       /* Initialize context map. */
+       for(i=0; i<MAX_CTXS; i++) ctx_tasks[i] = NULL;
+
+       /* Initialize the protection map */
+       protection_map[0] = __P000;
+       protection_map[1] = __P001;
+       protection_map[2] = __P010;
+       protection_map[3] = __P011;
+       protection_map[4] = __P100;
+       protection_map[5] = __P101;
+       protection_map[6] = __P110;
+       protection_map[7] = __P111;
+       protection_map[8] = __S000;
+       protection_map[9] = __S001;
+       protection_map[10] = __S010;
+       protection_map[11] = __S011;
+       protection_map[12] = __S100;
+       protection_map[13] = __S101;
+       protection_map[14] = __S110;
+       protection_map[15] = __S111;
+
+       start_mem = probe_devices(start_mem);
 
-       num_segs -= 1;
-       invalid_segment = num_segs;
+       return start_mem;
+}
 
-       start_mem = free_area_init(start_mem, end_mem);
+extern unsigned long sun4c_test_wp(unsigned long);
+extern void srmmu_test_wp(void);
 
-/* On the sparc we first need to allocate the segmaps for the
- * PROM's virtual space, and make those segmaps unusable. We
- * map the PROM in ALL contexts therefore the break key and the
- * sync command work no matter what state you took the machine
- * out of
- */
+void mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+       int codepages = 0;
+       int reservedpages = 0;
+       int datapages = 0;
+       unsigned long tmp2, addr;
+       extern char etext;
 
-       printk("mapping the prom...\n");
-       num_segs = map_the_prom(num_segs);
+       end_mem &= PAGE_MASK;
+       high_memory = end_mem;
 
        start_mem = PAGE_ALIGN(start_mem);
 
-       /* Set up static page tables in kernel space, this will be used
-        * so that the low-level page fault handler can fill in missing
-        * TLB entries since all mmu entries cannot be loaded at once
-        * on the sun4c.
-        */
-
-#if 0
-       /* ugly debugging code */
-       for(i=0; i<40960; i+=PAGE_SIZE)
-         printk("address=0x%x  vseg=%d  pte=0x%x\n", (unsigned int) i,
-                (int) get_segmap(i), (unsigned int) get_pte(i));
-#endif
-
-       printk("Setting up kernel static mmu table... bounce bounce\n");
-
-       address = 0; /* ((unsigned long) &end) + 524288; */
-       sun4c_mmu_table = (unsigned long *) start_mem;
-       pg_table = (pte_t *) start_mem;
-       curseg = curpte = num_inval = 0;
-       while(address < end_mem) {
-         if(curpte == 0)
-           put_segmap((address&PGDIR_MASK), curseg);
-         for(i=0; sp_banks[i].num_bytes != 0; i++)
-           if((address >= sp_banks[i].base_addr) && 
-              (address <= (sp_banks[i].base_addr + sp_banks[i].num_bytes)))
-             goto good_address;
-         /* No physical memory here, so set the virtual segment to
-          * the invalid one, and put an invalid pte in the static
-          * kernel table.
-          */
-         *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_INVALID);
-         pg_table++; curpte++; num_inval++;
-         if(curpte > 63) {
-           if(curpte == num_inval) {
-             put_segmap((address&PGDIR_MASK), invalid_segment);
-           } else {
-             put_segmap((address&PGDIR_MASK), curseg);
-             curseg++;
-           }
-           curpte = num_inval = 0;
-         }
-         address += PAGE_SIZE;
-         continue;
-
-         good_address:
-         /* create pte entry */
-         if(address < (((unsigned long) &end) + 524288)) {
-           pte_val(*pg_table) = get_pte(address);
-         } else {
-           *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_KERNEL);
-           put_pte(address, pte_val(*pg_table));
-         }
-
-         pg_table++; curpte++;
-         if(curpte > 63) {
-           put_segmap((address&PGDIR_MASK), curseg);
-           curpte = num_inval = 0;
-           curseg++;
-         }
-         address += PAGE_SIZE;
-       }         
-
-       start_mem = (unsigned long) pg_table;
-       /* ok, allocate the kernel pages, map them in all contexts
-        * (with help from the prom), and lock them. Isn't the sparc
-        * fun kiddies? TODO
-        */
-
-#if 0
-       /* ugly debugging code */
-       for(i=0x1a3000; i<(0x1a3000+40960); i+=PAGE_SIZE)
-         printk("address=0x%x  vseg=%d  pte=0x%x\n", (unsigned int) i,
-                (int) get_segmap(i), (unsigned int) get_pte(i));
-       halt();
-#endif
-
-       b=PGDIR_ALIGN(start_mem)>>18;
-       c= (char *)0x0;
-
-       printk("mapping kernel in all contexts...\n");
-
-       for(a=0; a<b; a++)
-         {
-           for(i=0; i<num_contexts; i++)
-             {
-               /* map the kernel virt_addrs */
-               (*(romvec->pv_setctxt))(i, (char *) c, a);
-             }
-           c += 0x40000;
-         }
-
-       /* Ok, since now mapped in all contexts, we can free up
-        * context zero to be used amongst user processes.
-        */
-
-       /* free context 0 here TODO */
-
-       /* invalidate all user pages and initialize the pte struct 
-        * for userland. TODO
-        */
-
-       /* Make the kernel text unwritable and cacheable, the prom
-        * loaded our text as writable, only sneaky sunos kernels need
-        * self-modifying code.
-        */
-
-       a= (unsigned long) &etext;
-       mask=~(PTE_NC|PTE_W);    /* make cacheable + not writable */
-
-       /* must do for every segment since kernel uses all contexts
-        * and unlike some sun kernels I know of, we can't hard wire
-        * context 0 just for the kernel, that is unnecessary.
-        */
-
-       for(i=0; i<8; i++)
-         {
-           b=PAGE_ALIGN((unsigned long) &trapbase);
-
-           switch_to_context(i);
-
-           for(;b<a; b+=4096)
-             {
-               put_pte(b, (get_pte(b) & mask));
-             }
-         }
+       addr = PAGE_OFFSET;
+       while(addr < start_mem) {
+               mem_map[MAP_NR(addr)] = MAP_PAGE_RESERVED;
+               addr += PAGE_SIZE;
+       }
 
-       invalidate(); /* flush the virtual address cache */
+       for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE)
+                       mem_map[MAP_NR(addr)] = 0;
 
-       printk("\nCurrently in context - ");
-       for(i=0; i<num_contexts; i++)
-         {
-           switch_to_context(i);
-           printk("%d ", (int) i);
-         }
-       printk("\n");
+#ifdef CONFIG_SCSI
+       scsi_mem_init(high_memory);
+#endif
 
-       switch_to_context(0);
+       for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+               if(mem_map[MAP_NR(addr)]) {
+                       if (addr < (unsigned long) &etext)
+                               codepages++;
+                       else if(addr < start_mem)
+                               datapages++;
+                       else
+                               reservedpages++;
+                       continue;
+               }
+               mem_map[MAP_NR(addr)] = 1;
+               free_page(addr);
+       }
 
-       invalidate();
-       return start_mem;
-}
+       tmp2 = nr_free_pages << PAGE_SHIFT;
 
-void mem_init(unsigned long start_mem, unsigned long end_mem)
-{
-  unsigned long start_low_mem = PAGE_SIZE;
-  int codepages = 0;
-  int reservedpages = 0;
-  int datapages = 0;
-  int i = 0;
-  unsigned long tmp, limit, tmp2, addr;
-  extern char etext;
-
-  end_mem &= PAGE_MASK;
-  high_memory = end_mem;
-
-  start_low_mem = PAGE_ALIGN(start_low_mem);
-  start_mem = PAGE_ALIGN(start_mem);
-
-  for(i = 0; sp_banks[i].num_bytes != 0; i++) {
-    tmp = sp_banks[i].base_addr;
-    limit = (sp_banks[i].base_addr + sp_banks[i].num_bytes);
-    if(tmp<start_mem) {
-      if(limit>start_mem)
-       tmp = start_mem;
-      else continue;
-    }
-
-    while(tmp<limit) {
-      mem_map[MAP_NR(tmp)] = 0;
-      tmp += PAGE_SIZE;
-    }
-    if(sp_banks[i+1].num_bytes != 0)
-      while(tmp < sp_banks[i+1].base_addr) {
-       mem_map[MAP_NR(tmp)] = MAP_PAGE_RESERVED;
-       tmp += PAGE_SIZE;
-      }
-  }
+       printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+              tmp2 >> 10,
+              (high_memory - PAGE_OFFSET) >> 10,
+              codepages << (PAGE_SHIFT-10),
+              reservedpages << (PAGE_SHIFT-10),
+              datapages << (PAGE_SHIFT-10));
 
-#ifdef CONFIG_SCSI
-  scsi_mem_init(high_memory);
+/* Heh, test write protection just like the i386, this is bogus but it is
+ * fun to do ;)
+ */
+       switch(sparc_cpu_model) {
+       case sun4c:
+               start_mem = sun4c_test_wp(start_mem);
+               break;
+       case sun4m:
+       case sun4d:
+       case sun4e:
+               srmmu_test_wp();
+               break;
+       default:
+               printk("mem_init: Could not test WP bit on this machine.\n");
+               printk("mem_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+               printk("mem_init: Halting...\n");
+               halt();
+       };
+
+#ifdef DEBUG_MEMINIT
+       printk("Breaker breaker...Roger roger.... Over and out...\n");
 #endif
+       invalidate();
 
-  for (addr = 0; addr < high_memory; addr += PAGE_SIZE) {
-    if(mem_map[MAP_NR(addr)]) {
-      if (addr < (unsigned long) &etext)
-       codepages++;
-      else if(addr < start_mem)
-       datapages++;
-      else
-       reservedpages++;
-      continue;
-    }
-    mem_map[MAP_NR(addr)] = 1;
-    free_page(addr);
-  }
-
-  tmp2 = nr_free_pages << PAGE_SHIFT;
-
-  printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
-        tmp2 >> 10,
-        high_memory >> 10,
-        codepages << (PAGE_SHIFT-10),
-        reservedpages << (PAGE_SHIFT-10),
-        datapages << (PAGE_SHIFT-10));
-
-  invalidate();
-  return;
+       return;
 }
 
 void si_meminfo(struct sysinfo *val)
diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c
new file mode 100644 (file)
index 0000000..c0ca5fc
--- /dev/null
@@ -0,0 +1,118 @@
+/* loadmmu.c:  This code loads up all the mm function pointers once the
+ *             machine type has been determined.  It also sets the static
+ *             mmu values such as PAGE_NONE, etc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+void (*invalidate)(void);
+
+unsigned int pmd_shift, pmd_size, pmd_mask;
+unsigned int (*pmd_align)(unsigned int);
+unsigned int pgdir_shift, pgdir_size, pgdir_mask;
+unsigned int (*pgdir_align)(unsigned int);
+unsigned int ptrs_per_pte, ptrs_per_pmd, ptrs_per_pgd;
+
+pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel;
+pgprot_t page_invalid;
+
+/* Grrr... function pointers galore... */
+unsigned long (*pte_page)(pte_t);
+unsigned long (*pmd_page)(pmd_t);
+unsigned long (*pgd_page)(pgd_t);
+
+void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
+unsigned long (*(vmalloc_start))(void);
+void (*switch_to_context)(int);
+
+int (*pte_none)(pte_t);
+int (*pte_present)(pte_t);
+int (*pte_inuse)(pte_t *);
+void (*pte_clear)(pte_t *);
+void (*pte_reuse)(pte_t *);
+
+int (*pmd_none)(pmd_t);
+int (*pmd_bad)(pmd_t);
+int (*pmd_present)(pmd_t);
+int (*pmd_inuse)(pmd_t *);
+void (*pmd_clear)(pmd_t *);
+void (*pmd_reuse)(pmd_t *);
+
+int (*pgd_none)(pgd_t);
+int (*pgd_bad)(pgd_t);
+int (*pgd_present)(pgd_t);
+int (*pgd_inuse)(pgd_t *);
+void (*pgd_clear)(pgd_t *);
+void (*pgd_reuse)(pgd_t *);
+
+pte_t (*mk_pte)(unsigned long, pgprot_t);
+void (*pgd_set)(pgd_t *, pte_t *);
+pte_t (*pte_modify)(pte_t, pgprot_t);
+pgd_t * (*pgd_offset)(struct task_struct *, unsigned long);
+pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
+pte_t * (*pte_offset)(pmd_t *, unsigned long);
+void (*pte_free_kernel)(pte_t *);
+pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
+
+void (*pmd_free_kernel)(pmd_t *);
+pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
+void (*pte_free)(pte_t *);
+pte_t * (*pte_alloc)(pmd_t *, unsigned long);
+
+void (*pmd_free)(pmd_t *);
+pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
+void (*pgd_free)(pgd_t *);
+
+pgd_t * (*pgd_alloc)(void);
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int (*pte_read)(pte_t);
+int (*pte_write)(pte_t);
+int (*pte_exec)(pte_t);
+int (*pte_dirty)(pte_t);
+int (*pte_young)(pte_t);
+int (*pte_cow)(pte_t);
+
+pte_t (*pte_wrprotect)(pte_t);
+pte_t (*pte_rdprotect)(pte_t);
+pte_t (*pte_exprotect)(pte_t);
+pte_t (*pte_mkclean)(pte_t);
+pte_t (*pte_mkold)(pte_t);
+pte_t (*pte_uncow)(pte_t);
+pte_t (*pte_mkwrite)(pte_t);
+pte_t (*pte_mkread)(pte_t);
+pte_t (*pte_mkexec)(pte_t);
+pte_t (*pte_mkdirty)(pte_t);
+pte_t (*pte_mkyoung)(pte_t);
+pte_t (*pte_mkcow)(pte_t);
+
+extern void ld_mmu_sun4c(void);
+extern void ld_mmu_srmmu(void);
+
+void
+load_mmu(void)
+{
+       switch(sparc_cpu_model) {
+       case sun4c:
+               ld_mmu_sun4c();
+               break;
+       case sun4m:
+       case sun4d:
+       case sun4e:
+               ld_mmu_srmmu();
+               break;
+       default:
+               printk("load_mmu:  MMU support not available for this architecture\n");
+               printk("load_mmu:  sparc_cpu_model = %d\n", (int) sparc_cpu_model);
+               printk("load_mmu:  Halting...\n");
+               halt();
+       };
+       return;
+}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
new file mode 100644 (file)
index 0000000..b4941e4
--- /dev/null
@@ -0,0 +1,912 @@
+/* srmmu.c:  SRMMU specific routines for memory management.
+ *
+ * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@lab.ipmce.su)
+ */
+
+#include <linux/kernel.h>  /* for printk */
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/kdebug.h>
+#include <asm/vaddrs.h>
+#include <asm/traps.h>
+#include <asm/mp.h>
+#include <asm/cache.h>
+#include <asm/oplib.h>
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
+unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+
+/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job.
+ * Many of the page table/directory functions on the SRMMU use this
+ * routine.
+ *
+ * Having a complete physical ram structure walk happen for each
+ * invocation is quite costly.  However, this does do some nice
+ * sanity checking and we'll see when our maps don't match.  Eventually
+ * when I trust my code I will just do a direct mmu probe in mk_pte().
+ */
+static inline unsigned int
+srmmu_virt_to_phys(unsigned int vaddr)
+{
+       unsigned int paddr = 0;
+       unsigned int voff = (vaddr - PAGE_OFFSET);
+       int i;
+
+       for(i=0; sp_banks[i].num_bytes != 0; i++) {
+               if(voff < paddr + sp_banks[i].num_bytes) {
+                       /* This matches. */
+                       return sp_banks[i].base_addr + voff - paddr;
+               } else
+                       paddr += sp_banks[i].num_bytes;
+       }
+       /* Shit, gotta consult the MMU, this shouldn't happen... */
+       printk("srmmu_virt_to_phys: SRMMU virt to phys translation failed, halting\n");
+       halt();
+}              
+
+static inline unsigned long
+srmmu_phys_to_virt(unsigned long paddr)
+{
+        int i;
+        unsigned long offset = PAGE_OFFSET;
+
+        for (i=0; sp_banks[i].num_bytes != 0; i++)
+        {
+                if (paddr >= sp_banks[i].base_addr &&
+                    paddr < (sp_banks[i].base_addr
+                             + sp_banks[i].num_bytes)) {
+                        return (paddr - sp_banks[i].base_addr) + offset;
+                } else
+                        offset += sp_banks[i].num_bytes;
+        }
+       printk("srmmu_phys_to_virt: Could not make translation, halting...\n");
+       halt();
+}
+
+unsigned long
+srmmu_vmalloc_start(void)
+{
+       return ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1));
+}
+
+unsigned long 
+srmmu_pmd_page(pmd_t pmd)
+{
+       unsigned long page;
+
+       page = (pmd_val(pmd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
+       return srmmu_phys_to_virt(page);
+}
+
+unsigned long
+srmmu_pgd_page(pgd_t pgd)
+{
+       unsigned long page;
+
+       page = (pgd_val(pgd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
+       return srmmu_phys_to_virt(page);
+}
+
+unsigned long 
+srmmu_pte_page(pte_t pte)
+{
+       unsigned long page;
+
+       page = (pte_val(pte) & (SRMMU_PTE_PPN_MASK)) << SRMMU_PTE_PPN_PADDR_SHIFT;
+       printk("srmmu_pte_page: page = %08lx\n", page);
+       return srmmu_phys_to_virt(page);
+}
+
+int srmmu_pte_none(pte_t pte)          { return !pte_val(pte); }
+int srmmu_pte_present(pte_t pte)       { return pte_val(pte) & SRMMU_ET_PTE; }
+int srmmu_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] != 1; }
+void srmmu_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
+void srmmu_pte_reuse(pte_t *ptep)
+{
+  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(ptep)]++;
+}
+
+int srmmu_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
+int srmmu_pmd_bad(pmd_t pmd)
+{
+       return ((pmd_val(pmd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
+               (srmmu_pmd_page(pmd) > high_memory);
+}
+
+int srmmu_pmd_present(pmd_t pmd)       { return pmd_val(pmd) & SRMMU_ET_PTD; }
+int srmmu_pmd_inuse(pmd_t *pmdp)        { return mem_map[MAP_NR(pmdp)] != 1; }
+void srmmu_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
+void srmmu_pmd_reuse(pmd_t * pmdp)
+{
+        if (!(mem_map[MAP_NR(pmdp)] & MAP_PAGE_RESERVED))
+                mem_map[MAP_NR(pmdp)]++;
+}
+
+int srmmu_pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
+int srmmu_pgd_bad(pgd_t pgd)
+{
+       return ((pgd_val(pgd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
+               (srmmu_pgd_page(pgd) > high_memory);
+}
+int srmmu_pgd_present(pgd_t pgd)       { return pgd_val(pgd) & SRMMU_ET_PTD; }
+int srmmu_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] != 1; }
+void srmmu_pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
+void srmmu_pgd_reuse(pgd_t *pgdp)
+{
+  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(pgdp)]++;
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int srmmu_pte_read(pte_t pte)          { return (pte_val(pte) & _SRMMU_PAGE_RDONLY) || (pte_val(pte) & _SRMMU_PAGE_WRITE_USR); }
+int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_WRITE_USR; }
+int srmmu_pte_exec(pte_t pte)          { return pte_val(pte) & _SRMMU_PAGE_EXEC; }
+int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_DIRTY; }
+int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_REF; }
+int srmmu_pte_cow(pte_t pte)           { return pte_val(pte) & _SRMMU_PAGE_COW; }
+
+/* When we change permissions, we first clear all bits in the ACCESS field
+ * then apply the wanted bits.
+ */
+pte_t srmmu_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
+pte_t srmmu_pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_NOREAD; return pte; }
+pte_t srmmu_pte_exprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
+pte_t srmmu_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_SRMMU_PAGE_DIRTY; return pte; }
+pte_t srmmu_pte_mkold(pte_t pte)       { pte_val(pte) &= ~_SRMMU_PAGE_REF; return pte; }
+pte_t srmmu_pte_uncow(pte_t pte)       { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_UNCOW; return pte; }
+pte_t srmmu_pte_mkwrite(pte_t pte)     { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
+pte_t srmmu_pte_mkread(pte_t pte)      { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_RDONLY; return pte; }
+pte_t srmmu_pte_mkexec(pte_t pte)      { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
+pte_t srmmu_pte_mkdirty(pte_t pte)     { pte_val(pte) |= _SRMMU_PAGE_DIRTY; return pte; }
+pte_t srmmu_pte_mkyoung(pte_t pte)     { pte_val(pte) |= _SRMMU_PAGE_REF; return pte; }
+pte_t srmmu_pte_mkcow(pte_t pte)       { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+pte_t
+srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
+{
+       pte_t pte;
+
+       if(page & (~PAGE_MASK)) panic("srmmu_mk_pte() called with unaligned page");
+       page = (srmmu_virt_to_phys(page) >> SRMMU_PTE_PPN_PADDR_SHIFT);
+       pte_val(pte) = (page & SRMMU_PTE_PPN_MASK);
+       pte_val(pte) |= pgprot_val(pgprot);
+       return pte;
+}
+
+void
+srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+       unsigned long page = (unsigned long) pmdp;
+
+       page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+
+       pgd_val(*pgdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
+}
+
+void
+srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+       unsigned long page = (unsigned long) ptep;
+
+       page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+
+       pmd_val(*pmdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
+}
+
+pte_t
+srmmu_pte_modify(pte_t pte, pgprot_t newprot)
+{
+       pte_val(pte) = (pte_val(pte) & (~SRMMU_PTE_ACC_MASK)) | pgprot_val(newprot);
+       return pte;
+}
+
+/* to find an entry in a top-level page table... */
+pgd_t *
+srmmu_pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+       return ((pgd_t *) tsk->tss.pgd_ptr) +
+               ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1));
+}
+
+/* Find an entry in the second-level page table.. */
+pmd_t *
+srmmu_pmd_offset(pgd_t * dir, unsigned long address)
+{
+       return ((pmd_t *) pgd_page(*dir)) +
+               ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+}
+
+/* Find an entry in the third-level page table.. */ 
+pte_t *
+srmmu_pte_offset(pmd_t * dir, unsigned long address)
+{
+       return ((pte_t *) pmd_page(*dir)) +
+               ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+}
+
+/* This must update the context register for this process. */
+void
+srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) 
+{
+       /* See if this process has a context entry already, like after execve() */
+       if(tsk->tss.context != -1) {
+               pgd_t *ctable_ptr = 0;
+               ctable_ptr = (pgd_t *) srmmu_phys_to_virt(srmmu_get_ctable_ptr());
+               ctable_ptr += tsk->tss.context;
+               srmmu_pgd_set(ctable_ptr, (pmd_t *) pgdir);
+               /* Should flush caches here too... */
+               srmmu_flush_whole_tlb();
+       }
+
+       tsk->tss.pgd_ptr = (unsigned long) pgdir;
+
+       return;
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+void
+srmmu_pte_free_kernel(pte_t *pte)
+{
+       mem_map[MAP_NR(pte)] = 1;
+       free_page((unsigned long) pte);
+}
+
+pte_t *
+srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+       pte_t *page;
+
+       address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
+       if (srmmu_pmd_none(*pmd)) {
+               page = (pte_t *) get_free_page(GFP_KERNEL);
+               if (srmmu_pmd_none(*pmd)) {
+                       if (page) {
+                               srmmu_pmd_set(pmd, page);
+                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+                               return page + address;
+                       }
+                       srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (srmmu_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+               srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+               return NULL;
+       }
+       return (pte_t *) srmmu_pmd_page(*pmd) + address;
+}
+
+/* Full three level on SRMMU */
+void
+srmmu_pmd_free_kernel(pmd_t *pmd)
+{
+       mem_map[MAP_NR(pmd)] = 1;
+       free_page((unsigned long) pmd);
+}
+
+pmd_t *
+srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+       pmd_t *page;
+
+       address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
+       if (srmmu_pgd_none(*pgd)) {
+               page = (pmd_t *) get_free_page(GFP_KERNEL);
+               if (srmmu_pgd_none(*pgd)) {
+                       if (page) {
+                               srmmu_pgd_set(pgd, page);
+                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+                               return page + address;
+                       }
+                       srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (srmmu_pgd_bad(*pgd)) {
+               printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+               srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+               return NULL;
+       }
+       return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+}
+
+void
+srmmu_pte_free(pte_t *pte)
+{
+       free_page((unsigned long) pte);
+}
+
+pte_t *
+srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
+{
+       pte_t *page;
+
+       address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
+       if (srmmu_pmd_none(*pmd)) {
+               page = (pte_t *) get_free_page(GFP_KERNEL);
+               if (srmmu_pmd_none(*pmd)) {
+                       if (page) {
+                               srmmu_pmd_set(pmd, page);
+                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+                               return page + address;
+                       }
+                       srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (srmmu_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+               srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+               return NULL;
+       }
+       return (pte_t *) srmmu_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void 
+srmmu_pmd_free(pmd_t * pmd)
+{
+       free_page((unsigned long) pmd);
+}
+
+pmd_t *
+srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+       pmd_t *page;
+
+       address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
+       if (srmmu_pgd_none(*pgd)) {
+               page = (pmd_t *) get_free_page(GFP_KERNEL);
+               if (srmmu_pgd_none(*pgd)) {
+                       if (page) {
+                               srmmu_pgd_set(pgd, page);
+                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+                               return page + address;
+                       }
+                       srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (srmmu_pgd_bad(*pgd)) {
+               printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+               srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+               return NULL;
+       }
+       return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+}
+
+void
+srmmu_pgd_free(pgd_t *pgd)
+{
+       free_page((unsigned long) pgd);
+}
+
+/* A page directory on the srmmu needs 1k, but for now to simplify the
+ * alignment constraints and allocation we just grab a whole page.
+ */
+
+pgd_t *
+srmmu_pgd_alloc(void)
+{
+       return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+/* Just flush the whole thing for now. We will need module
+ * specific invalidate routines in certain circumstances,
+ * because of different flushing facilities and hardware
+ * bugs.
+ */
+void
+srmmu_invalidate(void)
+{
+       srmmu_flush_whole_tlb();
+       return;
+}
+
+/* XXX Needs to be written */
+void
+srmmu_switch_to_context(int context)
+{
+       printk("switching to context %d\n", context);
+
+       return;
+}
+
+/* Low level IO area allocation on the SRMMU.
+ *
+ * I think we can get away with just using a regular page translation,
+ * just making sure the cacheable bit is off.  I would like to avoid
+ * having to mess with the IOMMU if at all possible at first.
+ *
+ * Aparently IOMMU is only necessary for SBus devices, maybe VME too.
+ * We'll see...
+ */
+void
+srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+               int bus_type, int rdonly)
+{
+  pgd_t *pgdp;
+  pmd_t *pmdp;
+  pte_t *ptep;
+
+  pgdp = srmmu_pgd_offset(&init_task, virt_addr);
+  pmdp = srmmu_pmd_offset(pgdp, virt_addr);
+  ptep = srmmu_pte_offset(pmdp, virt_addr);
+  pte_val(*ptep) = (physaddr >> SRMMU_PTE_PPN_PADDR_SHIFT) & SRMMU_PTE_PPN_MASK;
+
+  if(!rdonly)
+         pte_val(*ptep) |= (SRMMU_ACC_S_RDWREXEC | SRMMU_ET_PTE);
+  else
+         pte_val(*ptep) |= (SRMMU_ACC_S_RDEXEC | SRMMU_ET_PTE);
+
+  pte_val(*ptep) |= (bus_type << 28);
+  pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK); /* Make sure cacheable bit is off. */
+  srmmu_flush_whole_tlb();
+  flush_ei_ctx(0x0);
+
+  return;
+}
+
+/* Perfom a some soft of MMU tablewalk.
+ * Long contiguous mappings are not supported (yet ?).
+ *
+ * Origionally written by Peter Zaitcev, modified by David S.
+ * Miller.  This is only used to copy over the PROM/KADB mappings
+ * in srmmu_paging_init().
+ *
+ * The return value encodes at what level the entry was found,
+ * basically this is found in the lower 2 bits of the return
+ * value.  If the return value is zero, there was no valid mapping
+ * found at all, the low bits for a non-zero return value
+ * are:
+ *         0 -- Level 1 PTE
+ *         1 -- Level 2 PTE
+ *         2 -- Normal level 3 PTE
+ *         3 -- Context Table PTE (unlikely, but still)
+ * 
+ * Also note that this is called before the context table pointer
+ * register is changed, so the PROMs entry is still in there.  Also,
+ * it is safe to assume that the context 0 contains the mappings.
+ */
+/* TODO chop out 'trace' when stable */
+unsigned int
+srmmu_init_twalk(unsigned virt, int trace)
+{
+       unsigned int wh, root;
+
+       root = (unsigned int) srmmu_get_ctable_ptr();
+       if(trace) printk(":0x%x >> ", virt);
+
+       if(trace) printk(" 0x%x :", root);
+       wh = ldw_sun4m_bypass(root);
+       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+               if(trace) printk("\n");
+               return 0;
+       }
+       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+               wh &= ~SRMMU_PTE_ET_MASK;
+               wh |= 0x3;
+               if(trace) printk("\n");
+               printk("AIEEE context table level pte prom mapping!\n");
+               prom_halt();
+               return 0;
+       }
+               
+       if(trace) printk(" 0x%x .", wh);
+       wh = ldw_sun4m_bypass(
+                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
+                             + ((virt & SRMMU_IDX1_MASK) >> SRMMU_IDX1_SHIFT)*sizeof(pte_t));
+
+       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+               if(trace) printk("\n");
+               return 0;
+       }
+       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+               wh &= ~SRMMU_PTE_ET_MASK;
+               if(trace) printk("\n");
+               return wh;
+       }
+
+       if(trace) printk(" 0x%x .", wh);
+       wh = ldw_sun4m_bypass(
+                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
+                             + ((virt & SRMMU_IDX2_MASK) >> SRMMU_IDX2_SHIFT)*sizeof(pte_t));
+       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+               if(trace) printk("\n");
+               return 0;
+       }
+       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+               wh &= ~SRMMU_PTE_ET_MASK;
+               wh |= 0x1;
+               if(trace) printk("\n");
+               return wh;
+       }
+
+       if(trace) printk(" 0x%x .", wh);
+       wh = ldw_sun4m_bypass(
+                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
+                             + ((virt & SRMMU_IDX3_MASK) >> SRMMU_IDX3_SHIFT)*sizeof(pte_t));
+       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+               if(trace) printk("\n");
+               return 0;
+       }
+       if(trace) printk(" 0x%x\n", wh);
+       return wh;
+}
+
+
+/* Allocate a block of RAM which is aligned to its size.
+ * This procedure can be used until the call to mem_init().
+ *
+ * To get around the elf bootloader nastyness we have a
+ * early-on page table pool allocation area starting at
+ * C_LABEL(pg0) which is 256k, this should be enough for now.
+ */
+static void *
+srmmu_init_alloc(unsigned long *kbrk, unsigned size)
+{
+       register unsigned mask = size - 1;
+       register unsigned long ret;
+
+       if(size==0) return 0x0;
+       if(size & mask) {
+               printk("panic: srmmu_init_alloc botch\n");
+               prom_halt();
+       }
+       ret = (*kbrk + mask) & ~mask;
+       *kbrk = ret + size;
+       memset((void*) ret, 0, size);
+       return (void*) ret;
+}
+
+extern unsigned long srmmu_data_fault, srmmu_text_fault;
+
+/* Patch in the SRMMU fault handlers for the trap table. */
+void
+srmmu_patch_fhandlers(void)
+{
+       /* Say the following ten times fast... */
+       sparc_ttable[SP_TRAP_TFLT].inst_one = SPARC_MOV_CONST_L3(0x1);
+       sparc_ttable[SP_TRAP_TFLT].inst_two =
+               SPARC_BRANCH((unsigned long) &srmmu_text_fault, 
+                            (unsigned long) &sparc_ttable[SP_TRAP_TFLT].inst_two);
+       sparc_ttable[SP_TRAP_TFLT].inst_three = SPARC_RD_PSR_L0;
+       sparc_ttable[SP_TRAP_TFLT].inst_four = SPARC_NOP;
+
+       sparc_ttable[SP_TRAP_DFLT].inst_one = SPARC_MOV_CONST_L3(0x9);
+       sparc_ttable[SP_TRAP_DFLT].inst_two =
+               SPARC_BRANCH((unsigned long) &srmmu_data_fault,
+                            (unsigned long) &sparc_ttable[SP_TRAP_DFLT].inst_two);
+       sparc_ttable[SP_TRAP_DFLT].inst_three = SPARC_RD_PSR_L0;
+       sparc_ttable[SP_TRAP_DFLT].inst_four = SPARC_NOP;
+
+       return;
+}
+
+/* Paging initialization on the Sparc Reference MMU. */
+
+/* This is all poorly designed, we cannot assume any pages are valid
+ * past _end until *after* this routine runs, thus we can't use the
+ * start_mem mechanism during initialization...
+ */
+static unsigned long mempool;
+
+/* The following is global because trap_init needs it to fire up
+ * the other cpu's on multiprocessors.
+ */
+pgd_t *lnx_root;      /* Pointer to the new root table */
+
+extern char start[];
+
+unsigned long
+srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+       unsigned long vaddr;  /* Virtual counter */
+       int i;
+
+       pte_t *ptep = 0;
+       pmd_t *pmdp = 0;
+       pgd_t *pgdp = 0;
+
+       mempool = start_mem;
+       lnx_root = srmmu_init_alloc(&mempool, num_contexts*sizeof(pgd_t));
+
+       memset(swapper_pg_dir, 0, PAGE_SIZE);
+
+       /* For every entry in the new Linux context table, put in
+        * an entry which points to swapper_pg_dir .
+        */
+       pmdp = (pmd_t *) swapper_pg_dir;
+       for(i = 0; i < num_contexts; i++)
+               srmmu_pgd_set(&lnx_root[i], pmdp);
+
+       /* Make Linux physical page tables. */
+       for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
+               pgdp = srmmu_pgd_offset(&init_task, vaddr);
+               if(srmmu_pgd_none(*pgdp)) {
+                       pmdp = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                       srmmu_pgd_set(pgdp, pmdp);
+               }
+
+               pmdp = srmmu_pmd_offset(pgdp, vaddr);
+               if(srmmu_pmd_none(*pmdp)) {
+                       ptep = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                       srmmu_pmd_set(pmdp, ptep);
+               }
+
+               ptep = srmmu_pte_offset(pmdp, vaddr);
+               *ptep = srmmu_mk_pte(vaddr, SRMMU_PAGE_KERNEL);
+       }
+
+       /* Map IO areas. */
+       for(vaddr = IOBASE_VADDR; vaddr < (IOBASE_VADDR+IOBASE_LEN);
+           vaddr += SRMMU_PMD_SIZE) {
+               pgdp = srmmu_pgd_offset(&init_task, vaddr);
+               if(srmmu_pgd_none(*pgdp)) {
+                       pmdp = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                       srmmu_pgd_set(pgdp, pmdp);
+               }
+               pmdp = srmmu_pmd_offset(pgdp, vaddr);
+               if(srmmu_pmd_none(*pmdp)) {
+                       ptep = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                       srmmu_pmd_set(pmdp, ptep);
+               }
+       }
+
+       /* Map in the PERCPU areas in virtual address space. */
+       printk("PERCPU_VADDR + PERCPU_LEN = %08lx\n",
+              (PERCPU_VADDR + PERCPU_LEN));
+       for(vaddr = PERCPU_VADDR; vaddr < (PERCPU_VADDR + PERCPU_LEN);
+           vaddr += PERCPU_ENTSIZE) {
+               pgdp = srmmu_pgd_offset(&init_task, vaddr);
+               if(srmmu_pgd_none(*pgdp)) {
+                       pmdp = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                       srmmu_pgd_set(pgdp, pmdp);
+               }
+               pmdp = srmmu_pmd_offset(pgdp, vaddr);
+               if(srmmu_pmd_none(*pmdp)) {
+                       ptep = srmmu_init_alloc(&mempool,
+                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                       srmmu_pmd_set(pmdp, ptep);
+               }
+               ptep = srmmu_pte_offset(pmdp, vaddr);
+               /* Per-cpu trap table page. */
+               *ptep++ = srmmu_mk_pte((unsigned int) start, SRMMU_PAGE_KERNEL);
+               /* Per-cpu kernel stack page. */
+               *ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+                                      SRMMU_PAGE_KERNEL);
+               /* Per-cpu Prom MBox. */
+               *ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+                                      SRMMU_PAGE_KERNEL);
+               /* Per-cpu state variables. */
+               *ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+                                    SRMMU_PAGE_KERNEL);
+       }
+       percpu_table = (struct sparc_percpu *) PERCPU_VADDR;
+
+       /* Ugh, have to map DVMA that the prom has mapped too or else
+        * you will lose with video cards when we take over the ctx table.
+        * Also, must take into consideration that prom might be using level
+        * two or one PTE's. TODO
+        */
+       for(vaddr = KADB_DEBUGGER_BEGVM; vaddr != 0x0;) {
+               unsigned int prom_pte;
+
+               prom_pte = srmmu_init_twalk(vaddr, 0);
+
+               if(prom_pte) {
+                       pgdp = srmmu_pgd_offset(&init_task, vaddr);
+                       if((prom_pte&0x3) == 0x0) {
+                               prom_pte &= ~0x3;
+                               prom_pte |= SRMMU_ET_PTE;
+                               pgd_val(*pgdp) = prom_pte;
+                               vaddr = SRMMU_PGDIR_ALIGN(vaddr+1);
+                               continue;
+                       }
+                       if(srmmu_pgd_none(*pgdp)) {
+                               pmdp = srmmu_init_alloc(&mempool,
+                                                       SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                               srmmu_pgd_set(pgdp, pmdp);
+                       }
+
+                       pmdp = srmmu_pmd_offset(pgdp, vaddr);
+                       if((prom_pte&0x3) == 0x1) {
+                               prom_pte &= ~0x3;
+                               prom_pte |= SRMMU_ET_PTE;
+                               pgd_val(*pgdp) = prom_pte;
+                               vaddr = SRMMU_PMD_ALIGN(vaddr+1);
+                               continue;
+                       }
+                       if(srmmu_pmd_none(*pmdp)) {
+                               ptep = srmmu_init_alloc(&mempool,
+                                                       SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                               srmmu_pmd_set(pmdp, ptep);
+                       }
+                       /* A normal 3rd level PTE, no need to change ET bits. */
+                       ptep = srmmu_pte_offset(pmdp, vaddr);
+                       pte_val(*ptep) = prom_pte;
+
+               }
+               vaddr += PAGE_SIZE;
+       }
+
+       /* I believe I do not need to flush VAC here since my stores  */
+        /* probably already reached the physical RAM.             --P3 */
+
+       /* We probably do, and should do it just to be safe... -Davem */
+
+       /* Take the MMU over from the PROM */
+       printk("Taking over MMU from PROM.\n");
+
+       srmmu_set_ctable_ptr(srmmu_virt_to_phys((unsigned)lnx_root));
+
+       srmmu_flush_whole_tlb();
+
+       /* Now it is ok to use memory at start_mem. */
+       start_mem = PAGE_ALIGN(mempool);
+       start_mem = free_area_init(start_mem, end_mem);
+       start_mem = PAGE_ALIGN(start_mem);
+
+#if 0
+       printk("Testing context switches...\n");
+       for(i=0; i<num_contexts; i++)
+               srmmu_set_context(i);
+       printk("done...\n");
+       srmmu_set_context(0);
+#endif
+
+       printk("survived...\n");
+       return start_mem;
+}
+
+/* Test the WP bit on the Sparc Reference MMU. */
+void
+srmmu_test_wp(void)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       
+       wp_works_ok = -1;
+       /* We mapped page zero as a read-only page in paging_init()
+        * So fire up the test, then invalidate the pgd for page zero.
+        * It is no longer needed.
+        */
+
+       /* Let it rip... */
+       __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+       if (wp_works_ok < 0)
+               wp_works_ok = 0;
+
+       pgdp = srmmu_pgd_offset(&init_task, 0x0);
+       pgd_val(*pgdp) = 0x0;
+
+       return;
+}
+
+/* Load up routines and constants for sun4m mmu */
+void
+ld_mmu_srmmu(void)
+{
+       printk("Loading srmmu MMU routines\n");
+
+       /* First the constants */
+       pmd_shift = SRMMU_PMD_SHIFT;
+       pmd_size = SRMMU_PMD_SIZE;
+       pmd_mask = SRMMU_PMD_MASK;
+       pgdir_shift = SRMMU_PGDIR_SHIFT;
+       pgdir_size = SRMMU_PGDIR_SIZE;
+       pgdir_mask = SRMMU_PGDIR_MASK;
+
+       ptrs_per_pte = SRMMU_PTRS_PER_PTE;
+       ptrs_per_pmd = SRMMU_PTRS_PER_PMD;
+       ptrs_per_pgd = SRMMU_PTRS_PER_PGD;
+
+       page_none = SRMMU_PAGE_NONE;
+       page_shared = SRMMU_PAGE_SHARED;
+       page_copy = SRMMU_PAGE_COPY;
+       page_readonly = SRMMU_PAGE_READONLY;
+       page_kernel = SRMMU_PAGE_KERNEL;
+       page_invalid = SRMMU_PAGE_INVALID;
+       
+       /* Functions */
+       invalidate = srmmu_invalidate;
+       switch_to_context = srmmu_switch_to_context;
+       pmd_align = srmmu_pmd_align;
+       pgdir_align = srmmu_pgdir_align;
+       vmalloc_start = srmmu_vmalloc_start;
+
+       pte_page = srmmu_pte_page;
+       pmd_page = srmmu_pmd_page;
+       pgd_page = srmmu_pgd_page;
+
+       sparc_update_rootmmu_dir = srmmu_update_rootmmu_dir;
+
+       pte_none = srmmu_pte_none;
+       pte_present = srmmu_pte_present;
+       pte_inuse = srmmu_pte_inuse;
+       pte_clear = srmmu_pte_clear;
+       pte_reuse = srmmu_pte_reuse;
+
+       pmd_none = srmmu_pmd_none;
+       pmd_bad = srmmu_pmd_bad;
+       pmd_present = srmmu_pmd_present;
+       pmd_inuse = srmmu_pmd_inuse;
+       pmd_clear = srmmu_pmd_clear;
+       pmd_reuse = srmmu_pmd_reuse;
+
+       pgd_none = srmmu_pgd_none;
+       pgd_bad = srmmu_pgd_bad;
+       pgd_present = srmmu_pgd_present;
+       pgd_inuse = srmmu_pgd_inuse;
+       pgd_clear = srmmu_pgd_clear;
+       pgd_reuse = srmmu_pgd_reuse;
+
+       mk_pte = srmmu_mk_pte;
+       pgd_set = srmmu_pgd_set;  /* XXX needs a cast */
+       pte_modify = srmmu_pte_modify;
+       pgd_offset = srmmu_pgd_offset;
+       pmd_offset = srmmu_pmd_offset;
+       pte_offset = srmmu_pte_offset;
+       pte_free_kernel = srmmu_pte_free_kernel;
+       pmd_free_kernel = srmmu_pmd_free_kernel;
+       pte_alloc_kernel = srmmu_pte_alloc_kernel;
+       pmd_alloc_kernel = srmmu_pmd_alloc_kernel;
+       pte_free = srmmu_pte_free;
+       pte_alloc = srmmu_pte_alloc;
+       pmd_free = srmmu_pmd_free;
+       pmd_alloc = srmmu_pmd_alloc;
+       pgd_free = srmmu_pgd_free;
+       pgd_alloc = srmmu_pgd_alloc;
+
+       pte_read = srmmu_pte_read;
+       pte_write = srmmu_pte_write;
+       pte_exec = srmmu_pte_exec;
+       pte_dirty = srmmu_pte_dirty;
+       pte_young = srmmu_pte_young;
+       pte_cow = srmmu_pte_cow;
+       pte_wrprotect = srmmu_pte_wrprotect;
+       pte_rdprotect = srmmu_pte_rdprotect;
+       pte_exprotect = srmmu_pte_exprotect;
+       pte_mkclean = srmmu_pte_mkclean;
+       pte_mkold = srmmu_pte_mkold;
+       pte_uncow = srmmu_pte_uncow;
+       pte_mkwrite = srmmu_pte_mkwrite;
+       pte_mkread = srmmu_pte_mkread;
+       pte_mkexec = srmmu_pte_mkexec;
+       pte_mkdirty = srmmu_pte_mkdirty;
+       pte_mkyoung = srmmu_pte_mkyoung;
+       pte_mkcow = srmmu_pte_mkcow;
+
+       return;
+}
+
diff --git a/arch/sparc/mm/srmmuinv.c b/arch/sparc/mm/srmmuinv.c
new file mode 100644 (file)
index 0000000..95a60df
--- /dev/null
@@ -0,0 +1,168 @@
+/* srmmuinv.c:  Invalidate routines for the various different
+ *              SRMMU implementations.
+ *
+ * Copyright (C) 1995 David S. Miller
+ */
+
+/* HyperSparc */
+hyper_invalidate(void)
+{
+       volatile unsigned int sfsr_clear;
+
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       /* Flush ICACHE */
+       flush_whole_icache();
+       sfsr_clear = srmmu_get_fstatus();
+       return;
+}
+
+hyper_invalidate_mp(void)
+{
+       volatile unsigned int sfsr_clear;
+
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       /* Flush ICACHE */
+       flush_whole_icache();
+
+       sfsr_clear = srmmu_get_fstatus();
+
+       /* Tell other CPUS to each call the Uniprocessor
+        * invalidate routine.
+        */
+
+       return;
+}
+
+/* Cypress */
+void
+cypress_invalidate(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+void
+cypress_invalidate_mp(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       /* Tell other CPUS to call the UP version */
+
+       return;
+}
+
+void
+cypress_invalidate_asibad(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache w/o using ASIs */
+
+       return;
+}
+
+void
+cypress_invalidate_asibad_mp(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache w/o using ASIs */
+
+       /* Tell other CPUS to call the UP version */
+
+       return;
+}
+
+/* Swift */
+void
+swift_invalidate(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+void
+swift_invalidate_poke_kernel_pageperms(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+void
+swift_invalidate_poke_kernel_pte_cbits(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+void
+swift_invalidate_poke_everything(void)
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+/* Tsunami */
+tsunami_invalidate()
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Flush Virtual Address Cache */
+
+       return;
+}
+
+/* Viking */
+viking_invalidate()
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       return;
+}
+
+viking_invalidate_mp()
+{
+       /* Flush TLB */
+       srmmu_flush_whole_tlb();
+
+       /* Make other CPUS call UP routine. */
+
+       return;
+}
+
+/* That should be it */
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
new file mode 100644 (file)
index 0000000..c14d44a
--- /dev/null
@@ -0,0 +1,701 @@
+/* sun4c.c:  Sun4C specific mm routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
+ * where only so many translations can be loaded at once.  As Linus said
+ * in Boston, this is a broken way of doing things.
+ *
+ * NOTE:  Free page pool and tables now live in high memory, see
+ *        asm-sparc/pgtsun4c.c and asm-sparc/page.h for details.
+ */
+
+#include <linux/kernel.h>  /* for printk */
+#include <linux/sched.h>
+
+#include <asm/processor.h> /* for wp_works_ok */
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/vac-ops.h>
+#include <asm/vaddrs.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <asm/kdebug.h>
+
+unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
+unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+
+extern int num_segmaps, num_contexts;
+
+/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job.
+ * The only function that actually uses this is sun4c_mk_pte() and
+ * to have a complete physical ram structure walk happen for each
+ * invocation is quite costly.  However, this does do some nice
+ * sanity checking and we'll see when our maps don't match.  Eventually
+ * when I trust my code I will just do a direct mmu probe in mk_pte().
+ */
+static inline unsigned int sun4c_virt_to_phys(unsigned int vaddr)
+{
+       unsigned int paddr = 0;
+       unsigned int voff = (vaddr - PAGE_OFFSET);
+       int i;
+
+       for(i=0; sp_banks[i].num_bytes != 0; i++) {
+               if(voff < paddr + sp_banks[i].num_bytes) {
+                       /* This matches. */
+                       return sp_banks[i].base_addr + voff - paddr;
+               } else
+                       paddr += sp_banks[i].num_bytes;
+       }
+       /* Shit, gotta consult the MMU, this shouldn't happen... */
+       printk("sun4c_virt_to_phys: Could not make translation for vaddr %08lx\n", (unsigned long) vaddr);
+       SP_ENTER_DEBUGGER;
+}              
+
+static inline unsigned long
+sun4c_phys_to_virt(unsigned long paddr)
+{
+        int i;
+        unsigned long offset = PAGE_OFFSET;
+
+        for (i=0; sp_banks[i].num_bytes != 0; i++)
+        {
+                if (paddr >= sp_banks[i].base_addr &&
+                    paddr < (sp_banks[i].base_addr
+                             + sp_banks[i].num_bytes)) {
+                        return (paddr - sp_banks[i].base_addr) + offset;
+                } else
+                        offset += sp_banks[i].num_bytes;
+        }
+       printk("sun4c_phys_to_virt: Could not make translation for paddr %08lx\n", (unsigned long) paddr);
+       SP_ENTER_DEBUGGER;
+}
+
+unsigned long
+sun4c_vmalloc_start(void)
+{
+       return ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1));
+}
+
+/* Note that I have 16 page tables per page, thus four less
+ * bits of shifting than normal.
+ */
+
+unsigned long
+sun4c_pte_page(pte_t pte)
+{
+       unsigned long page;
+
+       page = ((pte_val(pte) & _SUN4C_PFN_MASK) << (PAGE_SHIFT));
+       return sun4c_phys_to_virt(page);
+}
+
+unsigned long 
+sun4c_pmd_page(pmd_t pmd)
+{
+       return ((pmd_val(pmd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
+}
+
+unsigned long
+sun4c_pgd_page(pgd_t pgd)
+{
+       return ((pgd_val(pgd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
+}
+
+/* Update the root mmu directory on the sun4c mmu. */
+void
+sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
+{
+       (tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
+
+       /* May have to do some flushing here. */
+
+       return;
+}
+
+int sun4c_pte_none(pte_t pte)          { return !pte_val(pte); }
+int sun4c_pte_present(pte_t pte)       { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] != 1; }
+void sun4c_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
+void sun4c_pte_reuse(pte_t *ptep)
+{
+  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(ptep)]++;
+}
+
+int sun4c_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
+int sun4c_pmd_bad(pmd_t pmd)
+{
+       return ((pmd_val(pmd) & _SUN4C_PGD_MMU_MASK) != _SUN4C_PAGE_TABLE);
+}
+
+int sun4c_pmd_present(pmd_t pmd)       { return pmd_val(pmd) & _SUN4C_PAGE_VALID; }
+int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
+void sun4c_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
+void sun4c_pmd_reuse(pmd_t * pmdp)      { }
+
+int sun4c_pgd_none(pgd_t pgd)          { return 0; }
+int sun4c_pgd_bad(pgd_t pgd)           { return 0; }
+int sun4c_pgd_present(pgd_t pgd)       { return 1; }
+int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] != 1; }
+void sun4c_pgd_clear(pgd_t * pgdp)     { }
+void sun4c_pgd_reuse(pgd_t *pgdp)
+{
+  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(pgdp)]++;
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int sun4c_pte_read(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_write(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
+int sun4c_pte_exec(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_dirty(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
+int sun4c_pte_young(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_REF; }
+int sun4c_pte_cow(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_COW; }
+
+pte_t sun4c_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
+pte_t sun4c_pte_rdprotect(pte_t pte)   { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_exprotect(pte_t pte)   { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
+pte_t sun4c_pte_mkold(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
+pte_t sun4c_pte_uncow(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
+pte_t sun4c_pte_mkwrite(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
+pte_t sun4c_pte_mkread(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkexec(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkdirty(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
+pte_t sun4c_pte_mkyoung(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
+pte_t sun4c_pte_mkcow(pte_t pte)       { pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+pte_t
+sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+{
+       pte_t pte;
+
+       if(page & (~PAGE_MASK)) panic("sun4c_mk_pte() called with unaligned page");
+       page = sun4c_virt_to_phys(page);
+       pte_val(pte) = ((page>>PAGE_SHIFT)&_SUN4C_PFN_MASK);
+       pte_val(pte) |= (pgprot_val(pgprot) & _SUN4C_MMU_MASK);
+       return pte;
+}
+
+void
+sun4c_pgd_set(pgd_t * pgdp, pte_t * ptep)
+{
+       pgd_val(*pgdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
+       pgd_val(*pgdp) |= (((((unsigned long) ptep)) >>
+                           (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
+}
+
+pte_t
+sun4c_pte_modify(pte_t pte, pgprot_t newprot)
+{
+       pte_val(pte) = (pte_val(pte) & _SUN4C_PAGE_CHG_MASK);
+       pte_val(pte) |= pgprot_val(newprot);
+       return pte;
+}
+
+/* to find an entry in a page-table-directory */
+pgd_t *
+sun4c_pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+       return ((pgd_t *) (tsk->tss.pgd_ptr)) +
+               (address >> SUN4C_PGDIR_SHIFT);
+}
+
+/* Find an entry in the second-level page table.. */
+pmd_t *
+sun4c_pmd_offset(pgd_t * dir, unsigned long address)
+{
+       return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+pte_t *
+sun4c_pte_offset(pmd_t * dir, unsigned long address)
+{
+       return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+void
+sun4c_pte_free_kernel(pte_t *pte)
+{
+       mem_map[MAP_NR(pte)] = 1;
+       free_page((unsigned long) pte);
+}
+
+static inline void
+sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+       pmd_val(*pmdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
+       pmd_val(*pmdp) |= ((((unsigned long) ptep) >> (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
+}
+
+
+pte_t *
+sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+       pte_t *page;
+
+
+       address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
+       if (sun4c_pmd_none(*pmd)) {
+               /* New scheme, use a whole page */
+               page = (pte_t *) get_free_page(GFP_KERNEL);
+               if (sun4c_pmd_none(*pmd)) {
+                       if (page) {
+                               sun4c_pmd_set(pmd, page);
+                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+                               return page + address;
+                       }
+                       sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (sun4c_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+               sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+               return NULL;
+       }
+
+       return (pte_t *) sun4c_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void
+sun4c_pmd_free_kernel(pmd_t *pmd)
+{
+       return;
+}
+
+pmd_t *
+sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+       return (pmd_t *) pgd;
+}
+
+void
+sun4c_pte_free(pte_t *pte)
+{
+       free_page((unsigned long) pte);
+}
+
+pte_t *
+sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
+{
+       pte_t *page;
+
+       address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
+       if (sun4c_pmd_none(*pmd)) {
+               page = (pte_t *) get_free_page(GFP_KERNEL);
+               if (sun4c_pmd_none(*pmd)) {
+                       if (page) {
+                               sun4c_pmd_set(pmd, page);
+                               return page + address;
+                       }
+                       sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+                       return NULL;
+               }
+               free_page((unsigned long) page);
+       }
+       if (sun4c_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+               sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+               halt();
+               return NULL;
+       }
+
+       return (pte_t *) sun4c_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void 
+sun4c_pmd_free(pmd_t * pmd)
+{
+       return;
+}
+
+pmd_t *
+sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+       return (pmd_t *) pgd;
+}
+
+/* This now works, as both our pgd's and pte's have 1024 entries. */
+void
+sun4c_pgd_free(pgd_t *pgd)
+{
+       free_page((unsigned long) pgd);
+}
+
+/* A page directory on the sun4c needs 64k, thus we request an order of
+ * four.  We must also clear it by hand, very inefficient.
+ */
+
+pgd_t *
+sun4c_pgd_alloc(void)
+{
+       return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+void
+sun4c_invalidate(void)
+{
+       flush_vac_context();
+}
+
+void
+sun4c_switch_to_context(int context)
+{
+       __asm__ __volatile__("stba %0, [%1] %2" : :
+                            "r" (context),
+                            "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+       return;
+}
+
+int 
+sun4c_get_context(void)
+{
+       register int ctx;
+
+       __asm__ __volatile__("lduba [%1] %2, %0" :
+                            "=r" (ctx) :
+                            "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+       return ctx;
+}
+
+/* Low level IO area allocation on the Sun4c MMU.  This function is called
+ * for each page of IO area you need.  Kernel code should not call this
+ * routine directly, use sparc_alloc_io() instead.
+ */
+void
+sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+               int bus_type, int rdonly)
+{
+  unsigned long page_entry;
+
+  page_entry = ((physaddr >> PAGE_SHIFT) & _SUN4C_PFN_MASK);
+
+  if(!rdonly)
+         page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO);  /* kernel io addr */
+  else
+         page_entry |= (PTE_V | PTE_P | PTE_NC | PTE_IO);  /* readonly io addr */
+
+  page_entry &= (~PTE_RESV);
+
+  /* Maybe have to do something with the bus_type on sun4c's? */
+
+
+  put_pte(virt_addr, page_entry);
+  return;
+}
+
+/* Paging initialization on the Sun4c. */
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long eintstack, intstack;
+
+/* This code was soooo krufty, I have to rewrite this now! XXX
+ * Ok, things are cleaning up.  I have now decided that it makes
+ * a lot of sense to put the free page pool in upper ram right
+ * after the kernel.  We map these free pages to be virtually
+ * contiguous, that way we don't get so many reserved pages
+ * during mem_init().  I think this will work out nicely.
+ */
+extern unsigned long start;
+
+static unsigned long mempool;  /* This allows us to work with elf bootloaders */
+
+unsigned long
+sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+       unsigned long addr, vaddr, kern_begin, kern_end;
+       unsigned long prom_begin, prom_end;
+       int phys_seg, i, min_prom_segmap;
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       mempool = start_mem;
+
+       /* 127 on most sun4c's, 255 on SS2 and IPX. */
+       invalid_segment = (num_segmaps - 1);
+
+       memset(swapper_pg_dir, 0, PAGE_SIZE);
+       memset(pg0, 0, PAGE_SIZE);
+       /* Delete low mapping of the kernel and sanitize invalid segmap. */
+       for(vaddr=0; vaddr<(4*1024*1024); vaddr+=SUN4C_REAL_PGDIR_SIZE) 
+               put_segmap(vaddr, invalid_segment);
+       for(vaddr=0; vaddr<(256*1024); vaddr+=PAGE_SIZE) put_pte(vaddr, 0);
+
+       /* Initialize phys_seg_map[] */
+       for(i=0; i<num_segmaps; i++) phys_seg_map[i] = PSEG_AVL;
+       for(i=num_segmaps; i<PSEG_ENTRIES; i++) phys_seg_map[i] = PSEG_RSV;
+
+       kern_begin = KERNBASE;
+       kern_end = ((unsigned long) &end);
+       prom_begin = LINUX_OPPROM_BEGVM;
+       prom_end = LINUX_OPPROM_ENDVM;
+
+       /* Set up swapper_pg_dir based upon three things:
+        * 1) Where the kernel lives (KERNBASE)
+        * 2) Where the PROM lives (PROM_BEGVM -> PROM_ENDVM)
+        *    This is cheese, should do it dynamically XXX
+        * 3) Where the valid physical pages are (sp_banks[])
+        *    This is done first.
+        *
+        * I'm trying to concentrate this into one big loop and localize
+        * the logic because it is so messy to do it in seperate loop
+        * stages.  If anyone else has better ideas, let me know.
+        */
+
+       if(sp_banks[0].base_addr != 0)
+               panic("sun4c_paging_init: First physical address in first bank is not zero!\n");
+       /* First, linearly map all physical RAM to the equivalent virtual pages.
+        * Then, we invalidate everything the kernel uses by either invalidating
+        * the entire segmep (if the whole segment is used by the kernel) or
+        * just invalidating the relevant pte's.
+        */
+
+       for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
+               pgdp = sun4c_pgd_offset(current, vaddr);
+               pmdp = sun4c_pmd_offset(pgdp, vaddr);
+               if(sun4c_pmd_none(*pmdp)) {
+                       pgd_set(pgdp, (pte_t *) mempool);
+                       mempool += PAGE_SIZE;
+               }
+               ptep = sun4c_pte_offset(pmdp, vaddr);
+               *ptep = sun4c_mk_pte(vaddr, SUN4C_PAGE_KERNEL);
+       }
+
+       /* Now map the kernel, and mark the segmaps as PSEG_KERN.
+        *
+        * NOTE: The first address of the upper kernel mapping must be
+        *       segment aligned.
+        */
+       if(kern_begin & (~SUN4C_REAL_PGDIR_MASK)) {
+               panic("paging_init() Kernel not segmap aligned, halting...");
+       }
+
+       /* Mark the segmaps so that our phys_seg allocator doesn't try to
+        * use them for TLB misses.
+        */
+       for(addr=kern_begin; addr < kern_end; addr += SUN4C_REAL_PGDIR_SIZE) {
+               if(get_segmap(addr) == invalid_segment) {
+                       panic("paging_init() AIEEE, Kernel has invalid mapping, halting...");
+               }
+               phys_seg = get_segmap(addr);
+               phys_seg_map[phys_seg] = PSEG_KERNEL;
+               /* Map this segment in every context */
+               for(i=0; i<num_contexts; i++)
+                       (*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
+       }
+
+       for(addr=((unsigned long) (&empty_zero_page)) + PAGE_SIZE; 
+           addr < ((unsigned long) (&etext)); addr += PAGE_SIZE)
+               put_pte(addr, (get_pte(addr) & (~(PTE_W | PTE_NC))));
+
+       /* Finally map the prom's address space.  Any segments that
+        * are not the invalid segment are marked as PSEG_RESV so
+        * they are never re-allocated.  This guarentees the PROM
+        * a sane state if we have to return execution over to it.
+        * Our kernel static tables make it look like nothing is
+        * mapped in these segments, if we get a page fault for
+        * a prom address either the user is gonna die or the kernel
+        * is doing something *really* bad.
+        */
+       if(prom_begin & (~SUN4C_REAL_PGDIR_MASK)) {
+               panic("paging_init() Boot PROM not segmap aligned, halting...");
+               halt();
+       }
+
+       min_prom_segmap = 254;
+       for(addr=KADB_DEBUGGER_BEGVM; addr < prom_end; addr += SUN4C_REAL_PGDIR_SIZE) {
+               if(get_segmap(addr) == invalid_segment)
+                       continue;
+               phys_seg = get_segmap(addr);
+               if(phys_seg < min_prom_segmap) min_prom_segmap = phys_seg;
+               phys_seg_map[phys_seg] = PSEG_RSV;
+               /* Make the prom pages unaccessible from userland.  However, we
+                * don't touch debugger segmaps/ptes.
+                */
+               if((addr>=LINUX_OPPROM_BEGVM) && (addr<LINUX_OPPROM_ENDVM))
+                       for(vaddr=addr; vaddr < (addr+SUN4C_REAL_PGDIR_SIZE); vaddr+=PAGE_SIZE)
+                               put_pte(vaddr, (get_pte(vaddr) | PTE_P));
+
+               /* Map this segment in every context */
+               for(i=0; i<num_contexts; i++)
+                       (*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
+       }
+
+       /* Finally, unmap kernel page zero. */
+       put_pte(0x0, 0x0);
+
+       /* Hard pin down the IO area segmaps */
+       phys_seg = (min_prom_segmap - 1);
+       for(addr = (IOBASE_VADDR + SUN4C_REAL_PGDIR_SIZE); addr < (IOBASE_VADDR + IOBASE_LEN);
+           addr += SUN4C_REAL_PGDIR_SIZE) {
+               if(addr & (~SUN4C_REAL_PGDIR_MASK)) {
+                       panic("paging_init() IO segment not aligned, halting...");
+               }
+               phys_seg_map[phys_seg] = PSEG_RSV; /* Don't touch */
+               put_segmap(addr, phys_seg--);
+       }
+       phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV;
+
+       start_mem = PAGE_ALIGN(mempool);
+       start_mem = free_area_init(start_mem, end_mem);
+       start_mem = PAGE_ALIGN(start_mem);
+
+       /* That should be it. */
+       invalidate();
+
+       return start_mem;
+}
+
+/* Test the WP bit on the sun4c. */
+unsigned long
+sun4c_test_wp(unsigned long start_mem)
+{
+       unsigned long addr, segmap;
+       unsigned long page_entry;
+
+       wp_works_ok = -1;
+       page_entry = pte_val(sun4c_mk_pte(PAGE_OFFSET, SUN4C_PAGE_READONLY));
+       put_pte((unsigned long) 0x0, page_entry);
+
+       /* Let it rip... */
+       __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+       put_pte((unsigned long) 0x0, 0x0);
+       if (wp_works_ok < 0)
+               wp_works_ok = 0;
+
+       /* Make all kernet static segmaps PSEG_KERNEL. */
+       for(addr=PAGE_OFFSET; addr<start_mem; addr+=SUN4C_REAL_PGDIR_SIZE)
+               phys_seg_map[get_segmap(addr)]=PSEG_KERNEL;
+
+       /* Map all the segmaps not valid on this machine as reserved. */
+       for(segmap=invalid_segment; segmap<PSEG_ENTRIES; segmap++)
+               phys_seg_map[segmap]=PSEG_RSV;
+
+       return start_mem;
+}
+
+/* Real work gets done here. */
+
+/* Load up routines and constants for sun4c mmu */
+void
+ld_mmu_sun4c(void)
+{
+       printk("Loading sun4c MMU routines\n");
+
+       /* First the constants */
+       pmd_shift = SUN4C_PMD_SHIFT;
+       pmd_size = SUN4C_PMD_SIZE;
+       pmd_mask = SUN4C_PMD_MASK;
+       pgdir_shift = SUN4C_PGDIR_SHIFT;
+       pgdir_size = SUN4C_PGDIR_SIZE;
+       pgdir_mask = SUN4C_PGDIR_MASK;
+
+       ptrs_per_pte = SUN4C_PTRS_PER_PTE;
+       ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
+       ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
+
+       page_none = SUN4C_PAGE_NONE;
+       page_shared = SUN4C_PAGE_SHARED;
+       page_copy = SUN4C_PAGE_COPY;
+       page_readonly = SUN4C_PAGE_READONLY;
+       page_kernel = SUN4C_PAGE_KERNEL;
+       page_invalid = SUN4C_PAGE_INVALID;
+       
+       /* Functions */
+       invalidate = sun4c_invalidate;
+       switch_to_context = sun4c_switch_to_context;
+       pmd_align = sun4c_pmd_align;
+       pgdir_align = sun4c_pgdir_align;
+       vmalloc_start = sun4c_vmalloc_start;
+
+       pte_page = sun4c_pte_page;
+       pmd_page = sun4c_pmd_page;
+       pgd_page = sun4c_pgd_page;
+
+       sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
+
+       pte_none = sun4c_pte_none;
+       pte_present = sun4c_pte_present;
+       pte_inuse = sun4c_pte_inuse;
+       pte_clear = sun4c_pte_clear;
+       pte_reuse = sun4c_pte_reuse;
+
+       pmd_none = sun4c_pmd_none;
+       pmd_bad = sun4c_pmd_bad;
+       pmd_present = sun4c_pmd_present;
+       pmd_inuse = sun4c_pmd_inuse;
+       pmd_clear = sun4c_pmd_clear;
+       pmd_reuse = sun4c_pmd_reuse;
+
+       pgd_none = sun4c_pgd_none;
+       pgd_bad = sun4c_pgd_bad;
+       pgd_present = sun4c_pgd_present;
+       pgd_inuse = sun4c_pgd_inuse;
+       pgd_clear = sun4c_pgd_clear;
+       pgd_reuse = sun4c_pgd_reuse;
+
+       mk_pte = sun4c_mk_pte;
+       pgd_set = sun4c_pgd_set;
+       pte_modify = sun4c_pte_modify;
+       pgd_offset = sun4c_pgd_offset;
+       pmd_offset = sun4c_pmd_offset;
+       pte_offset = sun4c_pte_offset;
+       pte_free_kernel = sun4c_pte_free_kernel;
+       pmd_free_kernel = sun4c_pmd_free_kernel;
+       pte_alloc_kernel = sun4c_pte_alloc_kernel;
+       pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
+       pte_free = sun4c_pte_free;
+       pte_alloc = sun4c_pte_alloc;
+       pmd_free = sun4c_pmd_free;
+       pmd_alloc = sun4c_pmd_alloc;
+       pgd_free = sun4c_pgd_free;
+       pgd_alloc = sun4c_pgd_alloc;
+
+       pte_read = sun4c_pte_read;
+       pte_write = sun4c_pte_write;
+       pte_exec = sun4c_pte_exec;
+       pte_dirty = sun4c_pte_dirty;
+       pte_young = sun4c_pte_young;
+       pte_cow = sun4c_pte_cow;
+       pte_wrprotect = sun4c_pte_wrprotect;
+       pte_rdprotect = sun4c_pte_rdprotect;
+       pte_exprotect = sun4c_pte_exprotect;
+       pte_mkclean = sun4c_pte_mkclean;
+       pte_mkold = sun4c_pte_mkold;
+       pte_uncow = sun4c_pte_uncow;
+       pte_mkwrite = sun4c_pte_mkwrite;
+       pte_mkread = sun4c_pte_mkread;
+       pte_mkexec = sun4c_pte_mkexec;
+       pte_mkdirty = sun4c_pte_mkdirty;
+       pte_mkyoung = sun4c_pte_mkyoung;
+       pte_mkcow = sun4c_pte_mkcow;
+
+       return;
+}
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
new file mode 100644 (file)
index 0000000..1885cd4
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Makefile for the Sun Boot PROM interface library under
+# Linux.
+#
+# 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 in the main makefile...
+
+.c.o:
+       $(CC) $(CFLAGS) -c $<
+
+OBJS  = bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
+        palloc.o ranges.o segment.o tree.o console.o printf.o
+
+all: promlib.a
+
+promlib.a: $(OBJS)
+       $(AR) rcs promlib.a $(OBJS)
+       sync
+
+dep:
+       $(CPP) -M *.c > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c
new file mode 100644 (file)
index 0000000..9b62dcc
--- /dev/null
@@ -0,0 +1,40 @@
+/* bootstr.c:  Boot string/argument acquisition from the PROM.
+ *
+ * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/oplib.h>
+
+static char barg_buf[128];
+
+char *
+prom_getbootargs(void)
+{
+       int iter;
+       char *cp;
+
+       switch(prom_vers) {
+       case PROM_V0:
+               cp = barg_buf;
+               for(iter = 0; iter < 8; iter++) {
+                       strcpy(cp, (*(romvec->pv_v0bootargs))->argv[iter]);
+                       cp += strlen(cp); *cp++=' ';
+               }
+               *cp = 0;
+               break;
+       case PROM_V2:
+       case PROM_V3:
+               cp = barg_buf;
+               strcpy(cp, *romvec->pv_v2bootargs.bootpath);
+               cp += strlen(cp);
+               *cp++ = ' ';
+               strcpy(cp, *romvec->pv_v2bootargs.bootargs);
+               cp += strlen(cp);
+               *cp = 0;
+               break;
+       default:
+               barg_buf[0] = 0;
+               break;
+       }
+       return barg_buf;
+}
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
new file mode 100644 (file)
index 0000000..7909282
--- /dev/null
@@ -0,0 +1,73 @@
+/* console.c: Routines that deal with sending and receiving IO
+ *            to/from the current console device using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Non blocking get character from console input device, returns -1
+ * if no input was taken.  This can be used for polling.
+ */
+int
+prom_nbgetchar(void)
+{
+       static char inc;
+
+       switch(prom_vers) {
+       case PROM_V0:
+               return (*(romvec->pv_nbgetchar))();
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1)
+                       return inc;
+               return -1;
+               break;
+       };
+       return 0; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Non blocking put character to console device, returns -1 if
+ * unsuccessful.
+ */
+int
+prom_nbputchar(char c)
+{
+       static char outc;
+
+       switch(prom_vers) {
+       case PROM_V0:
+               return (*(romvec->pv_nbputchar))(c);
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               outc = c;
+               if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1)
+                       return 0;
+               return -1;
+               break;
+       };
+       return 0; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Blocking version of get character routine above. */
+char
+prom_getchar(void)
+{
+       int character;
+       while((character = prom_nbgetchar()) == -1) ;
+       return (char) character;
+}
+
+/* Blocking version of put character routine above. */
+void
+prom_putchar(char c)
+{
+       while(prom_nbputchar(c) == -1) ;
+       return;
+}
+
diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c
new file mode 100644 (file)
index 0000000..24470b5
--- /dev/null
@@ -0,0 +1,34 @@
+/* promdevmap.c:  Map device/IO areas to virtual addresses.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Just like the routines in palloc.c, these should not be used
+ * by the kernel at all.  Bootloader facility mainly.  And again,
+ * this is only available on V2 proms and above.
+ */
+
+/* Map physical device address 'paddr' in IO space 'ios' of size
+ * 'num_bytes' to a virtual address, with 'vhint' being a hint to
+ * the prom as to where you would prefer the mapping.  We return
+ * where the prom actually mapped it.
+ */
+char *
+prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes)
+{
+       if((num_bytes == 0) || (paddr == 0)) return (char *) 0x0;
+       return (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
+                                                    num_bytes);
+}
+
+/* Unmap an IO/device area that was mapped using the above routine. */
+void
+prom_unmapio(char *vaddr, unsigned int num_bytes)
+{
+       if(num_bytes == 0x0) return;
+       (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
+       return;
+}
diff --git a/arch/sparc/prom/devops.c b/arch/sparc/prom/devops.c
new file mode 100644 (file)
index 0000000..12c4c56
--- /dev/null
@@ -0,0 +1,69 @@
+/* devops.c:  Device operations using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Open the device described by the string 'dstr'.  Returns the handle
+ * to that device used for subsequent operations on that device.
+ * Returns -1 on failure.
+ */
+int
+prom_devopen(char *dstr)
+{
+       int handle;
+       switch(prom_vers) {
+       case PROM_V0:
+               handle = (*(romvec->pv_v0devops.v0_devopen))(dstr);
+               if(handle == 0) return -1;
+               return handle;
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
+               return handle;
+               break;
+       };
+
+       return -1;
+}
+
+/* Close the device described by device handle 'dhandle'. */
+void
+prom_close(int dhandle)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+               (*(romvec->pv_v0devops.v0_devclose))(dhandle);
+               return;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               (*(romvec->pv_v2devops.v2_dev_close))(dhandle);
+               return;
+       };
+       return;
+}
+
+/* Seek to specified location described by 'seekhi' and 'seeklo'
+ * for device 'dhandle'.
+ */
+void
+prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+               (*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo);
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
+               break;
+       };
+
+       return;
+}
diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c
new file mode 100644 (file)
index 0000000..e77c6c0
--- /dev/null
@@ -0,0 +1,79 @@
+/* init.c:  Initialize internal variables used by the PROM
+ *          library functions.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+struct linux_romvec *romvec;
+enum prom_major_version prom_vers;
+unsigned int prom_rev, prom_prev;
+
+/* The root node of the prom device tree. */
+int prom_root_node;
+
+/* Pointer to the device tree operations structure. */
+struct linux_nodeops *prom_nodeops;
+
+/* You must call prom_init() before you attempt to use any of the
+ * routines in the prom library.  It returns 0 on success, 1 on
+ * failure.  It gets passed the pointer to the PROM vector.
+ */
+
+extern void prom_meminit(void);
+extern void prom_ranges_init(void);
+
+int
+prom_init(struct linux_romvec *rp)
+{
+       if(!rp) return 1;
+       romvec = rp;
+       if(romvec->pv_magic_cookie != LINUX_OPPROM_MAGIC)
+               return 1;
+
+       /* Ok, we seem to have a sane romvec here. */
+       switch(romvec->pv_romvers) {
+       case 0:
+               prom_vers = PROM_V0;
+               break;
+       case 2:
+               prom_vers = PROM_V2;
+               break;
+       case 3:
+               prom_vers = PROM_V3;
+               break;
+       case 4:
+               prom_vers = PROM_P1275;
+               prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
+               return 1;
+               break;
+       default:
+               prom_printf("PROMLIB: Bad PROM version %d\n",
+                           romvec->pv_romvers);
+               return 1;
+               break;
+       };
+
+       prom_rev = romvec->pv_plugin_revision;
+       prom_prev = romvec->pv_printrev;
+       prom_nodeops = romvec->pv_nodeops;
+
+       prom_root_node = prom_getsibling(0);
+       if((prom_root_node == 0) || (prom_root_node == -1))
+               return 1;
+
+       if((((unsigned long) prom_nodeops) == 0) || 
+          (((unsigned long) prom_nodeops) == -1))
+               return 1;
+
+       prom_meminit();
+       prom_ranges_init();
+
+       prom_printf("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
+                   romvec->pv_romvers, prom_rev);
+
+       /* Initialization successful. */
+       return 0;
+}
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
new file mode 100644 (file)
index 0000000..fcf6e5f
--- /dev/null
@@ -0,0 +1,193 @@
+/* memory.c: Prom routine for acquiring various bits of information
+ *           about RAM on the machine, both virtual and physical.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* This routine, for consistancy, returns the ram parameters in the
+ * V0 prom memory descriptor format.  I choose this format becuase I
+ * think it was the easiest to work with.  I feel the religious
+ * arguments now... ;)  Also, I return the linked lists sorted to
+ * prevent paging_init() upset stomache as I have not yet written
+ * the pepto-bismal kernel module yet.
+ */
+
+struct linux_prom_registers prom_reg_memlist[64];
+struct linux_prom_registers prom_reg_tmp[64];
+
+struct linux_mlist_v0 prom_phys_total[64];
+struct linux_mlist_v0 prom_prom_taken[64];
+struct linux_mlist_v0 prom_phys_avail[64];
+
+struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total;
+struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken;
+struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail;
+
+struct linux_mem_v0 prom_memlist;
+
+
+/* Internal Prom library routine to sort a linux_mlist_v0 memory
+ * list.  Used below in initialization.
+ */
+void
+prom_sortmemlist(struct linux_mlist_v0 *thislist)
+{
+       int swapi = 0;
+       int i, mitr, tmpsize;
+       char *tmpaddr;
+       char *lowest;
+
+       for(i=0; thislist[i].theres_more != 0; i++) {
+               lowest = thislist[i].start_adr;
+               for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+                       if(thislist[mitr].start_adr < lowest) {
+                               lowest = thislist[mitr].start_adr;
+                               swapi = mitr;
+                       }
+               if(lowest == thislist[i].start_adr) continue;
+               tmpaddr = thislist[swapi].start_adr;
+               tmpsize = thislist[swapi].num_bytes;
+               for(mitr = swapi; mitr > i; mitr--) {
+                       thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+                       thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+               }
+               thislist[i].start_adr = tmpaddr;
+               thislist[i].num_bytes = tmpsize;
+       }
+
+       return;
+}
+
+/* Initialize the memory lists based upon the prom version. */
+void
+prom_meminit(void)
+{
+       int node = 0;
+       unsigned int iter, num_regs;
+       struct linux_mlist_v0 *mptr;  /* ptr for traversal */
+
+       switch(prom_vers) {
+       case PROM_V0:
+               /* Nice, kind of easier to do in this case. */
+               /* First, the total physical descriptors. */
+               for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0;
+                   mptr; mptr=mptr->theres_more, iter++) {
+                       prom_phys_total[iter].start_adr = mptr->start_adr;
+                       prom_phys_total[iter].num_bytes = mptr->num_bytes;
+                       prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
+               }
+               prom_phys_total[iter-1].theres_more = 0x0;
+               /* Second, the total prom taken descriptors. */
+               for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
+                   mptr; mptr=mptr->theres_more, iter++) {
+                       prom_prom_taken[iter].start_adr = mptr->start_adr;
+                       prom_prom_taken[iter].num_bytes = mptr->num_bytes;
+                       prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
+               }
+               prom_prom_taken[iter-1].theres_more = 0x0;
+               /* Last, the available physical descriptors. */
+               for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
+                   mptr; mptr=mptr->theres_more, iter++) {
+                       prom_phys_avail[iter].start_adr = mptr->start_adr;
+                       prom_phys_avail[iter].num_bytes = mptr->num_bytes;
+                       prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
+               }
+               prom_phys_avail[iter-1].theres_more = 0x0;
+               /* Sort all the lists. */
+               prom_sortmemlist(prom_phys_total);
+               prom_sortmemlist(prom_prom_taken);
+               prom_sortmemlist(prom_phys_avail);
+               break;
+       case PROM_V2:
+       case PROM_V3:
+       case PROM_P1275:
+               /* Grrr, have to traverse the prom device tree ;( */
+               node = prom_getchild(prom_root_node);
+               node = prom_searchsiblings(node, "memory");
+               num_regs = prom_getproperty(node, "available",
+                                           (char *) prom_reg_memlist,
+                                           sizeof(prom_reg_memlist));
+               num_regs = (num_regs/sizeof(struct linux_prom_registers));
+               for(iter=0; iter<num_regs; iter++) {
+                       prom_phys_avail[iter].start_adr =
+                               prom_reg_memlist[iter].phys_addr;
+                       prom_phys_avail[iter].num_bytes =
+                               (unsigned long) prom_reg_memlist[iter].reg_size;
+                       prom_phys_avail[iter].theres_more =
+                               &prom_phys_avail[iter+1];
+               }
+               prom_phys_avail[iter-1].theres_more = 0x0;
+
+               num_regs = prom_getproperty(node, "reg",
+                                           (char *) prom_reg_memlist,
+                                           sizeof(prom_reg_memlist));
+               num_regs = (num_regs/sizeof(struct linux_prom_registers));
+               for(iter=0; iter<num_regs; iter++) {
+                       prom_phys_total[iter].start_adr =
+                               prom_reg_memlist[iter].phys_addr;
+                       prom_phys_total[iter].num_bytes =
+                               (unsigned long) prom_reg_memlist[iter].reg_size;
+                       prom_phys_total[iter].theres_more =
+                               &prom_phys_total[iter+1];
+               }
+               prom_phys_total[iter-1].theres_more = 0x0;
+
+               node = prom_getchild(prom_root_node);
+               node = prom_searchsiblings(node, "virtual-memory");
+               num_regs = prom_getproperty(node, "available",
+                                           (char *) prom_reg_memlist,
+                                           sizeof(prom_reg_memlist));
+               num_regs = (num_regs/sizeof(struct linux_prom_registers));
+
+               /* Convert available virtual areas to taken virtual
+                * areas.  First sort, then convert.
+                */
+               for(iter=0; iter<num_regs; iter++) {
+                       prom_prom_taken[iter].start_adr =
+                               prom_reg_memlist[iter].phys_addr;
+                       prom_prom_taken[iter].num_bytes =
+                               (unsigned long) prom_reg_memlist[iter].reg_size;
+                       prom_prom_taken[iter].theres_more =
+                               &prom_phys_total[iter+1];
+               }
+               prom_prom_taken[iter-1].theres_more = 0x0;
+
+               prom_sortmemlist(prom_prom_taken);
+
+               /* Finally, convert. */
+               for(iter=0; iter<num_regs; iter++) {
+                       prom_prom_taken[iter].start_adr =
+                               prom_prom_taken[iter].start_adr +
+                                       prom_prom_taken[iter].num_bytes;
+                       prom_prom_taken[iter].num_bytes =
+                               prom_prom_taken[iter+1].start_adr -
+                                       prom_prom_taken[iter].start_adr;
+               }
+               prom_prom_taken[iter-1].num_bytes =
+                       0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr;
+
+               /* Sort the other two lists. */
+               prom_sortmemlist(prom_phys_total);
+               prom_sortmemlist(prom_phys_avail);
+
+       };
+
+       /* Link all the lists into the top-level descriptor. */
+       prom_memlist.v0_totphys=&prom_ptot_ptr;
+       prom_memlist.v0_prommap=&prom_ptak_ptr;
+       prom_memlist.v0_available=&prom_pavl_ptr;
+
+       return;
+}
+
+/* This returns a pointer to our libraries internal v0 format
+ * memory descriptor.
+ */
+struct linux_mem_v0 *
+prom_meminfo(void)
+{
+       return &prom_memlist;
+}
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
new file mode 100644 (file)
index 0000000..3240335
--- /dev/null
@@ -0,0 +1,99 @@
+/* misc.c:  Miscellaneous prom functions that don't belong
+ *          anywhere else.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Reset and reboot the machine with the command 'bcommand'. */
+void
+prom_reboot(char *bcommand)
+{
+       (*(romvec->pv_reboot))(bcommand);
+       /* Never get here. */
+       return;
+}
+
+/* Forth evaluate the expression contained in 'fstring'. */
+void
+prom_feval(char *fstring)
+{
+       if(!fstring || fstring[0] == 0) return;
+       if(prom_vers == PROM_V0)
+               (*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring);
+       else
+               (*(romvec->pv_fortheval.v2_eval))(fstring);
+       return;
+}
+
+/* Drop into the prom, with the chance to continue with the 'go'
+ * prom command.
+ */
+void
+prom_halt(void)
+{
+       (*(romvec->pv_abort))();
+       return;
+}
+
+/* Drop into the prom, but completely terminate the program.
+ * No chance of continuing.
+ */
+void
+prom_die(void)
+{
+       (*(romvec->pv_halt))();
+       /* Never get here. */
+       return;
+}
+
+typedef void (*sfunc_t)(void);
+
+/* Set prom sync handler to call function 'funcp'. */
+void
+prom_setsync(sfunc_t funcp)
+{
+       if(!funcp) return;
+       *romvec->pv_synchook = funcp;
+       return;
+}
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char
+prom_getidp(char *idbuf, int num_bytes)
+{
+       int len;
+
+       len = prom_getproplen(prom_root_node, "idprom");
+       if((len>num_bytes) || (len==-1)) return 0xff;
+       if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
+               return idbuf[0];
+
+       return 0xff;
+}
+
+/* Get the major prom version number. */
+int
+prom_version(void)
+{
+       return romvec->pv_romvers;
+}
+
+/* Get the prom plugin-revision. */
+int
+prom_getrev(void)
+{
+       return prom_rev;
+}
+
+/* Get the prom firmware print revision. */
+int
+prom_getprev(void)
+{
+       return prom_prev;
+}
diff --git a/arch/sparc/prom/mp.c b/arch/sparc/prom/mp.c
new file mode 100644 (file)
index 0000000..008dd70
--- /dev/null
@@ -0,0 +1,86 @@
+/* mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
+ *        these on a UP or else you will halt and catch fire. ;)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Start cpu with prom-tree node 'cpunode' using context described
+ * by 'ctable_reg' in context 'ctx' at program counter 'pc'.
+ *
+ * XXX Have to look into what the return values mean. XXX
+ */
+int
+prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, char *pc)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+       case PROM_V2:
+               break;
+       case PROM_V3:
+       case PROM_P1275:
+               return (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc);
+               break;
+       };
+
+       return -1;
+}
+
+/* Stop CPU with device prom-tree node 'cpunode'.
+ * XXX Again, what does the return value really mean? XXX
+ */
+int
+prom_stopcpu(int cpunode)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+       case PROM_V2:
+               break;
+       case PROM_V3:
+       case PROM_P1275:
+               return (*(romvec->v3_cpustop))(cpunode);
+               break;
+       };
+
+       return -1;
+}
+
+/* Make CPU with device prom-tree node 'cpunode' idle.
+ * XXX Return value, anyone? XXX
+ */
+int
+prom_idlecpu(int cpunode)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+       case PROM_V2:
+               break;
+       case PROM_V3:
+       case PROM_P1275:
+               return (*(romvec->v3_cpuidle))(cpunode);
+               break;
+       };
+
+       return -1;
+}
+
+/* Resume the execution of CPU with nodeid 'cpunode'.
+ * XXX Come on, somebody has to know... XXX
+ */
+int
+prom_restartcpu(int cpunode)
+{
+       switch(prom_vers) {
+       case PROM_V0:
+       case PROM_V2:
+               break;
+       case PROM_V3:
+       case PROM_P1275:
+               return (*(romvec->v3_cpuresume))(cpunode);
+               break;
+       };
+
+       return -1;
+}
diff --git a/arch/sparc/prom/palloc.c b/arch/sparc/prom/palloc.c
new file mode 100644 (file)
index 0000000..9d06540
--- /dev/null
@@ -0,0 +1,43 @@
+/* palloc.c:  Memory allocation from the Sun PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* You should not call these routines after memory management
+ * has been initialized in the kernel, if fact you should not
+ * use these if at all possible in the kernel.  They are mainly
+ * to be used for a bootloader for temporary allocations which
+ * it will free before jumping into the kernel it has loaded.
+ *
+ * Also, these routines don't work on V0 proms, only V2 and later.
+ */
+
+/* Allocate a chunk of memory of size 'num_bytes' giving a suggestion
+ * of virtual_hint as the preferred virtual base address of this chunk.
+ * There are no guarentees that you will get the allocation, or that
+ * the prom will abide by your "hint".  So check your return value.
+ */
+char *
+prom_alloc(char *virtual_hint, unsigned int num_bytes)
+{
+       if(prom_vers == PROM_V0) return (char *) 0x0;
+       if(num_bytes == 0x0) return (char *) 0x0;
+       return (*(romvec->pv_v2devops.v2_dumb_mem_alloc))(virtual_hint, num_bytes);
+}
+
+/* Free a previously allocated chunk back to the prom at virtual address
+ * 'vaddr' of size 'num_bytes'.  NOTE: This vaddr is not the hint you
+ * used for the allocation, but the virtual address the prom actually
+ * returned to you.  They may be have been the same, they may have not,
+ * doesn't matter.
+ */
+void
+prom_free(char *vaddr, unsigned int num_bytes)
+{
+       if((prom_vers == PROM_V0) || (num_bytes == 0x0)) return;
+       (*(romvec->pv_v2devops.v2_dumb_mem_free))(vaddr, num_bytes);
+       return;
+}
diff --git a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c
new file mode 100644 (file)
index 0000000..50d3c24
--- /dev/null
@@ -0,0 +1,108 @@
+/* printf.c:  Internal prom library printf facility.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* This routine is internal to the prom library, no one else should know
+ * about or use it!  It's simple and smelly anyway....
+ */
+
+#include <stdarg.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+char hexstring[] = "0123456789abcdef";
+
+void
+prom_printf(char *fmt, ...)
+{
+       va_list args;
+       unsigned int ui_val;
+       int i_val, n_ctr;
+       char c_val;
+       char nstr_buf[32];
+       char *s_val;
+       
+       va_start(args, fmt);
+       while(*fmt) {
+               if(*fmt != '%') {
+                       if(*fmt == '\n')
+                               prom_putchar('\r');
+                       prom_putchar(*fmt++);
+                       continue;
+               }
+
+               fmt++;
+               if(!*fmt) break;
+               n_ctr = 0;
+               switch(*fmt) {
+               case 'c':
+                       c_val = va_arg(args, char);
+                       if(c_val == '\n')
+                               prom_putchar('\r');
+                       prom_putchar(c_val);
+                       fmt++;
+                       break;
+               case 's':
+                       s_val = va_arg(args, char *);
+                       while(*s_val != 0) {
+                               prom_putchar(*s_val);
+                               s_val++;
+                       }
+                       fmt++;
+                       break;
+               case 'd':
+                       /* Base 10 */
+                       i_val = va_arg(args, int);
+                       if(i_val==0x0)
+                               prom_putchar('0');
+                       else
+                               while(i_val != 0x0) {
+                                       nstr_buf[n_ctr] = hexstring[i_val%0xa];
+                                       i_val = ((unsigned long)i_val) / (unsigned) 0xa;
+                                       n_ctr++;
+                               };
+                       while(--n_ctr >= 0)
+                               prom_putchar(nstr_buf[n_ctr]);
+                       fmt++;
+                       break;
+               case 'x':
+                       /* Base 16 */
+                       ui_val = va_arg(args, unsigned int);
+                       if(ui_val==0x0)
+                               prom_putchar('0');
+                       else
+                               while(ui_val != 0x0) {
+                                       nstr_buf[n_ctr] = hexstring[ui_val%0x10];
+                                       ui_val = ((unsigned long) ui_val) / (unsigned) 0x10;
+                                       n_ctr++;
+                               };
+                       while(--n_ctr >= 0)
+                               prom_putchar(nstr_buf[n_ctr]);
+                       fmt++;
+                       break;
+               case 'o':
+                       /* Base 8 */
+                       ui_val = va_arg(args, unsigned int);
+                       if(ui_val==0x0)
+                               prom_putchar('0');
+                       else
+                               while(ui_val != 0x0) {
+                                       nstr_buf[n_ctr] = hexstring[ui_val%0x8];
+                                       ui_val = ((unsigned long) ui_val) / (unsigned) 0x8;
+                               };
+                       while(--n_ctr >= 0)
+                               prom_putchar(nstr_buf[n_ctr]);
+                       fmt++;
+                       break;
+               default:
+                       /* Uh oh, something we can't handle... skip it */
+                       fmt++;
+                       break;
+               };
+       }
+
+       /* We are done... */
+       return;
+}
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
new file mode 100644 (file)
index 0000000..b0caf0a
--- /dev/null
@@ -0,0 +1,109 @@
+/* ranges.c: Handle ranges in newer proms for obio.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
+struct linux_prom_ranges promlib_sbus_ranges[PROMREG_MAX];
+int num_obio_ranges, num_sbus_ranges;
+
+/* Adjust register values based upon the ranges parameters. */
+void
+prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
+                struct linux_prom_ranges *rangep, int nranges)
+{
+       int regc, rngc;
+
+       for(regc=0; regc < nregs; regc++) {
+               for(rngc=0; rngc < nranges; rngc++)
+                       if(regp[regc].which_io == rangep[rngc].ot_child_space)
+                               break; /* Fount it */
+               if(rngc==nranges) /* oops */
+                       prom_printf("adjust_regs: Could not find range with matching bus type...\n");
+               regp[regc].which_io = rangep[rngc].ot_parent_space;
+               regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+       }
+
+       return;
+}
+
+void
+prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
+                  struct linux_prom_ranges *ranges2, int nranges2)
+{
+       int rng1c, rng2c;
+
+       for(rng1c=0; rng1c < nranges1; rng1c++) {
+               for(rng2c=0; rng2c < nranges2; rng2c++)
+                       if(ranges1[rng1c].ot_child_space ==
+                          ranges2[rng2c].ot_child_space) break;
+               if(rng2c == nranges2) /* oops */
+                       prom_printf("adjust_ranges: Could not find matching bus type...\n");
+               ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space;
+               ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base;
+       }
+
+       return;
+}
+
+/* Apply probed obio ranges to registers passed, if no ranges return. */
+void
+prom_apply_obio_ranges(struct linux_prom_registers *regs, int nregs)
+{
+       if(!num_obio_ranges) return;
+       prom_adjust_regs(regs, nregs, promlib_obio_ranges, num_obio_ranges);
+       return;
+}
+
+/* Apply probed sbus ranges to registers passed, if no ranges return. */
+void
+prom_apply_sbus_ranges(struct linux_prom_registers *regs, int nregs)
+{
+       if(!num_sbus_ranges) return;
+       prom_adjust_regs(regs, nregs, promlib_sbus_ranges, num_sbus_ranges);
+       return;
+}
+
+void
+prom_ranges_init(void)
+{
+       int node, obio_node, sbus_node;
+       int success;
+
+       num_obio_ranges = 0;
+       num_sbus_ranges = 0;
+
+       /* Check for obio and sbus ranges. */
+       node = prom_getchild(prom_root_node);
+       obio_node = prom_searchsiblings(node, "obio");
+       sbus_node = prom_searchsiblings(node, "iommu");
+       if(sbus_node) {
+               sbus_node = prom_getchild(sbus_node);
+               sbus_node = prom_searchsiblings(sbus_node, "sbus");
+       }
+
+       if(obio_node) {
+               success = prom_getproperty(obio_node, "ranges",
+                                          (char *) promlib_obio_ranges,
+                                          sizeof(promlib_obio_ranges));
+               if(success != -1)
+                       num_obio_ranges = (success/sizeof(struct linux_prom_ranges));
+       }
+
+       if(sbus_node) {
+               success = prom_getproperty(sbus_node, "ranges",
+                                          (char *) promlib_sbus_ranges,
+                                          sizeof(promlib_sbus_ranges));
+               if(success != -1)
+                       num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
+       }
+
+       if(num_obio_ranges || num_sbus_ranges)
+               prom_printf("PROMLIB: obio_ranges %d sbus_ranges %d\n",
+                           num_obio_ranges, num_sbus_ranges);
+
+       return;
+}
diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c
new file mode 100644 (file)
index 0000000..383e0aa
--- /dev/null
@@ -0,0 +1,19 @@
+/* segment.c:  Prom routine to map segments in other contexts before
+ *             a standalone is completely mapped.  This is for sun4 and
+ *             sun4c architectures only.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Set physical segment 'segment' at virtual address 'vaddr' in
+ * context 'ctx'.
+ */
+void
+prom_putsegment(int ctx, unsigned long vaddr, int segment)
+{
+       (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
+       return;
+}
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c
new file mode 100644 (file)
index 0000000..662ffc5
--- /dev/null
@@ -0,0 +1,185 @@
+/* tree.c: Basic device tree traversal/scanning for the Linux
+ *         prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/string.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+static char promlib_buf[128];
+
+/* Return the child of node 'node' or zero if no this node has no
+ * direct descendent.
+ */
+int
+prom_getchild(int node)
+{
+       int cnode;
+
+       if(node == -1) return 0;
+       cnode = prom_nodeops->no_child(node);
+       if((cnode == 0) || (cnode == -1)) return 0;
+       return cnode;
+}
+
+/* Return the next sibling of node 'node' or zero if no more siblings
+ * at this level of depth in the tree.
+ */
+int
+prom_getsibling(int node)
+{
+       int sibnode;
+
+       if(node == -1) return 0;
+       sibnode = prom_nodeops->no_nextnode(node);
+       if((sibnode == 0) || (sibnode == -1)) return 0;
+       return sibnode;
+}
+
+/* Return the length in bytes of property 'prop' at node 'node'.
+ * Return -1 on error.
+ */
+int
+prom_getproplen(int node, char *prop)
+{
+       if((!node) || (!prop)) return -1;
+       return prom_nodeops->no_proplen(node, prop);
+}
+
+/* Acquire a property 'prop' at node 'node' and place it in
+ * 'buffer' which has a size of 'bufsize'.  If the acquisition
+ * was successful the length will be returned, else -1 is returned.
+ */
+int
+prom_getproperty(int node, char *prop, char *buffer, int bufsize)
+{
+       int plen;
+
+       plen = prom_getproplen(node, prop);
+       if((plen > bufsize) || (plen == 0) || (plen == -1)) return -1;
+
+       /* Ok, things seem all right. */
+       return prom_nodeops->no_getprop(node, prop, buffer);
+}
+
+/* Acquire an integer property and return it's value.  Returns -1
+ * on failure.
+ */
+int
+prom_getint(int node, char *prop)
+{
+       static int intprop;
+
+       if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
+               return intprop;
+
+       return -1;
+}
+
+/* Acquire an integer property, upon error return the passed default
+ * integer.
+ */
+
+int
+prom_getintdefault(int node, char *property, int deflt)
+{
+       int retval;
+
+       retval = prom_getint(node, property);
+       if(retval == -1) return deflt;
+
+       return retval;
+}
+
+/* Acquire a boolean property, 1=TRUE 0=FALSE. */
+int
+prom_getbool(int node, char *prop)
+{
+       int retval;
+
+       retval = prom_getproplen(node, prop);
+       if(retval == -1) return 0;
+       return 1;
+}
+
+/* Acquire a property whose value is a string, returns a null
+ * string on error.  The char pointer is the user supplied string
+ * buffer.
+ */
+void
+prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+{
+       int len;
+
+       len = prom_getproperty(node, prop, user_buf, ubuf_size);
+       if(len != -1) return;
+       user_buf[0] = 0;
+       return;
+}
+
+
+/* Does the device at node 'node' have name 'name'?
+ * YES = 1   NO = 0
+ */
+int
+prom_nodematch(int node, char *name)
+{
+       static char namebuf[128];
+       prom_getproperty(node, "name", namebuf, sizeof(namebuf));
+       if(strcmp(namebuf, name) == 0) return 1;
+       return 0;
+}
+
+/* Search siblings at 'node_start' for a node with name
+ * 'nodename'.  Return node if successful, zero if not.
+ */
+int
+prom_searchsiblings(int node_start, char *nodename)
+{
+       int thisnode, error;
+
+       for(thisnode = node_start; thisnode;
+           thisnode=prom_getsibling(thisnode)) {
+               error = prom_getproperty(thisnode, "name", promlib_buf,
+                                        sizeof(promlib_buf));
+               /* Should this ever happen? */
+               if(error == -1) continue;
+               if(strcmp(nodename, promlib_buf)==0) return thisnode;
+       }
+
+       return 0;
+}
+
+/* Return the first property type for node 'node'.
+ */
+char *
+prom_firstprop(int node)
+{
+       if(node == -1) return "";
+       return prom_nodeops->no_nextprop(node, (char *) 0x0);
+}
+
+/* Return the property type string after property type 'oprop'
+ * at node 'node' .  Returns NULL string if no more
+ * property types for this node.
+ */
+char *
+prom_nextprop(int node, char *oprop)
+{
+       if(node == -1) return "";
+       return prom_nodeops->no_nextprop(node, oprop);
+}
+
+/* Set property 'pname' at node 'node' to value 'value' which has a length
+ * of 'size' bytes.  Return the number of bytes the prom accepted.
+ */
+int
+prom_setprop(int node, char *pname, char *value, int size)
+{
+       if(size == 0) return 0;
+       if((pname == 0) || (value == 0)) return 0;
+       return prom_nodeops->no_setprop(node, pname, value, size);
+}
index 6a846f94862ec3c67d9fa2d42b88ac48221ab017..d0541f90cd2d819b0142408d2b2d6b0aeea57918 100644 (file)
@@ -28,6 +28,8 @@ BLOCK_MODULE_OBJS =
 ifdef CONFIG_BLK_DEV_FD
 OBJS := $(OBJS) floppy.o
 SRCS := $(SRCS) floppy.c
+else
+BLOCK_MODULE_OBJS := $(MODULES) floppy.o
 endif
 
 ifdef CONFIG_CDU31A
index 66e289452852d07f5faadc038882c9c7287972f8..6146bd6f5563fcae3464785f035fd6cdd41b5537 100644 (file)
 
 #define MAJOR_NR AZTECH_CDROM_MAJOR 
 
-#ifdef MODULE
-# include "/usr/src/linux/drivers/block/blk.h"
-#else
-# include "blk.h"
+#include "blk.h"
+#ifndef MODULE
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
 #endif
index 23295c2d347eebbc3f70e30df0e676f8f000d0c1..884102a4934368df88875d5bcb4118bee83b9881 100644 (file)
@@ -56,13 +56,7 @@ extern unsigned long sbpcd_init(unsigned long, unsigned long);
 #endif CONFIG_SBPCD
 extern void set_device_ro(int dev,int flag);
 
-extern void floppy_init(void);
-#ifdef FD_MODULE
-static
-#else
-extern
-#endif
-int new_floppy_init(void);
+extern int floppy_init(void);
 extern void rd_load(void);
 extern long rd_init(long mem_start, int length);
 extern int ramdisk_size;
index 972197c975e58f941066cfeddd3caba919ffe6e8..15352fa3c625cf15174a5ded4410547b1d5711ca 100644 (file)
  * errors to allow safe writing by specialized programs.
  */
 
+/* 1994/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
+ * by defining bit 1 of the "stretch" parameter to mean put sectors on the
+ * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
+ * drives are "upside-down").
+ */
+
 #define CONFIG_FLOPPY_SANITY
 #undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
 
 /* do print messages for unexpected interrupts */
 static int print_unex=1;
 
+#ifdef MODULE
+#define FD_MODULE
+
+#include <linux/module.h>
+/*
+ * NB. we must include the kernel idenfication string in to install the module.
+ */
+#include <linux/version.h>
+char kernel_version[] = UTS_RELEASE;
+
+int FLOPPY_IRQ=6;
+int FLOPPY_DMA=2;
+int ALLOWED_DRIVE_MASK = 0x33;
+int FDC1 = 0x3f0;
+int FDC2 = -1;
+
+#endif
+
 #ifndef FD_MODULE
 /* the following is the mask of allowed drives. By default units 2 and
  * 3 of both floppy controllers are disabled, because switching on the
@@ -120,10 +144,12 @@ static int FDC2=-1;
 #include <linux/fd.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
+#include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/ioport.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -134,20 +160,49 @@ static int FDC2=-1;
 #define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
+
+/* Dma Memory related stuff */
+
+/* Pure 2^n version of get_order */
+static inline int __get_order (int size)
+{
+       int order;
+
+#ifdef  _ASM_IO_H2
+       __asm__ __volatile__("bsr %1,%0"
+                            : "=r" (order)
+                            : "r" (size / PAGE_SIZE) );        
+#else
+       for (order = 0; order < NR_MEM_LISTS; ++order)
+               if (size <= (PAGE_SIZE << order))
+                       return order; 
+#endif
+       return NR_MEM_LISTS;
+}
+
+static unsigned long dma_mem_alloc(int size)
+{
+       int order = __get_order(size);
+       
+       if (order >= NR_MEM_LISTS)
+               return(0);
+       return __get_dma_pages(GFP_KERNEL,order);
+}
+
+/* End dma memory related stuff */
+
 static unsigned int fake_change = 0;
 static int initialising=1;
 
-#define FLOPPY0_TYPE   ((CMOS_READ(0x10) >> 4) & 15)
-#define FLOPPY1_TYPE   (CMOS_READ(0x10) & 15)
-
 /*
  * Again, the CMOS information doesn't work on the alpha..
  */
 #ifdef __alpha__
-#undef FLOPPY0_TYPE
-#undef FLOPPY1_TYPE
 #define FLOPPY0_TYPE 6
 #define FLOPPY1_TYPE 0
+#else
+#define FLOPPY0_TYPE   ((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE   (CMOS_READ(0x10) & 15)
 #endif
 
 #define N_FDC 2
@@ -186,6 +241,9 @@ printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
 #define DPRINT3(x,x1,x2,x3) \
 printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
 
+#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
+#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
+
 /* read/write */
 #define COMMAND raw_cmd.cmd[0]
 #define DR_SELECT raw_cmd.cmd[1]
@@ -213,6 +271,7 @@ printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
 #define MAX_DISK_SIZE 2 /* 3984*/
 
 
+#define K_64   0x10000         /* 64KB */
 
 /*
  * The DMA channel used by the floppy controller cannot access data at
@@ -222,8 +281,12 @@ printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
  * driver otherwise. It doesn't matter much for performance anyway, as most
  * floppy accesses go through the track buffer.
  */
-#define LAST_DMA_ADDR  (0x1000000)
-#define K_64 (0x10000) /* 64 k */
+#ifdef __alpha__
+# define CROSS_64KB(a,s)       (0)
+#else
+# define CROSS_64KB(a,s) \
+       ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)
+#endif
 
 /*
  * globals used by 'result()'
@@ -299,9 +362,16 @@ static struct floppy_raw_cmd raw_cmd;
 /*
  * This struct defines the different floppy types.
  *
- * The 'stretch' tells if the tracks need to be doubled for some
- * types (ie 360kB diskette in 1.2MB drive etc). Others should
- * be self-explanatory.
+ * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
+ * types (e.g. 360kB diskette in 1.2MB drive, etc.).  Bit 1 of 'stretch'
+ * tells if the disk is in Commodore 1581 format, which means side 0 sectors
+ * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
+ * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
+ * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
+ * side 0 is on physical side 0 (but with the misnamed sector IDs).
+ * 'stretch' should probably be renamed to something more general, like
+ * 'options'.  Other parameters should be self-explanatory (see also
+ * setfdprm(8)).
  */
 static struct floppy_struct floppy_type[32] = {
        {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    }, /*  0 no testing    */
@@ -399,8 +469,8 @@ static struct format_descr format_req;
  * corrupted/lost. Alignment of these is enforced in boot/head.S.
  * Note that you must not change the sizes below without updating head.S.
  */
-extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
-#define max_buffer_sectors MAX_BUFFER_SECTORS
+char *floppy_track_buffer=0;
+int max_buffer_sectors=0;
 
 int *errors;
 typedef void (*done_f)(int);
@@ -410,7 +480,7 @@ void (*interrupt)(void); /* this is called after the interrupt of the
 void (*redo)(void); /* this is called to retry the operation */
 void (*error)(void); /* this is called to tally an error */
 done_f done; /* this is called to say if the operation has succeeded/failed */
-} *cont;
+} *cont=NULL;
 
 static void floppy_ready(void);
 static void floppy_start(void);
@@ -483,6 +553,65 @@ static inline void debugt(char *message)
 #endif
 }
 
+typedef void (*timeout_fn)(unsigned long);
+static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
+                                              (timeout_fn) floppy_shutdown };
+
+static char *timeout_message;
+
+#ifdef CONFIG_FLOPPY_SANITY
+static void is_alive(char *message)
+{
+       /* this routine checks whether the floppy driver is "alive" */
+       if (fdc_busy && command_status < 2 && !fd_timeout.prev){
+               DPRINT1("timeout handler died: %s\n",message);
+       }
+}
+#endif
+
+#ifdef CONFIG_FLOPPY_SANITY
+
+#define OLOGSIZE 20
+
+void (*lasthandler)(void) = NULL;
+int interruptjiffies=0;
+int resultjiffies=0;
+int resultsize=0;
+int lastredo=0;
+
+static struct output_log {
+       unsigned char data;
+       unsigned char status;
+       unsigned long jiffies;
+} output_log[OLOGSIZE];
+
+static int output_log_pos=0;
+#endif
+
+#define CURRENTD -1
+#define MAXTIMEOUT -2
+
+
+
+static void reschedule_timeout(int drive, char *message, int marg)
+{
+       if (drive == CURRENTD )
+               drive = current_drive;
+       del_timer(&fd_timeout);
+       if (drive < 0 || drive > N_DRIVE) {
+               fd_timeout.expires = 2000;
+               drive=0;
+       } else
+               fd_timeout.expires = UDP->timeout;
+       add_timer(&fd_timeout);
+       if (UDP->flags & FD_DEBUG){
+               DPRINT("reschedule timeout ");
+               printk(message, marg);
+               printk("\n");
+       }
+       timeout_message = message;
+}
+
 /*
  * Bottom half floppy driver.
  * ==========================
@@ -668,15 +797,13 @@ static int lock_fdc(int drive, int interruptible)
        sti();
        command_status = FD_COMMAND_NONE;
        set_fdc(drive);
+       reschedule_timeout(drive, "lock fdc", 0);
        return 0;
 }
 
 #define LOCK_FDC(drive,interruptible) \
 if(lock_fdc(drive,interruptible)) return -EINTR;
 
-typedef void (*timeout_fn)(unsigned long);
-static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
-                                              (timeout_fn) floppy_shutdown };
 
 /* unlocks the driver */
 static inline void unlock_fdc(void)
@@ -689,6 +816,7 @@ static inline void unlock_fdc(void)
                        DEVICE_INTR);
        command_status = FD_COMMAND_NONE;
        del_timer(&fd_timeout);
+       cont = NULL;
        fdc_busy = 0;
        floppy_release_irq_and_dma();
        wake_up(&fdc_wait);
@@ -878,15 +1006,13 @@ static void setup_DMA(void)
                FDCS->reset=1;
                return;
        }
-       if ( ( (long)current_addr & ~(64*1024-1) ) !=
-           ((long)(current_addr + raw_cmd.length-1)  & ~(64*1024-1))){
+       if (CROSS_64KB(current_addr, raw_cmd.length)) {
                printk("DMA crossing 64-K boundary %p-%p\n",
                       current_addr, current_addr + raw_cmd.length);
                cont->done(0);
                FDCS->reset=1;
                return;
        }
-
 #endif
        cli();
        disable_dma(FLOPPY_DMA);
@@ -894,7 +1020,7 @@ static void setup_DMA(void)
        set_dma_mode(FLOPPY_DMA,
                     (raw_cmd.flags & FD_RAW_READ)?
                     DMA_MODE_READ : DMA_MODE_WRITE);
-       set_dma_addr(FLOPPY_DMA, (long) current_addr);
+       set_dma_addr(FLOPPY_DMA, virt_to_bus(current_addr));
        set_dma_count(FLOPPY_DMA, raw_cmd.length);
        enable_dma(FLOPPY_DMA);
        sti();
@@ -906,15 +1032,24 @@ static int output_byte(char byte)
 {
        int counter;
        unsigned char status;
+       unsigned char rstatus;
 
        if (FDCS->reset)
                return -1;
        for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
-               status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
+               rstatus = inb_p(FD_STATUS); 
+               status =  rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA);
                if (!(status & STATUS_READY))
                        continue;
                if (status == STATUS_READY){
                        outb_p(byte,FD_DATA);
+
+#ifdef CONFIG_FLOPPY_SANITY
+                       output_log[output_log_pos].data = byte;
+                       output_log[output_log_pos].status = rstatus;
+                       output_log[output_log_pos].jiffies = jiffies;
+                       output_log_pos = (output_log_pos + 1) % OLOGSIZE;
+#endif
                        return 0;
                } else
                        break;
@@ -939,8 +1074,13 @@ static int result(void)
                        (STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
                if (!(status & STATUS_READY))
                        continue;
-               if (status == STATUS_READY)
+               if (status == STATUS_READY){
+#ifdef CONFIG_FLOPPY_SANITY
+                       resultjiffies = jiffies;
+                       resultsize = i;
+#endif
                        return i;
+               }
                if (status & STATUS_DMA )
                        break;
                if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
@@ -1112,7 +1252,7 @@ static int fdc_dtr(void)
         * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
         */
        FDCS->dtr = raw_cmd.rate;
-       return(wait_for_completion(jiffies+2,
+       return(wait_for_completion(jiffies+2*HZ/100,
                                   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
@@ -1467,6 +1607,9 @@ static void floppy_interrupt(int irq, struct pt_regs * regs)
 {
        void (*handler)(void) = DEVICE_INTR;
 
+       lasthandler = handler;
+       interruptjiffies = jiffies;
+
        floppy_enable_hlt();
        CLEAR_INTR;
        if ( fdc >= N_FDC || FDCS->address == -1){
@@ -1474,11 +1617,13 @@ static void floppy_interrupt(int irq, struct pt_regs * regs)
                printk("DOR0=%x\n", fdc_state[0].dor);
                printk("floppy interrupt on bizarre fdc %d\n",fdc);
                printk("handler=%p\n", handler);
+               is_alive("bizarre fdc");
                return;
        }
        inr = result();
        if (!handler){
                unexpected_floppy_interrupt();
+               is_alive("unexpected");
                return;
        }
        if ( inr == 0 ){
@@ -1489,6 +1634,7 @@ static void floppy_interrupt(int irq, struct pt_regs * regs)
        }
        floppy_tq.routine = (void *)(void *) handler;
        queue_task_irq(&floppy_tq, &tq_timer);
+       is_alive("normal interrupt end");
 }
 
 static void recalibrate_floppy(void)
@@ -1545,6 +1691,27 @@ void show_floppy(void)
        printk("\n");
        printk("floppy driver state\n");
        printk("-------------------\n");
+       printk("now=%ld last interrupt=%d last called handler=%p\n", 
+              jiffies, interruptjiffies, lasthandler);
+
+
+#ifdef CONFIG_FLOPPY_SANITY
+       printk("timeout_message=%s\n", timeout_message);
+       printk("last output bytes:\n");
+       for(i=0; i < OLOGSIZE; i++)
+               printk("%2x %2x %ld\n",                
+                      output_log[(i+output_log_pos) % OLOGSIZE].data,
+                      output_log[(i+output_log_pos) % OLOGSIZE].status,
+                      output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
+       printk("last result at %d\n", resultjiffies);
+       printk("last redo_fd_request at %d\n", lastredo);
+       for(i=0; i<resultsize; i++){
+               printk("%2x ", reply_buffer[i]);
+       }
+       printk("\n");
+#endif
+
+#if 0
        for(i=0; i<N_FDC; i++){
                if(FDCS->address != -1){
                        printk("dor %d = %x\n", i, fdc_state[i].dor );
@@ -1552,6 +1719,7 @@ void show_floppy(void)
                        udelay(1000); /* maybe we'll catch an interrupt... */
                }
        }
+#endif
        printk("status=%x\n", inb_p(FD_STATUS));
        printk("fdc_busy=%d\n", fdc_busy);
        if( DEVICE_INTR)
@@ -1573,6 +1741,8 @@ void show_floppy(void)
 
 static void floppy_shutdown(void)
 {
+       if(!initialising)
+               show_floppy();
        CLEAR_INTR;
        floppy_tq.routine = (void *)(void *) empty;
        del_timer( &fd_timer);
@@ -1584,8 +1754,14 @@ static void floppy_shutdown(void)
        if(!initialising)
                DPRINT("floppy timeout\n");
        FDCS->reset = 1;
-       cont->done(0);
-       cont->redo(); /* this will recall reset when needed */
+       if (cont){
+               cont->done(0);
+               cont->redo(); /* this will recall reset when needed */
+       } else {
+               printk("no cont in shutdown!\n");
+               process_fd_request();
+       }
+       is_alive("floppy shutdown");
 }
 /*typedef void (*timeout_fn)(unsigned long);*/
 
@@ -1646,9 +1822,7 @@ static void floppy_ready(void)
 
 static void floppy_start(void)
 {
-       del_timer(&fd_timeout);
-       fd_timeout.expires = DP->timeout;
-       add_timer(&fd_timeout);
+       reschedule_timeout(CURRENTD, "floppy start", 0);
 
        scandrives();
 #ifdef DCL_DEBUG
@@ -1663,7 +1837,7 @@ static void floppy_start(void)
 /*
  * ========================================================================
  * here ends the bottom half. Exported routines are:
 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
+ * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
  * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
  * Initialisation also uses output_byte, result, set_dor, floppy_interrupt
  * and set_dor.
@@ -1676,7 +1850,7 @@ static void floppy_start(void)
 
 static void do_wakeup(void)
 {
-       del_timer(&fd_timeout);
+       reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
        cont = 0;
        command_status += 2;
        wake_up(&command_done);
@@ -1697,7 +1871,8 @@ static int wait_til_done( void (*handler)(void ), int interruptible )
        queue_task(&floppy_tq, &tq_timer);
 
        cli();
-       while(command_status < 2 && NO_SIGNAL)
+       while(command_status < 2 && NO_SIGNAL){
+               is_alive("wait_til_done");      
                if (current->pid)
                        interruptible_sleep_on(&command_done);
                else {
@@ -1705,6 +1880,7 @@ static int wait_til_done( void (*handler)(void ), int interruptible )
                        run_task_queue(&tq_timer);
                        cli();
                }
+       }
        if(command_status < 2){
                sti();
                floppy_shutdown();
@@ -1834,7 +2010,7 @@ static void setup_format_params(void)
        raw_cmd.rate = floppy->rate & 0x3;
        raw_cmd.cmd_count = NR_F;
        COMMAND = FM_MODE(floppy,FD_FORMAT);
-       DR_SELECT = UNIT(current_drive) + ( format_req.head << 2 );
+       DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head);
        F_SIZECODE = FD_SIZECODE(floppy);
        F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE;
        F_GAP = floppy->fmt_gap;
@@ -1881,7 +2057,7 @@ static void setup_format_params(void)
 
 static void redo_format(void)
 {
-       raw_cmd.track = format_req.track << floppy->stretch;
+       raw_cmd.track = format_req.track << STRETCH(floppy);
        buffer_track = -1;
        setup_format_params();
        floppy_start();
@@ -1933,7 +2109,7 @@ static void request_done(int uptodate)
        int block;
 
        probing = 0;
-       del_timer(&fd_timeout);
+       reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
 
        if (!CURRENT){
                DPRINT("request list destroyed in floppy request done\n");
@@ -2222,13 +2398,15 @@ static int make_raw_rw_request(void)
        }
 
        max_sector = floppy->sect * floppy->head;
+
        TRACK = CURRENT->sector / max_sector;
        sector_t = CURRENT->sector % max_sector;
        if ( floppy->track && TRACK >= floppy->track )
                return 0;
        HEAD = sector_t / floppy->sect;
 
-       if ( TESTF( FD_NEED_TWADDLE) && sector_t < floppy->sect )
+       if (((floppy->stretch & FD_SWAPSIDES) || TESTF( FD_NEED_TWADDLE)) && 
+           sector_t < floppy->sect )
                max_sector = floppy->sect;
 
        /* 2M disks have phantom sectors on the first track */
@@ -2253,8 +2431,8 @@ static int make_raw_rw_request(void)
                SIZECODE2 = 0xff;
        else
                SIZECODE2 = 0x80;
-       raw_cmd.track = TRACK << floppy->stretch;
-       DR_SELECT = UNIT(current_drive) + ( HEAD << 2 );
+       raw_cmd.track = TRACK << STRETCH(floppy);
+       DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,HEAD);
        GAP = floppy->gap;
        CODE2SIZE;
        SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE;
@@ -2296,18 +2474,17 @@ static int make_raw_rw_request(void)
                raw_cmd.flags &= ~FD_RAW_WRITE;
                raw_cmd.flags |= FD_RAW_READ;
                COMMAND = FM_MODE(floppy,FD_READ);
-       } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
+       } else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS ) {
                int direct, indirect;
 
                indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
                        sector_t;
 
                max_size = buffer_chain_size();
-               if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
-                       max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
+               if ( max_size > ( MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9)
+                       max_size=(MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9;
                /* 64 kb boundaries */
-               if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
-                    ((long) CURRENT->buffer ) / K_64 )
+               if (CROSS_64KB(CURRENT->buffer, max_size << 9))
                        max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
                direct = transfer_size(ssize,max_sector,max_size) - sector_t;
                /*
@@ -2443,11 +2620,16 @@ static void redo_fd_request(void)
        int tmp;
        int error;
 
+
        error = -1;
+       lastredo = jiffies;
        if (current_drive < N_DRIVE)
                floppy_off(current_drive);
 
-       if (CURRENT && CURRENT->dev < 0) return;
+       if (CURRENT && CURRENT->dev < 0){
+               DPRINT("current dev < 0!\n");
+               return;
+       }
 
        while(1){
                if (!CURRENT) {
@@ -2470,10 +2652,7 @@ static void redo_fd_request(void)
                error=-1;
                device = CURRENT->dev;
                set_fdc( DRIVE(device));
-
-               del_timer(&fd_timeout);
-               fd_timeout.expires = DP->timeout;
-               add_timer(&fd_timeout);
+               reschedule_timeout(CURRENTD, "redo fd request", 0);
 
                set_floppy(device);
                if(start_motor(redo_fd_request)) return;
@@ -2531,14 +2710,18 @@ static void process_fd_request(void)
 
 static void do_fd_request(void)
 {
-       if (fdc_busy)
+       if (fdc_busy){
                /* fdc busy, this new request will be treated when the
                   current one is done */
+               is_alive("do fd request, old request running");
                return;
+       }
        /* fdc_busy cannot be set by an interrupt or a bh */
        floppy_grab_irq_and_dma();
        fdc_busy=1;
+       reschedule_timeout(MAXTIMEOUT, "do fd request",0);
        process_fd_request();
+       is_alive("do fd request");
 }
 
 static struct cont_t poll_cont={
@@ -2592,9 +2775,7 @@ static int user_reset_fdc(int drive, int arg, int interruptible)
                FDCS->reset=1;
        if ( FDCS->reset ){
                cont = &reset_cont;
-               del_timer(&fd_timeout);
-               fd_timeout.expires = DP->timeout;
-               add_timer(&fd_timeout);
+               reschedule_timeout(CURRENTD, "user reset fdc", 0);
                WAIT(reset_fdc);
        }
        process_fd_request();
@@ -2757,8 +2938,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        return i;
                name = drive_name(type,drive);
                for ( cnt=0; cnt<16; cnt++){
-                       put_fs_byte(name[cnt],
-                                   ((char*)param)+cnt);
+                       put_user(name[cnt], ((char*)param)+cnt);
                        if ( ! *name )
                                break;
                }
@@ -2831,8 +3011,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                if(newparams.sect <= 0 ||
                   newparams.head <= 0 ||
                   newparams.track <= 0 ||
-                  newparams.track >
-                  UDP->tracks>>newparams.stretch)
+                  newparams.track > UDP->tracks>> STRETCH(&newparams) ||
+                  /* check if reserved bits are set */
+                  (newparams.stretch & ~(FD_STRETCH | FD_SWAPSIDES)) != 0)
                        return -EINVAL;
                if ( type){
                        if ( !suser() )
@@ -3022,6 +3203,8 @@ static int floppy_open(struct inode * inode, struct file * filp)
 {
        int drive;
        int old_dev;
+       int try;
+       char *tmp;
 
        if (!filp) {
                DPRINT("Weird, open called with filp=0\n");
@@ -3029,6 +3212,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
        }
 
        drive = DRIVE(inode->i_rdev);
+
        if (drive >= N_DRIVE || 
            !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
            fdc_state[FDC(drive)].version == FDC_NONE)
@@ -3057,6 +3241,33 @@ static int floppy_open(struct inode * inode, struct file * filp)
        else
                UDRS->fd_ref++;
 
+       if (!floppy_track_buffer){
+               /* if opening an ED drive, reserve a big buffer,
+                * else reserve a small one */
+               if ((UDP->cmos == 6) || (UDP->cmos == 5))
+                       try = 64; /* Only 48 actually useful */
+               else
+                       try = 32; /* Only 24 actually useful */
+
+               tmp=(char *)dma_mem_alloc(1024 * try);
+               if (!tmp) {
+                       try >>= 1; /* buffer only one side */
+                       if (try < 16)
+                               try=16;
+                       tmp= (char *)dma_mem_alloc(1024*try);
+               }
+               if (!tmp) {
+                       DPRINT("Unable to allocate DMA memory\n");
+                       RETERR(ENXIO);
+               }
+               if (floppy_track_buffer){
+                       free_pages((unsigned long)tmp,__get_order(try*1024));
+               }else {
+                       floppy_track_buffer = tmp;
+                       max_buffer_sectors = try;
+               }
+       }
+
        UDRS->fd_device = inode->i_rdev;
 
        if (old_dev && old_dev != inode->i_rdev) {
@@ -3353,10 +3564,7 @@ void floppy_setup(char *str, int *ints)
        DPRINT("Read linux/drivers/block/README.fd\n");
 }
 
-#ifdef FD_MODULE
-static
-#endif
-int new_floppy_init(void)
+int floppy_init(void)
 {
        int i,drive;
        int have_no_fdc=0;
@@ -3377,7 +3585,7 @@ int new_floppy_init(void)
        blk_size[MAJOR_NR] = floppy_sizes;
        blksize_size[MAJOR_NR] = floppy_blocksizes;
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       del_timer(&fd_timeout);
+       reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
        config_types();
 
        fdc_state[0].address = FDC1;
@@ -3407,6 +3615,8 @@ int new_floppy_init(void)
                UDRS->keep_data = 0;
                UDRS->fd_ref = 0;
                UDRS->fd_device = 0;
+               floppy_track_buffer = NULL;
+               max_buffer_sectors = 0;
                UDRWE->write_errors = 0;
                UDRWE->first_error_sector = 0;
                UDRWE->first_error_generation = 0;
@@ -3430,6 +3640,11 @@ int new_floppy_init(void)
                        FDCS->address = -1;
                        continue;
                }
+               
+               request_region(FDCS->address, 6, "floppy");
+               request_region(FDCS->address+7, 1, "floppy DIR");
+               /* address + 6 is reserved, and may be taken by IDE.
+                * Unfortunately, Adaptec doesn't know this :-(, */
 
                have_no_fdc = 0;
                /* Not all FDCs seem to be able to handle the version command
@@ -3440,6 +3655,7 @@ int new_floppy_init(void)
                user_reset_fdc(-1,FD_RESET_ALWAYS,0);
        }
        fdc=0;
+       del_timer(&fd_timeout);
        current_drive = 0;
        floppy_release_irq_and_dma();
        initialising=0;
@@ -3448,12 +3664,6 @@ int new_floppy_init(void)
        return have_no_fdc;
 }
 
-/* stupid compatibility hack... */
-void floppy_init(void)
-{
-       new_floppy_init();
-}
-
 static int floppy_grab_irq_and_dma(void)
 {
        int i;
@@ -3499,6 +3709,9 @@ static void floppy_release_irq_and_dma(void)
 #ifdef CONFIG_FLOPPY_SANITY
        int drive;
 #endif
+       long tmpsize;
+       void *tmpaddr;
+
        cli();
        if (--usage_count){
                sti();
@@ -3518,13 +3731,22 @@ static void floppy_release_irq_and_dma(void)
        set_dor(1, ~8, 0);
 #endif
        floppy_enable_hlt();
+
+       if (floppy_track_buffer && max_buffer_sectors) {
+               tmpsize = max_buffer_sectors*1024;
+               tmpaddr = (void *)floppy_track_buffer;
+               floppy_track_buffer = 0;
+               max_buffer_sectors = 0;
+               free_pages((unsigned long)tmpaddr, __get_order(tmpsize));
+       }
+
 #ifdef CONFIG_FLOPPY_SANITY
        for(drive=0; drive < N_FDC * 4; drive++)
                if( motor_off_timer[drive].next )
                        printk("motor off timer %d still active\n", drive);
        
        if(fd_timeout.next)
-               printk("floppy timer still active\n");
+               printk("floppy timer still active:%s\n", timeout_message);
        if (fd_timer.next)
                printk("auxiliary floppy timer still active\n");
        if(floppy_tq.sync)
@@ -3532,3 +3754,82 @@ static void floppy_release_irq_and_dma(void)
 #endif
 }
 
+
+#ifdef MODULE
+
+extern char *get_options(char *str, int *ints);
+
+#if 0
+/* assuming that insmod is compiled as a.out binary using a shared
+   C library ... */
+int ENVIRON = 0x60090b34;
+
+static void
+mod_setup(char *name,
+         void (*setup)(char *, int *)) {
+       char **environ,*env,*ptr,c,i;
+       char line[100];
+       int ints[11];
+
+       environ = (char **) get_fs_long( ENVIRON );
+       
+       while((env = (char *)get_fs_long(environ))){
+               for(i=0; i<strlen(name); i++)
+                       if ( (char) get_fs_byte(env++) != name[i] )
+                               break;
+               if(i == strlen(name)){
+                       ptr=line;
+                       while(ptr < line+99){
+                               c = (char)get_fs_byte(env++);
+                               if ( c== ' ' || !c ){
+                                       *ptr='\0';
+                                       if(ptr!=line)
+                                               setup(get_options(line,ints),
+                                                     ints);
+                                       ptr=line;
+                                       if (!c)
+                                               break;
+                               } else
+                                       *ptr++ = c;
+                       }
+               }
+               environ++;
+       }
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int init_module(void)
+{
+       int ret;
+       printk("inserting floppy driver for %s\n", kernel_version);
+
+       /*mod_setup("floppy=", floppy_setup);*/
+       /* Can't do that any more, insmod is now ELF */
+
+       ret = floppy_init();
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       int fdc;
+
+       for(fdc=0; fdc<2; fdc++)
+               if (FDCS->address != -1){
+                       release_region(FDCS->address, 6);
+                       release_region(FDCS->address+7, 1);
+                     }
+
+       unregister_blkdev(MAJOR_NR, "fd");
+
+       blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index f17aa86d96db5446f6aa9736225adcd4a7df718a..f6561f57458b642a65283061b907c96514ee54e5 100644 (file)
@@ -375,9 +375,9 @@ static void reset_controller(void)
        int     i;
 
        outb_p(4,HD_CMD);
-       for(i = 0; i < 1000; i++) nop();
+       for(i = 0; i < 1000; i++) barrier();
        outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-       for(i = 0; i < 1000; i++) nop();
+       for(i = 0; i < 1000; i++) barrier();
        if (drive_busy())
                printk("hd: controller still busy\n");
        else if ((hd_error = inb(HD_ERROR)) != 1)
@@ -794,13 +794,13 @@ static int hd_ioctl(struct inode * inode, struct file * file,
                        err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
                        if (err)
                                return err;
-                       put_fs_byte(bios_info[dev].head,
+                       put_user(bios_info[dev].head,
                                (char *) &loc->heads);
-                       put_fs_byte(bios_info[dev].sect,
+                       put_user(bios_info[dev].sect,
                                (char *) &loc->sectors);
-                       put_fs_word(bios_info[dev].cyl,
+                       put_user(bios_info[dev].cyl,
                                (short *) &loc->cylinders);
-                       put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
+                       put_user(hd[MINOR(inode->i_rdev)].start_sect,
                                (long *) &loc->start);
                        return 0;
                case BLKRASET:
@@ -813,14 +813,14 @@ static int hd_ioctl(struct inode * inode, struct file * file,
                        err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
                        if (err)
                                return err;
-                       put_fs_long(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+                       put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
                        return 0;
                case BLKGETSIZE:   /* Return device size */
                        if (!arg)  return -EINVAL;
                        err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
                        if (err)
                                return err;
-                       put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
+                       put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
                        return 0;
                case BLKFLSBUF:
                        if(!suser())  return -EACCES;
@@ -843,7 +843,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
                        err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
                        if (err)
                                return err;
-                       put_fs_long(unmask_intr[dev], (long *) arg);
+                       put_user(unmask_intr[dev], (long *) arg);
                        return 0;
 
                 case HDIO_GET_MULTCOUNT:
@@ -851,7 +851,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
                        err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
                        if (err)
                                return err;
-                       put_fs_long(mult_count[dev], (long *) arg);
+                       put_user(mult_count[dev], (long *) arg);
                        return 0;
 
                case HDIO_SET_MULTCOUNT:
@@ -954,12 +954,14 @@ static void hd_interrupt(int irq, struct pt_regs *regs)
  */
 static void hd_geninit(void)
 {
-       int drive, i;
-       extern struct drive_info drive_info;
-       unsigned char *BIOS = (unsigned char *) &drive_info;
-       int cmos_disks;
+       int i;
+
+#ifdef __i386__
+       if (!NR_HD) {
+               extern struct drive_info drive_info;
+               unsigned char *BIOS = (unsigned char *) &drive_info;
+               int cmos_disks, drive;
 
-       if (!NR_HD) {      
                for (drive=0 ; drive<2 ; drive++) {
                        bios_info[drive].cyl   = hd_info[drive].cyl = *(unsigned short *) BIOS;
                        bios_info[drive].head  = hd_info[drive].head = *(2+BIOS);
@@ -1002,6 +1004,7 @@ static void hd_geninit(void)
                        else
                                NR_HD = 1;
        }
+#endif /* __i386__ */
        i = NR_HD;
        while (i-- > 0) {
                /*
index a72ea3b0a15520cf0d634ac5053877603c0b7c20..9507c6a527661700e3e7b25d1eff84f7def43579 100644 (file)
 #define REALLY_SLOW_IO                 /* most systems can safely undef this */
 #include <asm/io.h>
 
+#ifdef __alpha__
+# ifndef SUPPORT_VLB_SYNC
+#  define SUPPORT_VLB_SYNC     0
+# endif
+#endif
+
 #undef REALLY_FAST_IO                  /* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT     0       /* off=0; on=2,4,8,16,32, etc.. */
 #ifndef SUPPORT_VLB_32BIT              /* 1 to support 32bit I/O on VLB */
@@ -286,11 +292,11 @@ static uint probe_dtc2278 = 0;
 /*
  * Timeouts for various operations:
  */
-#define WAIT_DRQ             /* 50msec - spec allows up to 20ms */
-#define WAIT_READY           /* 30msec - should be instantaneous */
-#define WAIT_PIDENTIFY 100     /* 1sec   - should be less than 3ms (?) */
-#define WAIT_WORSTCASE 3000    /* 30sec  - worst case when spinning up */
-#define WAIT_CMD       1000    /* 10sec  - maximum wait for an IRQ to happen */
+#define WAIT_DRQ       (5*HZ/100)      /* 50msec - spec allows up to 20ms */
+#define WAIT_READY     (3*HZ/100)      /* 30msec - should be instantaneous */
+#define WAIT_PIDENTIFY (1*HZ)  /* 1sec   - should be less than 3ms (?) */
+#define WAIT_WORSTCASE (30*HZ) /* 30sec  - worst case when spinning up */
+#define WAIT_CMD       (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
 
 /*
  * Now for the data we need to maintain per-device:  ide_dev_t
@@ -409,7 +415,7 @@ static struct gendisk       ide_gendisk  [2] =
 #include "blk.h"
 
 /*
- * For really screwy hardware (hey, at least it *can* be used with Linux!
+ * For really screwy hardware (hey, at least it *can* be used with Linux!)
  */
 #if (DISK_RECOVERY_TIME > 0)
 static unsigned long   ide_lastreq[] = {0,0}; /* completion time of last I/O */
@@ -1505,7 +1511,7 @@ static int write_fs_long (unsigned long useraddr, long value)
                return -EINVAL;
        if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
                return err;
-       put_fs_long((unsigned)value, (long *) useraddr);
+       put_user((unsigned)value, (long *) useraddr);
        return 0;
 }
 
@@ -1526,13 +1532,13 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        if (!loc || dev->type != disk) return -EINVAL;
                        err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
                        if (err) return err;
-                       put_fs_byte(dev->bios_head,
+                       put_user(dev->bios_head,
                                (char *) &loc->heads);
-                       put_fs_byte(dev->bios_sect,
+                       put_user(dev->bios_sect,
                                (char *) &loc->sectors);
-                       put_fs_word(dev->bios_cyl,
+                       put_user(dev->bios_cyl,
                                (short *) &loc->cylinders);
-                       put_fs_long((unsigned)ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].start_sect,
+                       put_user((unsigned)ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].start_sect,
                                (long *) &loc->start);
                        return 0;
 
@@ -1636,9 +1642,9 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        else {
                                if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long))))
                                {
-                                       args = get_fs_long((long *)arg);
+                                       args = get_user((long *)arg);
                                        err = do_drive_cmd(inode->i_rdev,(char *)&args);
-                                       put_fs_long(args,(long *)arg);
+                                       put_user(args,(long *)arg);
                                }
                        }
                        return err;
@@ -1808,8 +1814,11 @@ static void do_identify (ide_dev_t *dev, byte cmd)
 
                /* check for word-swapped "capacity" field in id information */
                check = (id->cur_capacity0 << 16) | id->cur_capacity1;
-               if (check == capacity)          /* was it swapped? */
-                       *((int *)&id->cur_capacity0) = capacity; /* fix it */
+               if (check == capacity) {        /* was it swapped? */
+                       /* yes, bring it into little-endian order: */
+                       id->cur_capacity0 = (capacity >>  0) & 0xffff;
+                       id->cur_capacity1 = (capacity >> 16) & 0xffff;
+               }
        }
        /* Use physical geometry if what we have still makes no sense */
        if ((!dev->head || dev->head > 16) && id->heads && id->heads <= 16) {
@@ -1848,9 +1857,13 @@ static void do_identify (ide_dev_t *dev, byte cmd)
        printk("\n");
 }
 
+/*
+ * Delay for *at least* 10ms.  As we don't know how much time is left
+ * until the next tick occurs, we wait an extra tick to be safe.
+ */
 static void delay_10ms (void)
 {
-       unsigned long timer = jiffies + 2;
+       unsigned long timer = jiffies + (HZ + 99)/100 + 1;
        while (timer > jiffies);
 }
 
@@ -1872,6 +1885,7 @@ static int try_to_identify (ide_dev_t *dev, byte cmd)
        OUT_BYTE(dev->ctl|2,HD_CMD);            /* disable device irq */
 #if PROBE_FOR_IRQS
        if (!irq_probed[DEV_HWIF]) {            /* already probed for IRQ? */
+               probe_irq_off(probe_irq_on());  /* clear dangling irqs */
                irqs = probe_irq_on();          /* start monitoring irqs */
                OUT_BYTE(dev->ctl,HD_CMD);      /* enable device irq */
        }
@@ -2167,9 +2181,10 @@ void hdd_setup(char *str, int *ints)
  * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value 
  * means we have an AT controller hard disk for that drive.
  */
-extern struct drive_info_struct drive_info;
 static void probe_cmos_for_drives (void)
 {
+#ifdef __i386__
+       extern struct drive_info_struct drive_info;
        byte drive, cmos_disks, *BIOS = (byte *) &drive_info;
 
        outb_p(0x12,0x70);              /* specify CMOS address 0x12 */
@@ -2190,6 +2205,7 @@ static void probe_cmos_for_drives (void)
                }
                BIOS += 16;
        }
+#endif
 }
 #endif /* CONFIG_BLK_DEV_HD */
 
@@ -2378,7 +2394,7 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end)
                                continue;
 #else
                                probe_cmos_for_drives ();
-#endif /* CONFIG_BLJ_DEV_HD */
+#endif /* CONFIG_BLK_DEV_HD */
                        probe_mem_start = (mem_start + 3uL) & ~3uL;
                        probe_for_drives (hwif);
                        mem_start = probe_mem_start;
index 53c1f97a0db17c15ce3c6db7b30b9111e278808c..36cbaffc9155695ea24009f2419518d5cf4488c5 100644 (file)
@@ -520,9 +520,9 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
 
 void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
 {
-       int i;
+       int i, j;
        int buffersize;
-       struct request * req;
+       struct request * req[8];
        unsigned int major = MAJOR(dev);
        struct semaphore sem = MUTEX_LOCKED;
 
@@ -542,20 +542,34 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
        
        buffersize = PAGE_SIZE / nb;
 
-       for (i=0; i<nb; i++, buf += buffersize)
+       for (j=0, i=0; i<nb;)
        {
-               req = get_request_wait(NR_REQUEST, dev);
-               req->cmd = rw;
-               req->errors = 0;
-               req->sector = (b[i] * buffersize) >> 9;
-               req->nr_sectors = buffersize >> 9;
-               req->current_nr_sectors = buffersize >> 9;
-               req->buffer = buf;
-               req->sem = &sem;
-               req->bh = NULL;
-               req->next = NULL;
-               add_request(major+blk_dev,req);
-               down(&sem);
+               for (; j < 8 && i < nb; j++, i++, buf += buffersize)
+               {
+                       if (j == 0) {
+                               req[j] = get_request_wait(NR_REQUEST, dev);
+                       } else {
+                               cli();
+                               req[j] = get_request(NR_REQUEST, dev);
+                               sti();
+                               if (req[j] == NULL)
+                                       break;
+                       }
+                       req[j]->cmd = rw;
+                       req[j]->errors = 0;
+                       req[j]->sector = (b[i] * buffersize) >> 9;
+                       req[j]->nr_sectors = buffersize >> 9;
+                       req[j]->current_nr_sectors = buffersize >> 9;
+                       req[j]->buffer = buf;
+                       req[j]->sem = &sem;
+                       req[j]->bh = NULL;
+                       req[j]->next = NULL;
+                       add_request(major+blk_dev,req[j]);
+               }
+               while (j > 0) {
+                       j--;
+                       down(&sem);
+               }
        }
 }
 
index 46cb09957631590652cffeb7c8ed4c5c85fddf64..f010f9879a4d0ec9e5146f94e033991feb4f8344 100644 (file)
@@ -246,10 +246,10 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
                                if (arg) {
                                        if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
                                                return (err);
-                                       put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
-                                       put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
-                                       put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
-                                       put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
+                                       put_user(xd_info[dev].heads, &geometry->heads);
+                                       put_user(xd_info[dev].sectors, &geometry->sectors);
+                                       put_user(xd_info[dev].cylinders, &geometry->cylinders);
+                                       put_user(xd[MINOR(inode->i_rdev)].start_sect,&geometry->start);
 
                                        return (0);
                                }
@@ -264,7 +264,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
                                if (arg) {
                                        if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
                                                return (err);
-                                       put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+                                       put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 
                                        return (0);
                                }
@@ -398,7 +398,7 @@ static void xd_interrupt_handler(int irq, struct pt_regs * regs)
 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
 {
        if (buffer < ((u_char *) 0x1000000 - count)) {          /* transfer to address < 16M? */
-               if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
+               if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) {
 #ifdef DEBUG_OTHER
                        printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 #endif /* DEBUG_OTHER */
index e885977187ff4761d6af9e7f2de47cef2f8dbeec..da70da8806c077595303d9340feef14c0681757d 100644 (file)
@@ -128,19 +128,19 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
                return -EAGAIN;
        ATIXL_MSE_DISABLE_UPDATE();
        /* Allowed interrupts to occur during data gathering - shouldn't hurt */
-       put_fs_byte((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
+       put_user((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
        if (mouse.dx < -127)
                mouse.dx = -127;
        if (mouse.dx > 127)
                mouse.dx =  127;
-       put_fs_byte((char)mouse.dx, buffer + 1);
+       put_user((char)mouse.dx, buffer + 1);
        if (mouse.dy < -127)
                mouse.dy = -127;
        if (mouse.dy > 127)
                mouse.dy =  127;
-       put_fs_byte((char)-mouse.dy, buffer + 2);
+       put_user((char)-mouse.dy, buffer + 2);
        for(i = 3; i < count; i++)
-               put_fs_byte(0x00, buffer + i);
+               put_user(0x00, buffer + i);
        mouse.dx = 0;
        mouse.dy = 0;
        mouse.latch_buttons = mouse.buttons;
index 7bbec7e404f727ce5788506fae54a64f5aeaa2cc..120efcb6e31f89ca6bcb435442843a2c8ea43c69 100644 (file)
@@ -151,7 +151,7 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
         * Obtain the current mouse parameters and limit as appropriate for
         * the return data format.  Interrupts are only disabled while 
         * obtaining the parameters, NOT during the puts_fs_byte() calls,
-        * so paging in put_fs_byte() does not effect mouse tracking.
+        * so paging in put_user() does not effect mouse tracking.
         */
 
        MSE_INT_OFF();
@@ -171,11 +171,11 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
        mouse.ready = 0;
        MSE_INT_ON();
 
-       put_fs_byte(buttons | 0x80, buffer);
-       put_fs_byte((char)dx, buffer + 1);
-       put_fs_byte((char)dy, buffer + 2);
+       put_user(buttons | 0x80, buffer);
+       put_user((char)dx, buffer + 1);
+       put_user((char)dy, buffer + 2);
        for (r = 3; r < count; r++)
-           put_fs_byte(0x00, buffer + r);
+           put_user(0x00, buffer + r);
        return r;
 }
 
index 8717106e28910d07b869d7e454936ad1ad15b456..603d7917d25a50ed88801cd3f98123e66ee460ce 100644 (file)
@@ -2441,10 +2441,10 @@ static int set_get_font(char * arg, int set, int ch512)
            arg += cmapsz;
            if (set)
              for (i=0; i<cmapsz ; i++)
-               *(charmap+i) = get_fs_byte(arg+i);
+               *(charmap+i) = get_user(arg+i);
            else
              for (i=0; i<cmapsz ; i++)
-               put_fs_byte(*(charmap+i), arg+i);
+               put_user(*(charmap+i), arg+i);
          };
 
        cli();
index b37e923f94ca8b611baaccd778929ff553ed39c6..424ed63b12d473302b9d8e942450fa420f8ca9a8 100644 (file)
@@ -221,7 +221,7 @@ int con_set_trans_old(char * arg)
                return i;
 
        for (i=0; i<E_TABSZ ; i++)
-               p[i] = UNI_DIRECT_BASE | get_fs_byte(arg+i);
+               p[i] = UNI_DIRECT_BASE | get_user(arg+i);
 
        set_inverse_transl(USER_MAP);
        return 0;
@@ -239,7 +239,7 @@ int con_get_trans_old(char * arg)
        for (i=0; i<E_TABSZ ; i++)
          {
            ch = conv_uni_to_pc(p[i]);
-           put_fs_byte((ch & ~0xff) ? 0 : ch, arg+i);
+           put_user((ch & ~0xff) ? 0 : ch, arg+i);
          }
        return 0;
 }
@@ -254,7 +254,7 @@ int con_set_trans_new(ushort * arg)
                return i;
 
        for (i=0; i<E_TABSZ ; i++)
-         p[i] = get_fs_word(arg+i);
+         p[i] = get_user(arg+i);
 
        set_inverse_transl(USER_MAP);
        return 0;
@@ -271,7 +271,7 @@ int con_get_trans_new(ushort * arg)
                return i;
 
        for (i=0; i<E_TABSZ ; i++)
-         put_fs_word(p[i], arg+i);
+         put_user(p[i], arg+i);
        
        return 0;
 }
@@ -331,7 +331,7 @@ con_set_unimap(ushort ct, struct unipair *list){
        if (!hashtable_contents_valid)
          con_clear_unimap(&hashdefaults);
        while(ct) {
-           u = get_fs_word(&list->unicode);
+           u = get_user(&list->unicode);
            i = u % hashsize;
            lct = 1;
            while ((hu = hashtable[i].unicode) != 0xffff && hu != u) {
@@ -344,7 +344,7 @@ con_set_unimap(ushort ct, struct unipair *list){
            if (lct > hashlevel)
              hashlevel = lct;
            hashtable[i].unicode = u;
-           hashtable[i].fontpos = get_fs_word(&list->fontpos);
+           hashtable[i].fontpos = get_user(&list->fontpos);
            list++;
            ct--;
        }
@@ -364,12 +364,12 @@ con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
          for (i = 0; i<hashsize; i++)
            if (hashtable[i].unicode != 0xffff) {
                if (ect++ < ct) {
-                   put_fs_word(hashtable[i].unicode, &list->unicode);
-                   put_fs_word(hashtable[i].fontpos, &list->fontpos);
+                   put_user(hashtable[i].unicode, &list->unicode);
+                   put_user(hashtable[i].fontpos, &list->fontpos);
                    list++;
                }
            }
-       put_fs_word(ect, uct);
+       put_user(ect, uct);
        return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
index cbeb31ae0c64a84ad2984b423562140298b84bb6..fe785607c90f1ab745091e57b9fa157e5916529f 100644 (file)
@@ -1851,7 +1851,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
             | ((status  & CyRI) ? TIOCM_RNG : 0)
             | ((status  & CyDSR) ? TIOCM_DSR : 0)
             | ((status  & CyCTS) ? TIOCM_CTS : 0);
-    put_fs_long(result,(unsigned long *) value);
+    put_user(result,value);
     return 0;
 } /* get_modem_info */
 
@@ -1862,7 +1862,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
   int card,chip,channel;
   unsigned char *base_addr;
   unsigned long flags;
-  unsigned int arg = get_fs_long((unsigned long *) value);
+  unsigned int arg = get_user(value);
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
@@ -2175,8 +2175,8 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
-                        (unsigned long *) arg);
+            put_user(C_CLOCAL(tty) ? 1 : 0,
+                        (unsigned int *) arg);
             break;
         case TIOCSSOFTCAR:
             arg = get_fs_long((unsigned long *) arg);
index 9264da38acd88c1414c3cf86cf21d9135d9f1b36..00077d85b00c023b0ce6cfacaa2c2d54c156f9bd 100644 (file)
@@ -248,7 +248,7 @@ static int lp_write_polled(struct inode * inode, struct file * file,
 
        temp = buf;
        while (count > 0) {
-               c = get_fs_byte(temp);
+               c = get_user(temp);
                retval = lp_char_polled(c, minor);
                /* only update counting vars if character was printed */
                if (retval) { count--; temp++;
@@ -527,17 +527,25 @@ static struct file_operations lp_fops = {
        lp_release
 };
 
-#ifndef MODULE
+#ifdef MODULE
+char kernel_version[]=UTS_RELEASE;
 
+int init_module(void)
+#else
 long lp_init(long kmem_start)
+#endif
 {
        int offset = 0;
        unsigned int testvalue = 0;
        int count = 0;
 
        if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
-               printk("unable to get major %d for line printer\n", LP_MAJOR);
+               printk("lp: unable to get major %d\n", LP_MAJOR);
+#ifdef MODULE
+               return -EIO;
+#else          
                return kmem_start;
+#endif
        }
        /* take on all known port values */
        for (offset = 0; offset < LP_NO; offset++) {
@@ -554,65 +562,35 @@ long lp_init(long kmem_start)
                        printk("lp%d at 0x%04x, ", offset,LP_B(offset));
                        request_region(LP_B(offset), 3, "lp");
                        if (LP_IRQ(offset))
-                               printk("using IRQ%d\n", LP_IRQ(offset));
+                               printk("(irq = %d)\n", LP_IRQ(offset));
                        else
-                               printk("using polling driver\n");
+                               printk("(polling)\n");
                        count++;
                }
        }
        if (count == 0)
-               printk("lp_init: no lp devices found\n");
-       return kmem_start;
-}
-
-#else
+               printk("lp: Driver configured but no interfaces found.\n");
 
-char kernel_version[]= UTS_RELEASE;
 
-int init_module(void)
-{
-       int offset = 0;
-       unsigned int testvalue = 0;
-       int count = 0;
-
-       if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
-               printk("unable to get major %d for line printer\n", LP_MAJOR);
-               return -EIO;
-       }
-       /* take on all known port values */
-       for (offset = 0; offset < LP_NO; offset++) {
-               /* write to port & read back to check */
-               outb_p( LP_DUMMY, LP_B(offset));
-               for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
-                       ;
-               testvalue = inb_p(LP_B(offset));
-               if (testvalue == LP_DUMMY) {
-                       LP_F(offset) |= LP_EXIST;
-                       lp_reset(offset);
-                       printk("lp%d at 0x%04x, ", offset,LP_B(offset));
-                       request_region(LP_B(offset),3,"lp");
-                       if (LP_IRQ(offset))
-                               printk("using IRQ%d\n", LP_IRQ(offset));
-                       else
-                               printk("using polling driver\n");
-                       count++;
-               }
-       }
-       if (count == 0)
-               printk("lp_init: no lp devices found\n");
+#ifdef MODULE
        return 0;
+#else  
+       return kmem_start;
+#endif
 }
 
+#ifdef MODULE
 void cleanup_module(void)
 {
         int offset;
        if(MOD_IN_USE)
                printk("lp: busy - remove delayed\n");
-        else
+        else {
                unregister_chrdev(LP_MAJOR,"lp");
               for (offset = 0; offset < LP_NO; offset++) 
                        if(LP_F(offset) && LP_EXIST) 
                                release_region(LP_B(offset),3);
+       }
 }
 
 #endif
index af8bc4273b06f4183ef82c7679af7b6cf38bcf63..be96f4cb8e79a208945fb15fce6b32bee16a16ae 100644 (file)
@@ -48,7 +48,7 @@ static int read_mem(struct inode * inode, struct file * file,char * buf, int cou
                count = high_memory - p;
        read = 0;
        while (p < PAGE_SIZE && count > 0) {
-               put_fs_byte(0,buf);
+               put_user(0,buf);
                buf++;
                p++;
                count--;
@@ -126,7 +126,7 @@ static int read_port(struct inode * inode,struct file * file,char * buf, int cou
        char * tmp = buf;
 
        while (count-- > 0 && i < 65536) {
-               put_fs_byte(inb(i),tmp);
+               put_user(inb(i),tmp);
                i++;
                tmp++;
        }
@@ -140,7 +140,7 @@ static int write_port(struct inode * inode,struct file * file,char * buf, int co
        char * tmp = buf;
 
        while (count-- > 0 && i < 65536) {
-               outb(get_fs_byte(tmp),i);
+               outb(get_user(tmp),i);
                i++;
                tmp++;
        }
@@ -163,7 +163,7 @@ static int read_zero(struct inode * node,struct file * file,char * buf,int count
        int left;
 
        for (left = count; left > 0; left--) {
-               put_fs_byte(0,buf);
+               put_user(0,buf);
                buf++;
        }
        return count;
index 6c4954ae56b4d3c31fdec58c39b6999c0d43c278..2b4c7e8b494f43dc6452e7c946cf8035ca93ab67 100644 (file)
@@ -109,13 +109,13 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
                return -EINVAL;
        if (!mouse.ready)
                return -EAGAIN;
-       put_fs_byte(mouse.buttons | 0x80, buffer);
+       put_user(mouse.buttons | 0x80, buffer);
        dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ?  127 :  mouse.dx;
        dy = mouse.dy < -127 ?  127 : mouse.dy > 127 ? -127 : -mouse.dy;
-       put_fs_byte((char)dx, buffer + 1);
-       put_fs_byte((char)dy, buffer + 2);
+       put_user((char)dx, buffer + 1);
+       put_user((char)dy, buffer + 2);
        for (i = 3; i < count; i++)
-               put_fs_byte(0x00, buffer + i);
+               put_user(0x00, buffer + i);
        mouse.dx -= dx;
        mouse.dy += dy;
        mouse.ready = 0;
index 28964d27e3bc1d2f121e341d1889d22a799c058f..1bafe6933ad1fc4e6d26f08f70e3225c7374fd32 100644 (file)
@@ -803,7 +803,7 @@ do_it_again:
                if (tty->packet && tty->link->ctrl_status) {
                        if (b != buf)
                                break;
-                       put_fs_byte(tty->link->ctrl_status, b++);
+                       put_user(tty->link->ctrl_status, b++);
                        tty->link->ctrl_status = 0;
                        break;
                }
@@ -840,7 +840,7 @@ do_it_again:
 
                /* Deal with packet mode. */
                if (tty->packet && b == buf) {
-                       put_fs_byte(TIOCPKT_DATA, b++);
+                       put_user(TIOCPKT_DATA, b++);
                        nr--;
                }
 
@@ -861,7 +861,7 @@ do_it_again:
                                tty->read_cnt--;
                                enable_bh(TQUEUE_BH);
                                if (!eol) {
-                                       put_fs_byte(c, b++);
+                                       put_user(c, b++);
                                        if (--nr)
                                                continue;
                                        break;
@@ -870,7 +870,7 @@ do_it_again:
                                        tty->canon_data = 0;
                                }
                                if (c != __DISABLED_CHAR) {
-                                       put_fs_byte(c, b++);
+                                       put_user(c, b++);
                                        nr--;
                                }
                                break;
@@ -939,7 +939,7 @@ static int write_chan(struct tty_struct * tty, struct file * file,
                }
                if (O_OPOST(tty)) {
                        while (nr > 0) {
-                               c = get_fs_byte(b);
+                               c = get_user(b);
                                if (opost(c, tty) < 0)
                                        break;
                                b++; nr--;
index 774a6669accea268bb4acbfda2808ee30d82ae26..4c4b534d17e2725da5667371fd257e61883d1672 100644 (file)
@@ -140,7 +140,7 @@ static int aux_write_ack(int val)
        while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL
                    && retries < MAX_RETRIES) {          /* wait for ack */
                        current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + 5;
+               current->timeout = jiffies + (5*HZ + 99) / 100;
                schedule();
                retries++;
         }
@@ -232,7 +232,9 @@ static void qp_interrupt(int cpl, struct pt_regs * regs)
 
 static void release_aux(struct inode * inode, struct file * file)
 {
+#ifndef __alpha__
        aux_write_dev(AUX_DISABLE_DEV);         /* disable aux device */
+#endif
        aux_write_cmd(AUX_INTS_OFF);            /* disable controller ints */
        poll_aux_status();
        outb_p(AUX_DISABLE,AUX_COMMAND);        /* Disable Aux device */
@@ -342,7 +344,7 @@ static int write_aux(struct inode * inode, struct file * file, char * buffer, in
                outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
                if (!poll_aux_status())
                        return -EIO;
-               outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
+               outb_p(get_user(buffer++),AUX_OUTPUT_PORT);
        }
        inode->i_mtime = CURRENT_TIME;
        return count;
@@ -361,7 +363,7 @@ static int write_qp(struct inode * inode, struct file * file, char * buffer, int
        while (i--) {
                if (!poll_qp_status())
                        return -EIO;
-               outb_p(get_fs_byte(buffer++), qp_data);
+               outb_p(get_user(buffer++), qp_data);
        }
        inode->i_mtime = CURRENT_TIME;
        return count;
@@ -394,7 +396,7 @@ repeat:
        }               
        while (i > 0 && !queue_empty()) {
                c = get_from_queue();
-               put_fs_byte(c, buffer++);
+               put_user(c, buffer++);
                i--;
        }
        aux_ready = !queue_empty();
@@ -489,7 +491,7 @@ static int poll_aux_status(void)
                if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
                        inb_p(AUX_INPUT_PORT);
                current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + 5;
+               current->timeout = jiffies + (5*HZ + 99) / 100;
                schedule();
                retries++;
        }
@@ -512,7 +514,7 @@ static int poll_qp_status(void)
                if (inb_p(qp_status)&(QP_RX_FULL))
                        inb_p(qp_data);
                current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + 5;
+               current->timeout = jiffies + (5*HZ + 99) / 100;
                schedule();
                retries++;
        }
index 81cbd9e5e1ed62e8fd1b9f278d58fcf835fa3cf0..75130f85ad398cd35e282bd719e839e763125958 100644 (file)
@@ -1018,7 +1018,7 @@ static inline int is_grouped(register struct scc_channel *scc)
                if (scc2 == scc || !(scc2->tty && grp2)) 
                        return 0;
                
-               if (grp1 & 0x3f == grp2 & 0x3f)
+               if ((grp1 & 0x3f) == (grp2 & 0x3f))
                {
                        if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
                                return 1;
@@ -1821,7 +1821,7 @@ scc_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned
                
                restore_flags(flags);
                        
-               put_fs_long(result,(unsigned long *) arg);
+               put_user(result,(unsigned int *) arg);
                return 0;
        case TIOCMBIS:
        case TIOCMBIC:
@@ -1836,7 +1836,7 @@ scc_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned
                        scc->wreg[R5] &= ~RTS;
                        break;
                case TIOCMSET:
-                       value = get_fs_long((unsigned long *) arg);
+                       value = get_user((unsigned int *) arg);
                        
                        if(value & TIOCM_DTR)
                                scc->wreg[R5] |= DTR;
index 552db4a61664d2a088b54eece6611ac9890a890d..d9c341ebbba0c8f9db2da3e3dd981f3474b52f09 100644 (file)
@@ -121,11 +121,11 @@ int set_selection(const unsigned long arg, struct tty_struct *tty)
        { unsigned short *args, xs, ys, xe, ye;
 
          args = (unsigned short *)(arg + 1);
-         xs = get_fs_word(args++) - 1;
-         ys = get_fs_word(args++) - 1;
-         xe = get_fs_word(args++) - 1;
-         ye = get_fs_word(args++) - 1;
-         sel_mode = get_fs_word(args);
+         xs = get_user(args++) - 1;
+         ys = get_user(args++) - 1;
+         xe = get_user(args++) - 1;
+         ye = get_user(args++) - 1;
+         sel_mode = get_user(args);
 
          xs = limit(xs, video_num_columns - 1);
          ys = limit(ys, video_num_lines - 1);
index fc78749642bd6d862a72d78d95b570ae5ee913bc..05464bef2e65ad5f3358ba6c47373395855c64cb 100644 (file)
@@ -1571,7 +1571,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
        status = serial_in(info, UART_LSR);
        sti();
        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       put_fs_long(result,(unsigned long *) value);
+       put_user(result,value);
        return 0;
 }
 
@@ -1591,7 +1591,7 @@ static int get_modem_info(struct async_struct * info, unsigned int *value)
                | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
                | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
                | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-       put_fs_long(result,(unsigned long *) value);
+       put_user(result,value);
        return 0;
 }
 
@@ -1604,7 +1604,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
        error = verify_area(VERIFY_READ, value, sizeof(int));
        if (error)
                return error;
-       arg = get_fs_long((unsigned long *) value);
+       arg = get_user(value);
        switch (cmd) {
        case TIOCMBIS: 
                if (arg & TIOCM_RTS) {
index dd37af685e068b3a00907f8a5c2103737adf4808..976990fed1e43b8858140f2d26191f3153942578 100644 (file)
@@ -1289,11 +1289,11 @@ static int do_get_ps_info(unsigned long arg)
                        c = (char *)(*p);
                        d = (char *)(ts->tasks+n);
                        for (i=0 ; i<sizeof(struct task_struct) ; i++)
-                               put_fs_byte(*c++, d++);
-                       put_fs_long(1, (unsigned long *)(ts->present+n));
+                               put_user(*c++, d++);
+                       put_user(1, ts->present+n);
                }
                else    
-                       put_fs_long(0, (unsigned long *)(ts->present+n));
+                       put_user(0, ts->present+n);
        return(0);                      
 }
 #endif
@@ -1326,7 +1326,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                        retval = verify_area(VERIFY_READ, (void *) arg, 1);
                        if (retval)
                                return retval;
-                       ch = get_fs_byte((char *) arg);
+                       ch = get_user((char *) arg);
                        tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
                        return 0;
                case TIOCGWINSZ:
@@ -1367,10 +1367,10 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                        redirect = real_tty;
                        return 0;
                case FIONBIO:
-                       retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+                       retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
                        if (retval)
                                return retval;
-                       arg = get_fs_long((unsigned long *) arg);
+                       arg = get_user((unsigned int *) arg);
                        if (arg)
                                file->f_flags |= O_NONBLOCK;
                        else
@@ -1432,7 +1432,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                                             sizeof (pid_t));
                        if (retval)
                                return retval;
-                       put_fs_long(real_tty->pgrp, (pid_t *) arg);
+                       put_user(real_tty->pgrp, (pid_t *) arg);
                        return 0;
                case TIOCSPGRP:
                        retval = tty_check_change(real_tty);
@@ -1442,7 +1442,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                            (current->tty != real_tty) ||
                            (real_tty->session != current->session))
                                return -ENOTTY;
-                       pgrp = get_fs_long((pid_t *) arg);
+                       pgrp = get_user((pid_t *) arg);
                        if (pgrp < 0)
                                return -EINVAL;
                        if (session_of_pgrp(pgrp) != current->session)
@@ -1451,16 +1451,16 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                        return 0;
                case TIOCGETD:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
-                                            sizeof (unsigned long));
+                                            sizeof (int));
                        if (retval)
                                return retval;
-                       put_fs_long(tty->ldisc.num, (unsigned long *) arg);
+                       put_user(tty->ldisc.num, (int *) arg);
                        return 0;
                case TIOCSETD:
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
-                       arg = get_fs_long((unsigned long *) arg);
+                       arg = get_user((int *) arg);
                        return tty_set_ldisc(tty, arg);
                case TIOCLINUX:
                        if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
@@ -1470,7 +1470,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                        retval = verify_area(VERIFY_READ, (void *) arg, 1);
                        if (retval)
                                return retval;
-                       switch (retval = get_fs_byte((char *)arg))
+                       switch (retval = get_user((char *)arg))
                        {
                                case 0:
                                case 8:
@@ -1498,10 +1498,10 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                         * kernel-internal variable; programs not closely
                         * related to the kernel should not use this.
                         */
-                                       put_fs_byte(shift_state,arg);
+                                       put_user(shift_state,(char *) arg);
                                        return 0;
                                case 7:
-                                       put_fs_byte(mouse_reporting(),arg);
+                                       put_user(mouse_reporting(),(char *) arg);
                                        return 0;
                                case 10:
                                        set_vesa_blanking(arg);
index 7e006628b52b26a452da2e69014801813b6d379e..bb029c97da2c53c3415e1136d631bc445a05fa06 100644 (file)
@@ -300,14 +300,14 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        return 0;
                case TIOCOUTQ:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
-                                            sizeof (unsigned long));
+                                            sizeof (int));
                        if (retval)
                                return retval;
                        if (tty->driver.chars_in_buffer)
-                               put_fs_long(tty->driver.chars_in_buffer(tty),
-                                           (unsigned long *) arg);
+                               put_user(tty->driver.chars_in_buffer(tty),
+                                        (int *) arg);
                        else
-                               put_fs_long(0, (unsigned long *) arg);
+                               put_user(0, (int *) arg);
                        return 0;
                case TIOCINQ:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
@@ -346,10 +346,10 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                            tty->driver.subtype != PTY_TYPE_MASTER)
                                return -ENOTTY;
                        retval = verify_area(VERIFY_READ, (void *) arg,
-                                            sizeof (unsigned long));
+                                            sizeof (int));
                        if (retval)
                                return retval;
-                       if (get_fs_long(arg)) {
+                       if (get_user((int*)arg)) {
                                if (!tty->packet) {
                                        tty->packet = 1;
                                        tty->link->ctrl_status = 0;
index f5f389cf855817ee07e5b207418f7166d122f0ab..d7928a208f38121bac3a7bc18aeee286d4f2bde3 100644 (file)
@@ -90,7 +90,7 @@ vcs_read(struct inode *inode, struct file *file, char *buf, int count)
        if (!attr) {
                org = screen_pos(cons, p, viewed);
                while (count-- > 0)
-                       put_fs_byte(scr_readw(org++) & 0xff, buf++);
+                       put_user(scr_readw(org++) & 0xff, buf++);
        } else {
                if (p < HEADER_SIZE) {
                        char header[HEADER_SIZE];
@@ -98,19 +98,19 @@ vcs_read(struct inode *inode, struct file *file, char *buf, int count)
                        header[1] = (char) video_num_columns;
                        getconsxy(cons, header+2);
                        while (p < HEADER_SIZE && count-- > 0)
-                           put_fs_byte(header[p++], buf++);
+                           put_user(header[p++], buf++);
                }
                p -= HEADER_SIZE;
                org = screen_pos(cons, p/2, viewed);
                if ((p & 1) && count-- > 0)
-                       put_fs_byte(scr_readw(org++) >> 8, buf++);
+                       put_user(scr_readw(org++) >> 8, buf++);
                while (count > 1) {
-                       put_fs_word(scr_readw(org++), buf);
+                       put_user(scr_readw(org++), (unsigned short *) buf);
                        buf += 2;
                        count -= 2;
                }
                if (count > 0)
-                       put_fs_byte(scr_readw(org) & 0xff, buf++);
+                       put_user(scr_readw(org) & 0xff, buf++);
        }
        read = buf - buf0;
        file->f_pos += read;
@@ -149,7 +149,7 @@ vcs_write(struct inode *inode, struct file *file, char *buf, int count)
                org = screen_pos(cons, p, viewed);
                while (count-- > 0) {
                        scr_writew((scr_readw(org) & 0xff00) |
-                               get_fs_byte(buf++), org);
+                                  get_user(buf++), org);
                        org++;
                }
        } else {
@@ -157,25 +157,25 @@ vcs_write(struct inode *inode, struct file *file, char *buf, int count)
                        char header[HEADER_SIZE];
                        getconsxy(cons, header+2);
                        while (p < HEADER_SIZE && count-- > 0)
-                               header[p++] = get_fs_byte(buf++);
+                               header[p++] = get_user(buf++);
                        if (!viewed)
                                putconsxy(cons, header+2);
                }
                p -= HEADER_SIZE;
                org = screen_pos(cons, p/2, viewed);
                if ((p & 1) && count-- > 0) {
-                       scr_writew((get_fs_byte(buf++) << 8) |
+                       scr_writew((get_user(buf++) << 8) |
                                   (scr_readw(org) & 0xff), org);
                        org++;
                }
                while (count > 1) {
-                       scr_writew(get_fs_word(buf), org++);
+                       scr_writew(get_user((unsigned short *) buf), org++);
                        buf += 2;
                        count -= 2;
                }
                if (count > 0)
                        scr_writew((scr_readw(org) & 0xff00) |
-                                  get_fs_byte(buf++), org);
+                                  get_user(buf++), org);
        }
        written = buf - buf0;
        file->f_pos += written;
index 8e5e17d31620a156afda5af4f799566a7add9188..7a66b8871ce50de6c786a48099630cce4f1aaf7d 100644 (file)
@@ -240,7 +240,7 @@ void vesa_unblank(void)
 
 void set_vesa_blanking(const unsigned long arg)
 {
-       char *argp = (char *)(arg + 1);
-       unsigned int mode = get_fs_byte(argp);
+       unsigned char *argp = (unsigned char *)(arg + 1);
+       unsigned int mode = get_user(argp);
        vesa_blanking_mode = ((mode < 3) ? mode : 0);
 }
index 9f0d8ddc9e6d9f0d3e26b53bdd022aaf50128854..613ca71afd6067477b7756c6c8efb55d394c935f 100644 (file)
@@ -234,7 +234,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                 */
                i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
                if (!i)
-                       put_fs_byte(KB_101, (char *) arg);
+                       put_user(KB_101, (char *) arg);
                return i;
 
        case KDADDIO:
@@ -286,9 +286,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                return 0;
 
        case KDGETMODE:
-               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                if (!i)
-                       put_fs_long(vt_cons[console]->vc_mode, (unsigned long *) arg);
+                       put_user(vt_cons[console]->vc_mode, (int *) arg);
                return i;
 
        case KDMAPDISP:
@@ -325,13 +325,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                return 0;
 
        case KDGKBMODE:
-               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                if (!i) {
                        ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
                                 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
                                 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
                                 K_XLATE);
-                       put_fs_long(ucval, (unsigned long *) arg);
+                       put_user(ucval, (int *) arg);
                }
                return i;
 
@@ -351,11 +351,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                return 0;
 
        case KDGKBMETA:
-               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                if (!i) {
                        ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
                                 K_METABIT);
-                       put_fs_long(ucval, (unsigned long *) arg);
+                       put_user(ucval, (int *) arg);
                }
                return i;
 
@@ -368,11 +368,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbkeycode));
                if (i)
                        return i;
-               sc = get_fs_long((int *) &a->scancode);
+               sc = get_user(&a->scancode);
                kc = getkeycode(sc);
                if (kc < 0)
                        return kc;
-               put_fs_long(kc, (int *) &a->keycode);
+               put_user(kc, &a->keycode);
                return 0;
        }
 
@@ -386,8 +386,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
                if (i)
                        return i;
-               sc = get_fs_long((int *) &a->scancode);
-               kc = get_fs_long((int *) &a->keycode);
+               sc = get_user(&a->scancode);
+               kc = get_user(&a->keycode);
                return setkeycode(sc, kc);
        }
 
@@ -400,9 +400,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
                if (i)
                        return i;
-               if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
+               if ((i = get_user(&a->kb_index)) >= NR_KEYS)
                        return -EINVAL;
-               if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
+               if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
                        return -EINVAL;
                key_map = key_maps[s];
                if (key_map) {
@@ -411,7 +411,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        val = K_HOLE;
                } else
                    val = (i ? K_HOLE : K_NOSUCHMAP);
-               put_fs_word(val, (short *) &a->kb_value);
+               put_user(val, &a->kb_value);
                return 0;
        }
 
@@ -427,11 +427,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
                if (i)
                        return i;
-               if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
+               if ((i = get_user(&a->kb_index)) >= NR_KEYS)
                        return -EINVAL;
-               if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
+               if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
                        return -EINVAL;
-               v = get_fs_word(&a->kb_value);
+               v = get_user(&a->kb_value);
                if (!i && v == K_NOSUCHMAP) {
                        /* disallocate map */
                        key_map = key_maps[s];
@@ -497,7 +497,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
                if (i)
                        return i;
-               if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
+               if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
                        return -EINVAL;
                sz = sizeof(a->kb_string) - 1; /* sz should have been
                                                  a struct member */
@@ -505,8 +505,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                p = func_table[i];
                if(p)
                        for ( ; *p && sz; p++, sz--)
-                               put_fs_byte(*p, q++);
-               put_fs_byte(0, q);
+                               put_user(*p, q++);
+               put_user('\0', q);
                return ((p && *p) ? -EOVERFLOW : 0);
        }
 
@@ -524,7 +524,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
                if (i)
                        return i;
-               if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC)
+               if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
                        return -EINVAL;
                q = func_table[i];
 
@@ -538,7 +538,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                delta = (q ? -strlen(q) : 1);
                sz = sizeof(a->kb_string);      /* sz should have been
                                                   a struct member */
-               for (p = a->kb_string; get_fs_byte(p) && sz; p++,sz--)
+               for (p = a->kb_string; get_user(p) && sz; p++,sz--)
                        delta++;
                if (!sz)
                        return -EOVERFLOW;
@@ -581,7 +581,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                    funcbufsize = sz;
                }
                for (p = a->kb_string, q = func_table[i]; ; p++, q++)
-                       if (!(*q = get_fs_byte(p)))
+                       if (!(*q = get_user(p)))
                                break;
                return 0;
        }
@@ -593,7 +593,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
                if (i)
                        return i;
-               put_fs_long(accent_table_size, &a->kb_cnt);
+               put_user(accent_table_size, &a->kb_cnt);
                memcpy_tofs(a->kbdiacr, accent_table,
                            accent_table_size*sizeof(struct kbdiacr));
                return 0;
@@ -609,7 +609,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
                if (i)
                        return i;
-               ct = get_fs_long(&a->kb_cnt);
+               ct = get_user(&a->kb_cnt);
                if (ct >= MAX_DIACR)
                        return -EINVAL;
                accent_table_size = ct;
@@ -623,8 +623,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
                if (i)
                        return i;
-               put_fs_byte(kbd->ledflagstate |
-                           (kbd->default_ledflagstate << 4), (char *) arg);
+               put_user(kbd->ledflagstate |
+                        (kbd->default_ledflagstate << 4), (char *) arg);
                return 0;
 
        case KDSKBLED:
@@ -643,7 +643,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
                if (i)
                        return i;
-               put_fs_byte(getledstate(), (char *) arg);
+               put_user(getledstate(), (char *) arg);
                return 0;
 
        case KDSETLED:
@@ -684,13 +684,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
                if (i)
                        return i;
-               mode = get_fs_byte(&vtmode->mode);
+               mode = get_user(&vtmode->mode);
                if (mode != VT_AUTO && mode != VT_PROCESS)
                        return -EINVAL;
                vt_cons[console]->vt_mode.mode = mode;
-               vt_cons[console]->vt_mode.waitv = get_fs_byte(&vtmode->waitv);
-               vt_cons[console]->vt_mode.relsig = get_fs_word(&vtmode->relsig);
-               vt_cons[console]->vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
+               vt_cons[console]->vt_mode.waitv = get_user(&vtmode->waitv);
+               vt_cons[console]->vt_mode.relsig = get_user(&vtmode->relsig);
+               vt_cons[console]->vt_mode.acqsig = get_user(&vtmode->acqsig);
                /* the frsig is ignored, so we set it to 0 */
                vt_cons[console]->vt_mode.frsig = 0;
                vt_cons[console]->vt_pid = current->pid;
@@ -705,11 +705,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
                if (i)
                        return i;
-               put_fs_byte(vt_cons[console]->vt_mode.mode, &vtmode->mode);
-               put_fs_byte(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
-               put_fs_word(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
-               put_fs_word(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
-               put_fs_word(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
+               put_user(vt_cons[console]->vt_mode.mode, &vtmode->mode);
+               put_user(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
+               put_user(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
+               put_user(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
+               put_user(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
                return 0;
        }
 
@@ -726,12 +726,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
                if (i)
                        return i;
-               put_fs_word(fg_console + 1, &vtstat->v_active);
+               put_user(fg_console + 1, &vtstat->v_active);
                state = 1;      /* /dev/tty0 is always open */
                for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
                        if (VT_IS_IN_USE(i))
                                state |= mask;
-               put_fs_word(state, &vtstat->v_state);
+               put_user(state, &vtstat->v_state);
                return 0;
        }
 
@@ -739,14 +739,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
         * Returns the first available (non-opened) console.
         */
        case VT_OPENQRY:
-               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+               i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                if (i)
                        return i;
                for (i = 0; i < MAX_NR_CONSOLES; ++i)
                        if (! VT_IS_IN_USE(i))
                                break;
-               put_fs_long(i < MAX_NR_CONSOLES ? (i+1) : -1,
-                           (unsigned long *)arg);
+               put_user(i < MAX_NR_CONSOLES ? (i+1) : -1, (int *) arg);
                return 0;
 
        /*
@@ -869,8 +868,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
                if (i)
                        return i;
-               ll = get_fs_word(&vtsizes->v_rows);
-               cc = get_fs_word(&vtsizes->v_cols);
+               ll = get_user(&vtsizes->v_rows);
+               cc = get_user(&vtsizes->v_cols);
                i = vc_resize(ll, cc);
                return i ? i :  kd_size_changed(ll, cc);
        }
@@ -884,12 +883,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
                if (i)
                        return i;
-               ll = get_fs_word(&vtconsize->v_rows);
-               cc = get_fs_word(&vtconsize->v_cols);
-               vlin = get_fs_word(&vtconsize->v_vlin);
-               clin = get_fs_word(&vtconsize->v_clin);
-               vcol = get_fs_word(&vtconsize->v_vcol);
-               ccol = get_fs_word(&vtconsize->v_ccol);
+               ll = get_user(&vtconsize->v_rows);
+               cc = get_user(&vtconsize->v_cols);
+               vlin = get_user(&vtconsize->v_vlin);
+               clin = get_user(&vtconsize->v_clin);
+               vcol = get_user(&vtconsize->v_vcol);
+               ccol = get_user(&vtconsize->v_ccol);
                vlin = vlin ? vlin : video_scan_lines;
                if ( clin )
                  {
@@ -926,7 +925,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 
                kd_size_changed(ll, cc);
                return 0;
-       }
+       }
 
        case PIO_FONT:
                if (!perm)
@@ -1043,8 +1042,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
                if (i == 0) {
                    ud = (struct unimapdesc *) arg;
-                   ct = get_fs_word(&ud->entry_ct);
-                   list = (struct unipair *) get_fs_long(&ud->entries);
+                   ct = get_user(&ud->entry_ct);
+                   list = get_user(&ud->entries);
                    i = verify_area(VERIFY_READ, (void *) list,
                                    ct*sizeof(struct unipair));
                }
@@ -1061,8 +1060,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
                if (i == 0) {
                    ud = (struct unimapdesc *) arg;
-                   ct = get_fs_word(&ud->entry_ct);
-                   list = (struct unipair *) get_fs_long(&ud->entries);
+                   ct = get_user(&ud->entry_ct);
+                   list = get_user(&ud->entries);
                    if (ct)
                      i = verify_area(VERIFY_WRITE, (void *) list,
                                      ct*sizeof(struct unipair));
index 0e9340b9a5c50ae64d472e7e205db148d43c463c..8e4adc56ef746816df2dc596c31114a37946178f 100644 (file)
@@ -170,6 +170,12 @@ else
 MODULES := $(MODULES) eexpress.o
 endif
 
+ifdef CONFIG_EEXPRESS_PRO
+NETDRV_OBJS := $(NETDRV_OBJS) eepro.o
+else
+MODULES := $(MODULES) eepro.o
+endif
+
 ifdef CONFIG_WAVELAN
 NETDRV_OBJS := $(NETDRV_OBJS) wavelan.o
 else
index 3ba3bfdf0aca25ecc3c718f6a4b2e73ed92020aa..1bfb24a46378df9b6e607b4dff3f0bed0c306ade 100644 (file)
@@ -46,6 +46,7 @@ extern int hp_probe(struct device *dev);
 extern int hp_plus_probe(struct device *dev);
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
+extern int eepro_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
@@ -112,6 +113,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_EEXPRESS         /* Intel EtherExpress */
        && express_probe(dev)
 #endif
+#ifdef CONFIG_EEXPRESS_PRO     /* Intel EtherExpress Pro/10 */
+       && eepro_probe(dev)
+#endif
 #ifdef CONFIG_DEPCA            /* DEC DEPCA */
        && depca_probe(dev)
 #endif
index 1f0fad4bdabdc8a3c85397897241407e6d870fe2..99af78f358b44572e3315431845e6923309dd9c0 100644 (file)
@@ -2,7 +2,7 @@
        Written 1994-95 by Avery Pennarun, derived from skeleton.c by
         Donald Becker.
 
-       Contact Avery at: apenwarr@tourism.807-city.on.ca or
+       Contact Avery at: apenwarr@foxnet.net or
        RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
        
        **********************
          
        **********************
 
+       v1.02 (95/06/21)
+         - A fix to make "exception" packets sent from Linux receivable
+           on other systems.  (The protocol_id byte was sometimes being set
+           incorrectly, and Linux wasn't checking it on receive so it
+           didn't show up)
+         - Updated my email address.  Please use apenwarr@foxnet.net
+           from now on.
        v1.01 (95/03/24)
          - Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski
             <motyl@tichy.ch.uj.edu.pl> for the patches to make arcnet work
@@ -79,7 +86,7 @@
  * 8 times every second.
  *
  * This should no longer be necessary.  if you experience "stuck" ARCnet
- * drivers, please email apenwarr@tourism.807-city.on.ca or I will remove
+ * drivers, please email apenwarr@foxnet.net or I will remove
  * this feature in a future release.
  */
 #undef USE_TIMER_HANDLER
@@ -87,7 +94,7 @@
 /**************************************************************************/
  
 static char *version =
- "arcnet.c:v1.01 95/03/24 Avery Pennarun <apenwarr@tourism.807-city.on.ca>\n";
+ "arcnet.c:v1.02 95/06/21 Avery Pennarun <apenwarr@foxnet.net>\n";
 
 /*
   Sources:
@@ -1249,7 +1256,7 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
                 * make the packet long enough to fit in a 512-byte
                 * frame.
                 */
-               arcpacket->raw[offset+0]=arcsoft->protocol_id;
+               arcpacket->raw[offset+0]=hdr->protocol_id;
                arcpacket->raw[offset+1]=0xFF; /* FF flag */
                        arcpacket->raw[offset+2]=0xFF; /* FF padding */
                        arcpacket->raw[offset+3]=0xFF; /* FF padding */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
new file mode 100644 (file)
index 0000000..866fd61
--- /dev/null
@@ -0,0 +1,1160 @@
+/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
+/*
+       Written 1994, 1995 by Bao C. Ha.
+
+       Copyright (C) 1994, 1995 by Bao C. Ha.
+
+       This software may be used and distributed
+       according to the terms of the GNU Public License,
+       incorporated herein by reference.
+
+       The author may be reached at bao@saigon.async.com 
+       or 418 Hastings Place, Martinez, GA 30907.
+
+       Things remaining to do:
+       Better record keeping of errors.
+       Eliminate transmit interrupt to reduce overhead.
+       Implement "concurrent processing". I won't be doing it!
+       Allow changes to the partition of the transmit and receive
+       buffers, currently the ratio is 3:1 of receive to transmit
+       buffer ratio.  
+
+       Bugs:
+
+       If you have a problem of not detecting the 82595 during a
+       reboot (warm reset), disable the FLASH memory should fix it.
+       This is a compatibility hardware problem.
+       
+       Versions:
+
+       0.07a   Fix a stat report which counts every packet as a
+               heart-beat failure. (BCH, 6/3/95)
+
+       0.07    Modified to support all other 82595-based lan cards.  
+               The IRQ vector of the EtherExpress Pro will be set
+               according to the value saved in the EEPROM.  For other
+               cards, I will do autoirq_request() to grab the next
+               available interrupt vector. (BCH, 3/17/95)
+
+       0.06a,b Interim released.  Minor changes in the comments and
+               print out format. (BCH, 3/9/95 and 3/14/95)
+
+       0.06    First stable release that I am comfortable with. (BCH,
+               3/2/95) 
+
+       0.05    Complete testing of multicast. (BCH, 2/23/95)   
+
+       0.04    Adding multicast support. (BCH, 2/14/95)        
+
+       0.03    First widely alpha release for public testing. 
+               (BCH, 2/14/95)  
+
+*/
+
+static char *version =
+       "eepro.c: v0.07a 6/5/95 Bao C. Ha (bao@saigon.async.com)\n";
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#include <linux/config.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+/*
+  Sources:
+
+       This driver wouldn't have been written without the availability 
+       of the Crynwr's Lan595 driver source code.  It helps me to 
+       familiarize with the 82595 chipset while waiting for the Intel 
+       documentation.  I also learned how to detect the 82595 using 
+       the packet driver's technique.
+
+       This driver is written by cutting and pasting the skeleton.c driver
+       provided by Donald Becker.  I also borrowed the EEPROM routine from
+       Donald Becker's 82586 driver.
+
+       Datasheet for the Intel 82595. It provides just enough info that 
+       the casual reader might think that it documents the i82595.
+
+       The User Manual for the 82595.  It provides a lot of the missing
+       information.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+extern struct device *init_etherdev(struct device *dev, int sizeof_private,
+                                               unsigned long *mem_startp);
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int eepro_portlist[] =
+   { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360, 0};
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define EEPRO_IO_EXTENT        16
+
+/* Information that need to be kept for each board. */
+struct eepro_local {
+       struct enet_statistics stats;
+       unsigned rx_start;
+       unsigned tx_start; /* start of the transmit chain */
+       int tx_last;  /* pointer to last packet in the transmit chain */
+       unsigned tx_end;   /* end of the transmit chain (plus 1) */
+       int eepro;      /* a flag, TRUE=1 for the EtherExpress Pro/10,
+                          FALSE = 0 for other 82595-based lan cards. */
+};
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00
+#define SA_ADDR1 0xaa
+#define SA_ADDR2 0x00
+
+/* Index to functions, as function prototypes. */
+
+extern int eepro_probe(struct device *dev);    
+
+static int     eepro_probe1(struct device *dev, short ioaddr);
+static int     eepro_open(struct device *dev);
+static int     eepro_send_packet(struct sk_buff *skb, struct device *dev);
+static void    eepro_interrupt(int irq, struct pt_regs *regs);
+static void    eepro_rx(struct device *dev);
+static void    eepro_transmit_interrupt(struct device *dev);
+static int     eepro_close(struct device *dev);
+static struct enet_statistics *eepro_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+
+static int read_eeprom(int ioaddr, int location);
+static void hardware_send_packet(struct device *dev, void *buf, short length);
+static int     eepro_grab_irq(struct device *dev);
+
+/*
+                       Details of the i82595.
+
+You will need either the datasheet or the user manual to understand what
+is going on here.  The 82595 is very different from the 82586, 82593.
+
+The receive algorithm in eepro_rx() is just an implementation of the
+RCV ring structure that the Intel 82595 imposes at the hardware level.
+The receive buffer is set at 24K, and the transmit buffer is 8K.  I
+am assuming that the total buffer memory is 32K, which is true for the
+Intel EtherExpress Pro/10.  If it is less than that on a generic card,
+the driver will be broken.
+
+The transmit algorithm in the hardware_send_packet() is similar to the
+one in the eepro_rx().  The transmit buffer is a ring linked list.
+I just queue the next available packet to the end of the list.  In my
+system, the 82595 is so fast that the list seems to always contain a
+single packet.  In other systems with faster computers and more congested
+network traffics, the ring linked list should improve performance by
+allowing up to 8K worth of packets to be queued.
+
+*/
+#define        RAM_SIZE        0x8000
+#define        RCV_HEADER      8
+#define        RCV_RAM         0x6000  /* 24KB for RCV buffer */
+#define        RCV_LOWER_LIMIT 0x00    /* 0x0000 */
+#define        RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8)    /* 0x5ffe */
+#define        XMT_RAM         (RAM_SIZE - RCV_RAM)    /* 8KB for XMT buffer */
+#define        XMT_LOWER_LIMIT (RCV_RAM >> 8)  /* 0x6000 */
+#define        XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8)   /* 0x7ffe */
+#define        XMT_HEADER      8
+
+#define        RCV_DONE        0x0008
+#define        RX_OK           0x2000
+#define        RX_ERROR        0x0d81
+
+#define        TX_DONE_BIT     0x0080
+#define        CHAIN_BIT       0x8000
+#define        XMT_STATUS      0x02
+#define        XMT_CHAIN       0x04
+#define        XMT_COUNT       0x06
+
+#define        BANK0_SELECT    0x00            
+#define        BANK1_SELECT    0x40            
+#define        BANK2_SELECT    0x80            
+
+/* Bank 0 registers */
+#define        COMMAND_REG     0x00    /* Register 0 */
+#define        MC_SETUP        0x03
+#define        XMT_CMD         0x04
+#define        DIAGNOSE_CMD    0x07
+#define        RCV_ENABLE_CMD  0x08
+#define        RCV_DISABLE_CMD 0x0a
+#define        STOP_RCV_CMD    0x0b
+#define        RESET_CMD       0x0e
+#define        POWER_DOWN_CMD  0x18
+#define        RESUME_XMT_CMD  0x1c
+#define        SEL_RESET_CMD   0x1e
+#define        STATUS_REG      0x01    /* Register 1 */
+#define        RX_INT          0x02
+#define        TX_INT          0x04
+#define        EXEC_STATUS     0x30
+#define        ID_REG          0x02    /* Register 2   */
+#define        R_ROBIN_BITS    0xc0    /* round robin counter */
+#define        ID_REG_MASK     0x2c
+#define        ID_REG_SIG      0x24
+#define        AUTO_ENABLE     0x10
+#define        INT_MASK_REG    0x03    /* Register 3   */
+#define        RX_STOP_MASK    0x01
+#define        RX_MASK         0x02
+#define        TX_MASK         0x04
+#define        EXEC_MASK       0x08
+#define        ALL_MASK        0x0f
+#define        RCV_BAR         0x04    /* The following are word (16-bit) registers */
+#define        RCV_STOP        0x06
+#define        XMT_BAR         0x0a
+#define        HOST_ADDRESS_REG        0x0c
+#define        IO_PORT         0x0e
+
+/* Bank 1 registers */
+#define        REG1    0x01
+#define        WORD_WIDTH      0x02
+#define        INT_ENABLE      0x80
+#define INT_NO_REG     0x02
+#define        RCV_LOWER_LIMIT_REG     0x08
+#define        RCV_UPPER_LIMIT_REG     0x09
+#define        XMT_LOWER_LIMIT_REG     0x0a
+#define        XMT_UPPER_LIMIT_REG     0x0b
+
+/* Bank 2 registers */
+#define        XMT_Chain_Int   0x20    /* Interrupt at the end of the transmit chain */
+#define        XMT_Chain_ErrStop       0x40 /* Interrupt at the end of the chain even if there are errors */
+#define        RCV_Discard_BadFrame    0x80 /* Throw bad frames away, and continue to receive others */
+#define        REG2            0x02
+#define        PRMSC_Mode      0x01
+#define        Multi_IA        0x20
+#define        REG3            0x03
+#define        TPE_BIT         0x04
+#define        BNC_BIT         0x20
+       
+#define        I_ADD_REG0      0x04
+#define        I_ADD_REG1      0x05
+#define        I_ADD_REG2      0x06
+#define        I_ADD_REG3      0x07
+#define        I_ADD_REG4      0x08
+#define        I_ADD_REG5      0x09
+
+#define EEPROM_REG 0x0a
+#define EESK 0x01
+#define EECS 0x02
+#define EEDI 0x04
+#define EEDO 0x08
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, allocate space for the device and return success
+   (detachable devices only).
+   */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+   boilerplate below. */
+struct netdev_entry netcard_drv =
+{"eepro", eepro_probe1, EEPRO_IO_EXTENT, eepro_portlist};
+#else
+int
+eepro_probe(struct device *dev)
+{
+       int i;
+       int base_addr = dev ? dev->base_addr : 0;
+
+       if (base_addr > 0x1ff)          /* Check a single specified location. */
+               return eepro_probe1(dev, base_addr);
+       else if (base_addr != 0)        /* Don't probe at all. */
+               return ENXIO;
+
+       for (i = 0; eepro_portlist[i]; i++) {
+               int ioaddr = eepro_portlist[i];
+               if (check_region(ioaddr, EEPRO_IO_EXTENT))
+                       continue;
+               if (eepro_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
+
+       return ENODEV;
+}
+#endif
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probes avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+int eepro_probe1(struct device *dev, short ioaddr)
+{
+       unsigned short station_addr[6], id, counter;
+       int i;
+       int eepro;      /* a flag, TRUE=1 for the EtherExpress Pro/10,
+                          FALSE = 0 for other 82595-based lan cards. */
+       char *ifmap[] = {"AUI", "10Base2", "10BaseT"};
+       enum iftype { AUI=0, BNC=1, TPE=2 };
+
+       /* Now, we are going to check for the signature of the
+          ID_REG (register 2 of bank 0) */
+
+       if (((id=inb(ioaddr + ID_REG)) & ID_REG_MASK) == ID_REG_SIG) {
+
+               /* We seem to have the 82595 signature, let's
+                  play with its counter (last 2 bits of
+                  register 2 of bank 0) to be sure. */
+       
+               counter = (id & R_ROBIN_BITS);  
+               if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == 
+                       (counter + 0x40)) {
+
+                       /* Yes, the 82595 has been found */
+
+                       /* Now, get the ethernet hardware address from
+                          the EEPROM */
+
+                       station_addr[0] = read_eeprom(ioaddr, 2);
+                       station_addr[1] = read_eeprom(ioaddr, 3);
+                       station_addr[2] = read_eeprom(ioaddr, 4);
+
+                       /* Check the station address for the manufacturer's code */
+
+                       if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
+                               eepro = 0;
+                               printk("%s: Intel 82595-based lan card at %#x,", 
+                                       dev->name, ioaddr);
+                       }
+                       else {
+                               eepro = 1;
+                               printk("%s: Intel EtherExpress Pro/10 at %#x,", 
+                                       dev->name, ioaddr);
+                       }
+
+                       /* Fill in the 'dev' fields. */
+                       dev->base_addr = ioaddr;
+                       
+                       for (i=0; i < 6; i++) {
+                               dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+                               printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+                       }
+                               
+                       outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+                       id = inb(ioaddr + REG3);
+                       if (id & TPE_BIT)
+                               dev->if_port = TPE;
+                       else dev->if_port = BNC;
+
+                       if (dev->irq < 2 && eepro) {
+                               i = read_eeprom(ioaddr, 1);
+                               switch (i & 0x07) {
+                                       case 0: dev->irq = 9; break;
+                                       case 1: dev->irq = 3; break;
+                                       case 2: dev->irq = 5; break;
+                                       case 3: dev->irq = 10; break;
+                                       case 4: dev->irq = 11; break;
+                                       default: /* should never get here !!!!! */
+                                               printk(" illegal interrupt vector stored in EEPROM.\n");
+                                               return ENODEV;
+                                       }
+                               }
+                       else if (dev->irq == 2)
+                               dev->irq = 9;
+
+                       if (dev->irq > 2) {
+                               printk(", IRQ %d, %s.\n", dev->irq,
+                                               ifmap[dev->if_port]);
+                               if (request_irq(dev->irq, &eepro_interrupt, 0, "eepro")) {
+                                       printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+                                       return -EAGAIN;
+                               }
+                       }
+                       else printk(", %s.\n", ifmap[dev->if_port]);
+                       
+                       if ((dev->mem_start & 0xf) > 0)
+                               net_debug = dev->mem_start & 7;
+
+                       if (net_debug > 3) {
+                               i = read_eeprom(ioaddr, 5);
+                               if (i & 0x2000) /* bit 13 of EEPROM word 5 */
+                                       printk("%s: Concurrent Processing is enabled but not used!\n",
+                                               dev->name);
+                       }
+
+                       if (net_debug) 
+                               printk(version);
+
+                       /* Grab the region so we can find another board if autoIRQ fails. */
+                       request_region(ioaddr, EEPRO_IO_EXTENT,"eepro");
+
+                       /* Initialize the device structure */
+                       if (dev->priv == NULL)
+                               dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+                       memset(dev->priv, 0, sizeof(struct eepro_local));
+
+                       dev->open = eepro_open;
+                       dev->stop = eepro_close;
+                       dev->hard_start_xmit = eepro_send_packet;
+                       dev->get_stats = eepro_get_stats;
+                       dev->set_multicast_list = &set_multicast_list;
+
+                       /* Fill in the fields of the device structure with
+                          ethernet generic values */
+
+                       ether_setup(dev);
+
+                       outb(RESET_CMD, ioaddr); /* RESET the 82595 */
+
+                       return 0;
+                       }
+               else return ENODEV;
+               }
+       else if (net_debug > 3)
+               printk ("EtherExpress Pro probed failed!\n");
+       return ENODEV;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+
+static char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static int     eepro_grab_irq(struct device *dev)
+{
+       int irqlist[] = { 5, 9, 10, 11, 4, 3, 0};       
+       int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
+
+       outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+
+       /* Enable the interrupt line. */
+       temp_reg = inb(ioaddr + REG1);
+       outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
+       
+       outb(BANK0_SELECT, ioaddr); /* be CAREFULL, BANK 0 now */
+
+       /* clear all interrupts */
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
+       /* Let EXEC event to interrupt */
+       outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG); 
+
+       do {
+               outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+
+               temp_reg = inb(ioaddr + INT_NO_REG);
+               outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG); 
+
+               outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+               if (request_irq (*irqp, NULL, 0, "bogus") != EBUSY) {
+                       /* Twinkle the interrupt, and check if it's seen */
+                       autoirq_setup(0);
+
+                       outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */
+                               
+                       if (*irqp == autoirq_report(2) &&  /* It's a good IRQ line */
+                               (request_irq(dev->irq = *irqp, &eepro_interrupt, 0, "eepro") == 0)) 
+                                       break;
+
+                       /* clear all interrupts */
+                       outb(ALL_MASK, ioaddr + STATUS_REG); 
+               }
+       } while (*++irqp);
+
+       outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+
+       /* Disable the physical interrupt line. */
+       temp_reg = inb(ioaddr + REG1);
+       outb(temp_reg & 0x7f, ioaddr + REG1); 
+
+       outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+       /* Mask all the interrupts. */
+       outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+
+       /* clear all interrupts */
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+       return dev->irq;
+}
+
+static int
+eepro_open(struct device *dev)
+{
+       unsigned short temp_reg;
+       int i, ioaddr = dev->base_addr;
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+
+       if (net_debug > 3)
+               printk("eepro: entering eepro_open routine.\n");
+
+       if (dev->dev_addr[0] == SA_ADDR0 &&
+                       dev->dev_addr[1] == SA_ADDR1 &&
+                       dev->dev_addr[2] == SA_ADDR2)
+               lp->eepro = 1; /* Yes, an Intel EtherExpress Pro/10 */
+       else lp->eepro = 0; /* No, it is a generic 82585 lan card */
+
+       /* Get the interrupt vector for the 82595 */    
+       if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
+               printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+                               
+       if (irq2dev_map[dev->irq] != 0
+               || (irq2dev_map[dev->irq] = dev) == 0)
+               return -EAGAIN;
+
+       /* Initialize the 82595. */
+
+       outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+       temp_reg = inb(ioaddr + EEPROM_REG);
+       if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
+               outb(temp_reg & 0xef, ioaddr + EEPROM_REG);
+       for (i=0; i < 6; i++) 
+               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); 
+                       
+       temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
+       outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
+               | RCV_Discard_BadFrame, ioaddr + REG1);  
+
+       temp_reg = inb(ioaddr + REG2); /* Match broadcast */
+       outb(temp_reg | 0x14, ioaddr + REG2);
+
+       temp_reg = inb(ioaddr + REG3);
+       outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
+
+       /* Set the receiving mode */
+       outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+       
+       temp_reg = inb(ioaddr + INT_NO_REG);
+       outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); 
+
+       /* Initialize the RCV and XMT upper and lower limits */
+       outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); 
+       outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); 
+       outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG); 
+       outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG); 
+
+       /* Enable the interrupt line. */
+       temp_reg = inb(ioaddr + REG1);
+       outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
+
+       outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+       /* Let RX and TX events to interrupt */
+       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+       /* clear all interrupts */
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+       /* Initialize RCV */
+       outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); 
+       lp->rx_start = (RCV_LOWER_LIMIT << 8) ;
+       outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); 
+
+       /* Initialize XMT */
+       outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); 
+       
+       outb(SEL_RESET_CMD, ioaddr);
+       /* We are supposed to wait for 2 us after a SEL_RESET */
+       SLOW_DOWN_IO;
+       SLOW_DOWN_IO;   
+
+       lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */
+       lp->tx_last = 0;  
+       
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       if (net_debug > 3)
+               printk("eepro: exiting eepro_open routine.\n");
+
+       outb(RCV_ENABLE_CMD, ioaddr);
+
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static int
+eepro_send_packet(struct sk_buff *skb, struct device *dev)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+
+       if (net_debug > 5)
+               printk("eepro: entering eepro_send_packet routine.\n");
+       
+       if (dev->tbusy) {
+               /* If we get here, some higher level has decided we are broken.
+                  There should really be a "kick me" function call instead. */
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 5)
+                       return 1;
+               if (net_debug > 1)
+                       printk("%s: transmit timed out, %s?\n", dev->name,
+                                  "network cable problem");
+               lp->stats.tx_errors++;
+               /* Try to restart the adaptor. */
+               outb(SEL_RESET_CMD, ioaddr); 
+               /* We are supposed to wait for 2 us after a SEL_RESET */
+               SLOW_DOWN_IO;
+               SLOW_DOWN_IO;
+
+               /* Do I also need to flush the transmit buffers here? YES? */
+               lp->tx_start = lp->tx_end = RCV_RAM; 
+               lp->tx_last = 0;
+       
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+
+               outb(RCV_ENABLE_CMD, ioaddr);
+
+       }
+
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       /* Block a timer-based transmit from overlapping. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
+       else {
+               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+               unsigned char *buf = skb->data;
+
+               hardware_send_packet(dev, buf, length);
+               dev->trans_start = jiffies;
+       }
+
+       dev_kfree_skb (skb, FREE_WRITE);
+
+       /* You might need to clean up and record Tx statistics here. */
+       /* lp->stats.tx_aborted_errors++; */
+
+       if (net_debug > 5)
+               printk("eepro: exiting eepro_send_packet routine.\n");
+       
+       return 0;
+}
+
+
+/*     The typical workload of the driver:
+       Handle the network interface interrupts. */
+static void
+eepro_interrupt(int irq, struct pt_regs * regs)
+{
+       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       int ioaddr, status, boguscount = 0;
+
+       if (net_debug > 5)
+               printk("eepro: entering eepro_interrupt routine.\n");
+       
+       if (dev == NULL) {
+               printk ("eepro_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+       dev->interrupt = 1;
+       
+       ioaddr = dev->base_addr;
+
+       do { 
+               status = inb(ioaddr + STATUS_REG);
+
+               if (status & RX_INT) {
+                       if (net_debug > 4)
+                               printk("eepro: packet received interrupt.\n");
+
+                       /* Acknowledge the RX_INT */
+                       outb(RX_INT, ioaddr + STATUS_REG); 
+
+                       /* Get the received packets */
+                       eepro_rx(dev);
+               }
+               else if (status & TX_INT) {
+                       if (net_debug > 4)
+                               printk("eepro: packet transmit interrupt.\n");
+
+                       /* Acknowledge the TX_INT */
+                       outb(TX_INT, ioaddr + STATUS_REG); 
+
+                       /* Process the status of transmitted packets */
+                       eepro_transmit_interrupt(dev);
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }               
+       } while ((++boguscount < 10) && (status & 0x06));
+
+       dev->interrupt = 0;
+       if (net_debug > 5)
+               printk("eepro: exiting eepro_interrupt routine.\n");
+       
+       return;
+}
+
+static int
+eepro_close(struct device *dev)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+       short temp_reg;
+
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+
+       /* Disable the physical interrupt line. */
+       temp_reg = inb(ioaddr + REG1);
+       outb(temp_reg & 0x7f, ioaddr + REG1); 
+
+       outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+       /* Flush the Tx and disable Rx. */
+       outb(STOP_RCV_CMD, ioaddr); 
+       lp->tx_start = lp->tx_end = RCV_RAM ;
+       lp->tx_last = 0;  
+
+       /* Mask all the interrupts. */
+       outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+
+       /* clear all interrupts */
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+       /* Reset the 82595 */
+       outb(RESET_CMD, ioaddr); 
+
+       /* release the interrupt */
+       free_irq(dev->irq);
+
+       irq2dev_map[dev->irq] = 0;
+
+       /* release the ioport-region */
+       release_region(ioaddr, 16);
+
+       /* Update the statistics here. What statistics? */
+
+       /* We are supposed to wait for 200 us after a RESET */
+       SLOW_DOWN_IO;
+       SLOW_DOWN_IO; /* May not be enough? */
+
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       return 0;
+}
+
+/* Get the current statistics. This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+eepro_get_stats(struct device *dev)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+
+       return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1     Promiscuous mode, receive all packets
+   num_addrs == 0      Normal mode, clear multicast list
+   num_addrs > 0       Multicast mode, receive normal and MC packets, and do
+                       best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       short ioaddr = dev->base_addr;
+       unsigned short mode;
+
+       if (num_addrs < -1 || num_addrs > 63) {
+               outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode | PRMSC_Mode, ioaddr + REG2); 
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+               printk("%s: promiscuous mode enabled.\n", dev->name);
+       } 
+       else if (num_addrs == 0) {
+               outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+       }
+       else {
+               unsigned short status, *eaddrs = addrs;
+               int i, boguscount = 0;
+               
+               /* Disable RX and TX interrupts.  Neccessary to avoid
+                  corruption of the HOST_ADDRESS_REG by interrupt
+                  service routines. */
+               outb(ALL_MASK, ioaddr + INT_MASK_REG);
+
+               outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+               mode = inb(ioaddr + REG2);
+               outb(mode | Multi_IA, ioaddr + REG2);   
+               mode = inb(ioaddr + REG3);
+               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+               outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+               outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
+               outw(MC_SETUP, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(6*(num_addrs + 1), ioaddr + IO_PORT);
+               for (i = 0; i < num_addrs; i++) {
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+                       outw(*eaddrs++, ioaddr + IO_PORT);
+               }
+               eaddrs = (unsigned short *) dev->dev_addr;
+               outw(eaddrs[0], ioaddr + IO_PORT);
+               outw(eaddrs[1], ioaddr + IO_PORT);
+               outw(eaddrs[2], ioaddr + IO_PORT);
+               outw(lp->tx_end, ioaddr + XMT_BAR);
+               outb(MC_SETUP, ioaddr);
+
+               /* Update the transmit queue */
+               i = lp->tx_end + XMT_HEADER + 6*(num_addrs + 1);
+               if (lp->tx_start != lp->tx_end) { 
+                       /* update the next address and the chain bit in the 
+                          last packet */
+                       outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+                       outw(i, ioaddr + IO_PORT);
+                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+                       status = inw(ioaddr + IO_PORT);
+                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+                       lp->tx_end = i ;
+               } else lp->tx_start = lp->tx_end = i ;
+
+               /* Acknowledge that the MC setup is done */
+               do { /* We should be doing this in the eepro_interrupt()! */
+                       SLOW_DOWN_IO;
+                       SLOW_DOWN_IO;
+                       if (inb(ioaddr + STATUS_REG) & 0x08) {
+                               i = inb(ioaddr);
+                               outb(0x08, ioaddr + STATUS_REG);
+                               if (i & 0x20) { /* command ABORTed */
+                                       printk("%s: multicast setup failed.\n", 
+                                               dev->name);
+                                       break;
+                               } else if ((i & 0x0f) == 0x03)  { /* MC-Done */
+                                       printk("%s: set Rx mode to %d addresses.\n", 
+                                               dev->name, num_addrs);
+                                       break;
+                               }
+                       }
+               } while (++boguscount < 100);
+
+               /* Re-enable RX and TX interrupts */
+               outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+       
+       }
+       outb(RCV_ENABLE_CMD, ioaddr);
+}
+
+/* The horrible routine to read a word from the serial EEPROM. */
+/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay() { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}
+#define EE_READ_CMD (6 << 6)
+
+int
+read_eeprom(int ioaddr, int location)
+{
+       int i;
+       unsigned short retval = 0;
+       short ee_addr = ioaddr + EEPROM_REG;
+       int read_cmd = location | EE_READ_CMD;
+       short ctrl_val = EECS ;
+       
+       outb(BANK2_SELECT, ioaddr);
+       outb(ctrl_val, ee_addr);
+       
+       /* Shift the read command bits out. */
+       for (i = 8; i >= 0; i--) {
+               short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
+                       : ctrl_val;
+               outb(outval, ee_addr);
+               outb(outval | EESK, ee_addr);   /* EEPROM clock tick. */
+               eeprom_delay();
+               outb(outval, ee_addr);  /* Finish EEPROM a clock tick. */
+               eeprom_delay();
+       }
+       outb(ctrl_val, ee_addr);
+       
+       for (i = 16; i > 0; i--) {
+               outb(ctrl_val | EESK, ee_addr);  eeprom_delay();
+               retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
+               outb(ctrl_val, ee_addr);  eeprom_delay();
+       }
+
+       /* Terminate the EEPROM access. */
+       ctrl_val &= ~EECS;
+       outb(ctrl_val | EESK, ee_addr);
+       eeprom_delay();
+       outb(ctrl_val, ee_addr);
+       eeprom_delay();
+       outb(BANK0_SELECT, ioaddr);
+       return retval;
+}
+
+static void
+hardware_send_packet(struct device *dev, void *buf, short length)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       short ioaddr = dev->base_addr;
+       unsigned status, tx_available, last, end, boguscount = 10;
+
+       if (net_debug > 5)
+               printk("eepro: entering hardware_send_packet routine.\n");
+
+       while (boguscount-- > 0) {
+
+               /* determine how much of the transmit buffer space is available */
+               if (lp->tx_end > lp->tx_start)
+                       tx_available = XMT_RAM - (lp->tx_end - lp->tx_start);
+               else if (lp->tx_end < lp->tx_start)
+                       tx_available = lp->tx_start - lp->tx_end;
+               else tx_available = XMT_RAM;
+
+               /* Disable RX and TX interrupts.  Neccessary to avoid
+                  corruption of the HOST_ADDRESS_REG by interrupt
+                  service routines. */
+               outb(ALL_MASK, ioaddr + INT_MASK_REG);
+
+               if (((((length + 1) >> 1) << 1) + 2*XMT_HEADER) 
+                       >= tx_available)   /* No space available ??? */
+                       continue;
+
+               last = lp->tx_end;
+               end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+
+               if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */
+                       if ((RAM_SIZE - last) <= XMT_HEADER) {  
+                       /* Arrrr!!!, must keep the xmt header together,
+                         several days were lost to chase this one down. */
+                               last = RCV_RAM;
+                               end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+                       }       
+                       else end = RCV_RAM + (end - RAM_SIZE);
+               }
+
+               outw(last, ioaddr + HOST_ADDRESS_REG);
+               outw(XMT_CMD, ioaddr + IO_PORT);
+               outw(0, ioaddr + IO_PORT);
+               outw(end, ioaddr + IO_PORT);
+               outw(length, ioaddr + IO_PORT);
+               outsw(ioaddr + IO_PORT, buf, (length + 1) >> 1);
+
+               if (lp->tx_start != lp->tx_end) { 
+                       /* update the next address and the chain bit in the 
+                          last packet */
+                       if (lp->tx_end != last) {
+                               outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+                               outw(last, ioaddr + IO_PORT);
+                       }
+                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+                       status = inw(ioaddr + IO_PORT);
+                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+               }
+
+               /* A dummy read to flush the DRAM write pipeline */
+               status = inw(ioaddr + IO_PORT); 
+
+               /* Enable RX and TX interrupts */
+               outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+       
+               if (lp->tx_start == lp->tx_end) {
+                       outw(last, ioaddr + XMT_BAR);
+                       outb(XMT_CMD, ioaddr);
+                       lp->tx_start = last;   /* I don't like to change tx_start here */
+               }
+               else    outb(RESUME_XMT_CMD, ioaddr);
+
+               lp->tx_last = last;
+               lp->tx_end = end;
+
+               if (dev->tbusy) {
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+
+               if (net_debug > 5)
+                       printk("eepro: exiting hardware_send_packet routine.\n");
+               return;
+       }
+       dev->tbusy = 1;
+       if (net_debug > 5)
+               printk("eepro: exiting hardware_send_packet routine.\n");
+}
+
+static void
+eepro_rx(struct device *dev)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       short ioaddr = dev->base_addr;
+       short boguscount = 20;
+       short rcv_car = lp->rx_start;
+       unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
+
+       if (net_debug > 5)
+               printk("eepro: entering eepro_rx routine.\n");
+       
+       /* Set the read pointer to the start of the RCV */
+       outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
+       rcv_event = inw(ioaddr + IO_PORT);
+
+       while (rcv_event == RCV_DONE) {
+               rcv_status = inw(ioaddr + IO_PORT);
+               rcv_next_frame = inw(ioaddr + IO_PORT);
+               rcv_size = inw(ioaddr + IO_PORT);
+
+               if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
+                       /* Malloc up new buffer. */
+                       struct sk_buff *skb;
+
+                       rcv_size &= 0x3fff;
+                       skb = alloc_skb(rcv_size, GFP_ATOMIC);
+                       if (skb == NULL) {
+                               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+                               lp->stats.rx_dropped++;
+                               break;
+                       }
+                       skb->len = rcv_size;
+                       skb->dev = dev;
+
+                       insw(ioaddr+IO_PORT, skb->data, (rcv_size + 1) >> 1);
+       
+                       skb->protocol = eth_type_trans(skb,dev);        
+                       netif_rx(skb);
+                       lp->stats.rx_packets++;
+               }
+               else { /* Not sure will ever reach here, 
+                         I set the 595 to discard bad received frames */
+                       lp->stats.rx_errors++;
+                       if (rcv_status & 0x0100)
+                               lp->stats.rx_over_errors++;
+                       else if (rcv_status & 0x0400)
+                               lp->stats.rx_frame_errors++;
+                       else if (rcv_status & 0x0800)
+                               lp->stats.rx_crc_errors++;
+                       printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", 
+                               dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
+               }
+               if (rcv_status & 0x1000)
+                       lp->stats.rx_length_errors++;
+               if (--boguscount == 0)
+                       break;
+
+               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+               lp->rx_start = rcv_next_frame;
+               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+               rcv_event = inw(ioaddr + IO_PORT);
+
+       } 
+       if (rcv_car == 0)
+               rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff;
+       outw(rcv_car - 1, ioaddr + RCV_STOP);
+
+       if (net_debug > 5)
+               printk("eepro: exiting eepro_rx routine.\n");
+}
+
+static void
+eepro_transmit_interrupt(struct device *dev)
+{
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+       short ioaddr = dev->base_addr;
+       short boguscount = 10; 
+       short xmt_status;
+
+       while (lp->tx_start != lp->tx_end) { 
+
+               outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
+               xmt_status = inw(ioaddr+IO_PORT);
+               if ((xmt_status & TX_DONE_BIT) == 0) break;
+               xmt_status = inw(ioaddr+IO_PORT);
+               lp->tx_start = inw(ioaddr+IO_PORT);
+       
+               if (dev->tbusy) {
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+
+               if (xmt_status & 0x2000)
+                       lp->stats.tx_packets++;
+               else {
+                       lp->stats.tx_errors++;
+                       if (xmt_status & 0x0400)
+                               lp->stats.tx_carrier_errors++;
+                       printk("%s: XMT status = %#x\n",
+                               dev->name, xmt_status);
+               }
+               if (xmt_status & 0x000f)
+                       lp->stats.collisions += (xmt_status & 0x000f);
+               if ((xmt_status & 0x0040) == 0x0)
+                       lp->stats.tx_heartbeat_errors++;
+
+               if (--boguscount == 0)
+                       break;  
+       }
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_eepro = {
+       "        " /*"eepro"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, eepro_probe };
+
+int
+init_module(void)
+{
+       if (register_netdev(&dev_eepro) != 0)
+               return -EIO;
+       return 0;
+}
+
+void
+cleanup_module(void)
+{
+       if (MOD_IN_USE)
+               printk("eepro: device busy, remove delayed\n");
+       else
+       {
+               unregister_netdev(&dev_eepro);
+               kfree_s(dev_eepro.priv,sizeof(struct eepro_local));
+               dev_eepro.priv=NULL;
+       }
+}
+#endif /* MODULE */
index 40e00a304a450ec81065eb98691dbd083462aeb5..03bc8128b9426c397c9324675dba04435531405e 100644 (file)
@@ -958,7 +958,7 @@ eql_schedule_slaves(slave_queue_t *queue)
 
              if ( slave->dev != 0)
                {
-                 if ( slave->dev->flags & IFF_UP == IFF_UP )
+                 if ((slave->dev->flags & IFF_UP) == IFF_UP )
                    {
                      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 
                        (priority_Bps) + bytes_queued * 8;
@@ -1105,7 +1105,7 @@ eql_timer(unsigned long param)
        {
          if (slave != 0)
            {
-             if ( slave->dev->flags & IFF_UP == IFF_UP )
+             if ((slave->dev->flags & IFF_UP) == IFF_UP )
                {
                  slave->bytes_queued -= slave->priority_Bps;
              
index f9254e49c2fea8fd82cbee6b6f947283c08aec41..643d1c4666f69465672c642181fb20e8587d2bdd 100644 (file)
@@ -342,7 +342,7 @@ ne_reset_8390(struct device *dev)
            printk("%s: ne_reset_8390() did not complete.\n", dev->name);
            break;
        }
-    outb_p(ENISR_RESET, NE_BASE + NE_RESET);   /* Ack intr. */
+    outb_p(ENISR_RESET, NE_BASE + EN0_ISR);    /* Ack intr. */
 }
 
 /* Block input and output, similar to the Crynwr packet driver.  If you
index ecadb93b57ff0cc47bdfbf0ff9b6302606dd2d65..9f0b41feb7aee9d0f05f3eb92898605877e656b9 100644 (file)
@@ -1292,12 +1292,12 @@ ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned
        return -EOVERFLOW;              /* ZZZ; HACK! */
       } else {
        /* have the space: copy the packet, faking the first two bytes */
-       put_fs_byte (PPP_ADDRESS, buf++);
-       put_fs_byte (PPP_CONTROL, buf++);
+       put_user (PPP_ADDRESS, buf++);
+       put_user (PPP_CONTROL, buf++);
        i = len;
        while (i-- > 0) {
          GETC (c);
-         put_fs_byte (c, buf++);
+         put_user (c, buf++);
        }
       }
 
@@ -1392,7 +1392,7 @@ ppp_write(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigne
   ppp->fcs = PPP_FCS_INIT;
   i = nr;
   while (i-- > 0)
-    ppp_stuff_char(ppp,get_fs_byte(buf++));
+    ppp_stuff_char(ppp,get_user(buf++));
 
   ppp_add_fcs(ppp);            /* concatenate FCS at end */
 
@@ -1438,7 +1438,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSMRU:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i = (int) get_fs_long (l);
+      temp_i = get_user ((int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
       if (ppp->mru != temp_i)
        ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
@@ -1452,7 +1452,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
 #ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
       temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
-      put_fs_long ((long) temp_i, l);
+      put_user (temp_i, (int *) l);
       PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n",
                  l,
                  temp_i));
@@ -1462,7 +1462,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSFLAGS:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i      = (int) get_fs_long (l);
+      temp_i      = get_user ((int *) l);
       ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i));
     }
@@ -1471,7 +1471,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCGASYNCMAP:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long (ppp->xmit_async_map[0], l);
+      put_user (ppp->xmit_async_map[0], (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
                  l, ppp->xmit_async_map[0]));
     }
@@ -1480,7 +1480,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSASYNCMAP:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->xmit_async_map[0] = get_fs_long (l);
+      ppp->xmit_async_map[0] = get_user ((int *) l);
       bset (ppp->xmit_async_map, PPP_FLAG);
       bset (ppp->xmit_async_map, PPP_ESC);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
@@ -1491,7 +1491,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCRASYNCMAP:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->recv_async_map = get_fs_long (l);
+      ppp->recv_async_map = get_user ((int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
                  ppp->recv_async_map));
     }
@@ -1500,7 +1500,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCGUNIT:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long (ppp->dev->base_addr, l);
+      put_user (ppp->dev->base_addr, (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
     }
     break;
@@ -1508,7 +1508,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSINPSIG:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->inp_sig     = (int) get_fs_long (l);
+      ppp->inp_sig     = get_user ((int *) l);
       ppp->inp_sig_pid = current->pid;
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig));
     }
@@ -1517,7 +1517,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSDEBUG:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp_debug = (int) get_fs_long (l);
+      ppp_debug = get_int ((int *) l);
       ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
       ppp_debug &= 0xff;
       PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", 
@@ -1528,7 +1528,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCGDEBUG:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long ((long) (ppp_debug | (ppp_debug_netpackets << 8)), l);
+      put_user ((long) (ppp_debug | (ppp_debug_netpackets << 8)), (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n", 
                  ppp_debug | (ppp_debug_netpackets << 8)));
     }
@@ -1596,7 +1596,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSMAXCID:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i = (int) get_fs_long (l) + 1;
+      temp_i = get_user ((int *) l) + 1;
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i));
       if (ppp->slcomp != NULL)
        slhc_free (ppp->slcomp);
@@ -2007,7 +2007,7 @@ static inline void ppp_print_hex (register char *out, char *in, int count)
   register unsigned char next_ch;
 
   while (count-- > 0) {
-    next_ch = (unsigned char) get_fs_byte (in);
+    next_ch = (unsigned char) get_user (in);
 
     *out++  = hex[(next_ch >> 4) & 0x0F];
     *out++  = hex[next_ch        & 0x0F];
@@ -2021,7 +2021,7 @@ static inline void ppp_print_char (register char *out, char *in, int count)
   register unsigned char next_ch;
 
   while (count-- > 0) {
-    next_ch = (unsigned char) get_fs_byte (in);
+    next_ch = (unsigned char) get_user (in);
 
     if (next_ch < 0x20 || next_ch > 0x7e)
       *out++ = '.';
index dd3c5a4e86c754a6aaa6331f35dbc7f0501e57d0..561d7d1a0f0a7693738e2dfda9623ac40d6c83e8 100644 (file)
@@ -1529,7 +1529,7 @@ static void SK_rxintr(struct device *dev)
         * not to be concerned (see Data sheet)
         */
 
-       if (rmdstat & (RX_STP | RX_ENP) != (RX_STP | RX_ENP))
+       if ((rmdstat & (RX_STP | RX_ENP)) != (RX_STP | RX_ENP))
        {
            /* Start of a frame > 1518 Bytes ? */
 
index 8b1bc947680ffac4398ac0ab37eaaf7c75514f03..84b3757e3eb87e419c24ac420cf2983b93c03f3d 100644 (file)
@@ -996,19 +996,19 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
                return 0;
 
        case SIOCGIFENCAP:
-               err = verify_area(VERIFY_WRITE, arg, sizeof(long));
+               err = verify_area(VERIFY_WRITE, arg, sizeof(int));
                if (err)  {
                        return -err;
                }
-               put_fs_long(sl->mode, (long *)arg);
+               put_user(sl->mode, (int *)arg);
                return 0;
 
        case SIOCSIFENCAP:
-               err = verify_area(VERIFY_READ, arg, sizeof(long));
+               err = verify_area(VERIFY_READ, arg, sizeof(int));
                if (err)  {
                        return -err;
                }
-               tmp = get_fs_long((long *)arg);
+               tmp = get_user((int *)arg);
 #ifndef SL_INCLUDE_CSLIP
                if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))  {
                        return -EINVAL;
index 764eb6fe0cbcfbf4c85fbf3e02c8a476fecf95bf..5d7e4ce15a1a0cf190765b9779bae1fee68f2d40 100644 (file)
@@ -7,6 +7,7 @@
 
 
 #define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1)
+
 /*
  * Define SCSI_MALLOC to use scsi_malloc instead of kmalloc.  Other than
  * preventing deadlock, I'm not sure why we'd want to do this.
@@ -181,12 +182,12 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host);
 static int NCR53c8xx_script_len;
 static int NCR53c8xx_dsa_len;
 static void NCR53c7x0_intr(int irq, struct pt_regs * regs);
-static int halt (struct Scsi_Host *host);
+static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
 static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
-static void print_dsa (struct Scsi_Host *host, unsigned long *dsa);
-static int print_insn (struct Scsi_Host *host, unsigned long *insn,
+static void print_dsa (struct Scsi_Host *host, u32 *dsa);
+static int print_insn (struct Scsi_Host *host, u32 *insn,
     char *prefix, int kernel);
 
 static void NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
@@ -271,8 +272,8 @@ static Scsi_Host_Template *the_template = NULL;
 struct pci_chip {
     unsigned short pci_device_id;
     int chip;
-    int max_revision;
     int min_revision;
+    int max_revision;
 };
 
 static struct pci_chip pci_chip_ids[] = { 
@@ -351,7 +352,7 @@ static void internal_setup(int board, int chip, char *str, int *ints) {
        } else {
            overrides[commandline_current].data.pci.bus = ints[1];
            overrides[commandline_current].data.pci.device = ints[2];
-           overrides[commandline_current].data.pci.device = ints[3];
+           overrides[commandline_current].data.pci.function = ints[3];
            overrides[commandline_current].options = (ints[0] >= 4) ?
                ints[4] : 0;
        }
@@ -463,7 +464,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
 /* Only the ISTAT register is readable when the NCR is running, so make 
    sure it's halted. */
-    halt(host);
+    ncr_halt(host);
 
 /* 
  * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
@@ -533,7 +534,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
            case DMODE_BL_4: i = 4; break;
            case DMODE_BL_8: i = 8; break;
            case DMODE_BL_16: i = 16; break;
-            default: i = 0;
+            default: i = 0;
            }
            printk ("scsi%d : burst length %d\n", host->host_no, i);
        }
@@ -608,7 +609,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
     hostdata->issue_queue = hostdata->running_list = 
        hostdata->finished_queue = NULL;
-    hostdata->issue_dsa_head = NULL;
+    hostdata->issue_dsa_head = 0;
     hostdata->issue_dsa_tail = NULL;
 
     if (hostdata->init_save_regs)
@@ -671,7 +672,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
  */
 
 static int normal_init (Scsi_Host_Template *tpnt, int board, int chip, 
-    int base, int io_port, int irq, int dma, int pci_valid, 
+    u32 base, int io_port, int irq, int dma, int pci_valid, 
     unsigned char pci_bus, unsigned char pci_device_fn, int options) {
     struct Scsi_Host *instance;
     struct NCR53c7x0_hostdata *hostdata;
@@ -708,7 +709,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
        printk ("scsi-ncr53c7,8xx : for better reliability and performance, please use the\n" 
                "        PCI override instead.\n"
                "        Syntax : ncr53c8{10,15,20,25}=pci,<bus>,<device>,<function>\n"
-               "                 <bus> and <device> are usually 0.\n");
+               "                 <bus> and <device> are usually 0.\n");
 
     if (options & OPTION_DEBUG_PROBE_ONLY) {
        printk ("scsi-ncr53c7,8xx : probe only enabled, aborting initialization\n");
@@ -762,7 +763,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
     hostdata = (struct NCR53c7x0_hostdata *) 
        instance->hostdata;
     hostdata->size = size;
-    hostdata->script_count = script_len / sizeof(long);
+    hostdata->script_count = script_len / sizeof(u32);
     hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
     hostdata->board = board;
     hostdata->chip = chip;
@@ -786,7 +787,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
      */
 
     if (base) {
-       instance->base = (unsigned char *) base;
+       instance->base = (unsigned char*) (unsigned long) base;
        /* Check for forced I/O mapping */
        if (!(options & OPTION_IO_MAPPED)) {
            options |= OPTION_MEMORY_MAPPED;
@@ -831,7 +832,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
 
 
 /* 
- * Function : static int ncr_init(Scsi_Host_Template *tpnt, int board, 
+ * Function : static int pci_init(Scsi_Host_Template *tpnt, int board, 
  *     int chip, int bus, int device_fn, int options)
  *
  * Purpose : initializes a NCR53c800 family based on the PCI
@@ -851,10 +852,11 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
  *
  */
 
-static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip, 
+static int ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip, 
     unsigned char bus, unsigned char device_fn, int options) {
     unsigned short vendor_id, device_id, command;
-    unsigned long base, io_port; 
+    u32 base;
+    int io_port; 
     unsigned char irq, revision;
     int error, expected_chip;
     int expected_id = -1, max_revision = -1, min_revision = -1;
@@ -885,8 +887,8 @@ static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip,
        (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE,
            &irq))) {
        printk ("scsi-ncr53c7,8xx : error %s not initializing due to error reading configuration space\n"
-               "        perhaps you specified an incorrect PCI bus, device, or function.\n"
-               , pcibios_strerror(error));
+               "        perhaps you specified an incorrect PCI bus, device, or function.\n"
+               , pci_strbioserr(error));
        return -1;
     }
 
@@ -907,13 +909,13 @@ static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip,
 
     if (command & PCI_COMMAND_IO) { 
        if ((io_port & 3) != 1) {
-           printk ("scsi-ncr53c7,8xx : disabling I/O mapping since base address 0 (0x%lx)\n"
+           printk ("scsi-ncr53c7,8xx : disabling I/O mapping since base address 0 (0x%x)\n"
                    "        bits 0..1 indicate a non-IO mapping\n", io_port);
            io_port = 0;
        } else
            io_port &= PCI_BASE_ADDRESS_IO_MASK;
     } else {
-       io_port = 0;
+           io_port = 0;
     }
 
     if (command & PCI_COMMAND_MEMORY) {
@@ -924,7 +926,7 @@ static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip,
        } else 
            base &= PCI_BASE_ADDRESS_MEM_MASK;
     } else {
-       base = 0;
+           base = 0;
     }
        
     if (!io_port && !base) {
@@ -959,7 +961,7 @@ static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip,
        printk ("scsi-ncr53c7,8xx : warning : revision of %d is less than %d.\n",
            (int) revision, min_revision);
 
-    return normal_init (tpnt, board, chip, (int) base, (int) io_port, 
+    return normal_init (tpnt, board, chip, (int) base, io_port, 
        (int) irq, DMA_NONE, 1, bus, device_fn, options);
 }
 
@@ -988,7 +990,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
     for (current_override = count = 0; current_override < OVERRIDE_LIMIT; 
         ++current_override) {
         if (overrides[current_override].pci ? 
-           !ncr_init (tpnt, overrides[current_override].board,
+           !ncr_pci_init (tpnt, overrides[current_override].board,
                overrides[current_override].chip,
                (unsigned char) overrides[current_override].data.pci.bus,
                (((overrides[current_override].data.pci.device
@@ -1013,7 +1015,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
                !pcibios_find_device (PCI_VENDOR_ID_NCR, 
                    pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
                    &pci_device_fn) && 
-               !ncr_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
+               !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
                    pci_bus, pci_device_fn, /* no options */ 0); 
                ++count, ++pci_index);
     }
@@ -1042,7 +1044,7 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
        host->hostdata;
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr, ncr_to_ncr;
-    unsigned long base;
+    u32 base;
     NCR53c7x0_local_setup(host);
 
 
@@ -1053,18 +1055,23 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
        sizeof(SCRIPT));
     /* Fixup labels */
     for (i = 0; i < PATCHES; ++i) 
-       hostdata->script[LABELPATCHES[i]] += 
-           (unsigned long) hostdata->script;
+       hostdata->script[LABELPATCHES[i]] +=
+           virt_to_bus(hostdata->script);
     /* Fixup addresses of constants that used to be EXTERNAL */
-    
+
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort, 
-       (long) &(hostdata->NCR53c7xx_msg_abort));
+       virt_to_bus(&hostdata->NCR53c7xx_msg_abort));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject, 
-       (long) &(hostdata->NCR53c7xx_msg_reject));
+       virt_to_bus(&hostdata->NCR53c7xx_msg_reject));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero, 
-       (long) &(hostdata->NCR53c7xx_zero));
+       virt_to_bus(&hostdata->NCR53c7xx_zero));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink, 
-       (long) &(hostdata->NCR53c7xx_sink));
+       virt_to_bus(&hostdata->NCR53c7xx_sink));
+
+    /* Fixup references to external variables: */
+    for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
+       hostdata->script[EXTERNAL_PATCHES[i].offset] +=
+         virt_to_bus(EXTERNAL_PATCHES[i].address);
 
     /* 
      * Fixup absolutes set at boot-time.
@@ -1085,12 +1092,12 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
     tmp &= (DMODE_800_ERL | DMODE_BL_MASK);
 
     if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
-       base = (long) host->io_port;
+       base = (u32) host->io_port;
        memory_to_ncr = tmp|DMODE_800_DIOM;
        ncr_to_memory = tmp|DMODE_800_SIOM;
        ncr_to_ncr = tmp|DMODE_800_DIOM|DMODE_800_SIOM;
     } else {
-       base = (long) host->base;
+       base = virt_to_phys(host->base);
        ncr_to_ncr = memory_to_ncr = ncr_to_memory = tmp;
     }
 
@@ -1112,18 +1119,20 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
     patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
     patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_ncr, ncr_to_ncr);
 
-    patch_abs_32 (hostdata->script, 0, issue_dsa_head, 
-       (long) &(hostdata->issue_dsa_head));
-    patch_abs_32 (hostdata->script, 0, msg_buf, (long) &(hostdata->msg_buf));
-    patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, 
-       (long) &(hostdata->reconnect_dsa_head));
-    patch_abs_32 (hostdata->script, 0, reselected_identify, 
-       (long) &(hostdata->reselected_identify));
-    patch_abs_32 (hostdata->script, 0, reselected_tag, 
-       (long) &(hostdata->reselected_tag));
+    patch_abs_32 (hostdata->script, 0, issue_dsa_head,
+                 virt_to_bus((void*)&hostdata->issue_dsa_head));
+    patch_abs_32 (hostdata->script, 0, msg_buf,
+                 virt_to_bus((void*)&hostdata->msg_buf));
+    patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
+                 virt_to_bus((void*)&hostdata->reconnect_dsa_head));
+    patch_abs_32 (hostdata->script, 0, reselected_identify,
+                 virt_to_bus((void*)&hostdata->reselected_identify));
+    patch_abs_32 (hostdata->script, 0, reselected_tag,
+                 virt_to_bus((void*)&hostdata->reselected_tag));
 
-    patch_abs_32 (hostdata->script, 0, test_dest, (long) &(hostdata->test_dest));
-    patch_abs_32 (hostdata->script, 0, test_src, (long) &(hostdata->test_source));
+    patch_abs_32 (hostdata->script, 0, test_dest,
+                 virt_to_bus((void*)&hostdata->test_dest));
+    patch_abs_32 (hostdata->script, 0, test_src, virt_to_bus(&hostdata->test_source));
 
 
     /*
@@ -1132,7 +1141,7 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
      */
 
 /* 
- * XXX - for cleanness, E_* fields should be type unsigned long *
+ * XXX - for cleanness, E_* fields should be type u32 *
  * and should reflect the _relocated_ addresses.  Change this.
  */
     hostdata->E_accept_message = Ent_accept_message;
@@ -1178,8 +1187,8 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
            host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
            Ent_dsa_zero);
 
-    printk("scsi%d : NCR code relocated to 0x%lx\n", host->host_no,
-       (unsigned long) hostdata->script);
+    printk("scsi%d : NCR code relocated to 0x%p\n", host->host_no,
+       hostdata->script);
 }
 
 /*
@@ -1201,10 +1210,10 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
-    unsigned long timeout, start;
+    unsigned long timeout;
+    u32 start;
     int failed, i;
     unsigned long flags;
-       
     NCR53c7x0_local_setup(host);
 
     /* The NCR chip _must_ be idle to run the test scripts */
@@ -1225,7 +1234,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
     if (hostdata->issue_dsa_head) {
        printk ("scsi%d : hostdata->issue_dsa_head corrupt before test 1\n",
            host->host_no);
-       hostdata->issue_dsa_head = NULL;
+       hostdata->issue_dsa_head = 0;
     }
        
     if (hostdata->options & OPTION_DEBUG_TEST1) {
@@ -1234,14 +1243,15 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
        hostdata->test_completed = -1;
        hostdata->test_dest = 0;
        hostdata->test_source = 0xdeadbeef;
-       start = ((unsigned long) hostdata->script) + hostdata->E_test_1;
+       start = virt_to_bus(hostdata->script) + hostdata->E_test_1;
        hostdata->state = STATE_RUNNING;
        printk ("scsi%d : test 1", host->host_no);
        NCR53c7x0_write32 (DSP_REG, start);
+       mb();
        printk (" started\n");
        sti();
 
-       timeout = jiffies + 50; /* arbitrary */
+       timeout = jiffies + 5 * HZ / 10;        /* arbitrary */
        while ((hostdata->test_completed == -1) && jiffies < timeout)
                barrier();
 
@@ -1251,31 +1261,31 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
                (hostdata->test_dest == 0xdeadbeef) ? 
                    " due to lost interrupt.\n"
                    "         Please verify that the correct IRQ is being used for your board,\n"
-                   "         and that the motherboard IRQ jumpering matches the PCI setup on\n"
+                   "         and that the motherboard IRQ jumpering matches the PCI setup on\n"
                    "         PCI systems.\n"
                    "         If you are using a NCR53c810 board in a PCI system, you should\n" 
                    "         also verify that the board is jumpered to use PCI INTA, since\n"
                    "         most PCI motherboards lack support for INTB, INTC, and INTD.\n"
                    : "");
        else if (hostdata->test_completed != 1) 
-           printk ("scsi%d : test 1 bad interrupt value (%ld)\n", host->host_no,
+           printk ("scsi%d : test 1 bad interrupt value (%d)\n", host->host_no,
                hostdata->test_completed);
        else 
            failed = (hostdata->test_dest != 0xdeadbeef);
 
        if (hostdata->test_dest != 0xdeadbeef) {
            printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
-                    "         probable cache invalidation problem.  Please configure caching\n"
-                   "         as write-through or disabled\n",
+                    "        probable cache invalidation problem.  Please configure caching\n"
+                   "        as write-through or disabled\n",
                host->host_no, hostdata->test_dest);
        }
 
        if (failed) {
-           printk ("scsi%d : DSP = 0x%lx (script at 0x%lx, start at 0x%lx)\n",
-               host->host_no, (unsigned long) NCR53c7x0_read32(DSP_REG),
-               (unsigned long) hostdata->script, start);
-           printk ("scsi%d : DSPS = 0x%lx\n", host->host_no,
-               (unsigned long) NCR53c7x0_read32(DSPS_REG));
+           printk ("scsi%d : DSP = 0x%x (script at 0x%p, start at 0x%x)\n",
+               host->host_no, NCR53c7x0_read32(DSP_REG),
+               hostdata->script, start);
+           printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+               NCR53c7x0_read32(DSPS_REG));
            restore_flags(flags);
            return -1;
        }
@@ -1285,11 +1295,11 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
     if (hostdata->issue_dsa_head) {
        printk ("scsi%d : hostdata->issue_dsa_head corrupt after test 1\n",
            host->host_no);
-       hostdata->issue_dsa_head = NULL;
+       hostdata->issue_dsa_head = 0;
     }
 
     if (hostdata->options & OPTION_DEBUG_TEST2) {
-       unsigned long dsa[48];
+       u32 dsa[48];
        unsigned char identify = IDENTIFY(0, 0);
        unsigned char cmd[6];
        unsigned char data[36];
@@ -1301,18 +1311,18 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
        cmd[4] = sizeof(data); 
 
        dsa[2] = 1;
-       dsa[3] = (unsigned long) &identify;
+       dsa[3] = virt_to_bus(&identify);
        dsa[4] = 6;
-       dsa[5] = (unsigned long) &cmd;
+       dsa[5] = virt_to_bus(&cmd);
        dsa[6] = sizeof(data);
-       dsa[7] = (unsigned long) &data;
+       dsa[7] = virt_to_bus(&data);
        dsa[8] = 1;
-       dsa[9] = (unsigned long) &status;
+       dsa[9] = virt_to_bus(&status);
        dsa[10] = 1;
-       dsa[11] = (unsigned long) &msg;
+       dsa[11] = virt_to_bus(&msg);
 
        for (i = 0; i < 3; ++i) {
-           cli();
+           cli();
            if (!hostdata->idle) {
                printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
                restore_flags(flags);
@@ -1324,16 +1334,18 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
            hostdata->idle = 0;
            hostdata->test_running = 2;
            hostdata->test_completed = -1;
-           start = ((unsigned long) hostdata->script) + hostdata->E_test_2;
+           start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
            hostdata->state = STATE_RUNNING;
-           NCR53c7x0_write32 (DSA_REG, (unsigned long) dsa);
+           NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
            NCR53c7x0_write32 (DSP_REG, start);
+           mb();
            sti();
 
-           timeout = jiffies + 500;    /* arbitrary */
+           timeout = jiffies + 5 * HZ; /* arbitrary */
            while ((hostdata->test_completed == -1) && jiffies < timeout)
                barrier();
            NCR53c7x0_write32 (DSA_REG, 0);
+           mb();
 
            if (hostdata->test_completed == 2) {
                data[35] = 0;
@@ -1361,7 +1373,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
            if (hostdata->issue_dsa_head) {
                printk ("scsi%d : hostdata->issue_dsa_head corrupt after test 2 id %d\n",
                    host->host_no, i);
-               hostdata->issue_dsa_head = NULL;
+               hostdata->issue_dsa_head = 0;
        }
        }
     }
@@ -1390,16 +1402,16 @@ static void NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
        hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
 
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long), 
-       dsa_temp_jump_resume, ((unsigned long) cmd->dsa) + 
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+       dsa_temp_jump_resume, virt_to_bus(cmd->dsa) + 
        Ent_dsa_jump_resume - Ent_dsa_zero);
-    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(long),
+    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
        dsa_temp_lun, c->lun);
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long),
-       dsa_temp_dsa_next, ((unsigned long) cmd->dsa) + A_dsa_next);
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long), 
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+       dsa_temp_dsa_next, virt_to_bus(cmd->dsa) + A_dsa_next);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
        dsa_temp_sync, hostdata->sync[c->target].select_indirect);
-    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(long),
+    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
        dsa_temp_target, c->target);
 }
 
@@ -1424,21 +1436,21 @@ static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     unsigned long flags;
-    char **prev, *search;
+    volatile u32 *prev, search;
     int i;
 
     save_flags(flags);
     cli();
     for (i = 0; i < 2; ++i) {
-       for (search = (char *) (i ? hostdata->issue_dsa_head : 
-               hostdata->reconnect_dsa_head), prev = (char **) (i ? 
-               &(hostdata->issue_dsa_head) : &(hostdata->reconnect_dsa_head));
-            search && (search + hostdata->dsa_start) != (char *) cmd->dsa;
-            prev = (char **) (search + hostdata->dsa_next), 
+       for (search = (i ? hostdata->issue_dsa_head :
+               hostdata->reconnect_dsa_head), prev = (i ? 
+               &hostdata->issue_dsa_head : &hostdata->reconnect_dsa_head);
+            search && ((char*)bus_to_virt(search) + hostdata->dsa_start) != (char *) cmd->dsa;
+            prev = (u32*) ((char*)bus_to_virt(search) + hostdata->dsa_next),
                search = *prev);
 
        if (search)
-           *prev = *(char **) (search + hostdata->dsa_next);
+           *prev = *(u32*) ((char*)bus_to_virt(search) + hostdata->dsa_next);
     }
 
     if (cmd->prev)
@@ -1479,7 +1491,7 @@ static void intr_break (struct Scsi_Host *host, struct
 #if 0
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
 #endif
-    unsigned long *dsp;
+    u32 *dsp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;         
     unsigned long flags;
@@ -1490,9 +1502,10 @@ static void intr_break (struct Scsi_Host *host, struct
      * dump the appropriate debugging information to standard 
      * output.  
      */
+
     save_flags(flags);
     cli();
-    dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
     for (bp = hostdata->breakpoints; bp && bp->address != dsp; 
        bp = bp->next);
     if (!bp) 
@@ -1507,13 +1520,14 @@ static void intr_break (struct Scsi_Host *host, struct
 
     NCR53c7x0_write8 (hostdata->dmode, 
        NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+    mb();
 
     /*
      * And update the DSP register, using the size of the old 
      * instruction in bytes.
      */
 
-    restore_flags(flags);
+     restore_flags(flags);
 }
 
 /*
@@ -1552,6 +1566,7 @@ static int asynchronous (struct Scsi_Host *host, int target) {
        }
     /* Offset = 0, transfer period = divide SCLK by 4 */
        NCR53c7x0_write8 (SXFER_REG, 0);
+       mb();
     }
     return 0;
 }
@@ -1599,7 +1614,7 @@ static void synchronous (struct Scsi_Host *host, int target, char *msg) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     int desire, divisor, i, limit;
-    unsigned long *script;
+    u32 *script;
     unsigned char scntl3, sxfer;
    
 /* Scale divisor by 10 to accommodate fractions */ 
@@ -1628,7 +1643,7 @@ static void synchronous (struct Scsi_Host *host, int target, char *msg) {
        hostdata->sync[target].select_indirect = (scntl3 << 24) | (target << 16) | 
                (sxfer << 8);
 
-       script = (long *) hostdata->sync[target].script;
+       script = (u32*) hostdata->sync[target].script;
 
        /* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
        if ((hostdata->chip / 100) == 8) {
@@ -1670,13 +1685,13 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;         
-    unsigned long dsps,*dsp;   /* Argument of the INT instruction */
+    u32 dsps,*dsp;     /* Argument of the INT instruction */
     NCR53c7x0_local_setup(host);
     dsps = NCR53c7x0_read32(DSPS_REG);
-    dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
     if (hostdata->options & OPTION_DEBUG_INTR) 
-       printk ("scsi%d : DSPS = 0x%lx\n", host->host_no, dsps);
+       printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
 
     switch (dsps) {
     case A_int_msg_1:
@@ -1692,14 +1707,14 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         */
        case MESSAGE_REJECT:
            hostdata->dsp = hostdata->script + hostdata->E_accept_message /
-               sizeof(long);
+               sizeof(u32);
            hostdata->dsp_changed = 1;
            break;
        case INITIATE_RECOVERY:
            printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
                host->host_no);
            hostdata->dsp = hostdata->script + hostdata->E_reject_message /
-               sizeof(long);
+               sizeof(u32);
            hostdata->dsp_changed = 1;
        }
        return SPECIFIC_INT_NOTHING;
@@ -1718,26 +1733,26 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         */
            if (cmd->flags & CMD_FLAG_SDTR) {
                cmd->flags &= ~CMD_FLAG_SDTR; 
-               synchronous (host, c->target, (unsigned char *) 
+               synchronous (host, c->target, (unsigned char *)
                    hostdata->msg_buf);
                hostdata->dsp = hostdata->script + hostdata->E_accept_message /
-                   sizeof(long);
+                   sizeof(u32);
                hostdata->dsp_changed = 1;
                return SPECIFIC_INT_NOTHING;
            } else {
                if (hostdata->options & OPTION_SYNCHRONOUS)  {
                    cmd->flags |= CMD_FLAG_DID_SDTR;
                    synchronous (host, c->target, (unsigned char *)
-                       hostdata->msg_buf);
+                       hostdata->msg_buf);
                } else {
                    hostdata->msg_buf[4] = 0;           /* 0 offset = async */
                }
 
                patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
                patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, 
-                   hostdata->msg_buf);
+                   virt_to_bus((void*)hostdata->msg_buf));
                hostdata->dsp = hostdata->script + 
-               hostdata->E_respond_message / sizeof(long);
+               hostdata->E_respond_message / sizeof(u32);
                hostdata->dsp_changed = 1;
            }
 
@@ -1760,7 +1775,7 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
        /* Fall through to abort */
     case A_int_msg_wdtr:
        hostdata->dsp = hostdata->script + hostdata->E_reject_message /
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
        return SPECIFIC_INT_NOTHING;
     case A_int_err_unexpected_phase:
@@ -1771,14 +1786,14 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
        printk ("scsi%d : selected by target %d\n", host->host_no,
            (int) NCR53c7x0_read8(SSID_REG_800) &7);
        hostdata->dsp = hostdata->script + hostdata->E_target_abort / 
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
        return SPECIFIC_INT_NOTHING;
     case A_int_err_unexpected_reselect:
        printk ("scsi%d : unexpected reselect by target %d\n", host->host_no,
            (int) NCR53c7x0_read8(SSID_REG_800));
        hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
        return SPECIFIC_INT_NOTHING;
 /*
@@ -1841,10 +1856,10 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         */
 
        patch_dsa_32 (cmd->dsa, dsa_dataout, 0, hostdata->E_other_transfer);
-       patch_dsa_32 (cmd->dsa, dsa_datain, 0, cmd->data_transfer_start);
+       patch_dsa_32 (cmd->dsa, dsa_datain, 0, virt_to_bus(cmd->data_transfer_start));
        cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
            DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
-       cmd->data_transfer_start[1] = (unsigned long) c->sense_buffer;
+       cmd->data_transfer_start[1] = virt_to_bus(c->sense_buffer);
 
        cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
            << 24) | DBC_TCI_TRUE;
@@ -1863,14 +1878,14 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         * Restart command as a REQUEST SENSE.
         */
        hostdata->dsp = hostdata->script + hostdata->E_select /
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
        return SPECIFIC_INT_NOTHING;
     case A_int_debug_break:
        return SPECIFIC_INT_BREAK;
     case A_int_norm_aborted:
        hostdata->dsp = hostdata->script + hostdata->E_schedule / 
-               sizeof(long);
+               sizeof(u32);
        hostdata->dsp_changed = 1;
        if (cmd)
            abnormal_finished (cmd, DID_ERROR << 16);
@@ -1880,13 +1895,13 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
        hostdata->idle = 1;
        hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
        if (hostdata->options & OPTION_DEBUG_INTR)
-           printk("scsi%d : test%ld complete\n", host->host_no,
+           printk("scsi%d : test %d complete\n", host->host_no,
                hostdata->test_completed);
        return SPECIFIC_INT_NOTHING;
 #ifdef A_int_debug_scheduled
     case A_int_debug_scheduled:
        if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
-           printk("scsi%d : new I/O 0x%lx scheduled\n", host->host_no,
+           printk("scsi%d : new I/O 0x%x scheduled\n", host->host_no,
                NCR53c7x0_read32(DSA_REG));
        }
        return SPECIFIC_INT_RESTART;
@@ -1908,7 +1923,7 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
 #ifdef A_int_debug_dsa_loaded
     case A_int_debug_dsa_loaded:
        if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
-           printk("scsi%d : DSA loaded with 0x%lx\n", host->host_no,
+           printk("scsi%d : DSA loaded with 0x%x\n", host->host_no,
                NCR53c7x0_read32(DSA_REG));
        }
        return SPECIFIC_INT_RESTART; 
@@ -1925,14 +1940,14 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
 #ifdef A_int_debug_head
     case A_int_debug_head:
        if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
-           printk("scsi%d : issue_dsa_head now 0x%lx\n",
-               host->host_no, (unsigned long) hostdata->issue_dsa_head);
+           printk("scsi%d : issue_dsa_head now 0x%x\n",
+               host->host_no, hostdata->issue_dsa_head);
        }
     return SPECIFIC_INT_RESTART;
 #endif
     default:
        if ((dsps & 0xff000000) == 0x03000000) {
-            printk ("scsi%d : misc debug interrupt 0x%lx\n",
+            printk ("scsi%d : misc debug interrupt 0x%x\n",
                host->host_no, dsps);
            return SPECIFIC_INT_RESTART;
        }
@@ -1989,7 +2004,7 @@ static const char debugger_help =
 "ms <addr> <size> <value>      - store memory\n"
 "rp <num> <size>               - print register\n"
 "rs <num> <size> <value>       - store register\n"
-"s                             - single step\n"        
+"s                             - single step\n"
 "tb                            - begin trace \n"
 "te                            - end trace\n";
 
@@ -1999,7 +2014,7 @@ static const char debugger_help =
  */
 
 static int debugger_fn_bc (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        instance->hostdata;
     struct NCR53c7x0_break *bp, **prev;
@@ -2031,7 +2046,7 @@ static int debugger_fn_bc (struct Scsi_Host *host, struct debugger_token *token,
 
 
 static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     struct NCR53c7x0_break *bp;
@@ -2057,7 +2072,7 @@ static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
            len = strlen(buf);
            if ((bp->old[0] & (DCMD_TYPE_MASK << 24)) ==
                (DCMD_TYPE_MMI << 24)) {
-               sprintf(buf + len, "%08x\n", * (long *) bp->addr);
+               sprintf(buf + len, "%08x\n", * (u32 *) bp->addr);
            } else {
                sprintf(buf + len, "\n");
            }
@@ -2069,13 +2084,14 @@ static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
 }
 
 static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     struct NCR53c7x0_break *bp;
     char buf[80];
     size_t len;
     unsigned long flags;
+
     save_flags(flags);
     cli();
 
@@ -2093,10 +2109,10 @@ static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
        return -1;
     }
 
-    bp->address = (unsigned long *) args[0];
+    bp->address = (u32 *) args[0];
     memcpy ((void *) bp->old_instruction, (void *) bp->address, 8);
     bp->old_size = (((bp->old_instruction[0] >> 24) & DCMD_TYPE_MASK) ==
-       DCMD_TYPE_MMI ? 3 : 2;
+       DCMD_TYPE_MMI ? 3 : 2);
     bp->next = hostdata->breakpoints;
     hostdata->breakpoints = bp->next;
     memcpy ((void *) bp->address, (void *) hostdata->E_debug_break, 8);
@@ -2109,7 +2125,7 @@ static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
 static const struct debugger_token {
     char *name;
     int numargs;
-    int (*fn)(struct debugger_token *token, unsigned long args[]);
+    int (*fn)(struct debugger_token *token, u32 args[]);
 } debugger_tokens[] = {
     TOKEN(bc,1), TOKEN(bl,0), TOKEN(bs,1), TOKEN(g,0), TOKEN(halt,0),
     {DT_help, "?", 0} , TOKEN(h,0), TOKEN(i,0), TOKEN(mp,2), 
@@ -2134,7 +2150,7 @@ static debugger_user_write (struct inode *inode,struct file *filp,
     struct NCR53c7x0_hostadata *hostdata;      
     char input_buf[80],                        /* Kernel space copy of buf */
        *ptr;                                   /* Pointer to argument list */
-    unsigned long args[3];                     /* Arguments */
+    u32 args[3];                               /* Arguments */
     int i, j, error, len;
 
     if (!(host = inode_to_host(inode)))
@@ -2192,6 +2208,7 @@ static debugger_kernel_write (struct Scsi_Host *host, char *buf, size_t
        host->hostdata;
     int copy, left;
     unsigned long flags;
+    
     save_flags(flags);
     cli();
     while (buflen) {
@@ -2242,7 +2259,9 @@ NCR53c8x0_soft_reset (struct Scsi_Host *host) {
      */
 
     NCR53c7x0_write8(ISTAT_REG_800, ISTAT_10_SRST);
+    mb();
     NCR53c7x0_write8(ISTAT_REG_800, 0);
+    mb();
     NCR53c7x0_write8(hostdata->dmode, hostdata->saved_dmode & ~DMODE_MAN);
 
 
@@ -2300,7 +2319,7 @@ NCR53c8x0_soft_reset (struct Scsi_Host *host) {
     /* Enable active negation */
     NCR53c7x0_write8(STEST3_REG_800, STEST3_800_TE);
 
-    
+    mb();
 }
 
 /*
@@ -2331,12 +2350,12 @@ create_cmd (Scsi_Cmnd *cmd) {
        dataout;
     int data_transfer_instructions, /* Count of dynamic instructions */
        i;                      /* Counter */
-    unsigned long *cmd_datain, /* Address of datain/dataout code */
+    u32 *cmd_datain,           /* Address of datain/dataout code */
        *cmd_dataout;           /* Incremented as we assemble */
 #ifdef notyet
     void *real;                        /* Real address */
     int size;                  /* Size of *tmp */
-    int        alignment;              /* Alignment adjustment (0 - 4) */
+    int alignment;             /* Alignment adjustment (0 - sizeof(long)-1) */
 #endif
     unsigned long flags;
     NCR53c7x0_local_setup(cmd->host);
@@ -2367,9 +2386,9 @@ create_cmd (Scsi_Cmnd *cmd) {
 #else
     /* kmalloc() can allocate any size, but historically has returned 
        unaligned addresses, so we need to allow for alignment */
-           size = hostdata->max_cmd_size + 4;
+           size = hostdata->max_cmd_size + sizeof(void*);
            real = kmalloc (size, GFP_ATOMIC);
-           alignment = 4 - (((unsigned) real) & 3);
+           alignment = sizeof(void*) - (((unsigned) real) & (sizeof(void*)-1));
            tmp = (struct NCR53c7x0_cmd *) (((char *) real) + alignment);
            if (!tmp)
                break;
@@ -2397,7 +2416,6 @@ create_cmd (Scsi_Cmnd *cmd) {
        }
     }
 
-
     /*
      * Decide whether we need to generate commands for DATA IN,
      * DATA OUT, neither, or both based on the SCSI command 
@@ -2465,7 +2483,6 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (data_transfer_instructions < 2)
        data_transfer_instructions = 2;
 
-
     /*
      * Initialize Linux specific fields.
      */
@@ -2479,7 +2496,7 @@ create_cmd (Scsi_Cmnd *cmd) {
      */
 
     tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end - 
-       hostdata->dsa_start) / sizeof(long);
+       hostdata->dsa_start) / sizeof(u32);
     tmp->data_transfer_end = tmp->data_transfer_start + 
        2 * data_transfer_instructions;
 
@@ -2498,8 +2515,8 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (hostdata->dsa_fixup)
        hostdata->dsa_fixup(tmp);
 
-    patch_dsa_32(tmp->dsa, dsa_next, 0, NULL);
-    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, cmd);
+    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
     patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
        select_indirect);
     /*
@@ -2512,26 +2529,24 @@ create_cmd (Scsi_Cmnd *cmd) {
 #else
     tmp->select[0] = IDENTIFY (0, cmd->lun);
 #endif
-    patch_dsa_32(tmp->dsa, dsa_msgout, 1, tmp->select);
+    patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
     patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, cmd->cmnd);
-    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
-       cmd_dataout : hostdata->script + hostdata->E_other_transfer / 
-           sizeof (long));
-    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ? 
-       cmd_datain : hostdata->script + hostdata->E_other_transfer / 
-           sizeof (long));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+       virt_to_bus(cmd_dataout) : virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
+       virt_to_bus(cmd_datain) : virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
     /* 
      * XXX - need to make endian aware, should use separate variables
      * for both status and message bytes.
      */
     patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, (((unsigned long) &cmd->result) + 1));
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
     patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, &cmd->result);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
-       &(hostdata->NCR53c7xx_msg_nop));
+       virt_to_bus(&hostdata->NCR53c7xx_msg_nop));
 
     
     /*
@@ -2571,12 +2586,12 @@ create_cmd (Scsi_Cmnd *cmd) {
 
     for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
        cmd_dataout += 4, ++i) {
-       unsigned long buf = (unsigned long) (cmd->use_sg ? 
-           ((struct scatterlist *)cmd->buffer)[i].address :
-           cmd->request_buffer);
-       unsigned long count = (unsigned long) (cmd->use_sg ?
+       u32 buf = cmd->use_sg ?
+           virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
+           virt_to_bus(cmd->request_buffer);
+       u32 count = cmd->use_sg ?
            ((struct scatterlist *)cmd->buffer)[i].length :
-           cmd->request_bufflen);
+           cmd->request_bufflen;
 
        if (datain) {
            cmd_datain[0] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
@@ -2585,8 +2600,8 @@ create_cmd (Scsi_Cmnd *cmd) {
            cmd_datain[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
                DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
                DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
-           cmd_datain[3] = (unsigned long) hostdata->script + 
-               hostdata->E_msg_in;
+           cmd_datain[3] = virt_to_bus(hostdata->script) +
+               hostdata->E_msg_in;
 #if 0
            print_insn (host, cmd_datain, "dynamic ", 1);
            print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -2599,8 +2614,8 @@ create_cmd (Scsi_Cmnd *cmd) {
            cmd_dataout[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
                DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
                DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
-           cmd_dataout[3] = (unsigned long) hostdata->script + 
-               hostdata->E_msg_in;
+           cmd_dataout[3] = virt_to_bus(hostdata->script) +
+               hostdata->E_msg_in;
 #if 0
            print_insn (host, cmd_dataout, "dynamic ", 1);
            print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -2617,8 +2632,8 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (datain) {
        cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
            DBC_TCI_TRUE;
-       cmd_datain[1] = (unsigned long) hostdata->script + 
-           hostdata->E_other_transfer;
+       cmd_datain[1] = virt_to_bus(hostdata->script) +
+           hostdata->E_other_transfer;
 #if 0
        print_insn (host, cmd_datain, "dynamic jump ", 1);
 #endif
@@ -2636,8 +2651,8 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (dataout) {
        cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
            DBC_TCI_TRUE;
-       cmd_dataout[1] = (unsigned long) hostdata->script + 
-           hostdata->E_other_transfer;
+       cmd_dataout[1] = virt_to_bus(hostdata->script) +
+           hostdata->E_other_transfer;
 #if 0
        print_insn (host, cmd_dataout, "dynamic jump ", 1);
 #endif
@@ -2762,23 +2777,24 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
                - hostdata->dsa_start;  
                /* dsa start is negative, so subtraction is used */
 #if 0  
-       printk("scsi%d : new dsa is 0x%x\n", host->host_no, (unsigned) dsa);
+       printk("scsi%d : new dsa is 0x%p\n", host->host_no, dsa);
 #endif
 
        if (hostdata->running_list)
            hostdata->running_list->prev = tmp;
 
-       tmp->next = hostdata->running_list;
+       tmp->next = (struct NCR53c7x0_cmd*) hostdata->running_list;
 
        if (!hostdata->running_list)
-           hostdata->running_list = tmp;
+           hostdata->running_list = (struct NCR53c7x0_cmd*) tmp;
        
 
        if (hostdata->idle) {
            hostdata->idle = 0;
            hostdata->state = STATE_RUNNING;
-           NCR53c7x0_write32 (DSP_REG,  ((unsigned long) hostdata->script) +
+           NCR53c7x0_write32 (DSP_REG,  virt_to_bus(hostdata->script) +
                hostdata->E_schedule);
+           mb();
        }
 
 /* XXX - make function */
@@ -2793,9 +2809,11 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
 #if 0
                printk ("scsi%d : no issue queue\n", host->host_no);
 #endif
-               hostdata->issue_dsa_tail = hostdata->issue_dsa_head = dsa;
+               hostdata->issue_dsa_tail = (u32 *) dsa;
+               hostdata->issue_dsa_head = virt_to_bus(dsa);
                NCR53c7x0_write8(hostdata->istat, 
                    NCR53c7x0_read8(hostdata->istat) | ISTAT_10_SIGP);
+               mb();
                break;
            /*
             * Otherwise, we blindly perform an atomic write 
@@ -2806,9 +2824,9 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
             */
            } else {
                printk ("scsi%d : existing issue queue\n", host->host_no);
-           /* XXX - Replace with XCHG or equivalent */
-               hostdata->issue_dsa_tail = *((unsigned char **) 
-                   (hostdata->issue_dsa_tail + hostdata->dsa_next)) = dsa;
+               hostdata->issue_dsa_tail[hostdata->dsa_next/sizeof(u32)]
+                 = virt_to_bus(dsa);
+               hostdata->issue_dsa_tail = (u32 *) dsa;
            /*
             * After which, one of two things will happen : 
             * The NCR will have scheduled a command, either this
@@ -2839,7 +2857,7 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
 }
 
 
-int fix_pointers (unsigned long dsa) {
+int fix_pointers (u32 dsa) {
     return 0;
 }
 
@@ -2861,11 +2879,13 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     unsigned char sstat0_sist0, sist1,                 /* Registers */
            fatal;                              /* Did a fatal interrupt 
                                                   occur ? */
+    int is_8xx_chip;
     NCR53c7x0_local_setup(host);
 
     fatal = 0;
   
-    if ((hostdata->chip / 100) == 8) {
+    is_8xx_chip = ((unsigned) (hostdata->chip - 800)) < 100;
+    if (is_8xx_chip) {
        sstat0_sist0 = NCR53c7x0_read8(SIST0_REG_800);
        udelay(1);
        sist1 = NCR53c7x0_read8(SIST1_REG_800);
@@ -2878,9 +2898,9 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
        printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
            sstat0_sist0, sist1);
 
-    /* 250ms selection timeout */
-    if ((((hostdata->chip / 100) == 8) && (sist1 & SIST1_800_STO)) || 
-        (((hostdata->chip / 100) != 8) && (sstat0_sist0 & SSTAT0_700_STO))) {
+    /* selection timeout */
+    if ((is_8xx_chip && (sist1 & SIST1_800_STO)) ||
+        (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
        fatal = 1;
        if (hostdata->options & OPTION_DEBUG_INTR) {
            printk ("scsi%d : Selection Timeout\n", host->host_no);
@@ -2924,7 +2944,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
            abnormal_finished(cmd, DID_ERROR << 16);
        }
        hostdata->dsp = hostdata->script + hostdata->E_schedule / 
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
     /* SCSI PARITY error */
     } 
@@ -2941,7 +2961,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
 
        /* XXX - Reduce synchronous transfer rate! */
        hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1; 
     /* SCSI GROSS error */
     } 
@@ -2951,7 +2971,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
        printk("scsi%d : gross error\n", host->host_no);
        /* XXX Reduce synchronous transfer rate! */
        hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-           sizeof(long);
+           sizeof(u32);
        hostdata->dsp_changed = 1;
     /* Phase mismatch */
     } 
@@ -2981,17 +3001,20 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
 #if 0
            if (NCR53c7x0_read8 (CTEST2_REG_800) & CTEST2_800_DDIR) {
                NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_FLF);
+               mb();
                while (!((hostdata->dstat = NCR53c7x0_read8(DSTAT_REG)) &
                    DSTAT_DFE));
            } else 
 #endif
            {
                NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_CLF);
+               mb();
                while (NCR53c7x0_read8 (CTEST3_REG_800) & CTEST3_800_CLF);
            }
        }
 
        NCR53c7x0_write8 (STEST3_REG_800, STEST3_800_CSF);
+       mb();
        while (NCR53c7x0_read8 (STEST3_REG_800) & STEST3_800_CSF);
     }
 #endif
@@ -3015,12 +3038,12 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
     struct NCR53c7x0_hostdata *hostdata;       /* host->hostdata */
     struct NCR53c7x0_cmd *cmd,                 /* command which halted */
        **cmd_prev_ptr;
-    unsigned long *dsa;                                /* DSA */
+    u32 *dsa;                                  /* DSA */
     int done = 1;                              /* Indicates when handler 
                                                   should terminate */
     int interrupted = 0;                       /* This HA generated 
                                                   an interrupt */
-    unsigned long flags;                               
+    unsigned long flags;
 
 #ifdef NCR_DEBUG
     char buf[80];                              /* Debugging sprintf buffer */
@@ -3033,8 +3056,7 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
 
     do {
        done = 1;
-       for (host = first_host; host; host = hostdata->next ?
-            hostdata->next : NULL) {
+       for (host = first_host; host; host = hostdata->next) {
            NCR53c7x0_local_setup(host);
 
            hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
@@ -3043,6 +3065,8 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
 
 
            do {
+               int is_8xx_chip;
+
                hostdata->dstat_valid = 0;
                interrupted = 0;
                /*
@@ -3058,8 +3082,9 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
                 * at the contents of the DSA register and continue running.
                 */
 /* XXX - this is getting big, and should move to intr_intfly() */
+               is_8xx_chip = ((unsigned) (hostdata->chip - 800)) < 100;
                if ((hostdata->options & OPTION_INTFLY) && 
-                   ((hostdata->chip / 100) == 8 && (istat & ISTAT_800_INTF))) {
+                   (is_8xx_chip && (istat & ISTAT_800_INTF))) {
                    char search_found = 0;      /* Got at least one ? */
                    done = 0;
                    interrupted = 1;
@@ -3069,6 +3094,7 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
                     * is self-clearing.
                     */
                    NCR53c7x0_write8(hostdata->istat, istat|ISTAT_800_INTF);
+                   mb();
 
                    if (hostdata->options & OPTION_DEBUG_INTR)
                        printk ("scsi%d : INTFLY\n", host->host_no); 
@@ -3170,10 +3196,10 @@ restart:
                    if (hostdata->options & OPTION_700) {
                        cmd = (struct NCR53c7x0_cmd *) hostdata->current;
                    } else {
-                       dsa = (unsigned long *) NCR53c7x0_read32(DSA_REG);
+                       dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
                        for (cmd = (struct NCR53c7x0_cmd *) 
                            hostdata->running_list; cmd &&
-                           (dsa + (hostdata->dsa_start / sizeof(long))) != 
+                           (dsa + (hostdata->dsa_start / sizeof(u32))) != 
                                cmd->dsa;
                            cmd = (struct NCR53c7x0_cmd *)(cmd->next));
                    }
@@ -3212,12 +3238,14 @@ restart:
            #if 0
                        if (NCR53c7x0_read8 (CTEST2_REG_800) & CTEST2_800_DDIR) {
                            NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_FLF);
+                           mb();
                            while (!((hostdata->dstat = NCR53c7x0_read8(DSTAT_REG)) &
                                DSTAT_DFE));
                        } else 
            #endif
                        {
                            NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_CLF);
+                           mb();
                            while (NCR53c7x0_read8 (CTEST3_REG_800) & CTEST3_800_CLF);
                        }
                    }
@@ -3240,16 +3268,17 @@ restart:
 
            if (!hostdata->idle && hostdata->state == STATE_HALTED) {
                if (!hostdata->dsp_changed) {
-                   hostdata->dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+                   hostdata->dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
                }
                        
 #if 0
-               printk("scsi%d : new dsp is 0x%lx\n", host->host_no, 
-                   (long) hostdata->dsp);
+               printk("scsi%d : new dsp is 0x%p\n", host->host_no, 
+                   hostdata->dsp);
 #endif
                
                hostdata->state = STATE_RUNNING;
-               NCR53c7x0_write32 (DSP_REG, (unsigned long) hostdata->dsp);
+               NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+               mb();
            }
        }
     } while (!done);
@@ -3274,7 +3303,7 @@ abort_connected (struct Scsi_Host *host) {
        host->hostdata;
 
     hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-       sizeof(long);
+       sizeof(u32);
     hostdata->dsp_changed = 1;
     printk ("scsi%d : DANGER : abort_connected() called \n",
        host->host_no);
@@ -3304,7 +3333,7 @@ abort_connected (struct Scsi_Host *host) {
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
     *cmd) {
     NCR53c7x0_local_declare();
-    unsigned long dbc_dcmd, *dsp, *dsp_next;
+    u32 dbc_dcmd, *dsp, *dsp_next;
     unsigned char dcmd, sbcl;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
@@ -3323,12 +3352,12 @@ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
      * occurred, as well as which SCSI phase we are currently in.
      */
 
-    dsp_next = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
     /*
      * Like other processors, the NCR adjusts the DSP pointer before
      * instruction decode.  Set the DSP address back to what it should
-     * be for this instruction based on its size (2 or 3 longs).
+     * be for this instruction based on its size (2 or 3 words).
      */
 
     dbc_dcmd = NCR53c7x0_read32(DBC_REG);
@@ -3372,7 +3401,7 @@ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
      * mismatches should only occur in the data transfer routines, or
      * when a command is being aborted.  
      */
-    if (dsp >= cmd->data_transfer_start & dsp < cmd->data_transfer_end) {
+    if (dsp >= cmd->data_transfer_start && dsp < cmd->data_transfer_end) {
 
        /*
         * There are three instructions used in our data transfer routines with
@@ -3391,7 +3420,7 @@ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
            if (hostdata->options & OPTION_DEBUG_INTR) 
                printk ("scsi%d : new phase = STATIN\n", host->host_no);
            hostdata->dsp = hostdata->script + hostdata->E_command_complete /
-               sizeof(long);
+               sizeof(u32);
            hostdata->dsp_changed = 1;
            return;
        /*
@@ -3409,9 +3438,10 @@ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
                    DCMD_BMI_OP_MOVE_I)) {
                dsp[0] = dbc_dcmd;
                dsp[1] = NCR53c7x0_read32(DNAD_REG);
-               NCR53c7x0_write32(TEMP_REG, (unsigned long) dsp);
+               NCR53c7x0_write32(TEMP_REG, virt_to_bus(dsp));
+               mb();
                hostdata->dsp = hostdata->script + hostdata->E_msg_in /
-                   sizeof(long);
+                   sizeof(u32);
                hostdata->dsp_changed = 1;
            } else {
                printk("scsi%d : unexpected MSGIN in dynamic NCR code, dcmd=0x%x.\n",
@@ -3440,8 +3470,8 @@ static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
      * Any other phase mismatches abort the currently executing command.
      */
     } else {
-       printk ("scsi%d : unexpected phase %s at dsp = 0x%x\n",
-           host->host_no, phase, (unsigned) dsp);
+       printk ("scsi%d : unexpected phase %s at dsp = 0x%p\n",
+           host->host_no, phase, dsp);
        print_insn (host, dsp, "", 1);
        print_insn (host, dsp_next, "", 1);
        abort_connected(host);
@@ -3464,7 +3494,7 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     unsigned char dstat;       /* DSTAT */     
-    unsigned long *dsp,
+    u32 *dsp,
        *next_dsp,              /* Current dsp */
        *dsa,
        dbc_dcmd;               /* DCMD (high eight bits) + DBC */
@@ -3483,10 +3513,10 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
        printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
 
     dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
-    next_dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
     dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
 /* XXX - check chip type */
-    dsa = (unsigned long *) NCR53c7x0_read32(DSA_REG);
+    dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
 
     /*
      * DSTAT_ABRT is the aborted interrupt.  This is set whenever the 
@@ -3529,6 +3559,7 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
 
            NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) & 
                ~DCNTL_SSM) | DCNTL_STD);
+           mb();
            restore_flags(flags);
        } else {
            printk("scsi%d : unexpected single step interrupt at\n"
@@ -3561,9 +3592,9 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
      * can ignore it.
      */
 
-       if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(long))) &&
+       if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
            (dsp <= (hostdata->script + hostdata->E_select_msgout / 
-           sizeof(long) + 8))) || (hostdata->test_running == 2)) {
+           sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
            if (hostdata->options & OPTION_DEBUG_INTR) 
                printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
                    host->host_no);
@@ -3581,12 +3612,12 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
        } else {
            printk("scsi%d : illegal instruction ", host->host_no);
            print_insn (host, dsp, "", 1);
-           printk("scsi%d : DSP=0x%lx, DCMD|DBC=0x%lx, DSA=0x%lx\n"
-              "         DSPS=0x%lx, TEMP=0x%lx, DMODE=0x%x,\n" 
-              "         DNAD=0x%lx\n",
-            host->host_no, (unsigned long) dsp, dbc_dcmd,
-            (unsigned long) dsa, NCR53c7x0_read32(DSPS_REG),
-            NCR53c7x0_read32(TEMP_REG), (int) NCR53c7x0_read8(hostdata->dmode),
+           printk("scsi%d : DSP=0x%p, DCMD|DBC=0x%x, DSA=0x%p\n"
+              "         DSPS=0x%x, TEMP=0x%x, DMODE=0x%x,\n" 
+              "         DNAD=0x%x\n",
+            host->host_no, dsp, dbc_dcmd,
+            dsa, NCR53c7x0_read32(DSPS_REG),
+            NCR53c7x0_read32(TEMP_REG), NCR53c7x0_read8(hostdata->dmode),
             NCR53c7x0_read32(DNAD_REG));
            panic("         mail drew@Colorado.EDU\n");
        }
@@ -3598,11 +3629,11 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
      */
     
     if (dstat & DSTAT_800_BF) {
-       printk("scsi%d : BUS FAULT, DSP=0x%lx, DCMD|DBC=0x%lx, DSA=0x%lx\n"
-              "         DSPS=0x%lx, TEMP=0x%lx, DMODE=0x%x\n", 
-            host->host_no, (unsigned long) dsp, NCR53c7x0_read32(DBC_REG),
-            (unsigned long) dsa, NCR53c7x0_read32(DSPS_REG),
-            NCR53c7x0_read32(TEMP_REG), (int) NCR53c7x0_read8(hostdata->dmode));
+       printk("scsi%d : BUS FAULT, DSP=0x%p, DCMD|DBC=0x%x, DSA=0x%p\n"
+              "         DSPS=0x%x, TEMP=0x%x, DMODE=0x%x\n", 
+            host->host_no, dsp, NCR53c7x0_read32(DBC_REG),
+            dsa, NCR53c7x0_read32(DSPS_REG),
+            NCR53c7x0_read32(TEMP_REG), NCR53c7x0_read8(hostdata->dmode));
        print_dsa (host, dsa);
        printk("scsi%d : DSP->\n", host->host_no);
        print_insn(host, dsp, "", 1);
@@ -3652,12 +3683,13 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
 
 /* All DMA interrupts are fatal.  Flush SCSI queue */
     NCR53c7x0_write8 (STEST3_REG_800, STEST3_800_CSF);
+    mb();
     while (NCR53c7x0_read8 (STEST3_REG_800) & STEST3_800_CSF);
 }
 
 /*
  * Function : static int print_insn (struct Scsi_Host *host, 
- *     unsigned long *insn, int kernel)
+ *     u32 *insn, int kernel)
  *
  * Purpose : print numeric representation of the instruction pointed
  *     to by insn to the debugging or kernel message buffer
@@ -3669,10 +3701,10 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
  * Inputs : host, insn - host, pointer to instruction, prefix - 
  *     string to prepend, kernel - use printk instead of debugging buffer.
  *
- * Returns : size, in longs, of instruction printed.
+ * Returns : size, in ints, of instruction printed.
  */
 
-static int print_insn (struct Scsi_Host *host, unsigned long *insn,
+static int print_insn (struct Scsi_Host *host, u32 *insn,
     char *prefix, int kernel) {
     char buf[80],              /* Temporary buffer and pointer */
        *tmp;                   
@@ -3680,11 +3712,11 @@ static int print_insn (struct Scsi_Host *host, unsigned long *insn,
     int size;
 
     dcmd = (insn[0] >> 24) & 0xff;
-    sprintf(buf, "%s%08lx : 0x%08lx 0x%08lx", (prefix ? prefix : ""), 
-       (unsigned long) insn, insn[0], insn[1]);
+    sprintf(buf, "%s%p : 0x%08x 0x%08x", (prefix ? prefix : ""), 
+       insn, insn[0], insn[1]);
     tmp = buf + strlen(buf);
     if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
-       sprintf (tmp, " 0x%08lx\n", insn[2]);
+       sprintf (tmp, " 0x%08x\n", insn[2]);
        size = 3;
     } else {
        sprintf (tmp, "\n");
@@ -3719,7 +3751,7 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
        host->hostdata;
     unsigned long flags;
-    struct NCR53c7x0_cmd *curr, **prev;
+    volatile struct NCR53c7x0_cmd *curr, **prev;
     save_flags(flags);
     cli();
 
@@ -3733,10 +3765,10 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
  * pull the command out of the old queue, and call it aborted.
  */
 
-    for (curr = (struct NCR53c7x0_cmd *) hostdata->issue_queue, 
-         prev = (struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
-        curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
-         &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+    for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->issue_queue, 
+         prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
+        curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **)
+         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
        *prev = (struct NCR53c7x0_cmd *) curr->next;
@@ -3758,10 +3790,10 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
  * commands.  If this is the case, drastic measures are called for.  
  */ 
 
-    for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list, 
-        prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
-        curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **) 
-         &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+    for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->running_list, 
+        prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->running_list);
+        curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **) 
+         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
        restore_flags(flags);
@@ -3802,8 +3834,8 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
  *
  * Returns : 0 on success.
  */
-int 
+
+int
 NCR53c7xx_reset (Scsi_Cmnd *cmd) {
     NCR53c7x0_local_declare();
     unsigned long flags;
@@ -3814,8 +3846,9 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd) {
     struct NCR53c7x0_hostdata *hostdata = host ? 
     (struct NCR53c7x0_hostdata *) host->hostdata : NULL;
     NCR53c7x0_local_setup(host);
+
     save_flags(flags);
-    halt (host);
+    ncr_halt (host);
     NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
     udelay(25);        /* Minimum amount of time to assert RST */
     NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
@@ -3840,9 +3873,6 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd) {
        cmd->scsi_done(cmd);
     }
     restore_flags(flags);
-
-    printk ("scsi%d : DANGER : NCR53c7xx_reset is NOP\n",
-       cmd->host->host_no);
     return SCSI_RESET_SUCCESS;
 }
 
@@ -3851,20 +3881,20 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd) {
  * therefore shares the scsicam_bios_param function.
  */
 
-static void print_dsa (struct Scsi_Host *host, unsigned long *dsa) {
+static void print_dsa (struct Scsi_Host *host, u32 *dsa) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     int i, len;
     char *ptr;
 
-    printk("scsi%d : dsa at 0x%x\n"
-           "        + %ld : dsa_msgout length = %lu, data = 0x%lx\n" ,
-           host->host_no, (unsigned) dsa, hostdata->dsa_msgout,
-           dsa[hostdata->dsa_msgout / sizeof(long)],
-           dsa[hostdata->dsa_msgout / sizeof(long) + 1]);
+    printk("scsi%d : dsa at 0x%p\n"
+           "        + %d : dsa_msgout length = %d, data = 0x%x\n" ,
+           host->host_no, dsa, hostdata->dsa_msgout,
+           dsa[hostdata->dsa_msgout / sizeof(u32)],
+           dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
 
-    for (i = dsa[hostdata->dsa_msgout / sizeof(long)],
-       ptr = (char *) dsa[hostdata->dsa_msgout / sizeof(long) + 1]; i > 0;
+    for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+       ptr = bus_to_virt(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); i > 0;
        ptr += len, i -= len) {
        printk("               ");
        len = print_msg (ptr);
@@ -3891,7 +3921,7 @@ shutdown (struct Scsi_Host *host) {
     NCR53c7x0_local_setup(host);
     save_flags (flags);
     cli();
-    halt (host);
+    ncr_halt (host);
     hostdata->soft_reset(host);
 /* 
  * For now, we take the simplest solution : reset the SCSI bus. Eventually,
@@ -3910,7 +3940,7 @@ shutdown (struct Scsi_Host *host) {
 
 
 /*
- * Function : static int halt (struct Scsi_Host *host)
+ * Function : static int ncr_halt (struct Scsi_Host *host)
  * 
  * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
  *
@@ -3920,7 +3950,7 @@ shutdown (struct Scsi_Host *host) {
  */
 
 static int 
-halt (struct Scsi_Host *host) {
+ncr_halt (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     unsigned long flags;
     unsigned char istat, tmp;
index 6a36159140cbea5229c52a1bda57042d549fcf93..d3c4339fb11ee78e07994c0f1532674d42488891 100644 (file)
 #ifndef NCR53c7x0_H
 #define NCR53c7x0_H
 
+#ifdef __alpha__
+
+# define ncr_readb(a)          ((unsigned int)readb((unsigned long)(a)))
+# define ncr_readw(a)          ((unsigned int)readw((unsigned long)(a)))
+# define ncr_readl(a)          ((unsigned int)readl((unsigned long)(a)))
+# define ncr_writeb(v,a)       (writeb((v), (unsigned long)(a)))
+# define ncr_writew(v,a)       (writew((v), (unsigned long)(a)))
+# define ncr_writel(v,a)       (writel((v), (unsigned long)(a)))
+
+#else
+
+# define ncr_readb(a)          (*(unsigned char*)(a))
+# define ncr_readw(a)          (*(unsigned short*)(a))
+# define ncr_readl(a)          (*(unsigned int*)(a))
+# define ncr_writeb(v,a)       (*(unsigned char*)(a) = (v))
+# define ncr_writew(v,a)       (*(unsigned short*)(a) = (v))
+# define ncr_writel(v,a)       (*(unsigned int*)(a) = (v))
+
+#endif
+
 
 /* 
  * Prevent name space pollution in hosts.c, and only provide the 
@@ -713,7 +733,7 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 #define DCMD_RWRI_OP_ADDC      0x07
 
 #define DCMD_TYPE_MMI          0xc0    /* Indicates a Memory Move instruction 
-                                          (three longs) */
+                                          (three words) */
 
 
 #define DNAD_REG               0x28    /* through 0x2b DMA next address for 
@@ -919,8 +939,8 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 #endif
                                
 struct NCR53c7x0_synchronous {
-    unsigned long select_indirect;     /* Value used for indirect selection */
-    unsigned long script[6];           /* Size ?? Script used when target is 
+    u32 select_indirect;               /* Value used for indirect selection */
+    u32 script[6];                     /* Size ?? Script used when target is 
                                                reselected */
     unsigned renegotiate:1;            /* Force renegotiation on next   
                                           select */
@@ -933,7 +953,7 @@ struct NCR53c7x0_synchronous {
 #define CMD_FLAG_DID_SDTR      4       /* did SDTR */
 
 struct NCR53c7x0_table_indirect {
-    unsigned long count;
+    u32 count;
     void *address;
 };
 
@@ -966,11 +986,11 @@ struct NCR53c7x0_cmd {
                                         
 
 
-    unsigned long *data_transfer_start;        /* Start of data transfer routines */
-    unsigned long *data_transfer_end;  /* Address after end of data transfer o
+    u32 *data_transfer_start;          /* Start of data transfer routines */
+    u32 *data_transfer_end;            /* Address after end of data transfer o
                                           routines */
 
-    unsigned long residual[8];         /* Residual data transfer
+    u32 residual[8];                   /* Residual data transfer
                                           shadow of data_transfer code.
 
                                           Has instruction with modified
@@ -978,13 +998,13 @@ struct NCR53c7x0_cmd {
                                           CALL routine following command.
                                         */
             
-    unsigned long dsa[0];              /* Variable length (depending
+    u32 dsa[0];                                /* Variable length (depending
                                           on host type, number of scatter /
                                           gather buffers, etc).  */
 };
 
 struct NCR53c7x0_break {
-    unsigned long *address, old_instruction[2];
+    u32 *address, old_instruction[2];
     struct NCR53c7x0_break *next;
     unsigned char old_size;            /* Size of old instruction */
 };
@@ -1050,7 +1070,7 @@ struct NCR53c7x0_hostdata {
     unsigned char pci_bus, pci_device_fn;
     unsigned pci_valid:1;
 
-    unsigned long *dsp;                        /* dsp to restart with after
+    u32 *dsp;                          /* dsp to restart with after
                                           all stacked interrupts are
                                           handled. */
 
@@ -1095,52 +1115,52 @@ struct NCR53c7x0_hostdata {
      * chip.  
      */
 
-    long dsa_start;                    
-    long dsa_end;                      
-    long dsa_next;
-    long dsa_prev;
-    long dsa_cmnd;
-    long dsa_select;
-    long dsa_msgout;
-    long dsa_cmdout;
-    long dsa_dataout;
-    long dsa_datain;
-    long dsa_msgin;
-    long dsa_msgout_other;
-    long dsa_write_sync;
-    long dsa_write_resume;
-    long dsa_jump_resume;
-    long dsa_check_reselect;
-    long dsa_status;
+    s32 dsa_start;                     
+    s32 dsa_end;                       
+    s32 dsa_next;
+    s32 dsa_prev;
+    s32 dsa_cmnd;
+    s32 dsa_select;
+    s32 dsa_msgout;
+    s32 dsa_cmdout;
+    s32 dsa_dataout;
+    s32 dsa_datain;
+    s32 dsa_msgin;
+    s32 dsa_msgout_other;
+    s32 dsa_write_sync;
+    s32 dsa_write_resume;
+    s32 dsa_jump_resume;
+    s32 dsa_check_reselect;
+    s32 dsa_status;
 
     /* 
      * Important entry points that generic fixup code needs
      * to know about, fixed up.
      */
 
-    long E_accept_message;
-    long E_dsa_code_template;
-    long E_dsa_code_template_end;
-    long E_command_complete;           
-    long E_msg_in;
-    long E_initiator_abort;
-    long E_other_transfer;
-    long E_target_abort;
-    long E_schedule;                   
-    long E_debug_break;        
-    long E_reject_message;
-    long E_respond_message;
-    long E_select;
-    long E_select_msgout;
-    long E_test_0;
-    long E_test_1;
-    long E_test_2;
-    long E_test_3;
-    long E_dsa_zero;
-    long E_dsa_jump_resume;
+    s32 E_accept_message;
+    s32 E_dsa_code_template;
+    s32 E_dsa_code_template_end;
+    s32 E_command_complete;            
+    s32 E_msg_in;
+    s32 E_initiator_abort;
+    s32 E_other_transfer;
+    s32 E_target_abort;
+    s32 E_schedule;                    
+    s32 E_debug_break; 
+    s32 E_reject_message;
+    s32 E_respond_message;
+    s32 E_select;
+    s32 E_select_msgout;
+    s32 E_test_0;
+    s32 E_test_1;
+    s32 E_test_2;
+    s32 E_test_3;
+    s32 E_dsa_zero;
+    s32 E_dsa_jump_resume;
 
     int options;                       /* Bitfielded set of options enabled */
-    long test_completed;               /* Test completed */
+    volatile u32 test_completed;       /* Test completed */
     int test_running;                  /* Test currently running */
     int test_source;
     volatile int test_dest;
@@ -1250,17 +1270,18 @@ struct NCR53c7x0_hostdata {
                                                
 
     /* Shared variables between SCRIPT and host driver */
-    volatile unsigned char *issue_dsa_head;    
+    volatile u32 issue_dsa_head;
                                                /* commands waiting to be 
                                                   issued, insertions are 
                                                   done by Linux driver,
                                                   deletions are done by
                                                   NCR */
-    volatile unsigned char *issue_dsa_tail;
+    u32 *issue_dsa_tail;                       /* issue queue tail pointer;
+                                                  used by Linux driver only */
     volatile unsigned char msg_buf[16];                /* buffer for messages
                                                   other than the command
                                                   complete message */
-    volatile unsigned char *reconnect_dsa_head;        
+    volatile u32 reconnect_dsa_head;
                                                /* disconnected commands,
                                                   maintained by NCR */
     /* Data identifying nexus we are trying to match during reselection */
@@ -1269,14 +1290,14 @@ struct NCR53c7x0_hostdata {
                                                   message or 0 */
     /* These were static variables before we moved them */
 
-    long NCR53c7xx_zero;
-    long NCR53c7xx_sink;
+    s32 NCR53c7xx_zero;
+    s32 NCR53c7xx_sink;
     char NCR53c7xx_msg_reject;
     char NCR53c7xx_msg_abort;
     char NCR53c7xx_msg_nop;
 
-    int script_count;                          /* Size of script in longs */
-    unsigned long script[0];                   /* Relocated SCSI script */
+    int script_count;                          /* Size of script in words */
+    u32 script[0];                             /* Relocated SCSI script */
 
 };
 
@@ -1293,62 +1314,59 @@ struct NCR53c7x0_hostdata {
 
 #define NCR53c7x0_local_declare()                                      \
     volatile unsigned char *NCR53c7x0_address_memory;                  \
-    unsigned short NCR53c7x0_address_io;                               \
+    unsigned int NCR53c7x0_address_io;                                 \
     int NCR53c7x0_memory_mapped
 
 #define NCR53c7x0_local_setup(host)                                    \
     NCR53c7x0_address_memory = (void *) (host)->base;                  \
-    NCR53c7x0_address_io = (unsigned short) (host)->io_port;           \
+    NCR53c7x0_address_io = (unsigned int) (host)->io_port;             \
     NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *)           \
        host->hostdata)-> options & OPTION_MEMORY_MAPPED 
 
 #define NCR53c7x0_read8(address)                                       \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *( (NCR53c7x0_address_memory) + (address))  :                   \
+       ncr_readb(NCR53c7x0_address_memory + (address))  :              \
        inb(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_read16(address)                                      \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *((unsigned short *) (NCR53c7x0_address_memory) + (address))  : \
+       ncr_readw(NCR53c7x0_address_memory + (address))  :              \
        inw(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_read32(address)                                      \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *((unsigned long *) (NCR53c7x0_address_memory) + (address))  :  \
+       ncr_readl(NCR53c7x0_address_memory + (address))  :              \
        inl(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write8(address,value)                                \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *((unsigned char *) (NCR53c7x0_address_memory) + (address)) =   \
-         (value) :                                                     \
+       ncr_writeb((value), NCR53c7x0_address_memory + (address)) :     \
        outb((value), NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write16(address,value)                               \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *((unsigned short *) (NCR53c7x0_address_memory) + (address)) =  \
-         (value) :                                                     \
+       ncr_writew((value), NCR53c7x0_address_memory + (address)) :     \
        outw((value), NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write32(address,value)                               \
     (NCR53c7x0_memory_mapped ?                                                 \
-       *((unsigned long *) (NCR53c7x0_address_memory) + (address)) =   \
-         (value) :                                                     \
+       ncr_writel((value), NCR53c7x0_address_memory + (address)) :     \
        outl((value), NCR53c7x0_address_io + (address)))
 
 #define patch_abs_32(script, offset, symbol, value)                    \
        for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof            \
-           (unsigned long)); ++i) {                                    \
+           (u32)); ++i) {                                              \
            (script)[A_##symbol##_used[i] - (offset)] += (value);       \
            if (hostdata->options & OPTION_DEBUG_FIXUP)                 \
-             printk("scsi%d : %s reference %d at 0x%lx in %s is now 0x%lx\n",\
+             printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
                host->host_no, #symbol, i, A_##symbol##_used[i] -       \
-               (offset), #script, (script)[A_##symbol##_used[i] -      \
+               (int)(offset), #script, (script)[A_##symbol##_used[i] - \
                (offset)]);                                             \
        }
 
 #define patch_abs_rwri_data(script, offset, symbol, value)             \
        for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof            \
-           (unsigned long)); ++i)                                      \
+           (u32)); ++i)                                                \
            (script)[A_##symbol##_used[i] - (offset)] =                 \
                ((script)[A_##symbol##_used[i] - (offset)] &            \
                ~DBC_RWRI_IMMEDIATE_MASK) |                             \
@@ -1357,12 +1375,12 @@ struct NCR53c7x0_hostdata {
 
 #define patch_dsa_32(dsa, symbol, word, value)                         \
        {                                                               \
-       (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(long) \
-               + (word)] = (unsigned long) (value);                    \
+       (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32)  \
+               + (word)] = (value);                                    \
        if (hostdata->options & OPTION_DEBUG_DSA)                       \
-           printk("scsi : dsa %s symbol %s(%ld) word %d now 0x%lx\n",  \
-               #dsa, #symbol, (long) hostdata->##symbol,               \
-               (int) (word), (long) (value));                                  \
+           printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",    \
+               #dsa, #symbol, hostdata->##symbol,                      \
+               (word), (u32)(value));                          \
        }
     
 
index 52ab39b116c561e11d5b8fc6784bf836436de246..e6e233fcfefbfe717c96b4aad4bc2f6411d4c029 100644 (file)
@@ -115,7 +115,7 @@ wrong_dsa:
        JUMP reselected_check_next
 
 ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines weather or not the current target and
+; dsa_check_reselect determines whether or not the current target and
 ; lun match the current DSA
 ENTRY dsa_code_check_reselect
 dsa_code_check_reselect:
@@ -402,7 +402,7 @@ select_msgout:
 issue_remove:
 ;      The actual UPDATE of the issue_dsa_head variable is 
 ;      atomic, with all of the setup code being irrelevant to
-;      weather the updated value being the old or new contents of 
+;      whether the updated value being the old or new contents of 
 ;      dsa_next field.
 ;
 ;      To insure synchronization, the host system merely needs to 
index e74804f6edd84e9dd615ac3c232477dee46c61ce..e0739d20c004a36d9b2395d479ba45ff345b1d87 100644 (file)
@@ -1,4 +1,4 @@
-unsigned long SCRIPT[] = {
+u32 SCRIPT[] = {
 /*
 ; NCR 53c810 driver, main script
 ; Sponsored by 
@@ -135,7 +135,7 @@ at 0x0000000c : */  0x80080000,0x000005ac,
 /*
 
 ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines weather or not the current target and
+; dsa_check_reselect determines whether or not the current target and
 ; lun match the current DSA
 ENTRY dsa_code_check_reselect
 dsa_code_check_reselect:
@@ -578,7 +578,7 @@ at 0x0000007c : */  0x78380000,0x00000000,
 issue_remove:
 ;      The actual UPDATE of the issue_dsa_head variable is 
 ;      atomic, with all of the setup code being irrelevant to
-;      weather the updated value being the old or new contents of 
+;      whether the updated value being the old or new contents of 
 ;      dsa_next field.
 ;
 ;      To insure synchronization, the host system merely needs to 
@@ -1816,31 +1816,31 @@ at 0x0000021c : */      0x90080000,0x00000000,
 };
 
 #define A_NCR53c7xx_msg_abort  0x00000000
-unsigned long A_NCR53c7xx_msg_abort_used[] = {
+u32 A_NCR53c7xx_msg_abort_used[] = {
        0x000001f5,
 };
 
 #define A_NCR53c7xx_msg_reject 0x00000000
-unsigned long A_NCR53c7xx_msg_reject_used[] = {
+u32 A_NCR53c7xx_msg_reject_used[] = {
        0x00000133,
 };
 
 #define A_NCR53c7xx_sink       0x00000000
-unsigned long A_NCR53c7xx_sink_used[] = {
+u32 A_NCR53c7xx_sink_used[] = {
        0x000001e5,
        0x000001e9,
        0x000001ed,
 };
 
 #define A_NCR53c7xx_zero       0x00000000
-unsigned long A_NCR53c7xx_zero_used[] = {
+u32 A_NCR53c7xx_zero_used[] = {
        0x0000015d,
        0x000001e1,
        0x000001f1,
 };
 
 #define A_addr_scratch 0x00000000
-unsigned long A_addr_scratch_used[] = {
+u32 A_addr_scratch_used[] = {
        0x00000007,
        0x0000003a,
        0x00000046,
@@ -1854,17 +1854,17 @@ unsigned long A_addr_scratch_used[] = {
 };
 
 #define A_addr_sfbr    0x00000000
-unsigned long A_addr_sfbr_used[] = {
+u32 A_addr_sfbr_used[] = {
        0x00000016,
 };
 
 #define A_addr_temp    0x00000000
-unsigned long A_addr_temp_used[] = {
+u32 A_addr_temp_used[] = {
        0x00000027,
 };
 
 #define A_dmode_memory_to_memory       0x00000000
-unsigned long A_dmode_memory_to_memory_used[] = {
+u32 A_dmode_memory_to_memory_used[] = {
        0x00000008,
        0x00000019,
        0x00000029,
@@ -1880,7 +1880,7 @@ unsigned long A_dmode_memory_to_memory_used[] = {
 };
 
 #define A_dmode_memory_to_ncr  0x00000000
-unsigned long A_dmode_memory_to_ncr_used[] = {
+u32 A_dmode_memory_to_ncr_used[] = {
        0x00000003,
        0x00000012,
        0x0000004c,
@@ -1888,7 +1888,7 @@ unsigned long A_dmode_memory_to_ncr_used[] = {
 };
 
 #define A_dmode_ncr_to_memory  0x00000000
-unsigned long A_dmode_ncr_to_memory_used[] = {
+u32 A_dmode_ncr_to_memory_used[] = {
        0x00000024,
        0x00000037,
        0x00000043,
@@ -1900,140 +1900,140 @@ unsigned long A_dmode_ncr_to_memory_used[] = {
 };
 
 #define A_dmode_ncr_to_ncr     0x00000000
-unsigned long A_dmode_ncr_to_ncr_used[] = {
+u32 A_dmode_ncr_to_ncr_used[] = {
 };
 
 #define A_dsa_check_reselect   0x00000000
-unsigned long A_dsa_check_reselect_used[] = {
+u32 A_dsa_check_reselect_used[] = {
        0x0000017f,
 };
 
 #define A_dsa_cmdout   0x00000048
-unsigned long A_dsa_cmdout_used[] = {
+u32 A_dsa_cmdout_used[] = {
        0x0000008c,
 };
 
 #define A_dsa_cmnd     0x00000038
-unsigned long A_dsa_cmnd_used[] = {
+u32 A_dsa_cmnd_used[] = {
 };
 
 #define A_dsa_datain   0x00000054
-unsigned long A_dsa_datain_used[] = {
+u32 A_dsa_datain_used[] = {
        0x000000b3,
 };
 
 #define A_dsa_dataout  0x00000050
-unsigned long A_dsa_dataout_used[] = {
+u32 A_dsa_dataout_used[] = {
        0x0000009d,
 };
 
 #define A_dsa_end      0x00000070
-unsigned long A_dsa_end_used[] = {
+u32 A_dsa_end_used[] = {
 };
 
 #define A_dsa_fields_start     0x00000024
-unsigned long A_dsa_fields_start_used[] = {
+u32 A_dsa_fields_start_used[] = {
 };
 
 #define A_dsa_msgin    0x00000058
-unsigned long A_dsa_msgin_used[] = {
+u32 A_dsa_msgin_used[] = {
        0x00000147,
 };
 
 #define A_dsa_msgout   0x00000040
-unsigned long A_dsa_msgout_used[] = {
+u32 A_dsa_msgout_used[] = {
        0x0000006c,
 };
 
 #define A_dsa_msgout_other     0x00000068
-unsigned long A_dsa_msgout_other_used[] = {
+u32 A_dsa_msgout_other_used[] = {
        0x0000013f,
 };
 
 #define A_dsa_next     0x00000030
-unsigned long A_dsa_next_used[] = {
+u32 A_dsa_next_used[] = {
        0x0000002f,
        0x0000006f,
 };
 
 #define A_dsa_select   0x0000003c
-unsigned long A_dsa_select_used[] = {
+u32 A_dsa_select_used[] = {
        0x00000067,
 };
 
 #define A_dsa_status   0x00000060
-unsigned long A_dsa_status_used[] = {
+u32 A_dsa_status_used[] = {
        0x00000143,
 };
 
 #define A_dsa_temp_dsa_next    0x00000000
-unsigned long A_dsa_temp_dsa_next_used[] = {
+u32 A_dsa_temp_dsa_next_used[] = {
        0x00000001,
        0x00000006,
        0x0000001c,
 };
 
 #define A_dsa_temp_jump_resume 0x00000000
-unsigned long A_dsa_temp_jump_resume_used[] = {
+u32 A_dsa_temp_jump_resume_used[] = {
        0x00000028,
 };
 
 #define A_dsa_temp_lun 0x00000000
-unsigned long A_dsa_temp_lun_used[] = {
+u32 A_dsa_temp_lun_used[] = {
        0x00000017,
 };
 
 #define A_dsa_temp_sync        0x00000000
-unsigned long A_dsa_temp_sync_used[] = {
+u32 A_dsa_temp_sync_used[] = {
        0x00000021,
 };
 
 #define A_dsa_temp_target      0x00000000
-unsigned long A_dsa_temp_target_used[] = {
+u32 A_dsa_temp_target_used[] = {
        0x00000010,
 };
 
 #define A_int_debug_break      0x03000000
-unsigned long A_int_debug_break_used[] = {
+u32 A_int_debug_break_used[] = {
        0x000001d3,
 };
 
 #define A_int_debug_dsa_loaded 0x03030000
-unsigned long A_int_debug_dsa_loaded_used[] = {
+u32 A_int_debug_dsa_loaded_used[] = {
 };
 
 #define A_int_debug_head       0x03050000
-unsigned long A_int_debug_head_used[] = {
+u32 A_int_debug_head_used[] = {
 };
 
 #define A_int_debug_idle       0x03020000
-unsigned long A_int_debug_idle_used[] = {
+u32 A_int_debug_idle_used[] = {
 };
 
 #define A_int_debug_reselected 0x03040000
-unsigned long A_int_debug_reselected_used[] = {
+u32 A_int_debug_reselected_used[] = {
 };
 
 #define A_int_debug_scheduled  0x03010000
-unsigned long A_int_debug_scheduled_used[] = {
+u32 A_int_debug_scheduled_used[] = {
 };
 
 #define A_int_err_check_condition      0x00030000
-unsigned long A_int_err_check_condition_used[] = {
+u32 A_int_err_check_condition_used[] = {
        0x00000157,
 };
 
 #define A_int_err_no_phase     0x00040000
-unsigned long A_int_err_no_phase_used[] = {
+u32 A_int_err_no_phase_used[] = {
 };
 
 #define A_int_err_selected     0x00010000
-unsigned long A_int_err_selected_used[] = {
+u32 A_int_err_selected_used[] = {
        0x0000019e,
 };
 
 #define A_int_err_unexpected_phase     0x00000000
-unsigned long A_int_err_unexpected_phase_used[] = {
+u32 A_int_err_unexpected_phase_used[] = {
        0x00000084,
        0x0000008a,
        0x0000008e,
@@ -2046,73 +2046,73 @@ unsigned long A_int_err_unexpected_phase_used[] = {
 };
 
 #define A_int_err_unexpected_reselect  0x00020000
-unsigned long A_int_err_unexpected_reselect_used[] = {
+u32 A_int_err_unexpected_reselect_used[] = {
        0x0000017c,
 };
 
 #define A_int_msg_1    0x01020000
-unsigned long A_int_msg_1_used[] = {
+u32 A_int_msg_1_used[] = {
        0x000000e2,
        0x000000e4,
 };
 
 #define A_int_msg_sdtr 0x01010000
-unsigned long A_int_msg_sdtr_used[] = {
+u32 A_int_msg_sdtr_used[] = {
        0x0000012d,
 };
 
 #define A_int_msg_wdtr 0x01000000
-unsigned long A_int_msg_wdtr_used[] = {
+u32 A_int_msg_wdtr_used[] = {
        0x00000121,
 };
 
 #define A_int_norm_aborted     0x02040000
-unsigned long A_int_norm_aborted_used[] = {
+u32 A_int_norm_aborted_used[] = {
        0x000001f9,
 };
 
 #define A_int_norm_command_complete    0x02020000
-unsigned long A_int_norm_command_complete_used[] = {
+u32 A_int_norm_command_complete_used[] = {
 };
 
 #define A_int_norm_disconnected        0x02030000
-unsigned long A_int_norm_disconnected_used[] = {
+u32 A_int_norm_disconnected_used[] = {
 };
 
 #define A_int_norm_reselect_complete   0x02010000
-unsigned long A_int_norm_reselect_complete_used[] = {
+u32 A_int_norm_reselect_complete_used[] = {
 };
 
 #define A_int_norm_reset       0x02050000
-unsigned long A_int_norm_reset_used[] = {
+u32 A_int_norm_reset_used[] = {
 };
 
 #define A_int_norm_select_complete     0x02000000
-unsigned long A_int_norm_select_complete_used[] = {
+u32 A_int_norm_select_complete_used[] = {
 };
 
 #define A_int_test_1   0x04000000
-unsigned long A_int_test_1_used[] = {
+u32 A_int_test_1_used[] = {
        0x000001b9,
 };
 
 #define A_int_test_2   0x04010000
-unsigned long A_int_test_2_used[] = {
+u32 A_int_test_2_used[] = {
        0x000001d1,
 };
 
 #define A_int_test_3   0x04020000
-unsigned long A_int_test_3_used[] = {
+u32 A_int_test_3_used[] = {
 };
 
 #define A_issue_dsa_head       0x00000000
-unsigned long A_issue_dsa_head_used[] = {
+u32 A_issue_dsa_head_used[] = {
        0x0000004f,
        0x00000080,
 };
 
 #define A_msg_buf      0x00000000
-unsigned long A_msg_buf_used[] = {
+u32 A_msg_buf_used[] = {
        0x000000d6,
        0x0000010f,
        0x00000119,
@@ -2122,7 +2122,7 @@ unsigned long A_msg_buf_used[] = {
 };
 
 #define A_reconnect_dsa_head   0x00000000
-unsigned long A_reconnect_dsa_head_used[] = {
+u32 A_reconnect_dsa_head_used[] = {
        0x0000003f,
        0x00000047,
        0x00000162,
@@ -2130,23 +2130,23 @@ unsigned long A_reconnect_dsa_head_used[] = {
 };
 
 #define A_reselected_identify  0x00000000
-unsigned long A_reselected_identify_used[] = {
+u32 A_reselected_identify_used[] = {
        0x00000015,
        0x0000015b,
 };
 
 #define A_reselected_tag       0x00000000
-unsigned long A_reselected_tag_used[] = {
+u32 A_reselected_tag_used[] = {
        0x0000015e,
 };
 
 #define A_test_dest    0x00000000
-unsigned long A_test_dest_used[] = {
+u32 A_test_dest_used[] = {
        0x000001b7,
 };
 
 #define A_test_src     0x00000000
-unsigned long A_test_src_used[] = {
+u32 A_test_src_used[] = {
        0x000001b6,
 };
 
@@ -2174,7 +2174,7 @@ unsigned long A_test_src_used[] = {
 #define Ent_test_1     0x000006d4
 #define Ent_test_2     0x000006e8
 #define Ent_test_2_msgout      0x00000700
-unsigned long LABELPATCHES[] = {
+u32 LABELPATCHES[] = {
        0x00000002,
        0x0000000b,
        0x0000000d,
@@ -2249,5 +2249,12 @@ unsigned long LABELPATCHES[] = {
        0x000001ef,
 };
 
-unsigned long INSTRUCTIONS     = 0x00000104;
-unsigned long PATCHES  = 0x00000048;
+struct {
+       u32     offset;
+       void            *address;
+} EXTERNAL_PATCHES[] = {
+};
+
+u32 INSTRUCTIONS       = 260;
+u32 PATCHES    = 72;
+u32 EXTERNAL_PATCHES_LEN       = 0;
index 860ac40dcceebb4982e334e98f4c30ebb3004113..c843fb721562f46ea437ffba49ff759980baa65e 100644 (file)
@@ -76,9 +76,9 @@ SCSI_OBJS := $(SCSI_OBJS) aha1740.o
 SCSI_SRCS := $(SCSI_SRCS) aha1740.c
 endif
 
-ifdef CONFIG_SCSI_AHA274X
-SCSI_OBJS := $(SCSI_OBJS) aha274x.o
-SCSI_SRCS := $(SCSI_SRCS) aha274x.c
+ifdef CONFIG_SCSI_AIC7XXX
+SCSI_OBJS := $(SCSI_OBJS) aic7xxx.o
+SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
 endif
 
 ifdef CONFIG_SCSI_BUSLOGIC
@@ -180,8 +180,8 @@ aha152x.o: aha152x.c
 aic7770:       aic7770.c
                $(CC) $(CFLAGS) -o $@ aic7770.c
 
-aha274x_seq.h: aic7770 aha274x.seq
-               ./aic7770 -o $@ aha274x.seq
+aic7xxx_seq.h: aic7770 aic7xxx.seq
+               ./aic7770 -o $@ aic7xxx.seq
 
 seagate.o: seagate.c
        $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c 
diff --git a/drivers/scsi/README-FIRST.aic7xxx b/drivers/scsi/README-FIRST.aic7xxx
new file mode 100644 (file)
index 0000000..efd0bbd
--- /dev/null
@@ -0,0 +1,17 @@
+The 274x/284x support is basically the same as in the kernel, with
+some minor structural changes.  The 294x support is preliminary, with
+a few things still hardwired (like the SCSI ID and FIFO threshold).
+You have been warned.
+
+To function properly, you must use this with a kernel version 1.1.68
+or above - these have the SCSI changes in the kernel which support
+varying numbers of outstanding SCSI commands per driver instance (they
+also contain the Adaptec PCI definitions).
+
+You can find instructions in the SCSI-HOWTO on how to install SCSI
+drivers into the kernel.  In a nutshell, find all the aha274x stuff
+and change it to aic7xxx.
+
+Please direct all problems to the AIC7770 mailing list - see the README
+for details.
+:ja
diff --git a/drivers/scsi/README.aha274x b/drivers/scsi/README.aha274x
deleted file mode 100644 (file)
index a6cb8c5..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-@(#)README 1.15 94/10/29 jda
-
-AHA274x/284x DRIVER
-
-***  THIS SHOULD BE CONSIDERED BETA SOFTWARE  ***
-
-BACKGROUND & LIMITATIONS
-
-For various reasons, we ended up with one of these cards under the
-impression that support was soon forthcoming.  In mid-May, I asked
-Scott Ferris (the official person who's supposed to be writing this
-driver) what documentation he used, _finally_ got it from Adaptec,
-and started writing this driver.  It is now at what I would consider
-a stable state - it runs our news server and is battered by SCSI
-requests 24 hours a day without dying.  There are a few devices it
-reportedly doesn't like working with - those are being sorted out.  Due
-to some unexpected equipment loans, I am able to support this at least
-for the time being.
-
-YOU MUST HAVE THE BIOS ENABLED OR THIS WILL NOT WORK.  The BIOS extracts
-some configuration information that I cannot get to portably yet, as
-well as provides some self-tests which this driver does not attempt to
-duplicate.
-
-Scott's driver development is stalled for now, and after discussions
-with him, this is now officially out of "pre-alpha" status and into
-beta until the remaining device problems can be resolved.  The latest
-patches can be obtained via anonymous ftp from ftp.cpsc.ucalgary.ca in
-/pub/systems/linux/aha274x.
-
-It supports both EISA 274x and VL-bus 284x, either single or twin-bus cards
-(but not the second SCSI bus of twin cards - see aha274x.c), and supports
-disconnection, synchronous SCSI, and scatter-gather.  Unlike previous
-versions, abort() and reset() are now implemented, and both hosts.c and
-aha274x.c should give a clean compile.  Code is now present to detect parity
-errors, but has not been tested.
-
-I wrote this using a 1.0.9 kernel.  Unfortunately, I'm getting tired of
-#ifdef'ing everything to handle two or three different evolutionary steps
-in the SCSI kernel code, so I've upgraded my system to 1.1.49, and will
-only leave in code to support versions from about 1.1.45 onward.
-
-Thanks to patches supplied by Mark Olson <molson@tricord.com>, this driver
-will now work with the 284x series (the VL-bus version of this card).  The
-294x (PCI-bus) is being worked on, and initial support for it will be ready
-soon.
-
-Under protest, this driver is subject to the GPL - see the file
-COPYING for details.
-
-Thanks to the following people for bug fixes/code improvements (also
-thanks to the people who have sent me feedback):
-
-       "David F. Carlson" <dave@ee.rochester.edu>
-       Jimen Ching <jiching@wiliki.eng.hawaii.edu>
-       mday@artisoft.com (Matt Day)
-       "Dean W. Gehnert" <deang@ims.com>
-       Darcy Grant <darcy@cpsc.ucalgary.ca>
-       Alan Hourihane <alanh@fairlite.demon.co.uk>
-       isely@fncrd8.fnal.gov (Mike Isely)
-       Mike Jerger <jerger@ux1.cso.uiuc.edu>
-       tm@netcom.com (Toshiyasu Morita)
-       neal@interact.org (Neal Norwitz)
-       Mark Olson <molson@tricord.com>
-       map@europa.ecn.uoknor.edu (Michael A. Parker)
-       Thomas Scheunemann <thomas@dagobert.uni-duisburg.de>
-
-Special thanks to Drew Eckhardt <drew@kinglear.cs.Colorado.EDU> for
-fielding my questions about synchronous negotiation.  Steffen Moeller
-<smoe0024@rz.uni-hildesheim.de> sent me installation instructions which
-were previously included in this README.
-
-David Pirie <pirie@cpsc.ucalgary.ca> was nice enough to loan me his
-2842 card for a week so I could track down one bug, as well as his
-CD-ROM drive later, and also thanks to Doug Fortune at Riley's Data Share
-in Calgary, who arranged a long-term loan of a 2842 board for further work.
-
-Many thanks to the fearless prerelease testers!  Dean Gehnert has been
-building Slackware boot disks for the driver, which are available from
-ftp.cpsc.ucalgary.ca in /pub/systems/linux/aha274x/slackware_boot.
-
-Carl Riches <cgr@poplar1.cfr.washington.edu> has set up a mailing list
-for aic7xxx driver development.  To subscribe, send a message to
-aic7770-list@poplar1.cfr.washington.edu with a message body of:
-
-    subscribe AIC7770-LIST <your name here, without the angle brackets>
-
-Please direct questions and discussions to that list instead of me.  When
-sending bug reports, please include a description of your hardware, the
-release numbers displayed by the driver at boot time, and as accurate a
-facsimile of any error message you're mailing about.
-
-John Aycock
-aycock@cpsc.ucalgary.ca
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
new file mode 100644 (file)
index 0000000..2f52b8b
--- /dev/null
@@ -0,0 +1,95 @@
+@(#)README 1.19 94/11/30 jda
+
+AHA274x/284x/294x DRIVER
+
+***  THIS SHOULD BE CONSIDERED BETA SOFTWARE  ***
+
+BACKGROUND & LIMITATIONS
+
+For various reasons, we ended up with one of these cards under the
+impression that support was soon forthcoming.  In mid-May, I asked
+Scott Ferris (the official person who's supposed to be writing this
+driver) what documentation he used, _finally_ got it from Adaptec,
+and started writing this driver.  It is now at what I would consider
+a stable state - it runs our news server and is battered by SCSI
+requests 24 hours a day without dying.  There are a few devices it
+reportedly doesn't like working with - those are being sorted out.  Due
+to some unexpected equipment loans, I am able to support this at least
+for the time being.
+
+YOU MUST HAVE THE BIOS ENABLED OR THIS WILL NOT WORK.  The BIOS extracts
+some configuration information that I cannot get to portably yet, as
+well as provides some self-tests which this driver does not attempt to
+duplicate.
+
+Scott's driver development is stalled for now, and after discussions
+with him, this is now officially out of "pre-alpha" status and into
+beta until the remaining device problems can be resolved.  The latest
+patches can be obtained via anonymous ftp from ftp.cpsc.ucalgary.ca in
+/pub/systems/linux/aha274x.
+
+It supports EISA 274x, VL-bus 284x, and PCI 294x, either single or twin-bus
+cards (but not the second SCSI bus of twin cards - see aha274x.c), and supports
+disconnection, synchronous SCSI, and scatter-gather.  Unlike previous
+versions, abort() and reset() are now implemented, and both hosts.c and
+aha274x.c should give a clean compile.  Code is now present to detect parity
+errors, but has not been tested.  Wide cards are not yet supported.
+
+I wrote this using a 1.0.9 kernel.  Unfortunately, I'm getting tired of
+#ifdef'ing everything to handle two or three different evolutionary steps
+in the SCSI kernel code, so I've upgraded my system to 1.1.49, and will
+only leave in code to support versions from about 1.1.45 onward.
+
+Thanks to patches supplied by Mark Olson <molson@tricord.com>, this driver
+will now work with the 284x series (the VL-bus version of this card).  The
+294x (PCI-bus) support is based on patches sent to me by Mark Olson and
+Alan Hourihane <alanh@fairlite.demon.co.uk>.
+
+Under protest, this driver is subject to the GPL - see the file
+COPYING for details.
+
+Thanks to the following people for bug fixes/code improvements (also
+thanks to the people who have sent me feedback):
+
+       "David F. Carlson" <dave@ee.rochester.edu>
+       Jimen Ching <jiching@wiliki.eng.hawaii.edu>
+       mday@artisoft.com (Matt Day)
+       "Dean W. Gehnert" <deang@ims.com>
+       Darcy Grant <darcy@cpsc.ucalgary.ca>
+       Alan Hourihane <alanh@fairlite.demon.co.uk>
+       isely@fncrd8.fnal.gov (Mike Isely)
+       Mike Jerger <jerger@ux1.cso.uiuc.edu>
+       tm@netcom.com (Toshiyasu Morita)
+       neal@interact.org (Neal Norwitz)
+       Mark Olson <molson@tricord.com>
+       map@europa.ecn.uoknor.edu (Michael A. Parker)
+       Thomas Scheunemann <thomas@dagobert.uni-duisburg.de>
+       Eric Youngdale <eric@aib.com>
+
+Special thanks to Drew Eckhardt <drew@kinglear.cs.Colorado.EDU> for
+fielding my questions about synchronous negotiation.  Steffen Moeller
+<smoe0024@rz.uni-hildesheim.de> sent me installation instructions which
+were previously included in this README.
+
+David Pirie <pirie@cpsc.ucalgary.ca> was nice enough to loan me his
+2842 card for a week so I could track down one bug, as well as his
+CD-ROM drive later, and also thanks to Doug Fortune at Riley's Data Share
+in Calgary, who arranged a long-term loan of a 2842 board for further work.
+
+Many thanks to the fearless prerelease testers!  Dean Gehnert has been
+building Slackware boot disks for the driver, which are available from
+ftp.cpsc.ucalgary.ca in /pub/systems/linux/aha274x/slackware_boot.
+
+Carl Riches <cgr@poplar1.cfr.washington.edu> has set up a mailing list
+for aic7xxx driver development.  To subscribe, send a message to
+aic7770-list-request@poplar1.cfr.washington.edu with a message body of:
+
+    subscribe AIC7770-LIST <your name here, without the angle brackets>
+
+Please direct questions and discussions to that list instead of me.  When
+sending bug reports, please include a description of your hardware, the
+release numbers displayed by the driver at boot time, and as accurate a
+facsimile of any error message you're mailing about.
+
+John Aycock
+aycock@cpsc.ucalgary.ca
diff --git a/drivers/scsi/aha274x.c b/drivers/scsi/aha274x.c
deleted file mode 100644 (file)
index a2317a8..0000000
+++ /dev/null
@@ -1,1490 +0,0 @@
-/*
- *  @(#)aha274x.c 1.29 94/10/29 jda
- *
- *  Adaptec 274x device driver for Linux.
- *  Copyright (c) 1994 The University of Calgary Department of Computer Science.
- *  
- *  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.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Sources include the Adaptec 1740 driver (aha1740.c), the
- *  Ultrastor 24F driver (ultrastor.c), various Linux kernel
- *  source, the Adaptec EISA config file (!adp7771.cfg), the
- *  Adaptec AHA-2740A Series User's Guide, the Linux Kernel
- *  Hacker's Guide, Writing a SCSI Device Driver for Linux,
- *  the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
- *  overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
- *  Technical Reference Manual, the Adaptec AIC-7770 Data
- *  Book, the ANSI SCSI specification, the ANSI SCSI-2
- *  specification (draft 10c), ...
- *
- *  On a twin-bus adapter card, channel B is ignored.  Rationale:
- *  it would greatly complicate the sequencer and host driver code,
- *  and both busses are multiplexed on to the EISA bus anyway.  So
- *  I don't really see any technical advantage to supporting both.
- *
- *  As well, multiple adapter card using the same IRQ level are
- *  not supported.  It doesn't make sense to configure the cards
- *  this way from a performance standpoint.  Not to mention that
- *  the kernel would have to support two devices per registered IRQ.
- */
-
-#include <stdarg.h>
-#include <asm/io.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
-#include "../block/blk.h"
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "aha274x.h"
-
-/*
- *  There should be a specific return value for this in scsi.h, but
- *  it seems that most drivers ignore it.
- */
-#define DID_UNDERFLOW  DID_ERROR
-
-/* EISA stuff */
-
-#define MINEISA                1
-#define MAXEISA                15
-#define SLOTBASE(x)    ((x) << 12)
-
-#define MAXIRQ         15
-
-/* AIC-7770 offset definitions */
-
-#define O_MINREG(x)    ((x) + 0xc00)           /* i/o range to reserve */
-#define O_MAXREG(x)    ((x) + 0xcbf)
-
-#define O_SCSISEQ(x)   ((x) + 0xc00)           /* scsi sequence control */
-#define O_SCSISIGI(x)  ((x) + 0xc03)           /* scsi control signal read */
-#define O_SCSISIGO(x)  ((x) + 0xc03)           /* scsi control signal write */
-#define O_SCSIID(x)    ((x) + 0xc05)           /* scsi id */
-#define O_SSTAT0(x)    ((x) + 0xc0b)           /* scsi status register 0 */
-#define O_CLRSINT1(x)  ((x) + 0xc0c)           /* clear scsi interrupt 1 */
-#define O_SSTAT1(x)    ((x) + 0xc0c)           /* scsi status register 1 */
-#define O_SELID(x)     ((x) + 0xc19)           /* [re]selection id */
-#define O_SBLKCTL(x)   ((x) + 0xc1f)           /* scsi block control */
-#define O_SEQCTL(x)    ((x) + 0xc60)           /* sequencer control */
-#define O_SEQRAM(x)    ((x) + 0xc61)           /* sequencer ram data */
-#define O_SEQADDR(x)   ((x) + 0xc62)           /* sequencer address (W) */
-#define O_BIDx(x)      ((x) + 0xc80)           /* board id */
-#define O_BCTL(x)      ((x) + 0xc84)           /* board control */
-#define O_HCNTRL(x)    ((x) + 0xc87)           /* host control */
-#define O_SCBPTR(x)    ((x) + 0xc90)           /* scb pointer */
-#define O_INTSTAT(x)   ((x) + 0xc91)           /* interrupt status */
-#define O_ERROR(x)     ((x) + 0xc92)           /* hard error */
-#define O_CLRINT(x)    ((x) + 0xc92)           /* clear interrupt status */
-#define O_SCBCNT(x)    ((x) + 0xc9a)           /* scb auto increment */
-#define O_QINFIFO(x)   ((x) + 0xc9b)           /* queue in fifo */
-#define O_QINCNT(x)    ((x) + 0xc9c)           /* queue in count */
-#define O_QOUTFIFO(x)  ((x) + 0xc9d)           /* queue out fifo */
-#define O_QOUTCNT(x)   ((x) + 0xc9e)           /* queue out count */
-#define O_SCBARRAY(x)  ((x) + 0xca0)           /* scb array start */
-
-/* host adapter offset definitions */
-
-#define HA_REJBYTE(x)  ((x) + 0xc31)           /* 1st message in byte */
-#define HA_MSG_FLAGS(x)        ((x) + 0xc35)           /* outgoing message flag */
-#define HA_MSG_LEN(x)  ((x) + 0xc36)           /* outgoing message length */
-#define HA_MSG_START(x)        ((x) + 0xc37)           /* outgoing message body */
-#define HA_ARG_1(x)    ((x) + 0xc4c)           /* sdtr <-> rate parameters */
-#define HA_ARG_2(x)    ((x) + 0xc4d)
-#define HA_RETURN_1(x) ((x) + 0xc4c)
-#define HA_RETURN_2(x) ((x) + 0xc4d)
-#define HA_SIGSTATE(x) ((x) + 0xc4e)           /* value in SCSISIGO */
-#define HA_NEEDSDTR(x) ((x) + 0xc4f)           /* synchronous negotiation? */
-
-#define HA_SCSICONF(x) ((x) + 0xc5a)           /* SCSI config register */
-#define HA_INTDEF(x)   ((x) + 0xc5c)           /* interrupt def'n register */
-#define HA_HOSTCONF(x) ((x) + 0xc5d)           /* host config def'n register */
-
-/* debugging code */
-
-#define AHA274X_DEBUG
-
-/*
- *  If a parity error occurs during a data transfer phase, run the
- *  command to completion - it's easier that way - making a note
- *  of the error condition in this location.  This then will modify
- *  a DID_OK status into a DID_PARITY one for the higher-level SCSI
- *  code.
- */
-#define aha274x_parity(cmd)    ((cmd)->SCp.Status)
-
-/*
- *  Since the sequencer code DMAs the scatter-gather structures
- *  directly from memory, we use this macro to assert that the
- *  kernel structure hasn't changed.
- */
-#define SG_STRUCT_CHECK(sg) \
-       ((char *)&(sg).address - (char *)&(sg) != 0 ||  \
-        (char *)&(sg).length  - (char *)&(sg) != 8 ||  \
-        sizeof((sg).address) != 4 ||                   \
-        sizeof((sg).length)  != 4 ||                   \
-        sizeof(sg)           != 12)
-
-/*
- *  "Static" structures.  Note that these are NOT initialized
- *  to zero inside the kernel - we have to initialize them all
- *  explicitly.
- *
- *  We support a maximum of one adapter card per IRQ level (see the
- *  rationale for this above).  On an interrupt, use the IRQ as an
- *  index into aha274x_boards[] to locate the card information.
- */
-static struct Scsi_Host *aha274x_boards[MAXIRQ + 1];
-
-struct aha274x_host {
-       int base;                                       /* card base address */
-       int startup;                                    /* intr type check */
-       volatile int unpause;                           /* value for HCNTRL */
-       volatile Scsi_Cmnd *SCB_array[AHA274X_MAXSCB];  /* active commands */
-};
-
-struct aha274x_scb {
-       unsigned char control;
-       unsigned char target_channel_lun;               /* 4/1/3 bits */
-       unsigned char SG_segment_count;
-       unsigned char SG_list_pointer[4];
-       unsigned char SCSI_cmd_pointer[4];
-       unsigned char SCSI_cmd_length;
-       unsigned char RESERVED[2];                      /* must be zero */
-       unsigned char target_status;
-       unsigned char residual_data_count[3];
-       unsigned char residual_SG_segment_count;
-       unsigned char data_pointer[4];
-       unsigned char data_count[3];
-#if 0
-       /*
-        *  No real point in transferring this to the
-        *  SCB registers.
-        */
-       unsigned char RESERVED[6];
-#endif
-};
-
-/*
- *  NB.  This table MUST be ordered shortest period first.
- */
-static struct {
-       short period;
-       short rate;
-       char *english;
-} aha274x_synctab[] = {
-       {100,   0,      "10.0"},
-       {125,   1,      "8.0"},
-       {150,   2,      "6.67"},
-       {175,   3,      "5.7"},
-       {200,   4,      "5.0"},
-       {225,   5,      "4.4"},
-       {250,   6,      "4.0"},
-       {275,   7,      "3.6"}
-};
-
-static int aha274x_synctab_max =
-       sizeof(aha274x_synctab) / sizeof(aha274x_synctab[0]);
-
-enum aha_type {
-       T_NONE,
-       T_274X,
-       T_284X,
-       T_MAX
-};
-
-#ifdef AHA274X_DEBUG
-
-       extern int vsprintf(char *, const char *, va_list);
-
-       static
-       void debug(const char *fmt, ...)
-       {
-               va_list ap;
-               char buf[256];
-
-               va_start(ap, fmt);
-                 vsprintf(buf, fmt, ap);
-                 printk(buf);
-               va_end(ap);
-       }
-
-       static
-       void debug_config(enum aha_type type, int base)
-       {
-               int ioport2, ioport3, ioport4;
-
-               static char *BRT[T_MAX][16] = {
-                       { },                                    /* T_NONE */
-                       {
-                               "2",   "???", "???", "12",      /* T_274X */
-                               "???", "???", "???", "28",
-                               "???", "???", "???", "44",
-                               "???", "???", "???", "60"
-                       },
-                       {
-                               "2",  "4",  "8",  "12",         /* T_284X */
-                               "16", "20", "24", "28",
-                               "32", "36", "40", "44",
-                               "48", "52", "56", "60"
-                       }
-               };
-               static int DFT[4] = {
-                       0, 50, 75, 100
-               };
-               static int SST[4] = {
-                       256, 128, 64, 32
-               };
-
-               ioport2 = inb(HA_HOSTCONF(base));
-               ioport3 = inb(HA_SCSICONF(base));
-               ioport4 = inb(HA_INTDEF(base));
-
-               if (type == T_284X)
-                       printk("AHA284X AT SLOT %d:\n", base >> 12);
-               else
-                       printk("AHA274X AT EISA SLOT %d:\n", base >> 12);
-
-               printk("    irq %d\n"
-                      "    bus release time %s bclks\n"
-                      "    data fifo threshold %d%%\n",
-                      ioport4 & 0xf,
-                      BRT[type][(ioport2 >> 2) & 0xf],
-                      DFT[(ioport2 >> 6) & 0x3]);
-
-               printk("    SCSI CHANNEL A:\n"
-                      "        scsi id %d\n"
-                      "        scsi bus parity check %sabled\n"
-                      "        scsi selection timeout %d ms\n"
-                      "        scsi bus reset at power-on %sabled\n",
-                      ioport3 & 0x7,
-                      (ioport3 & 0x20) ? "en" : "dis",
-                      SST[(ioport3 >> 3) & 0x3],
-                      (ioport3 & 0x40) ? "en" : "dis");
-
-               if (type == T_274X) {
-                       printk("        scsi bus termination %sabled\n",
-                              (ioport3 & 0x80) ? "en" : "dis");
-               }
-       }
-
-       static
-       void debug_rate(int base, int rate)
-       {
-               int target = inb(O_SCSIID(base)) >> 4;
-
-               if (rate) {
-                       printk("aha274x: target %d now synchronous at %sMb/s\n",
-                              target,
-                              aha274x_synctab[(rate >> 4) & 0x7].english);
-               } else {
-                       printk("aha274x: target %d using asynchronous mode\n",
-                              target);
-               }
-       }
-
-#else
-
-#      define debug(fmt, args...)
-#      define debug_config(x)
-#      define debug_rate(x,y)
-
-#endif AHA274X_DEBUG
-
-/*
- *  XXX - these options apply unilaterally to _all_ 274x/284x
- *       cards in the system.  This should be fixed, but then,
- *       does anyone really have more than one in a machine?
- */
-static int aha274x_extended = 0;               /* extended translation on? */
-
-void aha274x_setup(char *s, int *dummy)
-{
-       int i;
-       char *p;
-
-       static struct {
-               char *name;
-               int *flag;
-       } options[] = {
-               {"extended",    &aha274x_extended},
-               {NULL, NULL }
-       };
-
-       for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
-               for (i = 0; options[i].name; i++)
-                       if (!strcmp(options[i].name, p))
-                               *(options[i].flag) = !0;
-       }
-}
-
-static
-void aha274x_getscb(int base, struct aha274x_scb *scb)
-{
-       /*
-        *  This is almost identical to aha274x_putscb().
-        */
-       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
-
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "insb"
-                    : /* no output */
-                    :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-                    :"di", "cx", "dx");
-
-       outb(0, O_SCBCNT(base));
-}
-
-/*
- *  How much data should be transferred for this SCSI command?  Stop
- *  at segment sg_last if it's a scatter-gather command so we can
- *  compute underflow easily.
- */
-static
-unsigned aha274x_length(Scsi_Cmnd *cmd, int sg_last)
-{
-       int i, segments;
-       unsigned length;
-       struct scatterlist *sg;
-
-       segments = cmd->use_sg - sg_last;
-       sg = (struct scatterlist *)cmd->buffer;
-
-       if (cmd->use_sg) {
-               for (i = length = 0;
-                    i < cmd->use_sg && i < segments;
-                    i++)
-               {
-                       length += sg[i].length;
-               }
-       } else
-               length = cmd->request_bufflen;
-
-       return(length);
-}
-
-static
-void aha274x_sg_check(Scsi_Cmnd *cmd)
-{
-       int i;
-       struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
-
-       if (cmd->use_sg) {
-               for (i = 0; i < cmd->use_sg; i++)
-                       if ((unsigned)sg[i].length > 0xffff)
-                               panic("aha274x_sg_check: s/g segment > 64k\n");
-       }
-}
-
-static
-void aha274x_to_scsirate(unsigned char *rate,
-                        unsigned char transfer,
-                        unsigned char offset)
-{
-       int i;
-
-       transfer *= 4;
-
-       for (i = 0; i < aha274x_synctab_max-1; i++) {
-
-               if (transfer == aha274x_synctab[i].period) {
-                       *rate = (aha274x_synctab[i].rate << 4) | (offset & 0xf);
-                       return;
-               }
-
-               if (transfer > aha274x_synctab[i].period &&
-                   transfer < aha274x_synctab[i+1].period)
-               {
-                       *rate = (aha274x_synctab[i+1].rate << 4) |
-                               (offset & 0xf);
-                       return;
-               }
-       }
-       *rate = 0;
-}
-
-/*
- *  Pause the sequencer and wait for it to actually stop - this
- *  is important since the sequencer can disable pausing for critical
- *  sections.
- */
-#define PAUSE_SEQUENCER(p)     \
-       do {                                                            \
-               outb(0xe, O_HCNTRL(p->base));   /* IRQMS|PAUSE|INTEN */ \
-                                                                       \
-               while ((inb(O_HCNTRL(p->base)) & 0x4) == 0)             \
-                       ;                                               \
-       } while (0)
-
-/*
- *  Unpause the sequencer.  Unremarkable, yet done often enough to
- *  warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p)   \
-       outb(p->unpause, O_HCNTRL(p->base))     /* IRQMS|INTEN */
-
-/*
- *  See comments in aha274x_loadram() wrt this.
- */
-#define RESTART_SEQUENCER(p)   \
-       do {                                            \
-               do {                                    \
-                       outb(0x2, O_SEQCTL(p->base));   \
-               } while (inw(O_SEQADDR(p->base)) != 0); \
-                                                       \
-               UNPAUSE_SEQUENCER(p);                   \
-       } while (0)
-
-/*
- *  Since we declared this using SA_INTERRUPT, interrupts should
- *  be disabled all through this function unless we say otherwise.
- */
-static
-void aha274x_isr(int irq, struct pt_regs * regs)
-{
-       int base, intstat;
-       struct aha274x_host *p;
-       
-       p = (struct aha274x_host *)aha274x_boards[irq]->hostdata;
-       base = p->base;
-
-       /*
-        *  Check the startup flag - if no commands have been queued,
-        *  we probably have the interrupt type set wrong.  Reverse
-        *  the stored value and the active one in the host control
-        *  register.
-        */
-       if (p->startup) {
-               p->unpause ^= 0x8;
-               outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
-               return;
-       }
-
-       /*
-        *  Handle all the interrupt sources - especially for SCSI
-        *  interrupts, we won't get a second chance at them.
-        */
-       intstat = inb(O_INTSTAT(base));
-
-       if (intstat & 0x8) {                            /* BRKADRINT */
-
-               panic("aha274x_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
-                     inb(O_ERROR(base)), inw(O_SEQADDR(base)));
-       }
-
-       if (intstat & 0x4) {                            /* SCSIINT */
-
-               int scbptr = inb(O_SCBPTR(base));
-               int status = inb(O_SSTAT1(base));
-               Scsi_Cmnd *cmd;
-
-               cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
-               if (!cmd) {
-                       printk("aha274x_isr: no command for scb (scsiint)\n");
-                       /*
-                        *  Turn off the interrupt and set status
-                        *  to zero, so that it falls through the
-                        *  reset of the SCSIINT code.
-                        */
-                       outb(status, O_CLRSINT1(base));
-                       UNPAUSE_SEQUENCER(p);
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-                       status = 0;
-               }
-               p->SCB_array[scbptr] = NULL;
-
-               /*
-                *  Only the SCSI Status 1 register has information
-                *  about exceptional conditions that we'd have a
-                *  SCSIINT about; anything in SSTAT0 will be handled
-                *  by the sequencer.  Note that there can be multiple
-                *  bits set.
-                */
-               if (status & 0x80) {                    /* SELTO */
-                       /*
-                        *  Hardware selection timer has expired.  Turn
-                        *  off SCSI selection sequence.
-                        */
-                       outb(0, O_SCSISEQ(base));
-                       cmd->result = DID_TIME_OUT << 16;
-
-                       /*
-                        *  If there's an active message, it belongs to the
-                        *  command that is getting punted - remove it.
-                        */
-                       outb(0, HA_MSG_FLAGS(base));
-
-                       /*
-                        *  Shut off the offending interrupt sources, reset
-                        *  the sequencer address to zero and unpause it,
-                        *  then call the high-level SCSI completion routine.
-                        *
-                        *  WARNING!  This is a magic sequence!  After many
-                        *  hours of guesswork, turning off the SCSI interrupts
-                        *  in CLRSINT? does NOT clear the SCSIINT bit in
-                        *  INTSTAT.  By writing to the (undocumented, unused
-                        *  according to the AIC-7770 manual) third bit of
-                        *  CLRINT, you can clear INTSTAT.  But, if you do it
-                        *  while the sequencer is paused, you get a BRKADRINT
-                        *  with an Illegal Host Address status, so the
-                        *  sequencer has to be restarted first.
-                        */
-                       outb(0x80, O_CLRSINT1(base));   /* CLRSELTIMO */
-                       RESTART_SEQUENCER(p);
-
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-                       cmd->scsi_done(cmd);
-               }
-
-               if (status & 0x4) {                     /* SCSIPERR */
-                       /*
-                        *  A parity error has occurred during a data
-                        *  transfer phase.  Flag it and continue.
-                        */
-                       printk("aha274x: parity error on target %d, lun %d\n",
-                              cmd->target,
-                              cmd->lun);
-                       aha274x_parity(cmd) = DID_PARITY;
-
-                       /*
-                        *  Clear interrupt and resume as above.
-                        */
-                       outb(0x4, O_CLRSINT1(base));    /* CLRSCSIPERR */
-                       UNPAUSE_SEQUENCER(p);
-
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-               }
-
-               if ((status & (0x8|0x4)) == 0 && status) {
-                       /*
-                        *  We don't know what's going on.  Turn off the
-                        *  interrupt source and try to continue.
-                        */
-                       printk("aha274x_isr: sstat1 = 0x%x\n", status);
-                       outb(status, O_CLRSINT1(base));
-                       UNPAUSE_SEQUENCER(p);
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-               }
-       }
-
-       if (intstat & 0x2) {                            /* CMDCMPLT */
-
-               int complete, old_scbptr;
-               struct aha274x_scb scb;
-               unsigned actual;
-               Scsi_Cmnd *cmd;
-
-               /*
-                *  The sequencer will continue running when it
-                *  issues this interrupt.  There may be >1 commands
-                *  finished, so loop until we've processed them all.
-                */
-               do {
-                       complete = inb(O_QOUTFIFO(base));
-
-                       cmd = (Scsi_Cmnd *)p->SCB_array[complete];
-                       if (!cmd) {
-                               printk("aha274x warning: "
-                                      "no command for scb (cmdcmplt)\n");
-                               continue;
-                       }
-                       p->SCB_array[complete] = NULL;
-                       
-                       PAUSE_SEQUENCER(p);
-
-                       /*
-                        *  After pausing the sequencer (and waiting
-                        *  for it to stop), save its SCB pointer, then
-                        *  write in our completed one and read the SCB
-                        *  registers.  Afterwards, restore the saved
-                        *  pointer, unpause the sequencer and call the
-                        *  higher-level completion function - unpause
-                        *  first since we have no idea how long done()
-                        *  will take.
-                        */
-                       old_scbptr = inb(O_SCBPTR(base));
-                       outb(complete, O_SCBPTR(base));
-
-                       aha274x_getscb(base, &scb);
-                       outb(old_scbptr, O_SCBPTR(base));
-
-                       UNPAUSE_SEQUENCER(p);
-
-                       cmd->result = scb.target_status |
-                                    (aha274x_parity(cmd) << 16);
-
-                       /*
-                        *  Did we underflow?  At this time, there's only
-                        *  one other driver that bothers to check for this,
-                        *  and cmd->underflow seems to be set rather half-
-                        *  heartedly in the higher-level SCSI code.
-                        */
-                       actual = aha274x_length(cmd,
-                                               scb.residual_SG_segment_count);
-
-                       actual -= ((scb.residual_data_count[2] << 16) |
-                                  (scb.residual_data_count[1] <<  8) |
-                                  (scb.residual_data_count[0]));
-
-                       if (actual < cmd->underflow) {
-                               printk("aha274x: target %d underflow - "
-                                      "wanted (at least) %u, got %u\n",
-                                      cmd->target, cmd->underflow, actual);
-
-                               cmd->result = scb.target_status |
-                                            (DID_UNDERFLOW << 16);
-                       }
-
-                       cmd->scsi_done(cmd);
-
-                       /*
-                        *  Clear interrupt status before checking
-                        *  the output queue again.  This eliminates
-                        *  a race condition whereby a command could
-                        *  complete between the queue poll and the
-                        *  interrupt clearing, so notification of the
-                        *  command being complete never made it back
-                        *  up to the kernel.
-                        */
-                       outb(0x2, O_CLRINT(base));      /* CLRCMDINT */
-
-               } while (inb(O_QOUTCNT(base)));
-       }
-
-       if (intstat & 0x1) {                            /* SEQINT */
-
-               unsigned char transfer, offset, rate;
-
-               /*
-                *  Although the sequencer is paused immediately on
-                *  a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
-                *  condition will have unpaused the sequencer before
-                *  this point.
-                */
-               PAUSE_SEQUENCER(p);
-
-               switch (intstat & 0xf0) {
-                   case 0x00:
-                       panic("aha274x_isr: unknown scsi bus phase\n");
-                   case 0x10:
-                       debug("aha274x_isr warning: "
-                             "issuing message reject, 1st byte 0x%x\n",
-                             inb(HA_REJBYTE(base)));
-                       break;
-                   case 0x20:
-                       panic("aha274x_isr: reconnecting target %d "
-                             "didn't issue IDENTIFY message\n",
-                             (inb(O_SELID(base)) >> 4) & 0xf);
-                   case 0x30:
-                       debug("aha274x_isr: sequencer couldn't find match "
-                             "for reconnecting target %d - issuing ABORT\n",
-                             (inb(O_SELID(base)) >> 4) & 0xf);
-                       break;
-                   case 0x40:
-                       transfer = inb(HA_ARG_1(base));
-                       offset = inb(HA_ARG_2(base));
-                       aha274x_to_scsirate(&rate, transfer, offset);
-                       outb(rate, HA_RETURN_1(base));
-                       debug_rate(base, rate);
-                       break;
-                   default:
-                       debug("aha274x_isr: seqint, "
-                             "intstat = 0x%x, scsisigi = 0x%x\n",
-                             intstat, inb(O_SCSISIGI(base)));
-                       break;
-               }
-
-               outb(0x1, O_CLRINT(base));              /* CLRSEQINT */
-               UNPAUSE_SEQUENCER(p);
-       }
-}
-
-/*
- *  Probing for EISA boards: it looks like the first two bytes
- *  are a manufacturer code - three characters, five bits each:
- *
- *              BYTE 0   BYTE 1   BYTE 2   BYTE 3
- *             ?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- *  The characters are baselined off ASCII '@', so add that value
- *  to each to get the real ASCII code for it.  The next two bytes
- *  appear to be a product and revision number, probably vendor-
- *  specific.  This is what is being searched for at each port,
- *  and what should probably correspond to the ID= field in the
- *  ECU's .cfg file for the card - if your card is not detected,
- *  make sure your signature is listed in the array.
- *
- *  The fourth byte's lowest bit seems to be an enabled/disabled
- *  flag (rest of the bits are reserved?).
- */
-
-static
-enum aha_type aha274x_probe(int slot, int s_base)
-{
-       int i;
-       unsigned char buf[4];
-
-       static struct {
-               int n;
-               unsigned char signature[sizeof(buf)];
-               enum aha_type type;
-       } S[] = {
-               {4, { 0x04, 0x90, 0x77, 0x71 }, T_274X},        /* host adapter 274x */
-               {4, { 0x04, 0x90, 0x77, 0x70 }, T_274X},        /* motherboard 274x  */
-               {4, { 0x04, 0x90, 0x77, 0x56 }, T_284X},        /* 284x, BIOS enabled */
-       };
-
-       for (i = 0; i < sizeof(buf); i++) {
-               /*
-                *  The VL-bus cards need to be primed by
-                *  writing before a signature check.
-                */
-               outb(0x80 + i, s_base);
-               buf[i] = inb(s_base + i);
-       }
-
-       for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
-               if (!memcmp(buf, S[i].signature, S[i].n)) {
-                       /*
-                        *  Signature match on enabled card?
-                        */
-                       if (inb(s_base + 4) & 1)
-                               return(S[i].type);
-                       printk("aha274x disabled at slot %d, ignored\n", slot);
-               }
-       }
-       return(T_NONE);
-}
-
-/*
- *  Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
- *  wide channel, '?' for anything else.
- */
-
-static
-char aha274x_type(int base)
-{
-       /*
-        *  The AIC-7770 can be wired so that, on chip reset,
-        *  the SCSI Block Control register indicates how many
-        *  busses the chip is configured for.
-        */
-       switch (inb(O_SBLKCTL(base))) {
-           case 0:
-               return(' ');
-           case 2:
-               return('W');
-           case 8:
-               return('T');
-           default:
-               printk("aha274x has unknown bus configuration\n");
-               return('?');
-       }
-}
-
-static
-void aha274x_loadram(int base)
-{
-       static unsigned char seqprog[] = {
-               /*
-                *  Each sequencer instruction is 29 bits
-                *  long (fill in the excess with zeroes)
-                *  and has to be loaded from least -> most
-                *  significant byte, so this table has the
-                *  byte ordering reversed.
-                */
-#              include "aha274x_seq.h"
-       };
-
-       /*
-        *  When the AIC-7770 is paused (as on chip reset), the
-        *  sequencer address can be altered and a sequencer
-        *  program can be loaded by writing it, byte by byte, to
-        *  the sequencer RAM port - the Adaptec documentation
-        *  recommends using REP OUTSB to do this, hence the inline
-        *  assembly.  Since the address autoincrements as we load
-        *  the program, reset it back to zero afterward.  Disable
-        *  sequencer RAM parity error detection while loading, and
-        *  make sure the LOADRAM bit is enabled for loading.
-        */
-       outb(0x83, O_SEQCTL(base));     /* PERRORDIS|SEQRESET|LOADRAM */
-
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "outsb"
-                    : /* no output */
-                    :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
-                    :"si", "cx", "dx");
-
-       /*
-        *  WARNING!  This is a magic sequence!  After extensive
-        *  experimentation, it seems that you MUST turn off the
-        *  LOADRAM bit before you play with SEQADDR again, else
-        *  you will end up with parity errors being flagged on
-        *  your sequencer program.  (You would also think that
-        *  turning off LOADRAM and setting SEQRESET to reset the
-        *  address to zero would work, but you need to do it twice
-        *  for it to take effect on the address.  Timing problem?)
-        */
-       outb(0, O_SEQCTL(base));
-       do {
-               /*
-                *  Actually, reset it until
-                *  the address shows up as
-                *  zero just to be safe..
-                */
-               outb(0x2, O_SEQCTL(base));      /* SEQRESET */
-
-       } while (inw(O_SEQADDR(base)) != 0);
-}
-
-static
-int aha274x_register(Scsi_Host_Template *template,
-                    enum aha_type type,
-                    int base)
-{
-       int i, irq, scsi_id;
-       struct Scsi_Host *host;
-       struct aha274x_host *p;
-
-       /*
-        *  Give the AIC-7770 a reset - reading the 274x's registers
-        *  returns zeroes unless you do.  This forces a pause of the
-        *  Sequencer.
-        */
-       outb(1, O_HCNTRL(base));        /* CHIPRST */
-
-       /*
-        *  The IRQ level in i/o port 4 maps directly onto the real
-        *  IRQ number.  If it's ok, register it with the kernel.
-        *
-        *  NB. the Adaptec documentation says the IRQ number is only
-        *      in the lower four bits; the ECU information shows the
-        *      high bit being used as well.  Which is correct?
-        */
-       irq = inb(HA_INTDEF(base)) & 0xf;
-       if (irq < 9 || irq > 15) {
-               printk("aha274x uses unsupported IRQ level, ignoring\n");
-               return(0);
-       }
-       
-       /*
-        *  Lock out other contenders for our i/o space.
-        */
-       request_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base), "aha27x");
-
-       /*
-        *  Any card-type-specific adjustments before we register
-        *  the scsi host(s).
-        */
-
-       scsi_id = inb(HA_SCSICONF(base)) & 0x7;
-
-       switch (aha274x_type(base)) {
-           case 'T':
-               printk("aha274x warning: ignoring channel B of 274x-twin\n");
-               break;
-           case ' ':
-               break;
-           default:
-               printk("aha274x is an unsupported type, ignoring\n");
-               return(0);
-       }
-
-       /*
-        *  Before registry, make sure that the offsets of the
-        *  struct scatterlist are what the sequencer will expect,
-        *  otherwise disable scatter-gather altogether until someone
-        *  can fix it.  This is important since the sequencer will
-        *  DMA elements of the SG array in while executing commands.
-        */
-       if (template->sg_tablesize != SG_NONE) {
-               struct scatterlist sg;
-
-               if (SG_STRUCT_CHECK(sg)) {
-                       printk("aha274x warning: kernel scatter-gather "
-                              "structures changed, disabling it\n");
-                       template->sg_tablesize = SG_NONE;
-               }
-       }
-       
-       /*
-        *  Register each "host" and fill in the returned Scsi_Host
-        *  structure as best we can.  Some of the parameters aren't
-        *  really relevant for EISA, and none of the high-level SCSI
-        *  code looks at it anyway.. why are the fields there?  Also
-        *  save the pointer so that we can find the information when
-        *  an IRQ is triggered.
-        */
-       host = scsi_register(template, sizeof(struct aha274x_host));
-       host->this_id = scsi_id;
-       host->irq = irq;
-
-       aha274x_boards[irq] = host;
-       
-       p = (struct aha274x_host *)host->hostdata;
-       for (i = 0; i < AHA274X_MAXSCB; i++)
-               p->SCB_array[i] = NULL;
-       p->base = base;
-
-       /*
-        *  The interrupt trigger is different depending
-        *  on whether the card is EISA or VL-bus - sometimes.
-        *  The startup variable will be cleared once the first
-        *  command is queued, and is checked in the isr to
-        *  try and detect when the interrupt type is set
-        *  incorrectly, triggering an interrupt immediately.
-        */
-       p->unpause = (type != T_274X ? 0x2 : 0xa);
-       p->startup = !0;
-
-       /*
-        *  Register IRQ with the kernel _after_ the host information
-        *  is set up, in case we take an interrupt right away, due to
-        *  the interrupt type being set wrong.
-        */
-       if (request_irq(irq, aha274x_isr, SA_INTERRUPT, "AHA274x/284x")) {
-               printk("aha274x couldn't register irq %d, ignoring\n", irq);
-               return(0);
-       }
-
-       /*
-        *  A reminder until this can be detected automatically.
-        */
-       printk("aha274x: extended translation %sabled\n",
-              aha274x_extended ? "en" : "dis");
-
-       /*
-        *  Print out debugging information before re-enabling
-        *  the card - a lot of registers on it can't be read
-        *  when the sequencer is active.
-        */
-       debug_config(type, base);
-
-       /*
-        *  Load the sequencer program, then re-enable the board -
-        *  resetting the AIC-7770 disables it, leaving the lights
-        *  on with nobody home.
-        */
-       aha274x_loadram(base);
-       outb(1, O_BCTL(base));          /* ENABLE */
-
-       /*
-        *  Set the host adapter registers to indicate that synchronous
-        *  negotiation should be attempted the first time the targets
-        *  are communicated with.  Also initialize the active message
-        *  flag to indicate that there is no message.
-        */
-       outb(0xff, HA_NEEDSDTR(base));
-       outb(0, HA_MSG_FLAGS(base));
-
-       /*
-        *  Unpause the sequencer before returning and enable
-        *  interrupts - we shouldn't get any until the first
-        *  command is sent to us by the high-level SCSI code.
-        */
-       UNPAUSE_SEQUENCER(p);
-       return(1);
-}
-
-int aha274x_detect(Scsi_Host_Template *template)
-{
-       enum aha_type type;
-       int found = 0, slot, base;
-
-       for (slot = MINEISA; slot <= MAXEISA; slot++) {
-
-               base = SLOTBASE(slot);
-               
-               if (check_region(O_MINREG(base),
-                                O_MAXREG(base)-O_MINREG(base)))
-               {
-                       /*
-                        *  Some other driver has staked a
-                        *  claim to this i/o region already.
-                        */
-                       continue;
-               }
-
-               type = aha274x_probe(slot, O_BIDx(base));
-
-               if (type != T_NONE) {
-                       /*
-                        *  We "find" a 274x if we locate the card
-                        *  signature and we can set it up and register
-                        *  it with the kernel without incident.
-                        */
-                       found += aha274x_register(template, type, base);
-               }
-       }
-       template->name = (char *)aha274x_info(NULL);
-       return(found);
-}
-
-const char *aha274x_info(struct Scsi_Host * shost)
-{
-       return("Adaptec AHA274x/284x (EISA/VL-bus -> Fast SCSI) "
-              AHA274X_SEQ_VERSION "/"
-              AHA274X_H_VERSION "/"
-              "1.29");
-}
-
-int aha274x_command(Scsi_Cmnd *cmd)
-{
-       /*
-        *  This is a relic of non-interrupt-driven SCSI
-        *  drivers.  With the can_queue variable set, this
-        *  should never be called.
-        */
-       panic("aha274x_command was called\n");
-}
-
-static
-void aha274x_buildscb(struct aha274x_host *p,
-                     Scsi_Cmnd *cmd,
-                     struct aha274x_scb *scb)
-{
-       void *addr;
-       unsigned length;
-
-       memset(scb, 0, sizeof(*scb));
-
-       /*
-        *  NB. channel selection (bit 3) is always zero.
-        */
-       scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
-                                  (cmd->lun & 0x7);
-
-       /*
-        *  The interpretation of request_buffer and request_bufflen
-        *  changes depending on whether or not use_sg is zero; a
-        *  non-zero use_sg indicates the number of elements in the
-        *  scatter-gather array.
-        *
-        *  The AIC-7770 can't support transfers of any sort larger
-        *  than 2^24 (three-byte count) without backflips.  For what
-        *  the kernel is doing, this shouldn't occur.  I hope.
-        */
-       length = aha274x_length(cmd, 0);
-
-       /*
-        *  The sequencer code cannot yet handle scatter-gather segments
-        *  larger than 64k (two-byte length).  The 1.1.x kernels, however,
-        *  have a four-byte length field in the struct scatterlist, so
-        *  make sure we don't exceed 64k on these kernels for now.
-        */
-       aha274x_sg_check(cmd);
-
-       if (length > 0xffffff) {
-               panic("aha274x_buildscb: can't transfer > 2^24 - 1 bytes\n");
-       }
-
-       /*
-        *  XXX - this relies on the host data being stored in a
-        *        little-endian format.
-        */
-       addr = cmd->cmnd;
-       scb->SCSI_cmd_length = cmd->cmd_len;
-       memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
-
-       if (cmd->use_sg) {
-#if 0
-               debug("aha274x_buildscb: SG used, %d segments, length %u\n",
-                     cmd->use_sg,
-                     length);
-#endif
-               scb->SG_segment_count = cmd->use_sg;
-               memcpy(scb->SG_list_pointer,
-                      &cmd->request_buffer,
-                      sizeof(scb->SG_list_pointer));
-       } else {
-               scb->SG_segment_count = 0;
-               memcpy(scb->data_pointer,
-                      &cmd->request_buffer,
-                      sizeof(scb->data_pointer));
-               memcpy(scb->data_count,
-                      &cmd->request_bufflen,
-                      sizeof(scb->data_count));
-       }
-}
-
-static
-void aha274x_putscb(int base, struct aha274x_scb *scb)
-{
-       /*
-        *  By turning on the SCB auto increment, any reference
-        *  to the SCB I/O space postincrements the SCB address
-        *  we're looking at.  So turn this on and dump the relevant
-        *  portion of the SCB to the card.
-        */
-       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
-
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "outsb"
-                    : /* no output */
-                    :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-                    :"si", "cx", "dx");
-
-       outb(0, O_SCBCNT(base));
-}
-
-int aha274x_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
-{
-       long flags;
-       int empty, old_scbptr;
-       struct aha274x_host *p;
-       struct aha274x_scb scb;
-
-#if 0
-       debug("aha274x_queue: cmd 0x%x (size %u), target %d, lun %d\n",
-             cmd->cmnd[0],
-             cmd->cmd_len,
-             cmd->target,
-             cmd->lun);
-#endif
-
-       p = (struct aha274x_host *)cmd->host->hostdata;
-
-       /*
-        *  Construct the SCB beforehand, so the sequencer is
-        *  paused a minimal amount of time.
-        */
-       aha274x_buildscb(p, cmd, &scb);
-
-       /*
-        *  Clear the startup flag - we can now legitimately
-        *  expect interrupts.
-        */
-       p->startup = 0;
-
-       /*
-        *  This is a critical section, since we don't want the
-        *  interrupt routine mucking with the host data or the
-        *  card.  Since the kernel documentation is vague on
-        *  whether or not we are in a cli/sti pair already, save
-        *  the flags to be on the safe side.
-        */
-       save_flags(flags);
-       cli();
-
-       /*
-        *  Find a free slot in the SCB array to load this command
-        *  into.  Since can_queue is set to AHA274X_MAXSCB, we
-        *  should always find one.
-        */
-       for (empty = 0; empty < AHA274X_MAXSCB; empty++)
-               if (!p->SCB_array[empty])
-                       break;
-       if (empty == AHA274X_MAXSCB)
-               panic("aha274x_queue: couldn't find a free scb\n");
-
-       /*
-        *  Pause the sequencer so we can play with its registers -
-        *  wait for it to acknowledge the pause.
-        *
-        *  XXX - should the interrupts be left on while doing this?
-        */
-       PAUSE_SEQUENCER(p);
-
-       /*
-        *  Save the SCB pointer and put our own pointer in - this
-        *  selects one of the four banks of SCB registers.  Load
-        *  the SCB, then write its pointer into the queue in FIFO
-        *  and restore the saved SCB pointer.
-        */
-       old_scbptr = inb(O_SCBPTR(p->base));
-       outb(empty, O_SCBPTR(p->base));
-       
-       aha274x_putscb(p->base, &scb);
-
-       outb(empty, O_QINFIFO(p->base));
-       outb(old_scbptr, O_SCBPTR(p->base));
-
-       /*
-        *  Make sure the Scsi_Cmnd pointer is saved, the struct it
-        *  points to is set up properly, and the parity error flag
-        *  is reset, then unpause the sequencer and watch the fun
-        *  begin.
-        */
-       cmd->scsi_done = fn;
-       p->SCB_array[empty] = cmd;
-       aha274x_parity(cmd) = DID_OK;
-
-       UNPAUSE_SEQUENCER(p);
-
-       restore_flags(flags);
-       return(0);
-}
-
-/* return values from aha274x_kill */
-
-enum k_state {
-       k_ok,                           /* scb found and message sent */
-       k_busy,                         /* message already present */
-       k_absent,                       /* couldn't locate scb */
-       k_disconnect,                   /* scb found, but disconnected */
-};
-
-/*
- *  This must be called with interrupts disabled - it's going to
- *  be messing around with the host data, and an interrupt being
- *  fielded in the middle could get ugly.
- *
- *  Since so much of the abort and reset code is shared, this
- *  function performs more magic than it really should.  If the
- *  command completes ok, then it will call scsi_done with the
- *  result code passed in.  The unpause parameter controls whether
- *  or not the sequencer gets unpaused - the reset function, for
- *  instance, may want to do something more aggressive.
- *
- *  Note that the command is checked for in our SCB_array first
- *  before the sequencer is paused, so if k_absent is returned,
- *  then the sequencer is NOT paused.
- */
-
-static
-enum k_state aha274x_kill(Scsi_Cmnd *cmd, unsigned char message,
-                         unsigned int result, int unpause)
-{
-       struct aha274x_host *p;
-       int i, scb, found, queued;
-       unsigned char scbsave[AHA274X_MAXSCB];
-
-       p = (struct aha274x_host *)cmd->host->hostdata;
-
-       /*
-        *  If we can't find the command, assume it just completed
-        *  and shrug it away.
-        */
-       for (scb = 0; scb < AHA274X_MAXSCB; scb++)
-               if (p->SCB_array[scb] == cmd)
-                       break;
-
-       if (scb == AHA274X_MAXSCB)
-               return(k_absent);
-
-       PAUSE_SEQUENCER(p);
-
-       /*
-        *  This is the best case, really.  Check to see if the
-        *  command is still in the sequencer's input queue.  If
-        *  so, simply remove it.  Reload the queue afterward.
-        */
-       queued = inb(O_QINCNT(p->base));
-       
-       for (i = found = 0; i < queued; i++) {
-               scbsave[i] = inb(O_QINFIFO(p->base));
-
-               if (scbsave[i] == scb) {
-                       found = 1;
-                       i -= 1;
-               }
-       }
-
-       queued -= found;
-       for (i = 0; i < queued; i++)
-               outb(scbsave[i], O_QINFIFO(p->base));
-
-       if (found)
-               goto complete;
-
-       /*
-        *  Check the current SCB bank.  If it's not the one belonging
-        *  to the command we want to kill, assume that the command
-        *  is disconnected.  It's rather a pain to force a reconnect
-        *  and send a message to the target, so we abdicate responsibility
-        *  in this case.
-        */
-       if (inb(O_SCBPTR(p->base)) != scb) {
-               if (unpause)
-                       UNPAUSE_SEQUENCER(p);
-               return(k_disconnect);
-       }
-
-       /*
-        *  Presumably at this point our target command is active.  Check
-        *  to see if there's a message already in effect.  If not, place
-        *  our message in and assert ATN so the target goes into MESSAGE
-        *  OUT phase.
-        */
-       if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
-               if (unpause)
-                       UNPAUSE_SEQUENCER(p);
-               return(k_busy);
-       }
-
-       outb(0x80, HA_MSG_FLAGS(p->base));              /* active message */
-       outb(1, HA_MSG_LEN(p->base));                   /* length = 1 */
-       outb(message, HA_MSG_START(p->base));           /* message body */
-
-       /*
-        *  Assert ATN.  Use the value of SCSISIGO saved by the
-        *  sequencer code so we don't alter its contents radically
-        *  in the middle of something critical.
-        */
-       outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
-
-       /*
-        *  The command has been killed.  Do the bookkeeping, unpause
-        *  the sequencer, and notify the higher-level SCSI code.
-        */
-complete:
-       p->SCB_array[scb] = NULL;
-       if (unpause)
-               UNPAUSE_SEQUENCER(p);
-
-       cmd->result = result << 16;
-       cmd->scsi_done(cmd);
-       return(k_ok);
-}
-
-int aha274x_abort(Scsi_Cmnd *cmd)
-{
-       int rv;
-       long flags;
-
-       save_flags(flags);
-       cli();
-
-       switch (aha274x_kill(cmd, ABORT, DID_ABORT, !0)) {
-           case k_ok:          rv = SCSI_ABORT_SUCCESS;        break;
-           case k_busy:        rv = SCSI_ABORT_BUSY;           break;
-           case k_absent:      rv = SCSI_ABORT_NOT_RUNNING;    break;
-           case k_disconnect:  rv = SCSI_ABORT_SNOOZE;         break;
-           default:
-               panic("aha274x_do_abort: internal error\n");
-       }
-
-       restore_flags(flags);
-       return(rv);
-}
-
-/*
- *  Resetting the bus always succeeds - is has to, otherwise the
- *  kernel will panic!  Try a surgical technique - sending a BUS
- *  DEVICE RESET message - on the offending target before pulling
- *  the SCSI bus reset line.
- */
-
-int aha274x_reset(Scsi_Cmnd *cmd)
-{
-       int i;
-       long flags;
-       Scsi_Cmnd *reset;
-       struct aha274x_host *p;
-
-       p = (struct aha274x_host *)cmd->host->hostdata;
-       save_flags(flags);
-       cli();
-
-       switch (aha274x_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
-
-           case k_ok:
-               /*
-                *  The RESET message was sent to the target
-                *  with no problems.  Flag that target as
-                *  needing a SDTR negotiation on the next
-                *  connection and restart the sequencer.
-                */
-               outb((1 << cmd->target), HA_NEEDSDTR(p->base));
-               UNPAUSE_SEQUENCER(p);
-               break;
-
-           case k_absent:
-               /*
-                *  The sequencer will not be paused if aha274x_kill()
-                *  couldn't find the command.
-                */
-               PAUSE_SEQUENCER(p);
-               /* falls through */
-
-           case k_busy:
-           case k_disconnect:
-               /*
-                *  Do a hard reset of the SCSI bus.  According to the
-                *  SCSI-2 draft specification, reset has to be asserted
-                *  for at least 25us.  I'm invoking the kernel delay
-                *  function for 30us since I'm not totally trusting of
-                *  the busy loop timing.
-                *
-                *  XXX - I'm not convinced this works.  I tried resetting
-                *        the bus before, trying to get the devices on the
-                *        bus to revert to asynchronous transfer, and it
-                *        never seemed to work.
-                */
-               debug("aha274x: attempting to reset scsi bus and card\n");
-
-               outb(1, O_SCSISEQ(p->base));            /* SCSIRSTO */
-               udelay(30);
-               outb(0, O_SCSISEQ(p->base));            /* !SCSIRSTO */
-
-               outb(0xff, HA_NEEDSDTR(p->base));
-               UNPAUSE_SEQUENCER(p);
-
-               /*
-                *  Locate the command and return a "reset" status
-                *  for it.  This is not completely correct and will
-                *  probably return to haunt me later.
-                */
-               for (i = 0; i < AHA274X_MAXSCB; i++) {
-                       if (cmd == p->SCB_array[i]) {
-                               reset = (Scsi_Cmnd *)p->SCB_array[i];
-                               p->SCB_array[i] = NULL;
-                               reset->result = DID_RESET << 16;
-                               reset->scsi_done(reset);
-                               break;
-                       }
-               }
-               break;
-
-           default:
-               panic("aha274x_reset: internal error\n");
-       }
-
-       restore_flags(flags);
-       return(SCSI_RESET_SUCCESS);
-}
-
-int aha274x_biosparam(Disk *disk, int devno, int geom[])
-{
-       int heads, sectors, cylinders;
-
-       /*
-        *  XXX - if I could portably find the card's configuration
-        *        information, then this could be autodetected instead
-        *        of left to a boot-time switch.
-        */
-       heads = 64;
-       sectors = 32;
-       cylinders = disk->capacity / (heads * sectors);
-
-       if (aha274x_extended && cylinders > 1024) {
-               heads = 255;
-               sectors = 63;
-               cylinders = disk->capacity / (255 * 63);
-       }
-
-       geom[0] = heads;
-       geom[1] = sectors;
-       geom[2] = cylinders;
-
-       return(0);
-}
-
diff --git a/drivers/scsi/aha274x.h b/drivers/scsi/aha274x.h
deleted file mode 100644 (file)
index b2a1c9e..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* @(#)aha274x.h 1.11 94/09/06 jda */
-
-/*
- * Adaptec 274x device driver for Linux.
- * Copyright (c) 1994 The University of Calgary Department of Computer Science.
- * 
- * 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.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef aha274x_h
-#define aha274x_h
-
-#define        AHA274X_MAXSCB          4
-#define AHA274X_H_VERSION      "1.11"
-
-/*
- *  Scsi_Host_Template (see hosts.h) for 274x - some fields
- *  to do with card config are filled in after the card is
- *  detected.
- */
-#define AHA274X        {                                               \
-       NULL,                                                   \
-       NULL,                                                   \
-       NULL,                                                   \
-       aha274x_detect,                                         \
-       NULL,                                                   \
-       aha274x_info,                                           \
-       aha274x_command,                                        \
-       aha274x_queue,                                          \
-       aha274x_abort,                                          \
-       aha274x_reset,                                          \
-       NULL,                                                   \
-       aha274x_biosparam,                                      \
-       AHA274X_MAXSCB,         /* max simultaneous cmds      */\
-       -1,                     /* scsi id of host adapter    */\
-       SG_ALL,                 /* max scatter-gather cmds    */\
-       1,                      /* cmds per lun (linked cmds) */\
-       0,                      /* number of 274x's present   */\
-       0,                      /* no memory DMA restrictions */\
-       DISABLE_CLUSTERING                                      \
-}
-
-extern int aha274x_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aha274x_biosparam(Disk *, int, int[]);
-extern int aha274x_detect(Scsi_Host_Template *);
-extern int aha274x_command(Scsi_Cmnd *);
-extern int aha274x_abort(Scsi_Cmnd *);
-extern int aha274x_reset(Scsi_Cmnd *);
-extern const char *aha274x_info(struct Scsi_Host *);
-
-#endif
diff --git a/drivers/scsi/aha274x.seq b/drivers/scsi/aha274x.seq
deleted file mode 100644 (file)
index c8a2417..0000000
+++ /dev/null
@@ -1,1021 +0,0 @@
-# @(#)aha274x.seq 1.28 94/10/04 jda
-#
-# Adaptec 274x device driver for Linux.
-# Copyright (c) 1994 The University of Calgary Department of Computer Science.
-# 
-# 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.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-VERSION AHA274X_SEQ_VERSION 1.28
-
-MAXSCB         = 4
-
-SCSISEQ                = 0x00
-SXFRCTL0       = 0x01
-SXFRCTL1       = 0x02
-SCSISIGI       = 0x03
-SCSISIGO       = 0x03
-SCSIRATE       = 0x04
-SCSIID         = 0x05
-SCSIDATL       = 0x06
-STCNT          = 0x08
-STCNT+0                = 0x08
-STCNT+1                = 0x09
-STCNT+2                = 0x0a
-SSTAT0         = 0x0b
-CLRSINT1       = 0x0c
-SSTAT1         = 0x0c
-SIMODE1                = 0x11
-SCSIBUSL       = 0x12
-SHADDR         = 0x14
-SELID          = 0x19
-SBLKCTL                = 0x1f
-SEQCTL         = 0x60
-A              = 0x64                          # == ACCUM
-SINDEX         = 0x65
-DINDEX         = 0x66
-ALLZEROS       = 0x6a
-NONE           = 0x6a
-SINDIR         = 0x6c
-DINDIR         = 0x6d
-FUNCTION1      = 0x6e
-HADDR          = 0x88
-HCNT           = 0x8c
-HCNT+0         = 0x8c
-HCNT+1         = 0x8d
-HCNT+2         = 0x8e
-SCBPTR         = 0x90
-INTSTAT                = 0x91
-DFCNTRL                = 0x93
-DFSTATUS       = 0x94
-DFDAT          = 0x99
-QINFIFO                = 0x9b
-QINCNT         = 0x9c
-QOUTFIFO       = 0x9d
-
-SCSICONF       = 0x5a
-
-#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
-#  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
-#  to indicate whether or not to reload scatter-gather parameters after
-#  a disconnect.
-#
-SCBARRAY+0     = 0xa0
-SCBARRAY+1     = 0xa1
-SCBARRAY+2     = 0xa2
-SCBARRAY+3     = 0xa3
-SCBARRAY+7     = 0xa7
-SCBARRAY+11    = 0xab
-SCBARRAY+14    = 0xae
-SCBARRAY+15    = 0xaf
-SCBARRAY+16    = 0xb0
-SCBARRAY+17    = 0xb1
-SCBARRAY+18    = 0xb2
-SCBARRAY+19    = 0xb3
-SCBARRAY+20    = 0xb4
-SCBARRAY+21    = 0xb5
-SCBARRAY+22    = 0xb6
-SCBARRAY+23    = 0xb7
-SCBARRAY+24    = 0xb8
-SCBARRAY+25    = 0xb9
-
-SIGNAL_0       = 0x01                          # unknown scsi bus phase
-SIGNAL_1       = 0x11                          # message reject
-SIGNAL_2       = 0x21                          # no IDENTIFY after reconnect
-SIGNAL_3       = 0x31                          # no cmd match for reconnect
-SIGNAL_4       = 0x41                          # SDTR -> SCSIRATE conversion
-
-#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
-#  device information, 32-33 and 5a-5f as well.  Since we don't support
-#  wide or twin-bus SCSI, 28-2f can be reclaimed.  As it turns out, the
-#  BIOS trashes 20-27 anyway, writing the synchronous negotiation results
-#  on top of the BIOS values, so we re-use those for our per-target
-#  scratchspace (actually a value that can be copied directly into
-#  SCSIRATE).  This implies, since we can't get the BIOS config values,
-#  that all targets will be negotiated with for synchronous transfer.
-#  NEEDSDTR has one bit per target indicating if an SDTR message is
-#  needed for that device - this will be set initially, as well as
-#  after a bus reset condition.
-#
-#  The high bit of DROPATN is set if ATN should be dropped before the ACK
-#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
-#  message, so the driver can report an intelligible error if a message is
-#  rejected.
-#
-#  RESELECT's high bit is true if we are currently handling a reselect;
-#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
-#  from the reselecting target.  If we haven't had IDENTIFY, then we have
-#  no idea what the lun is, and we can't select the right SCB register
-#  bank, so force a kernel panic if the target attempts a data in/out or
-#  command phase instead of corrupting something.
-#
-#  Note that SG_NEXT occupies four bytes.
-#
-SYNCNEG                = 0x20
-DISC_DSB_A     = 0x32
-
-DROPATN                = 0x30
-REJBYTE                = 0x31
-RESELECT       = 0x34
-
-MSG_FLAGS      = 0x35
-MSG_LEN                = 0x36
-MSG_START+0    = 0x37
-MSG_START+1    = 0x38
-MSG_START+2    = 0x39
-MSG_START+3    = 0x3a
-MSG_START+4    = 0x3b
-MSG_START+5    = 0x3c
--MSG_START+0   = 0xc9                          # 2's complement of MSG_START+0
-
-ARG_1          = 0x4c                          # sdtr conversion args & return
-ARG_2          = 0x4d
-RETURN_1       = 0x4c
-
-SIGSTATE       = 0x4e                          # value written to SCSISIGO
-NEEDSDTR       = 0x4f                          # send SDTR message, 1 bit/trgt
-
-SG_SIZEOF      = 12                            # sizeof(struct scatterlist)
-SG_NOLOAD      = 0x50                          # load SG pointer/length?
-SG_COUNT       = 0x51                          # working value of SG count
-SG_NEXT                = 0x52                          # working value of SG pointer
-SG_NEXT+0      = 0x52
-SG_NEXT+1      = 0x53
-SG_NEXT+2      = 0x54
-SG_NEXT+3      = 0x55
-
-#  Poll QINCNT for work - the lower three bits contain
-#  the number of entries in the Queue In FIFO.
-#
-start:
-       test    SCSISIGI,0x4    jnz reselect    # BSYI
-       test    QINCNT,0x7      jz start
-
-#  We have at least one queued SCB now.  Set the SCB pointer
-#  from the FIFO so we see the right bank of SCB registers,
-#  then set SCSI options and set the initiator and target
-#  SCSI IDs.
-#
-       mov     SCBPTR,QINFIFO
-       mov     SCBARRAY+1      call initialize
-       clr     SG_NOLOAD
-       clr     RESELECT
-
-#  As soon as we get a successful selection, the target should go
-#  into the message out phase since we have ATN asserted.  Prepare
-#  the message to send, locking out the device driver.  If the device
-#  driver hasn't beaten us with an ABORT or RESET message, then tack
-#  on a SDTR negotiation if required.
-#
-#  Messages are stored in scratch RAM starting with a flag byte (high bit
-#  set means active message), one length byte, and then the message itself.
-#
-       mov     SCBARRAY+1      call disconnect # disconnect ok?
-
-       and     SINDEX,0x7,SCBARRAY+1           # lun
-       or      SINDEX,A                        # return value from disconnect
-       or      SINDEX,0x80     call mk_mesg    # IDENTIFY message
-
-       mov     A,SINDEX
-       cmp     MSG_START+0,A   jne !message    # did driver beat us?
-       mvi     MSG_START+1     call mk_sdtr    # build SDTR message if needed
-
-!message:
-
-#  Enable selection phase as an initiator, and do automatic ATN
-#  after the selection.
-#
-       mvi     SCSISEQ,0x48                    # ENSELO|ENAUTOATNO
-
-#  Wait for successful arbitration.  The AIC-7770 documentation says
-#  that SELINGO indicates successful arbitration, and that it should
-#  be used to look for SELDO.  However, if the sequencer is paused at
-#  just the right time - a parallel fsck(8) on two drives did it for
-#  me - then SELINGO can flip back to false before we've seen it.  This
-#  makes the sequencer sit in the arbitration loop forever.  This is
-#  Not Good.
-#
-#  Therefore, I've added a check in the arbitration loop for SELDO
-#  too.  This could arguably be made a critical section by disabling
-#  pauses, but I don't want to make a potentially infinite loop a CS.
-#  I suppose you could fold it into the select loop, too, but since
-#  I've been hunting this bug for four days it's kinda like a trophy.
-#
-arbitrate:
-       test    SSTAT0,0x40     jnz *select     # SELDO
-       test    SSTAT0,0x10     jz arbitrate    # SELINGO
-
-#  Wait for a successful selection.  If the hardware selection
-#  timer goes off, then the driver gets the interrupt, so we don't
-#  need to worry about it.
-#
-select:
-       test    SSTAT0,0x40     jz select       # SELDO
-       jmp     *select
-
-#  Reselection is being initiated by a target - we've seen the BSY
-#  line driven active, and we didn't do it!  Enable the reselection
-#  hardware, and wait for it to finish.  Make a note that we've been
-#  reselected, but haven't seen an IDENTIFY message from the target
-#  yet.
-#
-reselect:
-       mvi     SCSISEQ,0x10                    # ENRSELI
-
-reselect1:
-       test    SSTAT0,0x20     jz reselect1    # SELDI
-       mov     SELID           call initialize
-
-       mvi     RESELECT,0x80                   # reselected, no IDENTIFY
-
-#  After the [re]selection, make sure that the [re]selection enable
-#  bit is off.  This chip is flaky enough without extra things
-#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
-#  using it shortly.
-#
-*select:
-       clr     SCSISEQ
-       mvi     CLRSINT1,0x8                    # CLRBUSFREE
-
-#  Main loop for information transfer phases.  If BSY is false, then
-#  we have a bus free condition, expected or not.  Otherwise, wait
-#  for the target to assert REQ before checking MSG, C/D and I/O
-#  for the bus phase.
-#
-#  We can't simply look at the values of SCSISIGI here (if we want
-#  to do synchronous data transfer), because the target won't assert
-#  REQ if it's already sent us some data that we haven't acknowledged
-#  yet.
-#
-ITloop:
-       test    SSTAT1,0x8      jnz p_busfree   # BUSFREE
-       test    SSTAT1,0x1      jz ITloop       # REQINIT
-
-       and     A,0xe0,SCSISIGI                 # CDI|IOI|MSGI
-
-       cmp     ALLZEROS,A      je p_dataout
-       cmp     A,0x40          je p_datain
-       cmp     A,0x80          je p_command
-       cmp     A,0xc0          je p_status
-       cmp     A,0xa0          je p_mesgout
-       cmp     A,0xe0          je p_mesgin
-
-       mvi     INTSTAT,SIGNAL_0                # unknown - signal driver
-
-p_dataout:
-       mvi     0               call scsisig    # !CDO|!IOO|!MSGO
-       call    assert
-       call    sg_load
-
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+23     call bcopy
-
-       mvi     A,3
-       mvi     DINDEX,STCNT
-       mvi     SCBARRAY+23     call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+19     call bcopy
-
-       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
-                                               #   DIRECTION|FIFORESET
-
-#  After a DMA finishes, save the final transfer pointer and count
-#  back into the SCB, in case a device disconnects in the middle of
-#  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
-#  it's a reflection of how many bytes were transferred on the SCSI
-#  (as opposed to the host) bus.
-#
-       mvi     A,3
-       mvi     DINDEX,SCBARRAY+23
-       mvi     STCNT           call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,SCBARRAY+19
-       mvi     SHADDR          call bcopy
-
-       call    sg_advance
-       mov     SCBARRAY+18,SG_COUNT            # residual S/G count
-
-       jmp     ITloop
-
-p_datain:
-       mvi     0x40            call scsisig    # !CDO|IOO|!MSGO
-       call    assert
-       call    sg_load
-
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+23     call bcopy
-
-       mvi     A,3
-       mvi     DINDEX,STCNT
-       mvi     SCBARRAY+23     call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+19     call bcopy
-
-       mvi     0x39            call dma        # SCSIEN|SDMAEN|HDMAEN|
-                                               #   !DIRECTION|FIFORESET
-       mvi     A,3
-       mvi     DINDEX,SCBARRAY+23
-       mvi     STCNT           call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,SCBARRAY+19
-       mvi     SHADDR          call bcopy
-
-       call    sg_advance
-       mov     SCBARRAY+18,SG_COUNT            # residual S/G count
-
-       jmp     ITloop
-
-#  Command phase.  Set up the DMA registers and let 'er rip - the
-#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
-#  so we can copy those three bytes directly into HCNT.
-#
-p_command:
-       mvi     0x80            call scsisig    # CDO|!IOO|!MSGO
-       call    assert
-
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+11     call bcopy
-
-       mvi     A,3
-       mvi     DINDEX,STCNT
-       mvi     SCBARRAY+11     call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+7      call bcopy
-
-       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
-                                               #   DIRECTION|FIFORESET
-       jmp     ITloop
-
-#  Status phase.  Wait for the data byte to appear, then read it
-#  and store it into the SCB.
-#
-p_status:
-       mvi     0xc0            call scsisig    # CDO|IOO|!MSGO
-
-       mvi     SCBARRAY+14     call inb
-       jmp     ITloop
-
-#  Message out phase.  If there is no active message, but the target
-#  took us into this phase anyway, build a no-op message and send it.
-#
-p_mesgout:
-       mvi     0xa0            call scsisig    # CDO|!IOO|MSGO
-       mvi     0x8             call mk_mesg    # build NOP message
-
-#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
-#  SXFRCTL0 (SPIOEN) is already on.
-#
-       mvi     SINDEX,MSG_START+0
-       mov     DINDEX,MSG_LEN
-       clr     A
-
-#  When target asks for a byte, drop ATN if it's the last one in
-#  the message.  Otherwise, keep going until the message is exhausted.
-#  (We can't use outb for this since it wants the input in SINDEX.)
-#
-#  Keep an eye out for a phase change, in case the target issues
-#  a MESSAGE REJECT.
-#
-p_mesgout2:
-       test    SSTAT0,0x2      jz p_mesgout2   # SPIORDY
-       test    SSTAT1,0x10     jnz p_mesgout6  # PHASEMIS
-
-       cmp     DINDEX,1        jne p_mesgout3  # last byte?
-       mvi     CLRSINT1,0x40                   # CLRATNO - drop ATN
-
-#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
-#  send ACKs in automatic PIO or DMA mode unless you make sure that the
-#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
-#  behaviour is completely undocumented and caused me several days of
-#  grief.
-#
-#  After plugging in different drives to test with and using a longer
-#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
-#  especially when transferring >1 byte.  It seems to be much more stable
-#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
-#  polled for transfer completion - for both output _and_ input.  The
-#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
-#  is accessed (like the documentation says it does), and that on a longer
-#  cable run, the sequencer code was fast enough to loop back and see
-#  an SPIORDY that hadn't dropped yet.
-#
-p_mesgout3:
-       call    one_stcnt
-       mov     SCSIDATL,SINDIR
-
-p_mesgout4:
-       test    SSTAT0,0x4      jz p_mesgout4   # SDONE
-       dec     DINDEX
-       inc     A
-       cmp     MSG_LEN,A       jne p_mesgout2
-
-#  If the next bus phase after ATN drops is a message out, it means
-#  that the target is requesting that the last message(s) be resent.
-#
-p_mesgout5:
-       test    SSTAT1,0x8      jnz p_mesgout6  # BUSFREE
-       test    SSTAT1,0x1      jz p_mesgout5   # REQINIT
-
-       and     A,0xe0,SCSISIGI                 # CDI|IOI|MSGI
-       cmp     A,0xa0          jne p_mesgout6
-       mvi     0x10            call scsisig    # ATNO - re-assert ATN
-
-       jmp     ITloop
-
-p_mesgout6:
-       mvi     CLRSINT1,0x40                   # CLRATNO - in case of PHASEMIS
-       clr     MSG_FLAGS                       # no active msg
-       jmp     ITloop
-
-#  Message in phase.  Bytes are read using Automatic PIO mode, but not
-#  using inb.  This alleviates a race condition, namely that if ATN had
-#  to be asserted under Automatic PIO mode, it had to beat the SCSI
-#  circuitry sending an ACK to the target.  This showed up under heavy
-#  loads and really confused things, since ABORT commands wouldn't be
-#  seen by the drive after an IDENTIFY message in until it had changed
-#  to a data I/O phase.
-#
-p_mesgin:
-       mvi     0xe0            call scsisig    # CDO|IOO|MSGO
-       mvi     A               call inb_first  # read the 1st message byte
-       mvi     REJBYTE,A                       # save it for the driver
-
-       cmp     ALLZEROS,A      jne p_mesgin1
-
-#  We got a "command complete" message, so put the SCB pointer
-#  into the Queue Out, and trigger a completion interrupt.
-#
-       mov     QOUTFIFO,SCBPTR
-       mvi     INTSTAT,0x2                     # CMDCMPLT
-       jmp     p_mesgin_done
-
-#  Is it an extended message?  We only support the synchronous data
-#  transfer request message, which will probably be in response to
-#  an SDTR message out from us.  If it's not an SDTR, reject it -
-#  apparently this can be done after any message in byte, according
-#  to the SCSI-2 spec.
-#
-#  XXX - we should really reject this if we didn't initiate the SDTR
-#       negotiation; this may cause problems with unusual devices.
-#
-p_mesgin1:
-       cmp     A,1             jne p_mesgin2   # extended message code?
-       
-       mvi     A               call inb_next
-       cmp     A,3             jne p_mesginN   # extended mesg length = 3
-       mvi     A               call inb_next
-       cmp     A,1             jne p_mesginN   # SDTR code
-
-       mvi     ARG_1           call inb_next   # xfer period
-       mvi     ARG_2           call inb_next   # REQ/ACK offset
-       mvi     INTSTAT,SIGNAL_4                # call driver to convert
-
-       call    ndx_sdtr                        # index sync config for target
-       mov     DINDEX,SINDEX
-       mov     DINDIR,RETURN_1                 # save returned value
-
-       not     A                               # turn off "need sdtr" flag
-       and     NEEDSDTR,A
-
-#  Even though the SCSI-2 specification says that a device responding
-#  to our SDTR message should honor our parameters for transmitting
-#  to us, it doesn't seem to work too well in real life.  In particular,
-#  a lot of CD-ROM and tape units don't function: try using the SDTR
-#  parameters the device sent us for both transmitting and receiving.
-#
-       mov     SCSIRATE,RETURN_1
-       jmp     p_mesgin_done
-
-#  Is it a disconnect message?  Set a flag in the SCB to remind us
-#  and await the bus going free.
-#
-p_mesgin2:
-       cmp     A,4             jne p_mesgin3   # disconnect code?
-
-       or      SCBARRAY+0,0x4                  # set "disconnected" bit
-       jmp     p_mesgin_done
-
-#  Save data pointers message?  Copy working values into the SCB,
-#  usually in preparation for a disconnect.
-#
-p_mesgin3:
-       cmp     A,2             jne p_mesgin4   # save data pointers code?
-
-       call    sg_ram2scb
-       jmp     p_mesgin_done
-
-#  Restore pointers message?  Data pointers are recopied from the
-#  SCB anyway at the start of any DMA operation, so the only thing
-#  to copy is the scatter-gather values.
-#
-p_mesgin4:
-       cmp     A,3             jne p_mesgin5   # restore pointers code?
-
-       call    sg_scb2ram
-       jmp     p_mesgin_done
-
-#  Identify message?  For a reconnecting target, this tells us the lun
-#  that the reconnection is for - find the correct SCB and switch to it,
-#  clearing the "disconnected" bit so we don't "find" it by accident later.
-#
-p_mesgin5:
-       test    A,0x80          jz p_mesgin6    # identify message?
-
-       test    A,0x78          jnz p_mesginN   # !DiscPriv|!LUNTAR|!Reserved
-
-       mov     A               call findSCB    # switch to correct SCB
-
-#  If a active message is present after calling findSCB, then either it
-#  or the driver is trying to abort the command.  Either way, something
-#  untoward has happened and we should just leave it alone.
-#
-       test    MSG_FLAGS,0x80  jnz p_mesgin_done
-
-       xor     SCBARRAY+0,0x4                  # clear disconnect bit in SCB
-       mvi     RESELECT,0xc0                   # make note of IDENTIFY
-
-       call    sg_scb2ram                      # implied restore pointers
-                                               #   required on reselect
-       jmp     p_mesgin_done
-
-#  Message reject?  If we have an outstanding SDTR negotiation, assume
-#  that it's a response from the target selecting asynchronous transfer,
-#  otherwise just ignore it since we have no clue what it pertains to.
-#
-#  XXX - I don't have a device that responds this way.  Does this code
-#       actually work?
-#
-p_mesgin6:
-       cmp     A,7             jne p_mesgin7   # message reject code?
-
-       and     FUNCTION1,0x70,SCSIID           # outstanding SDTR message?
-       mov     A,FUNCTION1
-       test    NEEDSDTR,A      jz p_mesgin_done  # no - ignore rejection
-
-       call    ndx_sdtr                        # note use of asynch xfer
-       mov     DINDEX,SINDEX
-       clr     DINDIR
-
-       not     A                               # turn off "active sdtr" flag
-       and     NEEDSDTR,A
-
-       clr     SCSIRATE                        # select asynch xfer
-       jmp     p_mesgin_done
-
-#  [ ADD MORE MESSAGE HANDLING HERE ]
-#
-p_mesgin7:
-
-#  We have no idea what this message in is, and there's no way
-#  to pass it up to the kernel, so we issue a message reject and
-#  hope for the best.  Since we're now using manual PIO mode to
-#  read in the message, there should no longer be a race condition
-#  present when we assert ATN.  In any case, rejection should be a
-#  rare occurrence - signal the driver when it happens.
-#
-p_mesginN:
-       or      SINDEX,0x10,SIGSTATE            # turn on ATNO
-       call    scsisig
-       mvi     INTSTAT,SIGNAL_1                # let driver know
-
-       mvi     0x7             call mk_mesg    # MESSAGE REJECT message
-
-p_mesgin_done:
-       call    inb_last                        # ack & turn auto PIO back on
-       jmp     ITloop
-
-#  Bus free phase.  It might be useful to interrupt the device
-#  driver if we aren't expecting this.  For now, make sure that
-#  ATN isn't being asserted and look for a new command.
-#
-p_busfree:
-       mvi     CLRSINT1,0x40                   # CLRATNO
-       clr     SIGSTATE
-       jmp     start
-
-#  Bcopy: number of bytes to transfer should be in A, DINDEX should
-#  contain the destination address, and SINDEX should contain the
-#  source address.  All input parameters are trashed on return.
-#
-bcopy:
-       mov     DINDIR,SINDIR
-       dec     A
-       cmp     ALLZEROS,A      jne bcopy
-       ret
-
-#  Locking the driver out, build a one-byte message passed in SINDEX
-#  if there is no active message already.  SINDEX is returned intact.
-#
-mk_mesg:
-       mvi     SEQCTL,0x40                     # PAUSEDIS
-       test    MSG_FLAGS,0x80  jnz mk_mesg1    # active message?
-
-       mvi     MSG_FLAGS,0x80                  # if not, there is now
-       mvi     MSG_LEN,1                       # length = 1
-       mov     MSG_START+0,SINDEX              # 1-byte message
-
-mk_mesg1:
-       clr     SEQCTL                          # !PAUSEDIS
-       ret
-
-#  Input byte in Automatic PIO mode.  The address to store the byte
-#  in should be in SINDEX.  DINDEX will be used by this routine.
-#
-inb:
-       test    SSTAT0,0x2      jz inb          # SPIORDY
-       mov     DINDEX,SINDEX
-       call    one_stcnt                       # xfer one byte
-       mov     DINDIR,SCSIDATL
-inb1:
-       test    SSTAT0,0x4      jz inb1         # SDONE - wait to "finish"
-       ret
-
-#  Carefully read data in Automatic PIO mode.  I first tried this using
-#  Manual PIO mode, but it gave me continual underrun errors, probably
-#  indicating that I did something wrong, but I feel more secure leaving
-#  Automatic PIO on all the time.
-#
-#  According to Adaptec's documentation, an ACK is not sent on input from
-#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
-#  latched (the usual way), then read the data byte directly off the bus
-#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
-#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
-#  spec guarantees that the target will hold the data byte on the bus until
-#  we send our ACK.
-#
-#  The assumption here is that these are called in a particular sequence,
-#  and that REQ is already set when inb_first is called.  inb_{first,next}
-#  use the same calling convention as inb.
-#
-inb_first:
-       mov     DINDEX,SINDEX
-       mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
-
-inb_next:
-       mov     DINDEX,SINDEX                   # save SINDEX
-
-       call    one_stcnt                       # xfer one byte
-       mov     NONE,SCSIDATL                   # dummy read from latch to ACK
-inb_next1:
-       test    SSTAT0,0x4      jz inb_next1    # SDONE
-inb_next2:
-       test    SSTAT0,0x2      jz inb_next2    # SPIORDY - wait for next byte
-       mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
-
-inb_last:
-       call    one_stcnt                       # ACK with dummy read
-       mov     NONE,SCSIDATL
-inb_last1:
-       test    SSTAT0,0x4      jz inb_last1    # wait for completion
-       ret
-
-#  Output byte in Automatic PIO mode.  The byte to output should be
-#  in SINDEX.  If DROPATN's high bit is set, then ATN will be dropped
-#  before the byte is output.
-#
-outb:
-       test    SSTAT0,0x2      jz outb         # SPIORDY
-       call    one_stcnt                       # xfer one byte
-
-       test    DROPATN,0x80    jz outb1
-       mvi     CLRSINT1,0x40                   # CLRATNO
-       clr     DROPATN
-outb1:
-       mov     SCSIDATL,SINDEX
-outb2:
-       test    SSTAT0,0x4      jz outb2        # SDONE
-       ret
-
-#  Write the value "1" into the STCNT registers, for Automatic PIO
-#  transfers.
-#
-one_stcnt:
-       clr     STCNT+2
-       clr     STCNT+1
-       mvi     STCNT+0,1       ret
-
-#  DMA data transfer.  HADDR and HCNT must be loaded first, and
-#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
-#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
-#  during initialization.
-#
-dma:
-       mov     DFCNTRL,SINDEX
-dma1:
-dma2:
-       test    SSTAT0,0x1      jnz dma3        # DMADONE
-       test    SSTAT1,0x10     jz dma1         # PHASEMIS, ie. underrun
-
-#  We will be "done" DMAing when the transfer count goes to zero, or
-#  the target changes the phase (in light of this, it makes sense that
-#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
-#  doing a SCSI->Host transfer, flush the data FIFO.
-#
-dma3:
-       test    SINDEX,0x4      jnz dma5        # DIRECTION
-       and     SINDEX,0xfe                     # mask out FIFORESET
-       or      DFCNTRL,0x2,SINDEX              # FIFOFLUSH
-dma4:
-       test    DFCNTRL,0x2     jnz dma4        # FIFOFLUSHACK
-
-#  Now shut the DMA enables off, and copy STCNT (ie. the underrun
-#  amount, if any) to the SCB registers; SG_COUNT will get copied to
-#  the SCB's residual S/G count field after sg_advance is called.  Make
-#  sure that the DMA enables are actually off first lest we get an ILLSADDR.
-#
-dma5:
-       clr     DFCNTRL                         # disable DMA
-dma6:
-       test    DFCNTRL,0x38    jnz dma6        # SCSIENACK|SDMAENACK|HDMAENACK
-
-       mvi     A,3
-       mvi     DINDEX,SCBARRAY+15
-       mvi     STCNT           call bcopy
-
-       ret
-
-#  Common SCSI initialization for selection and reselection.  Expects
-#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
-#  contents are stomped on return.
-#
-initialize:
-       clr     SBLKCTL                         # channel A, !wide
-       and     SCSIID,0xf0,SINDEX              # target ID
-       and     A,0x7,SCSICONF                  # SCSI_ID_A[210]
-       or      SCSIID,A
-
-#  Esundry initialization.
-#
-       clr     DROPATN
-       clr     SIGSTATE
-
-#  Turn on Automatic PIO mode now, before we expect to see an REQ
-#  from the target.  It shouldn't hurt anything to leave it on.  Set
-#  CLRCHN here before the target has entered a data transfer mode -
-#  with synchronous SCSI, if you do it later, you blow away some
-#  data in the SCSI FIFO that the target has already sent to you.
-#
-       mvi     SXFRCTL0,0xa                    # SPIOEN|CLRCHN
-
-#  Set SCSI bus parity checking and the selection timeout value,
-#  and enable the hardware selection timer.  Set the SELTO interrupt
-#  to signal the driver.
-#
-       and     A,0x38,SCSICONF                 # PARITY_ENB_A|SEL_TIM_A[10]
-       or      SXFRCTL1,0x4,A                  # ENSTIMER
-       mvi     SIMODE1,0x84                    # ENSELTIMO|ENSCSIPERR
-       
-#  Initialize scatter-gather pointers by setting up the working copy
-#  in scratch RAM.
-#
-       call    sg_scb2ram
-
-#  Initialize SCSIRATE with the appropriate value for this target.
-#
-       call    ndx_sdtr
-       mov     SCSIRATE,SINDIR
-       ret
-
-#  Assert that if we've been reselected, then we've seen an IDENTIFY
-#  message.
-#
-assert:
-       test    RESELECT,0x80   jz assert1      # reselected?
-       test    RESELECT,0x40   jnz assert1     # seen IDENTIFY?
-
-       mvi     INTSTAT,SIGNAL_2                # no - cause a kernel panic
-
-assert1:
-       ret
-
-#  Find out if disconnection is ok from the information the BIOS has left
-#  us.  The target ID should be in the upper four bits of SINDEX; A will
-#  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
-#  on exit.
-#
-#  This is the only place the target ID is limited to three bits, so we
-#  can use the FUNCTION1 register.
-#
-disconnect:
-       and     FUNCTION1,0x70,SINDEX           # strip off extra just in case
-       mov     A,FUNCTION1
-       test    DISC_DSB_A,A    jz disconnect1  # bit nonzero if DISabled
-
-       clr     A               ret
-disconnect1:
-       mvi     A,0x40          ret
-
-#  Locate the SCB matching the target ID in SELID and the lun in the lower
-#  three bits of SINDEX, and switch the SCB to it.  Have the kernel print
-#  a warning message if it can't be found - this seems to happen occasionally
-#  under high loads.  Also, if not found, generate an ABORT message to the
-#  target.
-#
-findSCB:
-       and     A,0x7,SINDEX                    # lun in lower three bits
-       or      A,A,SELID                       # can I do this?
-       and     A,0xf7                          # only channel A implemented
-
-       clr     SINDEX
-
-findSCB1:
-       mov     SCBPTR,SINDEX                   # switch to new SCB
-       cmp     SCBARRAY+1,A    jne findSCB2    # target ID/channel/lun match?
-       test    SCBARRAY+0,0x4  jz findSCB2     # should be disconnected
-
-       ret
-
-findSCB2:
-       inc     SINDEX
-       cmp     SINDEX,MAXSCB   jne findSCB1
-
-       mvi     INTSTAT,SIGNAL_3                # not found - signal kernel
-       mvi     0x6             call mk_mesg    # ABORT message
-
-       or      SINDEX,0x10,SIGSTATE            # assert ATNO
-       call    scsisig
-       ret
-
-#  Make a working copy of the scatter-gather parameters in the SCB.
-#
-sg_scb2ram:
-       mov     SG_COUNT,SCBARRAY+2
-
-       mvi     A,4
-       mvi     DINDEX,SG_NEXT
-       mvi     SCBARRAY+3      call bcopy
-
-       mvi     SG_NOLOAD,0x80
-       test    SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g?
-       clr     SG_NOLOAD
-
-sg_scb2ram1:
-       ret
-
-#  Copying RAM values back to SCB, for Save Data Pointers message.
-#
-sg_ram2scb:
-       mov     SCBARRAY+2,SG_COUNT
-
-       mvi     A,4
-       mvi     DINDEX,SCBARRAY+3
-       mvi     SG_NEXT         call bcopy
-
-       and     SCBARRAY+0,0xef,SCBARRAY+0
-       test    SG_NOLOAD,0x80  jz sg_ram2scb1  # reload s/g?
-       or      SCBARRAY+0,0x10
-
-sg_ram2scb1:
-       ret
-
-#  Load a struct scatter if needed and set up the data address and
-#  length.  If the working value of the SG count is nonzero, then
-#  we need to load a new set of values.
-#
-#  This, like the above DMA, assumes a little-endian host data storage.
-#
-sg_load:
-       test    SG_COUNT,0xff   jz sg_load3     # SG being used?
-       test    SG_NOLOAD,0x80  jnz sg_load3    # don't reload s/g?
-
-       clr     HCNT+2
-       clr     HCNT+1
-       mvi     HCNT+0,SG_SIZEOF
-
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SG_NEXT         call bcopy
-
-       mvi     DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
-
-#  Wait for DMA from host memory to data FIFO to complete, then disable
-#  DMA and wait for it to acknowledge that it's off.
-#
-sg_load1:
-       test    DFSTATUS,0x8    jz sg_load1     # HDONE
-
-       clr     DFCNTRL                         # disable DMA
-sg_load2:
-       test    DFCNTRL,0x8     jnz sg_load2    # HDMAENACK
-
-#  Copy data from FIFO into SCB data pointer and data count.  This assumes
-#  that the struct scatterlist has this structure (this and sizeof(struct
-#  scatterlist) == 12 are asserted in aha274x.c):
-#
-#      struct scatterlist {
-#              char *address;          /* four bytes, little-endian order */
-#              ...                     /* four bytes, ignored */
-#              unsigned short length;  /* two bytes, little-endian order */
-#      }
-#
-       mov     SCBARRAY+19,DFDAT               # new data address
-       mov     SCBARRAY+20,DFDAT
-       mov     SCBARRAY+21,DFDAT
-       mov     SCBARRAY+22,DFDAT
-
-       mov     NONE,DFDAT                      # throw away four bytes
-       mov     NONE,DFDAT
-       mov     NONE,DFDAT
-       mov     NONE,DFDAT
-
-       mov     SCBARRAY+23,DFDAT
-       mov     SCBARRAY+24,DFDAT
-       clr     SCBARRAY+25
-
-sg_load3:
-       ret
-
-#  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
-#  and the SCSI transfer count is zero (note that this should be called
-#  right after a DMA finishes), then move the working copies of the SG
-#  pointer/length along.  If the SCSI transfer count is not zero, then
-#  presumably the target is disconnecting - do not reload the SG values
-#  next time.
-#
-sg_advance:
-       test    SG_COUNT,0xff   jz sg_advance2  # s/g enabled?
-
-       test    STCNT+0,0xff    jnz sg_advance1 # SCSI transfer count nonzero?
-       test    STCNT+1,0xff    jnz sg_advance1
-       test    STCNT+2,0xff    jnz sg_advance1
-
-       clr     SG_NOLOAD                       # reload s/g next time
-       dec     SG_COUNT                        # one less segment to go
-
-       clr     A                               # add sizeof(struct scatter)
-       add     SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
-       adc     SG_NEXT+1,A,SG_NEXT+1
-       adc     SG_NEXT+2,A,SG_NEXT+2
-       adc     SG_NEXT+3,A,SG_NEXT+3
-
-       ret
-
-sg_advance1:
-       mvi     SG_NOLOAD,0x80                  # don't reload s/g next time
-sg_advance2:
-       ret
-
-#  Add the array base SYNCNEG to the target offset (the target address
-#  is in SCSIID), and return the result in SINDEX.  The accumulator
-#  contains the 3->8 decoding of the target ID on return.
-#
-ndx_sdtr:
-       shr     A,SCSIID,4
-       and     A,0x7
-       add     SINDEX,SYNCNEG,A
-
-       and     FUNCTION1,0x70,SCSIID           # 3-bit target address decode
-       mov     A,FUNCTION1     ret
-
-#  If we need to negotiate transfer parameters, build the SDTR message
-#  starting at the address passed in SINDEX.  DINDEX is modified on return.
-#
-mk_sdtr:
-       mov     DINDEX,SINDEX                   # save SINDEX
-
-       call    ndx_sdtr
-       test    NEEDSDTR,A      jnz mk_sdtr1    # do we need negotiation?
-       ret
-
-mk_sdtr1:
-       mvi     DINDIR,1                        # extended message
-       mvi     DINDIR,3                        # extended message length = 3
-       mvi     DINDIR,1                        # SDTR code
-       mvi     DINDIR,25                       # REQ/ACK transfer period
-       mvi     DINDIR,15                       # REQ/ACK offset
-
-       add     MSG_LEN,-MSG_START+0,DINDEX     # update message length
-       ret
-
-#  Set SCSI bus control signal state.  This also saves the last-written
-#  value into a location where the higher-level driver can read it - if
-#  it has to send an ABORT or RESET message, then it needs to know this
-#  so it can assert ATN without upsetting SCSISIGO.  The new value is
-#  expected in SINDEX.  Change the actual state last to avoid contention
-#  from the driver.
-#
-scsisig:
-       mov     SIGSTATE,SINDEX
-       mov     SCSISIGO,SINDEX ret
diff --git a/drivers/scsi/aha274x_seq.h b/drivers/scsi/aha274x_seq.h
deleted file mode 100644 (file)
index f04f6eb..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-#define AHA274X_SEQ_VERSION "1.28"
-       0x04, 0x03, 0x12, 0x1a,
-       0x07, 0x9c, 0x00, 0x1e,
-       0xff, 0x9b, 0x90, 0x02,
-       0x00, 0xa1, 0xe6, 0x16,
-       0xff, 0x6a, 0x50, 0x02,
-       0xff, 0x6a, 0x34, 0x02,
-       0x00, 0xa1, 0xf8, 0x16,
-       0x07, 0xa1, 0x65, 0x02,
-       0x00, 0x65, 0x65, 0x00,
-       0x80, 0x65, 0xb5, 0x16,
-       0xff, 0x65, 0x64, 0x02,
-       0x00, 0x37, 0x0d, 0x18,
-       0x38, 0x6a, 0x47, 0x17,
-       0x48, 0x6a, 0x00, 0x00,
-       0x40, 0x0b, 0x16, 0x1a,
-       0x10, 0x0b, 0x0e, 0x1e,
-       0x40, 0x0b, 0x10, 0x1e,
-       0x00, 0x65, 0x16, 0x10,
-       0x10, 0x6a, 0x00, 0x00,
-       0x20, 0x0b, 0x13, 0x1e,
-       0x00, 0x19, 0xe6, 0x16,
-       0x80, 0x6a, 0x34, 0x00,
-       0xff, 0x6a, 0x00, 0x02,
-       0x08, 0x6a, 0x0c, 0x00,
-       0x08, 0x0c, 0xae, 0x1a,
-       0x01, 0x0c, 0x18, 0x1e,
-       0xe0, 0x03, 0x64, 0x02,
-       0x00, 0x6a, 0x22, 0x1c,
-       0x40, 0x64, 0x38, 0x1c,
-       0x80, 0x64, 0x4e, 0x1c,
-       0xc0, 0x64, 0x5b, 0x1c,
-       0xa0, 0x64, 0x5e, 0x1c,
-       0xe0, 0x64, 0x76, 0x1c,
-       0x01, 0x6a, 0x91, 0x00,
-       0x00, 0x6a, 0x52, 0x17,
-       0x00, 0x65, 0xf4, 0x16,
-       0x00, 0x65, 0x1c, 0x17,
-       0x03, 0x6a, 0x64, 0x00,
-       0x8c, 0x6a, 0x66, 0x00,
-       0xb7, 0x6a, 0xb1, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0x08, 0x6a, 0x66, 0x00,
-       0xb7, 0x6a, 0xb1, 0x16,
-       0x04, 0x6a, 0x64, 0x00,
-       0x88, 0x6a, 0x66, 0x00,
-       0xb3, 0x6a, 0xb1, 0x16,
-       0x3d, 0x6a, 0xd9, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0xb7, 0x6a, 0x66, 0x00,
-       0x08, 0x6a, 0xb1, 0x16,
-       0x04, 0x6a, 0x64, 0x00,
-       0xb3, 0x6a, 0x66, 0x00,
-       0x14, 0x6a, 0xb1, 0x16,
-       0x00, 0x65, 0x34, 0x17,
-       0xff, 0x51, 0xb2, 0x02,
-       0x00, 0x65, 0x18, 0x10,
-       0x40, 0x6a, 0x52, 0x17,
-       0x00, 0x65, 0xf4, 0x16,
-       0x00, 0x65, 0x1c, 0x17,
-       0x03, 0x6a, 0x64, 0x00,
-       0x8c, 0x6a, 0x66, 0x00,
-       0xb7, 0x6a, 0xb1, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0x08, 0x6a, 0x66, 0x00,
-       0xb7, 0x6a, 0xb1, 0x16,
-       0x04, 0x6a, 0x64, 0x00,
-       0x88, 0x6a, 0x66, 0x00,
-       0xb3, 0x6a, 0xb1, 0x16,
-       0x39, 0x6a, 0xd9, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0xb7, 0x6a, 0x66, 0x00,
-       0x08, 0x6a, 0xb1, 0x16,
-       0x04, 0x6a, 0x64, 0x00,
-       0xb3, 0x6a, 0x66, 0x00,
-       0x14, 0x6a, 0xb1, 0x16,
-       0x00, 0x65, 0x34, 0x17,
-       0xff, 0x51, 0xb2, 0x02,
-       0x00, 0x65, 0x18, 0x10,
-       0x80, 0x6a, 0x52, 0x17,
-       0x00, 0x65, 0xf4, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0x8c, 0x6a, 0x66, 0x00,
-       0xab, 0x6a, 0xb1, 0x16,
-       0x03, 0x6a, 0x64, 0x00,
-       0x08, 0x6a, 0x66, 0x00,
-       0xab, 0x6a, 0xb1, 0x16,
-       0x04, 0x6a, 0x64, 0x00,
-       0x88, 0x6a, 0x66, 0x00,
-       0xa7, 0x6a, 0xb1, 0x16,
-       0x3d, 0x6a, 0xd9, 0x16,
-       0x00, 0x65, 0x18, 0x10,
-       0xc0, 0x6a, 0x52, 0x17,
-       0xae, 0x6a, 0xbc, 0x16,
-       0x00, 0x65, 0x18, 0x10,
-       0xa0, 0x6a, 0x52, 0x17,
-       0x08, 0x6a, 0xb5, 0x16,
-       0x37, 0x6a, 0x65, 0x00,
-       0xff, 0x36, 0x66, 0x02,
-       0xff, 0x6a, 0x64, 0x02,
-       0x02, 0x0b, 0x63, 0x1e,
-       0x10, 0x0c, 0x73, 0x1a,
-       0x01, 0x66, 0x67, 0x18,
-       0x40, 0x6a, 0x0c, 0x00,
-       0x00, 0x65, 0xd6, 0x16,
-       0xff, 0x6c, 0x06, 0x02,
-       0x04, 0x0b, 0x69, 0x1e,
-       0xff, 0x66, 0x66, 0x06,
-       0x01, 0x64, 0x64, 0x06,
-       0x00, 0x36, 0x63, 0x18,
-       0x08, 0x0c, 0x73, 0x1a,
-       0x01, 0x0c, 0x6d, 0x1e,
-       0xe0, 0x03, 0x64, 0x02,
-       0xa0, 0x64, 0x73, 0x18,
-       0x10, 0x6a, 0x52, 0x17,
-       0x00, 0x65, 0x18, 0x10,
-       0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x6a, 0x35, 0x02,
-       0x00, 0x65, 0x18, 0x10,
-       0xe0, 0x6a, 0x52, 0x17,
-       0x64, 0x6a, 0xc2, 0x16,
-       0x00, 0x6a, 0x31, 0x00,
-       0x00, 0x6a, 0x7d, 0x18,
-       0xff, 0x90, 0x9d, 0x02,
-       0x02, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0xac, 0x10,
-       0x01, 0x64, 0x8c, 0x18,
-       0x64, 0x6a, 0xc4, 0x16,
-       0x03, 0x64, 0xa8, 0x18,
-       0x64, 0x6a, 0xc4, 0x16,
-       0x01, 0x64, 0xa8, 0x18,
-       0x4c, 0x6a, 0xc4, 0x16,
-       0x4d, 0x6a, 0xc4, 0x16,
-       0x41, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x42, 0x17,
-       0xff, 0x65, 0x66, 0x02,
-       0xff, 0x4c, 0x6d, 0x02,
-       0xff, 0x64, 0x64, 0x04,
-       0x00, 0x4f, 0x4f, 0x02,
-       0xff, 0x4c, 0x04, 0x02,
-       0x00, 0x65, 0xac, 0x10,
-       0x04, 0x64, 0x8f, 0x18,
-       0x04, 0xa0, 0xa0, 0x00,
-       0x00, 0x65, 0xac, 0x10,
-       0x02, 0x64, 0x92, 0x18,
-       0x00, 0x65, 0x14, 0x17,
-       0x00, 0x65, 0xac, 0x10,
-       0x03, 0x64, 0x95, 0x18,
-       0x00, 0x65, 0x0c, 0x17,
-       0x00, 0x65, 0xac, 0x10,
-       0x80, 0x64, 0x9d, 0x1e,
-       0x78, 0x64, 0xa8, 0x1a,
-       0x00, 0x64, 0xfd, 0x16,
-       0x80, 0x35, 0xac, 0x1a,
-       0x04, 0xa0, 0xa0, 0x04,
-       0xc0, 0x6a, 0x34, 0x00,
-       0x00, 0x65, 0x0c, 0x17,
-       0x00, 0x65, 0xac, 0x10,
-       0x07, 0x64, 0xa8, 0x18,
-       0x70, 0x05, 0x6e, 0x02,
-       0xff, 0x6e, 0x64, 0x02,
-       0x00, 0x4f, 0xac, 0x1e,
-       0x00, 0x65, 0x42, 0x17,
-       0xff, 0x65, 0x66, 0x02,
-       0xff, 0x6a, 0x6d, 0x02,
-       0xff, 0x64, 0x64, 0x04,
-       0x00, 0x4f, 0x4f, 0x02,
-       0xff, 0x6a, 0x04, 0x02,
-       0x00, 0x65, 0xac, 0x10,
-       0x10, 0x4e, 0x65, 0x00,
-       0x00, 0x65, 0x52, 0x17,
-       0x11, 0x6a, 0x91, 0x00,
-       0x07, 0x6a, 0xb5, 0x16,
-       0x00, 0x65, 0xca, 0x16,
-       0x00, 0x65, 0x18, 0x10,
-       0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x6a, 0x4e, 0x02,
-       0x00, 0x65, 0x00, 0x10,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x64, 0x64, 0x06,
-       0x00, 0x6a, 0xb1, 0x18,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x40, 0x6a, 0x60, 0x00,
-       0x80, 0x35, 0xba, 0x1a,
-       0x80, 0x6a, 0x35, 0x00,
-       0x01, 0x6a, 0x36, 0x00,
-       0xff, 0x65, 0x37, 0x02,
-       0xff, 0x6a, 0x60, 0x02,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x02, 0x0b, 0xbc, 0x1e,
-       0xff, 0x65, 0x66, 0x02,
-       0x00, 0x65, 0xd6, 0x16,
-       0xff, 0x06, 0x6d, 0x02,
-       0x04, 0x0b, 0xc0, 0x1e,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x65, 0x66, 0x02,
-       0xff, 0x12, 0x6d, 0x03,
-       0xff, 0x65, 0x66, 0x02,
-       0x00, 0x65, 0xd6, 0x16,
-       0xff, 0x06, 0x6a, 0x02,
-       0x04, 0x0b, 0xc7, 0x1e,
-       0x02, 0x0b, 0xc8, 0x1e,
-       0xff, 0x12, 0x6d, 0x03,
-       0x00, 0x65, 0xd6, 0x16,
-       0xff, 0x06, 0x6a, 0x02,
-       0x04, 0x0b, 0xcc, 0x1e,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x02, 0x0b, 0xce, 0x1e,
-       0x00, 0x65, 0xd6, 0x16,
-       0x80, 0x30, 0xd3, 0x1e,
-       0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x6a, 0x30, 0x02,
-       0xff, 0x65, 0x06, 0x02,
-       0x04, 0x0b, 0xd4, 0x1e,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x6a, 0x0a, 0x02,
-       0xff, 0x6a, 0x09, 0x02,
-       0x01, 0x6a, 0x08, 0x01,
-       0xff, 0x65, 0x93, 0x02,
-       0x01, 0x0b, 0xdc, 0x1a,
-       0x10, 0x0c, 0xda, 0x1e,
-       0x04, 0x65, 0xe0, 0x1a,
-       0xfe, 0x65, 0x65, 0x02,
-       0x02, 0x65, 0x93, 0x00,
-       0x02, 0x93, 0xdf, 0x1a,
-       0xff, 0x6a, 0x93, 0x02,
-       0x38, 0x93, 0xe1, 0x1a,
-       0x03, 0x6a, 0x64, 0x00,
-       0xaf, 0x6a, 0x66, 0x00,
-       0x08, 0x6a, 0xb1, 0x16,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x6a, 0x1f, 0x02,
-       0xf0, 0x65, 0x05, 0x02,
-       0x07, 0x5a, 0x64, 0x02,
-       0x00, 0x05, 0x05, 0x00,
-       0xff, 0x6a, 0x30, 0x02,
-       0xff, 0x6a, 0x4e, 0x02,
-       0x0a, 0x6a, 0x01, 0x00,
-       0x38, 0x5a, 0x64, 0x02,
-       0x04, 0x64, 0x02, 0x00,
-       0x84, 0x6a, 0x11, 0x00,
-       0x00, 0x65, 0x0c, 0x17,
-       0x00, 0x65, 0x42, 0x17,
-       0xff, 0x6c, 0x04, 0x02,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x80, 0x34, 0xf7, 0x1e,
-       0x40, 0x34, 0xf7, 0x1a,
-       0x21, 0x6a, 0x91, 0x00,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x70, 0x65, 0x6e, 0x02,
-       0xff, 0x6e, 0x64, 0x02,
-       0x00, 0x32, 0xfc, 0x1e,
-       0xff, 0x6a, 0x64, 0x03,
-       0x40, 0x6a, 0x64, 0x01,
-       0x07, 0x65, 0x64, 0x02,
-       0x00, 0x19, 0x64, 0x00,
-       0xf7, 0x64, 0x64, 0x02,
-       0xff, 0x6a, 0x65, 0x02,
-       0xff, 0x65, 0x90, 0x02,
-       0x00, 0xa1, 0x05, 0x19,
-       0x04, 0xa0, 0x05, 0x1f,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x01, 0x65, 0x65, 0x06,
-       0x04, 0x65, 0x01, 0x19,
-       0x31, 0x6a, 0x91, 0x00,
-       0x06, 0x6a, 0xb5, 0x16,
-       0x10, 0x4e, 0x65, 0x00,
-       0x00, 0x65, 0x52, 0x17,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0xa2, 0x51, 0x02,
-       0x04, 0x6a, 0x64, 0x00,
-       0x52, 0x6a, 0x66, 0x00,
-       0xa3, 0x6a, 0xb1, 0x16,
-       0x80, 0x6a, 0x50, 0x00,
-       0x10, 0xa0, 0x13, 0x1b,
-       0xff, 0x6a, 0x50, 0x02,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x51, 0xa2, 0x02,
-       0x04, 0x6a, 0x64, 0x00,
-       0xa3, 0x6a, 0x66, 0x00,
-       0x52, 0x6a, 0xb1, 0x16,
-       0xef, 0xa0, 0xa0, 0x02,
-       0x80, 0x50, 0x1b, 0x1f,
-       0x10, 0xa0, 0xa0, 0x00,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x51, 0x33, 0x1f,
-       0x80, 0x50, 0x33, 0x1b,
-       0xff, 0x6a, 0x8e, 0x02,
-       0xff, 0x6a, 0x8d, 0x02,
-       0x0c, 0x6a, 0x8c, 0x00,
-       0x04, 0x6a, 0x64, 0x00,
-       0x88, 0x6a, 0x66, 0x00,
-       0x52, 0x6a, 0xb1, 0x16,
-       0x0d, 0x6a, 0x93, 0x00,
-       0x08, 0x94, 0x25, 0x1f,
-       0xff, 0x6a, 0x93, 0x02,
-       0x08, 0x93, 0x27, 0x1b,
-       0xff, 0x99, 0xb3, 0x02,
-       0xff, 0x99, 0xb4, 0x02,
-       0xff, 0x99, 0xb5, 0x02,
-       0xff, 0x99, 0xb6, 0x02,
-       0xff, 0x99, 0x6a, 0x02,
-       0xff, 0x99, 0x6a, 0x02,
-       0xff, 0x99, 0x6a, 0x02,
-       0xff, 0x99, 0x6a, 0x02,
-       0xff, 0x99, 0xb7, 0x02,
-       0xff, 0x99, 0xb8, 0x02,
-       0xff, 0x6a, 0xb9, 0x02,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x51, 0x41, 0x1f,
-       0xff, 0x08, 0x40, 0x1b,
-       0xff, 0x09, 0x40, 0x1b,
-       0xff, 0x0a, 0x40, 0x1b,
-       0xff, 0x6a, 0x50, 0x02,
-       0xff, 0x51, 0x51, 0x06,
-       0xff, 0x6a, 0x64, 0x02,
-       0x0c, 0x52, 0x52, 0x06,
-       0x00, 0x53, 0x53, 0x08,
-       0x00, 0x54, 0x54, 0x08,
-       0x00, 0x55, 0x55, 0x08,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x80, 0x6a, 0x50, 0x00,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x4c, 0x05, 0x64, 0x0a,
-       0x07, 0x64, 0x64, 0x02,
-       0x20, 0x64, 0x65, 0x06,
-       0x70, 0x05, 0x6e, 0x02,
-       0xff, 0x6e, 0x64, 0x03,
-       0xff, 0x65, 0x66, 0x02,
-       0x00, 0x65, 0x42, 0x17,
-       0x00, 0x4f, 0x4b, 0x1b,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x01, 0x6a, 0x6d, 0x00,
-       0x03, 0x6a, 0x6d, 0x00,
-       0x01, 0x6a, 0x6d, 0x00,
-       0x19, 0x6a, 0x6d, 0x00,
-       0x0f, 0x6a, 0x6d, 0x00,
-       0xc9, 0x66, 0x36, 0x06,
-       0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x65, 0x4e, 0x02,
-       0xff, 0x65, 0x03, 0x03,
index 9b66d1981c4007474b89a2d86b97c3bb8fcb7279..42b14a92700db9a77e34af71265e65818caa9328 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Adaptec 274x device driver for Linux.
+ * Adaptec 274x/284x/294x device driver for Linux.
  * Copyright (c) 1994 The University of Calgary Department of Computer Science.
  * 
  * This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
new file mode 100644 (file)
index 0000000..e062127
--- /dev/null
@@ -0,0 +1,1715 @@
+/*
+ *  @(#)aic7xxx.c 1.34 94/11/30 jda
+ *
+ *  Adaptec 274x/284x/294x device driver for Linux.
+ *  Copyright (c) 1994 The University of Calgary Department of Computer Science.
+ *  
+ *  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.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Sources include the Adaptec 1740 driver (aha1740.c), the
+ *  Ultrastor 24F driver (ultrastor.c), various Linux kernel
+ *  source, the Adaptec EISA config file (!adp7771.cfg), the
+ *  Adaptec AHA-2740A Series User's Guide, the Linux Kernel
+ *  Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ *  the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
+ *  overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
+ *  Technical Reference Manual, the Adaptec AIC-7770 Data
+ *  Book, the ANSI SCSI specification, the ANSI SCSI-2
+ *  specification (draft 10c), ...
+ *
+ *  On a twin-bus adapter card, channel B is ignored.  Rationale:
+ *  it would greatly complicate the sequencer and host driver code,
+ *  and both busses are multiplexed on to the EISA bus anyway.  So
+ *  I don't really see any technical advantage to supporting both.
+ *
+ *  As well, multiple adapter card using the same IRQ level are
+ *  not supported.  It doesn't make sense to configure the cards
+ *  this way from a performance standpoint.  Not to mention that
+ *  the kernel would have to support two devices per registered IRQ.
+ */
+
+#include <stdarg.h>
+#include <asm/io.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "../block/blk.h"
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "aic7xxx.h"
+
+/*
+ *  There should be a specific return value for this in scsi.h, but
+ *  it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW  DID_ERROR
+
+/* EISA/VL-bus stuff */
+
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)    ((x) << 12)
+
+#define MAXIRQ         15
+
+/* AIC-7770 offset definitions */
+
+#define O_MINREG(x)    ((x) + 0xc00)           /* i/o range to reserve */
+#define O_MAXREG(x)    ((x) + 0xcbf)
+
+#define O_SCSISEQ(x)   ((x) + 0xc00)           /* scsi sequence control */
+#define O_SCSISIGI(x)  ((x) + 0xc03)           /* scsi control signal read */
+#define O_SCSISIGO(x)  ((x) + 0xc03)           /* scsi control signal write */
+#define O_SCSIID(x)    ((x) + 0xc05)           /* scsi id */
+#define O_SSTAT0(x)    ((x) + 0xc0b)           /* scsi status register 0 */
+#define O_CLRSINT1(x)  ((x) + 0xc0c)           /* clear scsi interrupt 1 */
+#define O_SSTAT1(x)    ((x) + 0xc0c)           /* scsi status register 1 */
+#define O_SELID(x)     ((x) + 0xc19)           /* [re]selection id */
+#define O_SBLKCTL(x)   ((x) + 0xc1f)           /* scsi block control */
+#define O_SEQCTL(x)    ((x) + 0xc60)           /* sequencer control */
+#define O_SEQRAM(x)    ((x) + 0xc61)           /* sequencer ram data */
+#define O_SEQADDR(x)   ((x) + 0xc62)           /* sequencer address (W) */
+#define O_BIDx(x)      ((x) + 0xc80)           /* board id */
+#define O_BCTL(x)      ((x) + 0xc84)           /* board control */
+#define O_HCNTRL(x)    ((x) + 0xc87)           /* host control */
+#define O_SCBPTR(x)    ((x) + 0xc90)           /* scb pointer */
+#define O_INTSTAT(x)   ((x) + 0xc91)           /* interrupt status */
+#define O_ERROR(x)     ((x) + 0xc92)           /* hard error */
+#define O_CLRINT(x)    ((x) + 0xc92)           /* clear interrupt status */
+#define O_SCBCNT(x)    ((x) + 0xc9a)           /* scb auto increment */
+#define O_QINFIFO(x)   ((x) + 0xc9b)           /* queue in fifo */
+#define O_QINCNT(x)    ((x) + 0xc9c)           /* queue in count */
+#define O_QOUTFIFO(x)  ((x) + 0xc9d)           /* queue out fifo */
+#define O_QOUTCNT(x)   ((x) + 0xc9e)           /* queue out count */
+#define O_SCBARRAY(x)  ((x) + 0xca0)           /* scb array start */
+
+/* AIC-7870-only definitions */
+
+#define O_DSPCISTATUS(x) ((x) + 0xc86)         /* ??? */
+
+/* host adapter offset definitions */
+
+#define HA_REJBYTE(x)  ((x) + 0xc31)           /* 1st message in byte */
+#define HA_MSG_FLAGS(x)        ((x) + 0xc35)           /* outgoing message flag */
+#define HA_MSG_LEN(x)  ((x) + 0xc36)           /* outgoing message length */
+#define HA_MSG_START(x)        ((x) + 0xc37)           /* outgoing message body */
+#define HA_ARG_1(x)    ((x) + 0xc4c)           /* sdtr <-> rate parameters */
+#define HA_ARG_2(x)    ((x) + 0xc4d)
+#define HA_RETURN_1(x) ((x) + 0xc4c)
+#define HA_RETURN_2(x) ((x) + 0xc4d)
+#define HA_SIGSTATE(x) ((x) + 0xc4e)           /* value in SCSISIGO */
+#define HA_NEEDSDTR(x) ((x) + 0xc4f)           /* synchronous negotiation? */
+#define HA_SCBCOUNT(x) ((x) + 0xc56)           /* number of hardware SCBs */
+
+#define HA_SCSICONF(x) ((x) + 0xc5a)           /* SCSI config register */
+#define HA_INTDEF(x)   ((x) + 0xc5c)           /* interrupt def'n register */
+#define HA_HOSTCONF(x) ((x) + 0xc5d)           /* host config def'n register */
+
+/* debugging code */
+
+/*
+#define AIC7XXX_DEBUG
+*/
+
+/*
+ *  If a parity error occurs during a data transfer phase, run the
+ *  command to completion - it's easier that way - making a note
+ *  of the error condition in this location.  This then will modify
+ *  a DID_OK status into a DID_PARITY one for the higher-level SCSI
+ *  code.
+ */
+#define aic7xxx_parity(cmd)    ((cmd)->SCp.Status)
+
+/*
+ *  Since the sequencer code DMAs the scatter-gather structures
+ *  directly from memory, we use this macro to assert that the
+ *  kernel structure hasn't changed.
+ */
+#define SG_STRUCT_CHECK(sg) \
+       ((char *)&(sg).address - (char *)&(sg) != 0 ||  \
+        (char *)&(sg).length  - (char *)&(sg) != 8 ||  \
+        sizeof((sg).address) != 4 ||                   \
+        sizeof((sg).length)  != 4 ||                   \
+        sizeof(sg)           != 12)
+
+/*
+ *  "Static" structures.  Note that these are NOT initialized
+ *  to zero inside the kernel - we have to initialize them all
+ *  explicitly.
+ *
+ *  We support a maximum of one adapter card per IRQ level (see the
+ *  rationale for this above).  On an interrupt, use the IRQ as an
+ *  index into aic7xxx_boards[] to locate the card information.
+ */
+static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
+
+/*
+ *  The maximum number of SCBs we could have for ANY type
+ *  of card.  DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ *  SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB 16
+
+struct aic7xxx_host {
+       int base;                                       /* card base address */
+       int maxscb;                                     /* hardware SCBs */
+       int startup;                                    /* intr type check */
+       int extended;                                   /* extended xlate? */
+       volatile int unpause;                           /* value for HCNTRL */
+       volatile Scsi_Cmnd *SCB_array[AIC7XXX_MAXSCB];  /* active commands */
+};
+
+struct aic7xxx_host_config {
+       int irq;                                        /* IRQ number */
+       int base;                                       /* I/O base */
+       int maxscb;                                     /* hardware SCBs */
+       int unpause;                                    /* value for HCNTRL */
+       int scsi_id;                                    /* host SCSI id */
+       int extended;                                   /* extended xlate? */
+};
+
+struct aic7xxx_scb {
+       unsigned char control;
+       unsigned char target_channel_lun;               /* 4/1/3 bits */
+       unsigned char SG_segment_count;
+       unsigned char SG_list_pointer[4];
+       unsigned char SCSI_cmd_pointer[4];
+       unsigned char SCSI_cmd_length;
+       unsigned char RESERVED[2];                      /* must be zero */
+       unsigned char target_status;
+       unsigned char residual_data_count[3];
+       unsigned char residual_SG_segment_count;
+       unsigned char data_pointer[4];
+       unsigned char data_count[3];
+#if 0
+       /*
+        *  No real point in transferring this to the
+        *  SCB registers.
+        */
+       unsigned char RESERVED[6];
+#endif
+};
+
+/*
+ *  NB.  This table MUST be ordered shortest period first.
+ */
+static struct {
+       short period;
+       short rate;
+       char *english;
+} aic7xxx_synctab[] = {
+       100,    0,      "10.0",
+       125,    1,      "8.0",
+       150,    2,      "6.67",
+       175,    3,      "5.7",
+       200,    4,      "5.0",
+       225,    5,      "4.4",
+       250,    6,      "4.0",
+       275,    7,      "3.6"
+};
+
+static int aic7xxx_synctab_max =
+       sizeof(aic7xxx_synctab) / sizeof(aic7xxx_synctab[0]);
+
+enum aha_type {
+       T_NONE,
+       T_274X,
+       T_284X,
+       T_294X,
+       T_MAX
+};
+
+#ifdef AIC7XXX_DEBUG
+
+       extern int vsprintf(char *, const char *, va_list);
+
+       static
+       void debug(const char *fmt, ...)
+       {
+               va_list ap;
+               char buf[256];
+
+               va_start(ap, fmt);
+                 vsprintf(buf, fmt, ap);
+                 printk(buf);
+               va_end(ap);
+       }
+
+       static
+       void debug_config(enum aha_type type, struct aic7xxx_host_config *p)
+       {
+               int ioport2, ioport3;
+
+               static char *BRT[T_MAX][16] = {
+                       { },                                    /* T_NONE */
+                       {
+                               "2",   "???", "???", "12",      /* T_274X */
+                               "???", "???", "???", "28",
+                               "???", "???", "???", "44",
+                               "???", "???", "???", "60"
+                       },
+                       {
+                               "2",  "4",  "8",  "12",         /* T_284X */
+                               "16", "20", "24", "28",
+                               "32", "36", "40", "44",
+                               "48", "52", "56", "60"
+                       },
+                       {
+                               "???", "???", "???", "???",     /* T_294X */
+                               "???", "???", "???", "???",
+                               "???", "???", "???", "???",
+                               "???", "???", "???", "???"
+                       }
+               };
+               static int DFT[4] = {
+                       0, 50, 75, 100
+               };
+               static int SST[4] = {
+                       256, 128, 64, 32
+               };
+
+               ioport2 = inb(HA_HOSTCONF(p->base));
+               ioport3 = inb(HA_SCSICONF(p->base));
+
+               switch (type) {
+                   case T_274X:
+                       printk("AHA274X AT EISA SLOT %d:\n", p->base >> 12);
+                       break;
+                   case T_284X:
+                       printk("AHA284X AT SLOT %d:\n", p->base >> 12);
+                       break;
+                   case T_294X:
+                       printk("AHA294X (PCI-bus):\n");
+                       break;
+                   default:
+                       panic("aic7xxx debug_config: internal error\n");
+               }
+
+               printk("    irq %d\n"
+                      "    bus release time %s bclks\n"
+                      "    data fifo threshold %d%%\n",
+                      p->irq,
+                      BRT[type][(ioport2 >> 2) & 0xf],
+                      DFT[(ioport2 >> 6) & 0x3]);
+
+               printk("    SCSI CHANNEL A:\n"
+                      "        scsi id %d\n"
+                      "        scsi bus parity check %sabled\n"
+                      "        scsi selection timeout %d ms\n"
+                      "        scsi bus reset at power-on %sabled\n",
+                      ioport3 & 0x7,
+                      (ioport3 & 0x20) ? "en" : "dis",
+                      SST[(ioport3 >> 3) & 0x3],
+                      (ioport3 & 0x40) ? "en" : "dis");
+
+               if (type == T_274X) {
+                       printk("        scsi bus termination %sabled\n",
+                              (ioport3 & 0x80) ? "en" : "dis");
+               }
+       }
+
+       static
+       void debug_rate(int base, int rate)
+       {
+               int target = inb(O_SCSIID(base)) >> 4;
+
+               if (rate) {
+                       printk("aic7xxx: target %d now synchronous at %sMb/s\n",
+                              target,
+                              aic7xxx_synctab[(rate >> 4) & 0x7].english);
+               } else {
+                       printk("aic7xxx: target %d using asynchronous mode\n",
+                              target);
+               }
+       }
+
+#else
+
+#      define debug(fmt, args...)
+#      define debug_config(x)
+#      define debug_rate(x,y)
+
+#endif AIC7XXX_DEBUG
+
+/*
+ *  XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system.  This should be fixed, but then,
+ *       does anyone really have more than one in a machine?
+ */
+static int aic7xxx_extended = 0;               /* extended translation on? */
+
+void aic7xxx_setup(char *s, int *dummy)
+{
+       int i;
+       char *p;
+
+       static struct {
+               char *name;
+               int *flag;
+       } options[] = {
+               "extended",     &aic7xxx_extended,
+               NULL
+       };
+
+       for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
+               for (i = 0; options[i].name; i++)
+                       if (!strcmp(options[i].name, p))
+                               *(options[i].flag) = !0;
+       }
+}
+
+static
+void aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
+{
+       /*
+        *  This is almost identical to aic7xxx_putscb().
+        */
+       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
+
+       asm volatile("cld\n\t"
+                    "rep\n\t"
+                    "insb"
+                    : /* no output */
+                    :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
+                    :"di", "cx", "dx");
+
+       outb(0, O_SCBCNT(base));
+}
+
+/*
+ *  How much data should be transferred for this SCSI command?  Stop
+ *  at segment sg_last if it's a scatter-gather command so we can
+ *  compute underflow easily.
+ */
+static
+unsigned aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
+{
+       int i, segments;
+       unsigned length;
+       struct scatterlist *sg;
+
+       segments = cmd->use_sg - sg_last;
+       sg = (struct scatterlist *)cmd->buffer;
+
+       if (cmd->use_sg) {
+               for (i = length = 0;
+                    i < cmd->use_sg && i < segments;
+                    i++)
+               {
+                       length += sg[i].length;
+               }
+       } else
+               length = cmd->request_bufflen;
+
+       return(length);
+}
+
+static
+void aic7xxx_sg_check(Scsi_Cmnd *cmd)
+{
+       int i;
+       struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
+
+       if (cmd->use_sg) {
+               for (i = 0; i < cmd->use_sg; i++)
+                       if ((unsigned)sg[i].length > 0xffff)
+                               panic("aic7xxx_sg_check: s/g segment > 64k\n");
+       }
+}
+
+static
+void aic7xxx_to_scsirate(unsigned char *rate,
+                        unsigned char transfer,
+                        unsigned char offset)
+{
+       int i;
+
+       transfer *= 4;
+
+       for (i = 0; i < aic7xxx_synctab_max-1; i++) {
+
+               if (transfer == aic7xxx_synctab[i].period) {
+                       *rate = (aic7xxx_synctab[i].rate << 4) | (offset & 0xf);
+                       return;
+               }
+
+               if (transfer > aic7xxx_synctab[i].period &&
+                   transfer < aic7xxx_synctab[i+1].period)
+               {
+                       *rate = (aic7xxx_synctab[i+1].rate << 4) |
+                               (offset & 0xf);
+                       return;
+               }
+       }
+       *rate = 0;
+}
+
+/*
+ *  Pause the sequencer and wait for it to actually stop - this
+ *  is important since the sequencer can disable pausing for critical
+ *  sections.
+ */
+#define PAUSE_SEQUENCER(p)     \
+       do {                                                            \
+               outb(0xe, O_HCNTRL(p->base));   /* IRQMS|PAUSE|INTEN */ \
+                                                                       \
+               while ((inb(O_HCNTRL(p->base)) & 0x4) == 0)             \
+                       ;                                               \
+       } while (0)
+
+/*
+ *  Unpause the sequencer.  Unremarkable, yet done often enough to
+ *  warrant an easy way to do it.
+ */
+#define UNPAUSE_SEQUENCER(p)   \
+       outb(p->unpause, O_HCNTRL(p->base))     /* IRQMS|INTEN */
+
+/*
+ *  See comments in aic7xxx_loadram() wrt this.
+ */
+#define RESTART_SEQUENCER(p)   \
+       do {                                                    \
+               do {                                            \
+                       outb(0x2, O_SEQCTL(p->base));           \
+                                                               \
+               } while (inb(O_SEQADDR(p->base)) != 0 &&        \
+                        inb(O_SEQADDR(p->base) + 1) != 0);     \
+                                                               \
+               UNPAUSE_SEQUENCER(p);                           \
+       } while (0)
+
+/*
+ *  Since we declared this using SA_INTERRUPT, interrupts should
+ *  be disabled all through this function unless we say otherwise.
+ */
+static
+void aic7xxx_isr(int irq)
+{
+       int base, intstat;
+       struct aic7xxx_host *p;
+       
+       p = (struct aic7xxx_host *)aic7xxx_boards[irq]->hostdata;
+       base = p->base;
+
+       /*
+        *  Check the startup flag - if no commands have been queued,
+        *  we probably have the interrupt type set wrong.  Reverse
+        *  the stored value and the active one in the host control
+        *  register.
+        */
+       if (p->startup) {
+               p->unpause ^= 0x8;
+               outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
+               return;
+       }
+
+       /*
+        *  Handle all the interrupt sources - especially for SCSI
+        *  interrupts, we won't get a second chance at them.
+        */
+       intstat = inb(O_INTSTAT(base));
+
+       if (intstat & 0x8) {                            /* BRKADRINT */
+
+               panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
+                     inb(O_ERROR(base)), inw(O_SEQADDR(base)));
+       }
+
+       if (intstat & 0x4) {                            /* SCSIINT */
+
+               int scbptr = inb(O_SCBPTR(base));
+               int status = inb(O_SSTAT1(base));
+               Scsi_Cmnd *cmd;
+
+               cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
+               if (!cmd) {
+                       printk("aic7xxx_isr: no command for scb (scsiint)\n");
+                       /*
+                        *  Turn off the interrupt and set status
+                        *  to zero, so that it falls through the
+                        *  reset of the SCSIINT code.
+                        */
+                       outb(status, O_CLRSINT1(base));
+                       UNPAUSE_SEQUENCER(p);
+                       outb(0x4, O_CLRINT(base));      /* undocumented */
+                       status = 0;
+               }
+               p->SCB_array[scbptr] = NULL;
+
+               /*
+                *  Only the SCSI Status 1 register has information
+                *  about exceptional conditions that we'd have a
+                *  SCSIINT about; anything in SSTAT0 will be handled
+                *  by the sequencer.  Note that there can be multiple
+                *  bits set.
+                */
+               if (status & 0x80) {                    /* SELTO */
+                       /*
+                        *  Hardware selection timer has expired.  Turn
+                        *  off SCSI selection sequence.
+                        */
+                       outb(0, O_SCSISEQ(base));
+                       cmd->result = DID_TIME_OUT << 16;
+
+                       /*
+                        *  If there's an active message, it belongs to the
+                        *  command that is getting punted - remove it.
+                        */
+                       outb(0, HA_MSG_FLAGS(base));
+
+                       /*
+                        *  Shut off the offending interrupt sources, reset
+                        *  the sequencer address to zero and unpause it,
+                        *  then call the high-level SCSI completion routine.
+                        *
+                        *  WARNING!  This is a magic sequence!  After many
+                        *  hours of guesswork, turning off the SCSI interrupts
+                        *  in CLRSINT? does NOT clear the SCSIINT bit in
+                        *  INTSTAT.  By writing to the (undocumented, unused
+                        *  according to the AIC-7770 manual) third bit of
+                        *  CLRINT, you can clear INTSTAT.  But, if you do it
+                        *  while the sequencer is paused, you get a BRKADRINT
+                        *  with an Illegal Host Address status, so the
+                        *  sequencer has to be restarted first.
+                        */
+                       outb(0x80, O_CLRSINT1(base));   /* CLRSELTIMO */
+                       RESTART_SEQUENCER(p);
+
+                       outb(0x4, O_CLRINT(base));      /* undocumented */
+                       cmd->scsi_done(cmd);
+               }
+
+               if (status & 0x4) {                     /* SCSIPERR */
+                       /*
+                        *  A parity error has occurred during a data
+                        *  transfer phase.  Flag it and continue.
+                        */
+                       printk("aic7xxx: parity error on target %d, lun %d\n",
+                              cmd->target,
+                              cmd->lun);
+                       aic7xxx_parity(cmd) = DID_PARITY;
+
+                       /*
+                        *  Clear interrupt and resume as above.
+                        */
+                       outb(0x4, O_CLRSINT1(base));    /* CLRSCSIPERR */
+                       UNPAUSE_SEQUENCER(p);
+
+                       outb(0x4, O_CLRINT(base));      /* undocumented */
+               }
+
+               if ((status & (0x8|0x4)) == 0 && status) {
+                       /*
+                        *  We don't know what's going on.  Turn off the
+                        *  interrupt source and try to continue.
+                        */
+                       printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
+                       outb(status, O_CLRSINT1(base));
+                       UNPAUSE_SEQUENCER(p);
+                       outb(0x4, O_CLRINT(base));      /* undocumented */
+               }
+       }
+
+       if (intstat & 0x2) {                            /* CMDCMPLT */
+
+               int complete, old_scbptr;
+               struct aic7xxx_scb scb;
+               unsigned actual;
+               Scsi_Cmnd *cmd;
+
+               /*
+                *  The sequencer will continue running when it
+                *  issues this interrupt.  There may be >1 commands
+                *  finished, so loop until we've processed them all.
+                */
+               do {
+                       complete = inb(O_QOUTFIFO(base));
+
+                       cmd = (Scsi_Cmnd *)p->SCB_array[complete];
+                       if (!cmd) {
+                               printk("aic7xxx warning: "
+                                      "no command for scb (cmdcmplt)\n");
+                               continue;
+                       }
+                       p->SCB_array[complete] = NULL;
+                       
+                       PAUSE_SEQUENCER(p);
+
+                       /*
+                        *  After pausing the sequencer (and waiting
+                        *  for it to stop), save its SCB pointer, then
+                        *  write in our completed one and read the SCB
+                        *  registers.  Afterwards, restore the saved
+                        *  pointer, unpause the sequencer and call the
+                        *  higher-level completion function - unpause
+                        *  first since we have no idea how long done()
+                        *  will take.
+                        */
+                       old_scbptr = inb(O_SCBPTR(base));
+                       outb(complete, O_SCBPTR(base));
+
+                       aic7xxx_getscb(base, &scb);
+                       outb(old_scbptr, O_SCBPTR(base));
+
+                       UNPAUSE_SEQUENCER(p);
+
+                       cmd->result = scb.target_status |
+                                    (aic7xxx_parity(cmd) << 16);
+
+                       /*
+                        *  Did we underflow?  At this time, there's only
+                        *  one other driver that bothers to check for this,
+                        *  and cmd->underflow seems to be set rather half-
+                        *  heartedly in the higher-level SCSI code.
+                        */
+                       actual = aic7xxx_length(cmd,
+                                               scb.residual_SG_segment_count);
+
+                       actual -= ((scb.residual_data_count[2] << 16) |
+                                  (scb.residual_data_count[1] <<  8) |
+                                  (scb.residual_data_count[0]));
+
+                       if (actual < cmd->underflow) {
+                               printk("aic7xxx: target %d underflow - "
+                                      "wanted (at least) %u, got %u\n",
+                                      cmd->target, cmd->underflow, actual);
+
+                               cmd->result = scb.target_status |
+                                            (DID_UNDERFLOW << 16);
+                       }
+
+                       cmd->scsi_done(cmd);
+
+                       /*
+                        *  Clear interrupt status before checking
+                        *  the output queue again.  This eliminates
+                        *  a race condition whereby a command could
+                        *  complete between the queue poll and the
+                        *  interrupt clearing, so notification of the
+                        *  command being complete never made it back
+                        *  up to the kernel.
+                        */
+                       outb(0x2, O_CLRINT(base));      /* CLRCMDINT */
+
+               } while (inb(O_QOUTCNT(base)));
+       }
+
+       if (intstat & 0x1) {                            /* SEQINT */
+
+               unsigned char transfer, offset, rate;
+
+               /*
+                *  Although the sequencer is paused immediately on
+                *  a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
+                *  condition will have unpaused the sequencer before
+                *  this point.
+                */
+               PAUSE_SEQUENCER(p);
+
+               switch (intstat & 0xf0) {
+                   case 0x00:
+                       panic("aic7xxx_isr: unknown scsi bus phase\n");
+                   case 0x10:
+                       debug("aic7xxx_isr warning: "
+                             "issuing message reject, 1st byte 0x%x\n",
+                             inb(HA_REJBYTE(base)));
+                       break;
+                   case 0x20:
+                       panic("aic7xxx_isr: reconnecting target %d "
+                             "didn't issue IDENTIFY message\n",
+                             (inb(O_SELID(base)) >> 4) & 0xf);
+                   case 0x30:
+                       debug("aic7xxx_isr: sequencer couldn't find match "
+                             "for reconnecting target %d - issuing ABORT\n",
+                             (inb(O_SELID(base)) >> 4) & 0xf);
+                       break;
+                   case 0x40:
+                       transfer = inb(HA_ARG_1(base));
+                       offset = inb(HA_ARG_2(base));
+                       aic7xxx_to_scsirate(&rate, transfer, offset);
+                       outb(rate, HA_RETURN_1(base));
+                       debug_rate(base, rate);
+                       break;
+                   default:
+                       debug("aic7xxx_isr: seqint, "
+                             "intstat = 0x%x, scsisigi = 0x%x\n",
+                             intstat, inb(O_SCSISIGI(base)));
+                       break;
+               }
+
+               outb(0x1, O_CLRINT(base));              /* CLRSEQINT */
+               UNPAUSE_SEQUENCER(p);
+       }
+}
+
+/*
+ *  Probing for EISA boards: it looks like the first two bytes
+ *  are a manufacturer code - three characters, five bits each:
+ *
+ *              BYTE 0   BYTE 1   BYTE 2   BYTE 3
+ *             ?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ *  The characters are baselined off ASCII '@', so add that value
+ *  to each to get the real ASCII code for it.  The next two bytes
+ *  appear to be a product and revision number, probably vendor-
+ *  specific.  This is what is being searched for at each port,
+ *  and what should probably correspond to the ID= field in the
+ *  ECU's .cfg file for the card - if your card is not detected,
+ *  make sure your signature is listed in the array.
+ *
+ *  The fourth byte's lowest bit seems to be an enabled/disabled
+ *  flag (rest of the bits are reserved?).
+ */
+
+static
+enum aha_type aic7xxx_probe(int slot, int s_base)
+{
+       int i;
+       unsigned char buf[4];
+
+       static struct {
+               int n;
+               unsigned char signature[sizeof(buf)];
+               enum aha_type type;
+       } S[] = {
+               4, { 0x04, 0x90, 0x77, 0x71 }, T_274X,  /* host adapter 274x */
+               4, { 0x04, 0x90, 0x77, 0x70 }, T_274X,  /* motherboard 274x  */
+               4, { 0x04, 0x90, 0x77, 0x56 }, T_284X,  /* 284x, BIOS enabled */
+       };
+
+       for (i = 0; i < sizeof(buf); i++) {
+               /*
+                *  The VL-bus cards need to be primed by
+                *  writing before a signature check.
+                */
+               outb(0x80 + i, s_base);
+               buf[i] = inb(s_base + i);
+       }
+
+       for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
+               if (!memcmp(buf, S[i].signature, S[i].n)) {
+                       /*
+                        *  Signature match on enabled card?
+                        */
+                       if (inb(s_base + 4) & 1)
+                               return(S[i].type);
+                       printk("aic7xxx disabled at slot %d, ignored\n", slot);
+               }
+       }
+       return(T_NONE);
+}
+
+/*
+ *  Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
+ *  wide channel, '?' for anything else.
+ */
+
+static
+char aic7xxx_type(int base)
+{
+       /*
+        *  AIC-7770/7870s can be wired so that, on chip reset,
+        *  the SCSI Block Control register indicates how many
+        *  busses the chip is configured for.  The two high bits
+        *  set indicate a 294x.
+        */
+       switch (inb(O_SBLKCTL(base))) {
+           case 0:
+           case 0xc0:
+               return(' ');
+           case 2:
+           case 0xc2:
+               return('W');
+           case 8:
+               return('T');
+           default:
+               printk("aic7xxx has unknown bus configuration\n");
+               return('?');
+       }
+}
+
+static
+void aic7xxx_loadram(int base)
+{
+       static unsigned char seqprog[] = {
+               /*
+                *  Each sequencer instruction is 29 bits
+                *  long (fill in the excess with zeroes)
+                *  and has to be loaded from least -> most
+                *  significant byte, so this table has the
+                *  byte ordering reversed.
+                */
+#              include "aic7xxx_seq.h"
+       };
+
+       /*
+        *  When the AIC-7770 is paused (as on chip reset), the
+        *  sequencer address can be altered and a sequencer
+        *  program can be loaded by writing it, byte by byte, to
+        *  the sequencer RAM port - the Adaptec documentation
+        *  recommends using REP OUTSB to do this, hence the inline
+        *  assembly.  Since the address autoincrements as we load
+        *  the program, reset it back to zero afterward.  Disable
+        *  sequencer RAM parity error detection while loading, and
+        *  make sure the LOADRAM bit is enabled for loading.
+        */
+       outb(0x83, O_SEQCTL(base));     /* PERRORDIS|SEQRESET|LOADRAM */
+
+       asm volatile("cld\n\t"
+                    "rep\n\t"
+                    "outsb"
+                    : /* no output */
+                    :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
+                    :"si", "cx", "dx");
+
+       /*
+        *  WARNING!  This is a magic sequence!  After extensive
+        *  experimentation, it seems that you MUST turn off the
+        *  LOADRAM bit before you play with SEQADDR again, else
+        *  you will end up with parity errors being flagged on
+        *  your sequencer program.  (You would also think that
+        *  turning off LOADRAM and setting SEQRESET to reset the
+        *  address to zero would work, but you need to do it twice
+        *  for it to take effect on the address.  Timing problem?)
+        */
+       outb(0, O_SEQCTL(base));
+       do {
+               /*
+                *  Actually, reset it until
+                *  the address shows up as
+                *  zero just to be safe..
+                */
+               outb(0x2, O_SEQCTL(base));      /* SEQRESET */
+
+       } while (inb(O_SEQADDR(base)) != 0 && inb(O_SEQADDR(base) + 1) != 0);
+}
+
+static
+void aha274x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+       int base = va_arg(ap, int);
+
+       /*
+        *  Give the AIC-7770 a reset - reading the 274x's registers
+        *  returns zeroes unless you do.  This forces a pause of the
+        *  Sequencer.
+        */
+       outb(1, O_HCNTRL(base));        /* CHIPRST */
+
+       p->base = base;
+       p->irq = inb(HA_INTDEF(base)) & 0xf;
+       p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+
+       /*
+        *  This value for HCNTRL may be changed in the ISR if we
+        *  catch a spurious interrupt right away.
+        */
+       p->unpause = 0xa;
+
+       /*
+        *  XXX - these are values that I don't know how to query
+        *        the hardware for.  Apparently some revision E
+        *        '7770s can have more SCBs, and I don't know how
+        *        to get the "extended translation" flag from the
+        *        EISA data area.
+        */
+       p->maxscb = 4;
+       p->extended = aic7xxx_extended;
+
+       /*
+        *  A reminder until this can be detected automatically.
+        */
+       printk("aha274x: extended translation %sabled\n",
+               p->extended ? "en" : "dis");
+}
+
+static
+void aha284x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+       int base = va_arg(ap, int);
+
+       /*
+        *  Give the AIC-7770 a reset - this forces a pause of the
+        *  Sequencer and returns everything to default values.
+        */
+       outb(1, O_HCNTRL(base));        /* CHIPRST */
+
+       p->base = base;
+       p->unpause = 0x2;
+       p->irq = inb(HA_INTDEF(base)) & 0xf;
+       p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+
+       /*
+        *  XXX - these are values that I don't know how to query
+        *        the hardware for.  Apparently some revision E
+        *        '7770s can have more SCBs, and I don't know how
+        *        to get the "extended translation" flag from the
+        *        onboard memory.
+        */
+       p->maxscb = 4;
+       p->extended = aic7xxx_extended;
+
+       /*
+        *  A reminder until this can be detected automatically.
+        */
+       printk("aha284x: extended translation %sabled\n",
+               p->extended ? "en" : "dis");
+}
+
+static
+void aha294x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+       int error;
+       unsigned long io_port;
+       unsigned char bus, device_fn, irq;
+
+       bus = va_arg(ap, unsigned char);
+       device_fn = va_arg(ap, unsigned char);
+
+       /*
+        *  Read esundry information from PCI BIOS.
+        */
+       error = pcibios_read_config_dword(bus,
+                                         device_fn,
+                                         PCI_BASE_ADDRESS_0,
+                                         &io_port);
+       if (error) {
+               panic("aha294x_config: error %s reading i/o port\n",
+                     pcibios_strerror(error));
+       }
+
+       error = pcibios_read_config_byte(bus,
+                                        device_fn,
+                                        PCI_INTERRUPT_LINE,
+                                        &irq);
+       if (error) {
+               panic("aha294x_config: error %s reading irq\n",
+                     pcibios_strerror(error));
+       }
+
+       /*
+        *  Make the base I/O register look like EISA and VL-bus.
+        */
+       p->base = io_port - 0xc01;
+
+       /*
+        *  Give the AIC-7870 a reset - this forces a pause of the
+        *  Sequencer and returns everything to default values.
+        */
+       outb(1, O_HCNTRL(p->base));     /* CHIPRST */
+
+       p->irq = irq;
+       p->maxscb = 16;
+       p->unpause = 0xa;
+
+       /*
+        *  XXX - these are values that I don't know how to query
+        *        the hardware for, so for now the SCSI host ID is
+        *        hardwired to 7, and the "extended translation"
+        *        flag is taken from boot-time flags.
+        */
+       p->scsi_id = 7;
+       p->extended = aic7xxx_extended;
+
+       /*
+        *  XXX - force data fifo threshold to 100%.  Why does this
+        *        need to be done?
+        */
+#      define  DFTHRESH        3
+
+       outb(DFTHRESH << 6, O_DSPCISTATUS(p->base));
+       outb(p->scsi_id | (DFTHRESH << 6), HA_SCSICONF(p->base));
+
+       /*
+        *  A reminder until this can be detected automatically.
+        */
+       printk("aha294x: extended translation %sabled\n",
+               p->extended ? "en" : "dis");
+}
+
+static
+int aic7xxx_register(Scsi_Host_Template *template, enum aha_type type, ...)
+{
+       va_list ap;
+       int i, base;
+       struct Scsi_Host *host;
+       struct aic7xxx_host *p;
+       struct aic7xxx_host_config config;
+
+       va_start(ap, type);
+       
+       switch (type) {
+           case T_274X:
+               aha274x_config(&config, ap);
+               break;
+           case T_284X:
+               aha284x_config(&config, ap);
+               break;
+           case T_294X:
+               aha294x_config(&config, ap);
+               break;
+           default:
+               panic("aic7xxx_register: internal error\n");
+       }
+       va_end(ap);
+
+       base = config.base;
+
+       /*
+        *  The IRQ level in i/o port 4 maps directly onto the real
+        *  IRQ number.  If it's ok, register it with the kernel.
+        *
+        *  NB. the Adaptec documentation says the IRQ number is only
+        *      in the lower four bits; the ECU information shows the
+        *      high bit being used as well.  Which is correct?
+        */
+       if (config.irq < 9 || config.irq > 15) {
+               printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+               return(0);
+       }
+       
+       /*
+        *  Lock out other contenders for our i/o space.
+        */
+       snarf_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base));
+
+       /*
+        *  Any card-type-specific adjustments before we register
+        *  the scsi host(s).
+        */
+       switch (aic7xxx_type(base)) {
+           case 'T':
+               printk("aic7xxx warning: ignoring channel B of 274x-twin\n");
+               break;
+           case ' ':
+               break;
+           default:
+               printk("aic7xxx is an unsupported type, ignoring\n");
+               return(0);
+       }
+
+       /*
+        *  Before registry, make sure that the offsets of the
+        *  struct scatterlist are what the sequencer will expect,
+        *  otherwise disable scatter-gather altogether until someone
+        *  can fix it.  This is important since the sequencer will
+        *  DMA elements of the SG array in while executing commands.
+        */
+       if (template->sg_tablesize != SG_NONE) {
+               struct scatterlist sg;
+
+               if (SG_STRUCT_CHECK(sg)) {
+                       printk("aic7xxx warning: kernel scatter-gather "
+                              "structures changed, disabling it\n");
+                       template->sg_tablesize = SG_NONE;
+               }
+       }
+       
+       /*
+        *  Register each "host" and fill in the returned Scsi_Host
+        *  structure as best we can.  Some of the parameters aren't
+        *  really relevant for bus types beyond ISA, and none of the
+        *  high-level SCSI code looks at it anyway.. why are the fields
+        *  there?  Also save the pointer so that we can find the
+        *  information when an IRQ is triggered.
+        */
+       host = scsi_register(template, sizeof(struct aic7xxx_host));
+       host->can_queue = config.maxscb;
+       host->this_id = config.scsi_id;
+       host->irq = config.irq;
+
+       aic7xxx_boards[config.irq] = host;
+       
+       p = (struct aic7xxx_host *)host->hostdata;
+       for (i = 0; i < AIC7XXX_MAXSCB; i++)
+               p->SCB_array[i] = NULL;
+
+       p->base = config.base;
+       p->maxscb = config.maxscb;
+       p->extended = config.extended;
+
+       /*
+        *  The interrupt trigger is different depending
+        *  on whether the card is EISA or VL-bus - sometimes.
+        *  The startup variable will be cleared once the first
+        *  command is queued, and is checked in the isr to
+        *  try and detect when the interrupt type is set
+        *  incorrectly, triggering an interrupt immediately.
+        *  This is now just set on a per-card-type basis.
+        */
+       p->unpause = config.unpause;
+       p->startup = !0;
+
+       /*
+        *  Register IRQ with the kernel _after_ the host information
+        *  is set up, in case we take an interrupt right away, due to
+        *  the interrupt type being set wrong.
+        */
+       if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx")) {
+               printk("aic7xxx couldn't register irq %d, ignoring\n",
+                      config.irq);
+               return(0);
+       }
+
+       /*
+        *  Print out debugging information before re-enabling
+        *  the card - a lot of registers on it can't be read
+        *  when the sequencer is active.
+        */
+#ifdef AIC7XXX_DEBUG
+       debug_config(type, &config);
+#endif
+
+       /*
+        *  Load the sequencer program, then re-enable the board -
+        *  resetting the AIC-7770 disables it, leaving the lights
+        *  on with nobody home.  On the PCI bus you *may* be home,
+        *  but then your mailing address is dynamically assigned
+        *  so no one can find you anyway :-)
+        */
+       aic7xxx_loadram(base);
+       if (type != T_294X)
+               outb(1, O_BCTL(base));  /* ENABLE */
+
+       /*
+        *  Set the host adapter registers to indicate that synchronous
+        *  negotiation should be attempted the first time the targets
+        *  are communicated with.  Also initialize the active message
+        *  flag to indicate that there is no message.
+        */
+       outb(0xff, HA_NEEDSDTR(base));
+       outb(0, HA_MSG_FLAGS(base));
+
+       /*
+        *  For reconnecting targets, the sequencer code needs to
+        *  know how many SCBs it has to search through.
+        */
+       outb(config.maxscb, HA_SCBCOUNT(base));
+
+       /*
+        *  Unpause the sequencer before returning and enable
+        *  interrupts - we shouldn't get any until the first
+        *  command is sent to us by the high-level SCSI code.
+        */
+       UNPAUSE_SEQUENCER(p);
+       return(1);
+}
+
+int aic7xxx_detect(Scsi_Host_Template *template)
+{
+       enum aha_type type;
+       int found = 0, slot, base;
+
+       /*
+        *  EISA/VL-bus card signature probe.
+        */
+       for (slot = MINSLOT; slot <= MAXSLOT; slot++) {
+
+               base = SLOTBASE(slot);
+               
+               if (check_region(O_MINREG(base),
+                                O_MAXREG(base)-O_MINREG(base)))
+               {
+                       /*
+                        *  Some other driver has staked a
+                        *  claim to this i/o region already.
+                        */
+                       continue;
+               }
+
+               type = aic7xxx_probe(slot, O_BIDx(base));
+
+               if (type != T_NONE) {
+                       /*
+                        *  We "find" a 274x if we locate the card
+                        *  signature and we can set it up and register
+                        *  it with the kernel without incident.
+                        */
+                       found += aic7xxx_register(template, type, base);
+               }
+       }
+
+       /*
+        *  PCI-bus probe.
+        */
+       if (pcibios_present()) {
+               int index = 0;
+               unsigned char bus, device_fn;
+
+               while (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                                           PCI_DEVICE_ID_ADAPTEC_2940,
+                                           index,
+                                           &bus,
+                                           &device_fn))
+               {
+                       found += aic7xxx_register(template, T_294X,
+                                                 bus, device_fn);
+                       index += 1;
+               }
+       }
+
+       template->name = (char *)aic7xxx_info(NULL);
+       return(found);
+}
+
+const char *aic7xxx_info(struct Scsi_Host *notused)
+{
+       return("Adaptec AHA274x/284x/294x (EISA/VL-bus/PCI -> Fast SCSI) "
+              AIC7XXX_SEQ_VERSION "/"
+              AIC7XXX_H_VERSION "/"
+              "1.34");
+}
+
+static
+void aic7xxx_buildscb(struct aic7xxx_host *p,
+                     Scsi_Cmnd *cmd,
+                     struct aic7xxx_scb *scb)
+{
+       void *addr;
+       unsigned length;
+
+       memset(scb, 0, sizeof(*scb));
+
+       /*
+        *  NB. channel selection (bit 3) is always zero.
+        */
+       scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
+                                  (cmd->lun & 0x7);
+
+       /*
+        *  The interpretation of request_buffer and request_bufflen
+        *  changes depending on whether or not use_sg is zero; a
+        *  non-zero use_sg indicates the number of elements in the
+        *  scatter-gather array.
+        *
+        *  The AIC-7770 can't support transfers of any sort larger
+        *  than 2^24 (three-byte count) without backflips.  For what
+        *  the kernel is doing, this shouldn't occur.  I hope.
+        */
+       length = aic7xxx_length(cmd, 0);
+
+       /*
+        *  The sequencer code cannot yet handle scatter-gather segments
+        *  larger than 64k (two-byte length).  The 1.1.x kernels, however,
+        *  have a four-byte length field in the struct scatterlist, so
+        *  make sure we don't exceed 64k on these kernels for now.
+        */
+       aic7xxx_sg_check(cmd);
+
+       if (length > 0xffffff) {
+               panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+       }
+
+       /*
+        *  XXX - this relies on the host data being stored in a
+        *        little-endian format.
+        */
+       addr = cmd->cmnd;
+       scb->SCSI_cmd_length = cmd->cmd_len;
+       memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+
+       if (cmd->use_sg) {
+#if 0
+               debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
+                     cmd->use_sg,
+                     length);
+#endif
+               scb->SG_segment_count = cmd->use_sg;
+               memcpy(scb->SG_list_pointer,
+                      &cmd->request_buffer,
+                      sizeof(scb->SG_list_pointer));
+       } else {
+               scb->SG_segment_count = 0;
+               memcpy(scb->data_pointer,
+                      &cmd->request_buffer,
+                      sizeof(scb->data_pointer));
+               memcpy(scb->data_count,
+                      &cmd->request_bufflen,
+                      sizeof(scb->data_count));
+       }
+}
+
+static
+void aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
+{
+       /*
+        *  By turning on the SCB auto increment, any reference
+        *  to the SCB I/O space postincrements the SCB address
+        *  we're looking at.  So turn this on and dump the relevant
+        *  portion of the SCB to the card.
+        */
+       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
+
+       asm volatile("cld\n\t"
+                    "rep\n\t"
+                    "outsb"
+                    : /* no output */
+                    :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
+                    :"si", "cx", "dx");
+
+       outb(0, O_SCBCNT(base));
+}
+
+int aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+       long flags;
+       int empty, old_scbptr;
+       struct aic7xxx_host *p;
+       struct aic7xxx_scb scb;
+
+#if 0
+       debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, lun %d\n",
+             cmd->cmnd[0],
+             cmd->cmd_len,
+             cmd->target,
+             cmd->lun);
+#endif
+
+       p = (struct aic7xxx_host *)cmd->host->hostdata;
+
+       /*
+        *  Construct the SCB beforehand, so the sequencer is
+        *  paused a minimal amount of time.
+        */
+       aic7xxx_buildscb(p, cmd, &scb);
+
+       /*
+        *  Clear the startup flag - we can now legitimately
+        *  expect interrupts.
+        */
+       p->startup = 0;
+
+       /*
+        *  This is a critical section, since we don't want the
+        *  interrupt routine mucking with the host data or the
+        *  card.  Since the kernel documentation is vague on
+        *  whether or not we are in a cli/sti pair already, save
+        *  the flags to be on the safe side.
+        */
+       save_flags(flags);
+       cli();
+
+       /*
+        *  Find a free slot in the SCB array to load this command
+        *  into.  Since can_queue is set to the maximum number of
+        *  SCBs for the card, we should always find one.
+        */
+       for (empty = 0; empty < p->maxscb; empty++)
+               if (!p->SCB_array[empty])
+                       break;
+       if (empty == p->maxscb)
+               panic("aic7xxx_queue: couldn't find a free scb\n");
+
+       /*
+        *  Pause the sequencer so we can play with its registers -
+        *  wait for it to acknowledge the pause.
+        *
+        *  XXX - should the interrupts be left on while doing this?
+        */
+       PAUSE_SEQUENCER(p);
+
+       /*
+        *  Save the SCB pointer and put our own pointer in - this
+        *  selects one of the four banks of SCB registers.  Load
+        *  the SCB, then write its pointer into the queue in FIFO
+        *  and restore the saved SCB pointer.
+        */
+       old_scbptr = inb(O_SCBPTR(p->base));
+       outb(empty, O_SCBPTR(p->base));
+       
+       aic7xxx_putscb(p->base, &scb);
+
+       outb(empty, O_QINFIFO(p->base));
+       outb(old_scbptr, O_SCBPTR(p->base));
+
+       /*
+        *  Make sure the Scsi_Cmnd pointer is saved, the struct it
+        *  points to is set up properly, and the parity error flag
+        *  is reset, then unpause the sequencer and watch the fun
+        *  begin.
+        */
+       cmd->scsi_done = fn;
+       p->SCB_array[empty] = cmd;
+       aic7xxx_parity(cmd) = DID_OK;
+
+       UNPAUSE_SEQUENCER(p);
+
+       restore_flags(flags);
+       return(0);
+}
+
+/* return values from aic7xxx_kill */
+
+enum k_state {
+       k_ok,                           /* scb found and message sent */
+       k_busy,                         /* message already present */
+       k_absent,                       /* couldn't locate scb */
+       k_disconnect,                   /* scb found, but disconnected */
+};
+
+/*
+ *  This must be called with interrupts disabled - it's going to
+ *  be messing around with the host data, and an interrupt being
+ *  fielded in the middle could get ugly.
+ *
+ *  Since so much of the abort and reset code is shared, this
+ *  function performs more magic than it really should.  If the
+ *  command completes ok, then it will call scsi_done with the
+ *  result code passed in.  The unpause parameter controls whether
+ *  or not the sequencer gets unpaused - the reset function, for
+ *  instance, may want to do something more aggressive.
+ *
+ *  Note that the command is checked for in our SCB_array first
+ *  before the sequencer is paused, so if k_absent is returned,
+ *  then the sequencer is NOT paused.
+ */
+
+static
+enum k_state aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
+                         unsigned int result, int unpause)
+{
+       struct aic7xxx_host *p;
+       int i, scb, found, queued;
+       unsigned char scbsave[AIC7XXX_MAXSCB];
+
+       p = (struct aic7xxx_host *)cmd->host->hostdata;
+
+       /*
+        *  If we can't find the command, assume it just completed
+        *  and shrug it away.
+        */
+       for (scb = 0; scb < p->maxscb; scb++)
+               if (p->SCB_array[scb] == cmd)
+                       break;
+
+       if (scb == p->maxscb)
+               return(k_absent);
+
+       PAUSE_SEQUENCER(p);
+
+       /*
+        *  This is the best case, really.  Check to see if the
+        *  command is still in the sequencer's input queue.  If
+        *  so, simply remove it.  Reload the queue afterward.
+        */
+       queued = inb(O_QINCNT(p->base));
+       
+       for (i = found = 0; i < queued; i++) {
+               scbsave[i] = inb(O_QINFIFO(p->base));
+
+               if (scbsave[i] == scb) {
+                       found = 1;
+                       i -= 1;
+               }
+       }
+
+       queued -= found;
+       for (i = 0; i < queued; i++)
+               outb(scbsave[i], O_QINFIFO(p->base));
+
+       if (found)
+               goto complete;
+
+       /*
+        *  Check the current SCB bank.  If it's not the one belonging
+        *  to the command we want to kill, assume that the command
+        *  is disconnected.  It's rather a pain to force a reconnect
+        *  and send a message to the target, so we abdicate responsibility
+        *  in this case.
+        */
+       if (inb(O_SCBPTR(p->base)) != scb) {
+               if (unpause)
+                       UNPAUSE_SEQUENCER(p);
+               return(k_disconnect);
+       }
+
+       /*
+        *  Presumably at this point our target command is active.  Check
+        *  to see if there's a message already in effect.  If not, place
+        *  our message in and assert ATN so the target goes into MESSAGE
+        *  OUT phase.
+        */
+       if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
+               if (unpause)
+                       UNPAUSE_SEQUENCER(p);
+               return(k_busy);
+       }
+
+       outb(0x80, HA_MSG_FLAGS(p->base));              /* active message */
+       outb(1, HA_MSG_LEN(p->base));                   /* length = 1 */
+       outb(message, HA_MSG_START(p->base));           /* message body */
+
+       /*
+        *  Assert ATN.  Use the value of SCSISIGO saved by the
+        *  sequencer code so we don't alter its contents radically
+        *  in the middle of something critical.
+        */
+       outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
+
+       /*
+        *  The command has been killed.  Do the bookkeeping, unpause
+        *  the sequencer, and notify the higher-level SCSI code.
+        */
+complete:
+       p->SCB_array[scb] = NULL;
+       if (unpause)
+               UNPAUSE_SEQUENCER(p);
+
+       cmd->result = result << 16;
+       cmd->scsi_done(cmd);
+       return(k_ok);
+}
+
+int aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+       int rv;
+       long flags;
+
+       save_flags(flags);
+       cli();
+
+       switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0)) {
+           case k_ok:          rv = SCSI_ABORT_SUCCESS;        break;
+           case k_busy:        rv = SCSI_ABORT_BUSY;           break;
+           case k_absent:      rv = SCSI_ABORT_NOT_RUNNING;    break;
+           case k_disconnect:  rv = SCSI_ABORT_SNOOZE;         break;
+           default:
+               panic("aic7xxx_do_abort: internal error\n");
+       }
+
+       restore_flags(flags);
+       return(rv);
+}
+
+/*
+ *  Resetting the bus always succeeds - is has to, otherwise the
+ *  kernel will panic!  Try a surgical technique - sending a BUS
+ *  DEVICE RESET message - on the offending target before pulling
+ *  the SCSI bus reset line.
+ */
+
+int aic7xxx_reset(Scsi_Cmnd *cmd)
+{
+       int i;
+       long flags;
+       Scsi_Cmnd *reset;
+       struct aic7xxx_host *p;
+
+       p = (struct aic7xxx_host *)cmd->host->hostdata;
+       save_flags(flags);
+       cli();
+
+       switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
+
+           case k_ok:
+               /*
+                *  The RESET message was sent to the target
+                *  with no problems.  Flag that target as
+                *  needing a SDTR negotiation on the next
+                *  connection and restart the sequencer.
+                */
+               outb((1 << cmd->target), HA_NEEDSDTR(p->base));
+               UNPAUSE_SEQUENCER(p);
+               break;
+
+           case k_absent:
+               /*
+                *  The sequencer will not be paused if aic7xxx_kill()
+                *  couldn't find the command.
+                */
+               PAUSE_SEQUENCER(p);
+               /* falls through */
+
+           case k_busy:
+           case k_disconnect:
+               /*
+                *  Do a hard reset of the SCSI bus.  According to the
+                *  SCSI-2 draft specification, reset has to be asserted
+                *  for at least 25us.  I'm invoking the kernel delay
+                *  function for 30us since I'm not totally trusting of
+                *  the busy loop timing.
+                *
+                *  XXX - I'm not convinced this works.  I tried resetting
+                *        the bus before, trying to get the devices on the
+                *        bus to revert to asynchronous transfer, and it
+                *        never seemed to work.
+                */
+               debug("aic7xxx: attempting to reset scsi bus and card\n");
+
+               outb(1, O_SCSISEQ(p->base));            /* SCSIRSTO */
+               udelay(30);
+               outb(0, O_SCSISEQ(p->base));            /* !SCSIRSTO */
+
+               outb(0xff, HA_NEEDSDTR(p->base));
+               UNPAUSE_SEQUENCER(p);
+
+               /*
+                *  Locate the command and return a "reset" status
+                *  for it.  This is not completely correct and will
+                *  probably return to haunt me later.
+                */
+               for (i = 0; i < p->maxscb; i++) {
+                       if (cmd == p->SCB_array[i]) {
+                               reset = (Scsi_Cmnd *)p->SCB_array[i];
+                               p->SCB_array[i] = NULL;
+                               reset->result = DID_RESET << 16;
+                               reset->scsi_done(reset);
+                               break;
+                       }
+               }
+               break;
+
+           default:
+               panic("aic7xxx_reset: internal error\n");
+       }
+
+       restore_flags(flags);
+       return(SCSI_RESET_SUCCESS);
+}
+
+int aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+{
+       int heads, sectors, cylinders;
+       struct aic7xxx_host *p;
+       
+       p = (struct aic7xxx_host *)disk->device->host->hostdata;
+
+       /*
+        *  XXX - if I could portably find the card's configuration
+        *        information, then this could be autodetected instead
+        *        of left to a boot-time switch.
+        */
+       heads = 64;
+       sectors = 32;
+       cylinders = disk->capacity / (heads * sectors);
+
+       if (p->extended && cylinders > 1024) {
+               heads = 255;
+               sectors = 63;
+               cylinders = disk->capacity / (255 * 63);
+       }
+
+       geom[0] = heads;
+       geom[1] = sectors;
+       geom[2] = cylinders;
+
+       return(0);
+}
+
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
new file mode 100644 (file)
index 0000000..027772a
--- /dev/null
@@ -0,0 +1,63 @@
+/* @(#)aic7xxx.h 1.14 94/11/30 jda */
+
+/*
+ * Adaptec 274x/284x/294x device driver for Linux.
+ * Copyright (c) 1994 The University of Calgary Department of Computer Science.
+ * 
+ * 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.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef aic7xxx_h
+#define aic7xxx_h
+
+#define AIC7XXX_H_VERSION      "1.14"
+
+/*
+ *  Scsi_Host_Template (see hosts.h) for 274x - some fields
+ *  to do with card config are filled in after the card is
+ *  detected.
+ */
+#define AIC7XXX        {                                               \
+       NULL,                                                   \
+       NULL,                                                   \
+       NULL,                                                   \
+       aic7xxx_detect,                                         \
+       NULL,                                                   \
+       aic7xxx_info,                                           \
+       NULL,                                                   \
+       aic7xxx_queue,                                          \
+       aic7xxx_abort,                                          \
+       aic7xxx_reset,                                          \
+       NULL,                                                   \
+       aic7xxx_biosparam,                                      \
+       -1,                     /* max simultaneous cmds      */\
+       -1,                     /* scsi id of host adapter    */\
+       SG_ALL,                 /* max scatter-gather cmds    */\
+       1,                      /* cmds per lun (linked cmds) */\
+       0,                      /* number of 274x's present   */\
+       0,                      /* no memory DMA restrictions */\
+       DISABLE_CLUSTERING                                      \
+}
+
+extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+extern int aic7xxx_biosparam(Disk *, int, int[]);
+extern int aic7xxx_detect(Scsi_Host_Template *);
+extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_abort(Scsi_Cmnd *);
+extern int aic7xxx_reset(Scsi_Cmnd *);
+
+extern const char *aic7xxx_info(struct Scsi_Host *);
+
+#endif
diff --git a/drivers/scsi/aic7xxx.seq b/drivers/scsi/aic7xxx.seq
new file mode 100644 (file)
index 0000000..8538e8f
--- /dev/null
@@ -0,0 +1,1029 @@
+# @(#)aic7xxx.seq 1.32 94/11/29 jda
+#
+# Adaptec 274x/284x/294x device driver for Linux.
+# Copyright (c) 1994 The University of Calgary Department of Computer Science.
+# 
+# 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.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+VERSION AIC7XXX_SEQ_VERSION 1.32
+
+SCBMASK                = 0x1f
+
+SCSISEQ                = 0x00
+SXFRCTL0       = 0x01
+SXFRCTL1       = 0x02
+SCSISIGI       = 0x03
+SCSISIGO       = 0x03
+SCSIRATE       = 0x04
+SCSIID         = 0x05
+SCSIDATL       = 0x06
+STCNT          = 0x08
+STCNT+0                = 0x08
+STCNT+1                = 0x09
+STCNT+2                = 0x0a
+SSTAT0         = 0x0b
+CLRSINT1       = 0x0c
+SSTAT1         = 0x0c
+SIMODE1                = 0x11
+SCSIBUSL       = 0x12
+SHADDR         = 0x14
+SELID          = 0x19
+SBLKCTL                = 0x1f
+SEQCTL         = 0x60
+A              = 0x64                          # == ACCUM
+SINDEX         = 0x65
+DINDEX         = 0x66
+ALLZEROS       = 0x6a
+NONE           = 0x6a
+SINDIR         = 0x6c
+DINDIR         = 0x6d
+FUNCTION1      = 0x6e
+HADDR          = 0x88
+HCNT           = 0x8c
+HCNT+0         = 0x8c
+HCNT+1         = 0x8d
+HCNT+2         = 0x8e
+SCBPTR         = 0x90
+INTSTAT                = 0x91
+DFCNTRL                = 0x93
+DFSTATUS       = 0x94
+DFDAT          = 0x99
+QINFIFO                = 0x9b
+QINCNT         = 0x9c
+QOUTFIFO       = 0x9d
+
+SCSICONF       = 0x5a
+
+#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
+#  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
+#  to indicate whether or not to reload scatter-gather parameters after
+#  a disconnect.
+#
+SCBARRAY+0     = 0xa0
+SCBARRAY+1     = 0xa1
+SCBARRAY+2     = 0xa2
+SCBARRAY+3     = 0xa3
+SCBARRAY+7     = 0xa7
+SCBARRAY+11    = 0xab
+SCBARRAY+14    = 0xae
+SCBARRAY+15    = 0xaf
+SCBARRAY+16    = 0xb0
+SCBARRAY+17    = 0xb1
+SCBARRAY+18    = 0xb2
+SCBARRAY+19    = 0xb3
+SCBARRAY+20    = 0xb4
+SCBARRAY+21    = 0xb5
+SCBARRAY+22    = 0xb6
+SCBARRAY+23    = 0xb7
+SCBARRAY+24    = 0xb8
+SCBARRAY+25    = 0xb9
+
+SIGNAL_0       = 0x01                          # unknown scsi bus phase
+SIGNAL_1       = 0x11                          # message reject
+SIGNAL_2       = 0x21                          # no IDENTIFY after reconnect
+SIGNAL_3       = 0x31                          # no cmd match for reconnect
+SIGNAL_4       = 0x41                          # SDTR -> SCSIRATE conversion
+
+#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
+#  device information, 32-33 and 5a-5f as well.  Since we don't support
+#  wide or twin-bus SCSI, 28-2f can be reclaimed.  As it turns out, the
+#  BIOS trashes 20-27 anyway, writing the synchronous negotiation results
+#  on top of the BIOS values, so we re-use those for our per-target
+#  scratchspace (actually a value that can be copied directly into
+#  SCSIRATE).  This implies, since we can't get the BIOS config values,
+#  that all targets will be negotiated with for synchronous transfer.
+#  NEEDSDTR has one bit per target indicating if an SDTR message is
+#  needed for that device - this will be set initially, as well as
+#  after a bus reset condition.
+#
+#  The high bit of DROPATN is set if ATN should be dropped before the ACK
+#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
+#  message, so the driver can report an intelligible error if a message is
+#  rejected.
+#
+#  RESELECT's high bit is true if we are currently handling a reselect;
+#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
+#  from the reselecting target.  If we haven't had IDENTIFY, then we have
+#  no idea what the lun is, and we can't select the right SCB register
+#  bank, so force a kernel panic if the target attempts a data in/out or
+#  command phase instead of corrupting something.
+#
+#  Note that SG_NEXT occupies four bytes.
+#
+SYNCNEG                = 0x20
+DISC_DSB_A     = 0x32
+
+DROPATN                = 0x30
+REJBYTE                = 0x31
+RESELECT       = 0x34
+
+MSG_FLAGS      = 0x35
+MSG_LEN                = 0x36
+MSG_START+0    = 0x37
+MSG_START+1    = 0x38
+MSG_START+2    = 0x39
+MSG_START+3    = 0x3a
+MSG_START+4    = 0x3b
+MSG_START+5    = 0x3c
+-MSG_START+0   = 0xc9                          # 2's complement of MSG_START+0
+
+ARG_1          = 0x4c                          # sdtr conversion args & return
+ARG_2          = 0x4d
+RETURN_1       = 0x4c
+
+SIGSTATE       = 0x4e                          # value written to SCSISIGO
+NEEDSDTR       = 0x4f                          # send SDTR message, 1 bit/trgt
+
+SG_SIZEOF      = 12                            # sizeof(struct scatterlist)
+SG_NOLOAD      = 0x50                          # load SG pointer/length?
+SG_COUNT       = 0x51                          # working value of SG count
+SG_NEXT                = 0x52                          # working value of SG pointer
+SG_NEXT+0      = 0x52
+SG_NEXT+1      = 0x53
+SG_NEXT+2      = 0x54
+SG_NEXT+3      = 0x55
+
+SCBCOUNT       = 0x56                          # the actual number of SCBs
+
+#  Poll QINCNT for work - the lower bits contain
+#  the number of entries in the Queue In FIFO.
+#
+start:
+       test    SCSISIGI,0x4    jnz reselect    # BSYI
+       test    QINCNT,SCBMASK  jz start
+
+#  We have at least one queued SCB now.  Set the SCB pointer
+#  from the FIFO so we see the right bank of SCB registers,
+#  then set SCSI options and set the initiator and target
+#  SCSI IDs.
+#
+       mov     SCBPTR,QINFIFO
+       mov     SCBARRAY+1      call initialize
+       clr     SG_NOLOAD
+       clr     RESELECT
+
+#  As soon as we get a successful selection, the target should go
+#  into the message out phase since we have ATN asserted.  Prepare
+#  the message to send, locking out the device driver.  If the device
+#  driver hasn't beaten us with an ABORT or RESET message, then tack
+#  on a SDTR negotiation if required.
+#
+#  Messages are stored in scratch RAM starting with a flag byte (high bit
+#  set means active message), one length byte, and then the message itself.
+#
+       mov     SCBARRAY+1      call disconnect # disconnect ok?
+
+       and     SINDEX,0x7,SCBARRAY+1           # lun
+       or      SINDEX,A                        # return value from disconnect
+       or      SINDEX,0x80     call mk_mesg    # IDENTIFY message
+
+       mov     A,SINDEX
+       cmp     MSG_START+0,A   jne !message    # did driver beat us?
+       mvi     MSG_START+1     call mk_sdtr    # build SDTR message if needed
+
+!message:
+
+#  Enable selection phase as an initiator, and do automatic ATN
+#  after the selection.
+#
+       mvi     SCSISEQ,0x48                    # ENSELO|ENAUTOATNO
+
+#  Wait for successful arbitration.  The AIC-7770 documentation says
+#  that SELINGO indicates successful arbitration, and that it should
+#  be used to look for SELDO.  However, if the sequencer is paused at
+#  just the right time - a parallel fsck(8) on two drives did it for
+#  me - then SELINGO can flip back to false before we've seen it.  This
+#  makes the sequencer sit in the arbitration loop forever.  This is
+#  Not Good.
+#
+#  Therefore, I've added a check in the arbitration loop for SELDO
+#  too.  This could arguably be made a critical section by disabling
+#  pauses, but I don't want to make a potentially infinite loop a CS.
+#  I suppose you could fold it into the select loop, too, but since
+#  I've been hunting this bug for four days it's kinda like a trophy.
+#
+arbitrate:
+       test    SSTAT0,0x40     jnz *select     # SELDO
+       test    SSTAT0,0x10     jz arbitrate    # SELINGO
+
+#  Wait for a successful selection.  If the hardware selection
+#  timer goes off, then the driver gets the interrupt, so we don't
+#  need to worry about it.
+#
+select:
+       test    SSTAT0,0x40     jz select       # SELDO
+       jmp     *select
+
+#  Reselection is being initiated by a target - we've seen the BSY
+#  line driven active, and we didn't do it!  Enable the reselection
+#  hardware, and wait for it to finish.  Make a note that we've been
+#  reselected, but haven't seen an IDENTIFY message from the target
+#  yet.
+#
+reselect:
+       mvi     SCSISEQ,0x10                    # ENRSELI
+
+reselect1:
+       test    SSTAT0,0x20     jz reselect1    # SELDI
+       mov     SELID           call initialize
+
+       mvi     RESELECT,0x80                   # reselected, no IDENTIFY
+
+#  After the [re]selection, make sure that the [re]selection enable
+#  bit is off.  This chip is flaky enough without extra things
+#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
+#  using it shortly.
+#
+*select:
+       clr     SCSISEQ
+       mvi     CLRSINT1,0x8                    # CLRBUSFREE
+
+#  Main loop for information transfer phases.  If BSY is false, then
+#  we have a bus free condition, expected or not.  Otherwise, wait
+#  for the target to assert REQ before checking MSG, C/D and I/O
+#  for the bus phase.
+#
+#  We can't simply look at the values of SCSISIGI here (if we want
+#  to do synchronous data transfer), because the target won't assert
+#  REQ if it's already sent us some data that we haven't acknowledged
+#  yet.
+#
+ITloop:
+       test    SSTAT1,0x8      jnz p_busfree   # BUSFREE
+       test    SSTAT1,0x1      jz ITloop       # REQINIT
+
+       and     A,0xe0,SCSISIGI                 # CDI|IOI|MSGI
+
+       cmp     ALLZEROS,A      je p_dataout
+       cmp     A,0x40          je p_datain
+       cmp     A,0x80          je p_command
+       cmp     A,0xc0          je p_status
+       cmp     A,0xa0          je p_mesgout
+       cmp     A,0xe0          je p_mesgin
+
+       mvi     INTSTAT,SIGNAL_0                # unknown - signal driver
+
+p_dataout:
+       mvi     0               call scsisig    # !CDO|!IOO|!MSGO
+       call    assert
+       call    sg_load
+
+       mvi     A,3
+       mvi     DINDEX,HCNT
+       mvi     SCBARRAY+23     call bcopy
+
+       mvi     A,3
+       mvi     DINDEX,STCNT
+       mvi     SCBARRAY+23     call bcopy
+
+       mvi     A,4
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+19     call bcopy
+
+       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
+                                               #   DIRECTION|FIFORESET
+
+#  After a DMA finishes, save the final transfer pointer and count
+#  back into the SCB, in case a device disconnects in the middle of
+#  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
+#  it's a reflection of how many bytes were transferred on the SCSI
+#  (as opposed to the host) bus.
+#
+       mvi     A,3
+       mvi     DINDEX,SCBARRAY+23
+       mvi     STCNT           call bcopy
+
+       mvi     A,4
+       mvi     DINDEX,SCBARRAY+19
+       mvi     SHADDR          call bcopy
+
+       call    sg_advance
+       mov     SCBARRAY+18,SG_COUNT            # residual S/G count
+
+       jmp     ITloop
+
+p_datain:
+       mvi     0x40            call scsisig    # !CDO|IOO|!MSGO
+       call    assert
+       call    sg_load
+
+       mvi     A,3
+       mvi     DINDEX,HCNT
+       mvi     SCBARRAY+23     call bcopy
+
+       mvi     A,3
+       mvi     DINDEX,STCNT
+       mvi     SCBARRAY+23     call bcopy
+
+       mvi     A,4
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+19     call bcopy
+
+       mvi     0x39            call dma        # SCSIEN|SDMAEN|HDMAEN|
+                                               #   !DIRECTION|FIFORESET
+       mvi     A,3
+       mvi     DINDEX,SCBARRAY+23
+       mvi     STCNT           call bcopy
+
+       mvi     A,4
+       mvi     DINDEX,SCBARRAY+19
+       mvi     SHADDR          call bcopy
+
+       call    sg_advance
+       mov     SCBARRAY+18,SG_COUNT            # residual S/G count
+
+       jmp     ITloop
+
+#  Command phase.  Set up the DMA registers and let 'er rip - the
+#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
+#  so we can copy those three bytes directly into HCNT.
+#
+p_command:
+       mvi     0x80            call scsisig    # CDO|!IOO|!MSGO
+       call    assert
+
+       mvi     A,3
+       mvi     DINDEX,HCNT
+       mvi     SCBARRAY+11     call bcopy
+
+       mvi     A,3
+       mvi     DINDEX,STCNT
+       mvi     SCBARRAY+11     call bcopy
+
+       mvi     A,4
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+7      call bcopy
+
+       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
+                                               #   DIRECTION|FIFORESET
+       jmp     ITloop
+
+#  Status phase.  Wait for the data byte to appear, then read it
+#  and store it into the SCB.
+#
+p_status:
+       mvi     0xc0            call scsisig    # CDO|IOO|!MSGO
+
+       mvi     SCBARRAY+14     call inb
+       jmp     ITloop
+
+#  Message out phase.  If there is no active message, but the target
+#  took us into this phase anyway, build a no-op message and send it.
+#
+p_mesgout:
+       mvi     0xa0            call scsisig    # CDO|!IOO|MSGO
+       mvi     0x8             call mk_mesg    # build NOP message
+
+#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
+#  SXFRCTL0 (SPIOEN) is already on.
+#
+       mvi     SINDEX,MSG_START+0
+       mov     DINDEX,MSG_LEN
+       clr     A
+
+#  When target asks for a byte, drop ATN if it's the last one in
+#  the message.  Otherwise, keep going until the message is exhausted.
+#  (We can't use outb for this since it wants the input in SINDEX.)
+#
+#  Keep an eye out for a phase change, in case the target issues
+#  a MESSAGE REJECT.
+#
+p_mesgout2:
+       test    SSTAT0,0x2      jz p_mesgout2   # SPIORDY
+       test    SSTAT1,0x10     jnz p_mesgout6  # PHASEMIS
+
+       cmp     DINDEX,1        jne p_mesgout3  # last byte?
+       mvi     CLRSINT1,0x40                   # CLRATNO - drop ATN
+
+#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
+#  send ACKs in automatic PIO or DMA mode unless you make sure that the
+#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
+#  behaviour is completely undocumented and caused me several days of
+#  grief.
+#
+#  After plugging in different drives to test with and using a longer
+#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
+#  especially when transferring >1 byte.  It seems to be much more stable
+#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
+#  polled for transfer completion - for both output _and_ input.  The
+#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
+#  is accessed (like the documentation says it does), and that on a longer
+#  cable run, the sequencer code was fast enough to loop back and see
+#  an SPIORDY that hadn't dropped yet.
+#
+p_mesgout3:
+       call    one_stcnt
+       mov     SCSIDATL,SINDIR
+
+p_mesgout4:
+       test    SSTAT0,0x4      jz p_mesgout4   # SDONE
+       dec     DINDEX
+       inc     A
+       cmp     MSG_LEN,A       jne p_mesgout2
+
+#  If the next bus phase after ATN drops is a message out, it means
+#  that the target is requesting that the last message(s) be resent.
+#
+p_mesgout5:
+       test    SSTAT1,0x8      jnz p_mesgout6  # BUSFREE
+       test    SSTAT1,0x1      jz p_mesgout5   # REQINIT
+
+       and     A,0xe0,SCSISIGI                 # CDI|IOI|MSGI
+       cmp     A,0xa0          jne p_mesgout6
+       mvi     0x10            call scsisig    # ATNO - re-assert ATN
+
+       jmp     ITloop
+
+p_mesgout6:
+       mvi     CLRSINT1,0x40                   # CLRATNO - in case of PHASEMIS
+       clr     MSG_FLAGS                       # no active msg
+       jmp     ITloop
+
+#  Message in phase.  Bytes are read using Automatic PIO mode, but not
+#  using inb.  This alleviates a race condition, namely that if ATN had
+#  to be asserted under Automatic PIO mode, it had to beat the SCSI
+#  circuitry sending an ACK to the target.  This showed up under heavy
+#  loads and really confused things, since ABORT commands wouldn't be
+#  seen by the drive after an IDENTIFY message in until it had changed
+#  to a data I/O phase.
+#
+p_mesgin:
+       mvi     0xe0            call scsisig    # CDO|IOO|MSGO
+       mvi     A               call inb_first  # read the 1st message byte
+       mvi     REJBYTE,A                       # save it for the driver
+
+       cmp     ALLZEROS,A      jne p_mesgin1
+
+#  We got a "command complete" message, so put the SCB pointer
+#  into the Queue Out, and trigger a completion interrupt.
+#
+       mov     QOUTFIFO,SCBPTR
+       mvi     INTSTAT,0x2                     # CMDCMPLT
+       jmp     p_mesgin_done
+
+#  Is it an extended message?  We only support the synchronous data
+#  transfer request message, which will probably be in response to
+#  an SDTR message out from us.  If it's not an SDTR, reject it -
+#  apparently this can be done after any message in byte, according
+#  to the SCSI-2 spec.
+#
+#  XXX - we should really reject this if we didn't initiate the SDTR
+#       negotiation; this may cause problems with unusual devices.
+#
+p_mesgin1:
+       cmp     A,1             jne p_mesgin2   # extended message code?
+       
+       mvi     A               call inb_next
+       cmp     A,3             jne p_mesginN   # extended mesg length = 3
+       mvi     A               call inb_next
+       cmp     A,1             jne p_mesginN   # SDTR code
+
+       mvi     ARG_1           call inb_next   # xfer period
+       mvi     ARG_2           call inb_next   # REQ/ACK offset
+       mvi     INTSTAT,SIGNAL_4                # call driver to convert
+
+       call    ndx_sdtr                        # index sync config for target
+       mov     DINDEX,SINDEX
+       mov     DINDIR,RETURN_1                 # save returned value
+
+       not     A                               # turn off "need sdtr" flag
+       and     NEEDSDTR,A
+
+#  Even though the SCSI-2 specification says that a device responding
+#  to our SDTR message should honor our parameters for transmitting
+#  to us, it doesn't seem to work too well in real life.  In particular,
+#  a lot of CD-ROM and tape units don't function: try using the SDTR
+#  parameters the device sent us for both transmitting and receiving.
+#
+       mov     SCSIRATE,RETURN_1
+       jmp     p_mesgin_done
+
+#  Is it a disconnect message?  Set a flag in the SCB to remind us
+#  and await the bus going free.
+#
+p_mesgin2:
+       cmp     A,4             jne p_mesgin3   # disconnect code?
+
+       or      SCBARRAY+0,0x4                  # set "disconnected" bit
+       jmp     p_mesgin_done
+
+#  Save data pointers message?  Copy working values into the SCB,
+#  usually in preparation for a disconnect.
+#
+p_mesgin3:
+       cmp     A,2             jne p_mesgin4   # save data pointers code?
+
+       call    sg_ram2scb
+       jmp     p_mesgin_done
+
+#  Restore pointers message?  Data pointers are recopied from the
+#  SCB anyway at the start of any DMA operation, so the only thing
+#  to copy is the scatter-gather values.
+#
+p_mesgin4:
+       cmp     A,3             jne p_mesgin5   # restore pointers code?
+
+       call    sg_scb2ram
+       jmp     p_mesgin_done
+
+#  Identify message?  For a reconnecting target, this tells us the lun
+#  that the reconnection is for - find the correct SCB and switch to it,
+#  clearing the "disconnected" bit so we don't "find" it by accident later.
+#
+p_mesgin5:
+       test    A,0x80          jz p_mesgin6    # identify message?
+
+       test    A,0x78          jnz p_mesginN   # !DiscPriv|!LUNTAR|!Reserved
+
+       mov     A               call findSCB    # switch to correct SCB
+
+#  If a active message is present after calling findSCB, then either it
+#  or the driver is trying to abort the command.  Either way, something
+#  untoward has happened and we should just leave it alone.
+#
+       test    MSG_FLAGS,0x80  jnz p_mesgin_done
+
+       xor     SCBARRAY+0,0x4                  # clear disconnect bit in SCB
+       mvi     RESELECT,0xc0                   # make note of IDENTIFY
+
+       call    sg_scb2ram                      # implied restore pointers
+                                               #   required on reselect
+       jmp     p_mesgin_done
+
+#  Message reject?  If we have an outstanding SDTR negotiation, assume
+#  that it's a response from the target selecting asynchronous transfer,
+#  otherwise just ignore it since we have no clue what it pertains to.
+#
+#  XXX - I don't have a device that responds this way.  Does this code
+#       actually work?
+#
+p_mesgin6:
+       cmp     A,7             jne p_mesgin7   # message reject code?
+
+       and     FUNCTION1,0x70,SCSIID           # outstanding SDTR message?
+       mov     A,FUNCTION1
+       test    NEEDSDTR,A      jz p_mesgin_done  # no - ignore rejection
+
+       call    ndx_sdtr                        # note use of asynch xfer
+       mov     DINDEX,SINDEX
+       clr     DINDIR
+
+       not     A                               # turn off "active sdtr" flag
+       and     NEEDSDTR,A
+
+       clr     SCSIRATE                        # select asynch xfer
+       jmp     p_mesgin_done
+
+#  [ ADD MORE MESSAGE HANDLING HERE ]
+#
+p_mesgin7:
+
+#  We have no idea what this message in is, and there's no way
+#  to pass it up to the kernel, so we issue a message reject and
+#  hope for the best.  Since we're now using manual PIO mode to
+#  read in the message, there should no longer be a race condition
+#  present when we assert ATN.  In any case, rejection should be a
+#  rare occurrence - signal the driver when it happens.
+#
+p_mesginN:
+       or      SINDEX,0x10,SIGSTATE            # turn on ATNO
+       call    scsisig
+       mvi     INTSTAT,SIGNAL_1                # let driver know
+
+       mvi     0x7             call mk_mesg    # MESSAGE REJECT message
+
+p_mesgin_done:
+       call    inb_last                        # ack & turn auto PIO back on
+       jmp     ITloop
+
+#  Bus free phase.  It might be useful to interrupt the device
+#  driver if we aren't expecting this.  For now, make sure that
+#  ATN isn't being asserted and look for a new command.
+#
+p_busfree:
+       mvi     CLRSINT1,0x40                   # CLRATNO
+       clr     SIGSTATE
+       jmp     start
+
+#  Bcopy: number of bytes to transfer should be in A, DINDEX should
+#  contain the destination address, and SINDEX should contain the
+#  source address.  All input parameters are trashed on return.
+#
+bcopy:
+       mov     DINDIR,SINDIR
+       dec     A
+       cmp     ALLZEROS,A      jne bcopy
+       ret
+
+#  Locking the driver out, build a one-byte message passed in SINDEX
+#  if there is no active message already.  SINDEX is returned intact.
+#
+mk_mesg:
+       mvi     SEQCTL,0x40                     # PAUSEDIS
+       test    MSG_FLAGS,0x80  jnz mk_mesg1    # active message?
+
+       mvi     MSG_FLAGS,0x80                  # if not, there is now
+       mvi     MSG_LEN,1                       # length = 1
+       mov     MSG_START+0,SINDEX              # 1-byte message
+
+mk_mesg1:
+       clr     SEQCTL                          # !PAUSEDIS
+       ret
+
+#  Input byte in Automatic PIO mode.  The address to store the byte
+#  in should be in SINDEX.  DINDEX will be used by this routine.
+#
+inb:
+       test    SSTAT0,0x2      jz inb          # SPIORDY
+       mov     DINDEX,SINDEX
+       call    one_stcnt                       # xfer one byte
+       mov     DINDIR,SCSIDATL
+inb1:
+       test    SSTAT0,0x4      jz inb1         # SDONE - wait to "finish"
+       ret
+
+#  Carefully read data in Automatic PIO mode.  I first tried this using
+#  Manual PIO mode, but it gave me continual underrun errors, probably
+#  indicating that I did something wrong, but I feel more secure leaving
+#  Automatic PIO on all the time.
+#
+#  According to Adaptec's documentation, an ACK is not sent on input from
+#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+#  latched (the usual way), then read the data byte directly off the bus
+#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+#  spec guarantees that the target will hold the data byte on the bus until
+#  we send our ACK.
+#
+#  The assumption here is that these are called in a particular sequence,
+#  and that REQ is already set when inb_first is called.  inb_{first,next}
+#  use the same calling convention as inb.
+#
+inb_first:
+       mov     DINDEX,SINDEX
+       mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
+
+inb_next:
+       mov     DINDEX,SINDEX                   # save SINDEX
+
+       call    one_stcnt                       # xfer one byte
+       mov     NONE,SCSIDATL                   # dummy read from latch to ACK
+inb_next1:
+       test    SSTAT0,0x4      jz inb_next1    # SDONE
+inb_next2:
+       test    SSTAT0,0x2      jz inb_next2    # SPIORDY - wait for next byte
+       mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
+
+inb_last:
+       call    one_stcnt                       # ACK with dummy read
+       mov     NONE,SCSIDATL
+inb_last1:
+       test    SSTAT0,0x4      jz inb_last1    # wait for completion
+       ret
+
+#  Output byte in Automatic PIO mode.  The byte to output should be
+#  in SINDEX.  If DROPATN's high bit is set, then ATN will be dropped
+#  before the byte is output.
+#
+outb:
+       test    SSTAT0,0x2      jz outb         # SPIORDY
+       call    one_stcnt                       # xfer one byte
+
+       test    DROPATN,0x80    jz outb1
+       mvi     CLRSINT1,0x40                   # CLRATNO
+       clr     DROPATN
+outb1:
+       mov     SCSIDATL,SINDEX
+outb2:
+       test    SSTAT0,0x4      jz outb2        # SDONE
+       ret
+
+#  Write the value "1" into the STCNT registers, for Automatic PIO
+#  transfers.
+#
+one_stcnt:
+       clr     STCNT+2
+       clr     STCNT+1
+       mvi     STCNT+0,1       ret
+
+#  DMA data transfer.  HADDR and HCNT must be loaded first, and
+#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
+#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+#  during initialization.
+#
+dma:
+       mov     DFCNTRL,SINDEX
+dma1:
+dma2:
+       test    SSTAT0,0x1      jnz dma3        # DMADONE
+       test    SSTAT1,0x10     jz dma1         # PHASEMIS, ie. underrun
+
+#  We will be "done" DMAing when the transfer count goes to zero, or
+#  the target changes the phase (in light of this, it makes sense that
+#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+#  doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+#  magically on STCNT=0 or a phase change, so just wait for FIFO empty
+#  status.
+#
+dma3:
+       test    SINDEX,0x4      jnz dma5        # DIRECTION
+dma4:
+       test    DFSTATUS,0x1    jz dma4         # !FIFOEMP
+
+#  Now shut the DMA enables off, and copy STCNT (ie. the underrun
+#  amount, if any) to the SCB registers; SG_COUNT will get copied to
+#  the SCB's residual S/G count field after sg_advance is called.  Make
+#  sure that the DMA enables are actually off first lest we get an ILLSADDR.
+#
+dma5:
+       clr     DFCNTRL                         # disable DMA
+dma6:
+       test    DFCNTRL,0x38    jnz dma6        # SCSIENACK|SDMAENACK|HDMAENACK
+
+       mvi     A,3
+       mvi     DINDEX,SCBARRAY+15
+       mvi     STCNT           call bcopy
+
+       ret
+
+#  Common SCSI initialization for selection and reselection.  Expects
+#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
+#  contents are stomped on return.
+#
+initialize:
+       clr     SBLKCTL                         # channel A, !wide
+       and     SCSIID,0xf0,SINDEX              # target ID
+       and     A,0x7,SCSICONF                  # SCSI_ID_A[210]
+       or      SCSIID,A
+
+#  Esundry initialization.
+#
+       clr     DROPATN
+       clr     SIGSTATE
+
+#  Turn on Automatic PIO mode now, before we expect to see an REQ
+#  from the target.  It shouldn't hurt anything to leave it on.  Set
+#  CLRCHN here before the target has entered a data transfer mode -
+#  with synchronous SCSI, if you do it later, you blow away some
+#  data in the SCSI FIFO that the target has already sent to you.
+#
+#  DFON is a 7870 bit enabling digital filtering of REQ and ACK signals.
+#
+       mvi     SXFRCTL0,0x8a                   # DFON|SPIOEN|CLRCHN
+
+#  Set SCSI bus parity checking and the selection timeout value,
+#  and enable the hardware selection timer.  Set the SELTO interrupt
+#  to signal the driver.
+#
+#  STPWEN is 7870-specific, enabling an external termination power source.
+#
+       and     A,0x38,SCSICONF                 # PARITY_ENB_A|SEL_TIM_A[10]
+       or      SXFRCTL1,0x5,A                  # ENSTIMER|STPWEN
+       mvi     SIMODE1,0x84                    # ENSELTIMO|ENSCSIPERR
+       
+#  Initialize scatter-gather pointers by setting up the working copy
+#  in scratch RAM.
+#
+       call    sg_scb2ram
+
+#  Initialize SCSIRATE with the appropriate value for this target.
+#
+       call    ndx_sdtr
+       mov     SCSIRATE,SINDIR
+       ret
+
+#  Assert that if we've been reselected, then we've seen an IDENTIFY
+#  message.
+#
+assert:
+       test    RESELECT,0x80   jz assert1      # reselected?
+       test    RESELECT,0x40   jnz assert1     # seen IDENTIFY?
+
+       mvi     INTSTAT,SIGNAL_2                # no - cause a kernel panic
+
+assert1:
+       ret
+
+#  Find out if disconnection is ok from the information the BIOS has left
+#  us.  The target ID should be in the upper four bits of SINDEX; A will
+#  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
+#  on exit.
+#
+#  This is the only place the target ID is limited to three bits, so we
+#  can use the FUNCTION1 register.
+#
+disconnect:
+       and     FUNCTION1,0x70,SINDEX           # strip off extra just in case
+       mov     A,FUNCTION1
+       test    DISC_DSB_A,A    jz disconnect1  # bit nonzero if DISabled
+
+       clr     A               ret
+disconnect1:
+       mvi     A,0x40          ret
+
+#  Locate the SCB matching the target ID in SELID and the lun in the lower
+#  three bits of SINDEX, and switch the SCB to it.  Have the kernel print
+#  a warning message if it can't be found, and generate an ABORT message
+#  to the target.
+#
+findSCB:
+       and     A,0x7,SINDEX                    # lun in lower three bits
+       or      A,A,SELID                       # can I do this?
+       and     A,0xf7                          # only channel A implemented
+       mov     DINDEX,A                        # save in DINDEX for later
+
+       clr     SINDEX
+
+findSCB1:
+       mov     A,DINDEX                        # reload A after 1st iteration
+       mov     SCBPTR,SINDEX                   # switch to new SCB
+       cmp     SCBARRAY+1,A    jne findSCB2    # target ID/channel/lun match?
+       test    SCBARRAY+0,0x4  jz findSCB2     # should be disconnected
+
+       ret
+
+findSCB2:
+       inc     SINDEX
+       mov     A,SCBCOUNT
+       cmp     SINDEX,A        jne findSCB1
+
+       mvi     INTSTAT,SIGNAL_3                # not found - signal kernel
+       mvi     0x6             call mk_mesg    # ABORT message
+
+       or      SINDEX,0x10,SIGSTATE            # assert ATNO
+       call    scsisig
+       ret
+
+#  Make a working copy of the scatter-gather parameters in the SCB.
+#
+sg_scb2ram:
+       mov     SG_COUNT,SCBARRAY+2
+
+       mvi     A,4
+       mvi     DINDEX,SG_NEXT
+       mvi     SCBARRAY+3      call bcopy
+
+       mvi     SG_NOLOAD,0x80
+       test    SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g?
+       clr     SG_NOLOAD
+
+sg_scb2ram1:
+       ret
+
+#  Copying RAM values back to SCB, for Save Data Pointers message.
+#
+sg_ram2scb:
+       mov     SCBARRAY+2,SG_COUNT
+
+       mvi     A,4
+       mvi     DINDEX,SCBARRAY+3
+       mvi     SG_NEXT         call bcopy
+
+       and     SCBARRAY+0,0xef,SCBARRAY+0
+       test    SG_NOLOAD,0x80  jz sg_ram2scb1  # reload s/g?
+       or      SCBARRAY+0,0x10
+
+sg_ram2scb1:
+       ret
+
+#  Load a struct scatter if needed and set up the data address and
+#  length.  If the working value of the SG count is nonzero, then
+#  we need to load a new set of values.
+#
+#  This, like the above DMA, assumes a little-endian host data storage.
+#
+sg_load:
+       test    SG_COUNT,0xff   jz sg_load3     # SG being used?
+       test    SG_NOLOAD,0x80  jnz sg_load3    # don't reload s/g?
+
+       clr     HCNT+2
+       clr     HCNT+1
+       mvi     HCNT+0,SG_SIZEOF
+
+       mvi     A,4
+       mvi     DINDEX,HADDR
+       mvi     SG_NEXT         call bcopy
+
+       mvi     DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
+
+#  Wait for DMA from host memory to data FIFO to complete, then disable
+#  DMA and wait for it to acknowledge that it's off.
+#
+sg_load1:
+       test    DFSTATUS,0x8    jz sg_load1     # HDONE
+
+       clr     DFCNTRL                         # disable DMA
+sg_load2:
+       test    DFCNTRL,0x8     jnz sg_load2    # HDMAENACK
+
+#  Copy data from FIFO into SCB data pointer and data count.  This assumes
+#  that the struct scatterlist has this structure (this and sizeof(struct
+#  scatterlist) == 12 are asserted in aic7xxx.c):
+#
+#      struct scatterlist {
+#              char *address;          /* four bytes, little-endian order */
+#              ...                     /* four bytes, ignored */
+#              unsigned short length;  /* two bytes, little-endian order */
+#      }
+#
+       mov     SCBARRAY+19,DFDAT               # new data address
+       mov     SCBARRAY+20,DFDAT
+       mov     SCBARRAY+21,DFDAT
+       mov     SCBARRAY+22,DFDAT
+
+       mov     NONE,DFDAT                      # throw away four bytes
+       mov     NONE,DFDAT
+       mov     NONE,DFDAT
+       mov     NONE,DFDAT
+
+       mov     SCBARRAY+23,DFDAT
+       mov     SCBARRAY+24,DFDAT
+       clr     SCBARRAY+25
+
+sg_load3:
+       ret
+
+#  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
+#  and the SCSI transfer count is zero (note that this should be called
+#  right after a DMA finishes), then move the working copies of the SG
+#  pointer/length along.  If the SCSI transfer count is not zero, then
+#  presumably the target is disconnecting - do not reload the SG values
+#  next time.
+#
+sg_advance:
+       test    SG_COUNT,0xff   jz sg_advance2  # s/g enabled?
+
+       test    STCNT+0,0xff    jnz sg_advance1 # SCSI transfer count nonzero?
+       test    STCNT+1,0xff    jnz sg_advance1
+       test    STCNT+2,0xff    jnz sg_advance1
+
+       clr     SG_NOLOAD                       # reload s/g next time
+       dec     SG_COUNT                        # one less segment to go
+
+       clr     A                               # add sizeof(struct scatter)
+       add     SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
+       adc     SG_NEXT+1,A,SG_NEXT+1
+       adc     SG_NEXT+2,A,SG_NEXT+2
+       adc     SG_NEXT+3,A,SG_NEXT+3
+
+       ret
+
+sg_advance1:
+       mvi     SG_NOLOAD,0x80                  # don't reload s/g next time
+sg_advance2:
+       ret
+
+#  Add the array base SYNCNEG to the target offset (the target address
+#  is in SCSIID), and return the result in SINDEX.  The accumulator
+#  contains the 3->8 decoding of the target ID on return.
+#
+ndx_sdtr:
+       shr     A,SCSIID,4
+       and     A,0x7
+       add     SINDEX,SYNCNEG,A
+
+       and     FUNCTION1,0x70,SCSIID           # 3-bit target address decode
+       mov     A,FUNCTION1     ret
+
+#  If we need to negotiate transfer parameters, build the SDTR message
+#  starting at the address passed in SINDEX.  DINDEX is modified on return.
+#
+mk_sdtr:
+       mov     DINDEX,SINDEX                   # save SINDEX
+
+       call    ndx_sdtr
+       test    NEEDSDTR,A      jnz mk_sdtr1    # do we need negotiation?
+       ret
+
+mk_sdtr1:
+       mvi     DINDIR,1                        # extended message
+       mvi     DINDIR,3                        # extended message length = 3
+       mvi     DINDIR,1                        # SDTR code
+       mvi     DINDIR,25                       # REQ/ACK transfer period
+       mvi     DINDIR,15                       # REQ/ACK offset
+
+       add     MSG_LEN,-MSG_START+0,DINDEX     # update message length
+       ret
+
+#  Set SCSI bus control signal state.  This also saves the last-written
+#  value into a location where the higher-level driver can read it - if
+#  it has to send an ABORT or RESET message, then it needs to know this
+#  so it can assert ATN without upsetting SCSISIGO.  The new value is
+#  expected in SINDEX.  Change the actual state last to avoid contention
+#  from the driver.
+#
+scsisig:
+       mov     SIGSTATE,SINDEX
+       mov     SCSISIGO,SINDEX ret
index 806dc0151de231335ac285811cc12da7604135b9..23e9fa8904bc5ca0cca9b373f93d60fa389675ef 100644 (file)
@@ -1,10 +1,10 @@
 /* fdomain.c -- Future Domain TMC-16x0 SCSI driver
  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Mon Jun  5 09:21:54 1995 by faith@cs.unc.edu
+ * Revised: Fri Jun 23 17:07:09 1995 by r.faith@ieee.org
  * Author: Rickard E. Faith, faith@cs.unc.edu
  * Copyright 1992, 1993, 1994, 1995 Rickard E. Faith
  *
- * $Id: fdomain.c,v 5.28 1995/06/05 13:21:57 faith Exp $
+ * $Id: fdomain.c,v 5.31 1995/06/23 21:07:16 faith Exp $
 
  * 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
  (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective
  work on the Quantum RAM layout.
 
+ Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for
+ providing patches for proper PCI BIOS32-mediated detection of the TMC-3260
+ card (a PCI bus card with the 36C70 chip).  Please send James PCI-related
+ bug reports.
  All of the alpha testers deserve much thanks.
 
 
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
 
-#define VERSION          "$Revision: 5.28 $"
+#define VERSION          "$Revision: 5.31 $"
 
 /* START OF USER DEFINABLE OPTIONS */
 
@@ -411,17 +418,22 @@ static void print_banner( struct Scsi_Host *shpnt )
    printk( " at 0x%x using scsi id %d\n",
           (unsigned)bios_base, shpnt->this_id );
 
+                               /* If this driver works for later FD PCI
+                                   boards, we will have to modify banner
+                                   for additional PCI cards, but for now if
+                                   it's PCI it's a TMC-3260 - JTM */
    printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
           shpnt->host_no,
           chip == tmc1800 ? "TMC-1800"
           : (chip == tmc18c50 ? "TMC-18C50"
-             : (chip == tmc18c30 ? "TMC-18C30" : "Unknown")),
+             : (chip == tmc18c30 ?
+                (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30")
+                : "Unknown")),
           port_base );
 
    if (interrupt_level) printk( "%d", interrupt_level );
    else                 printk( "<none>" );
 
-   if (PCI_bus)         printk( " (PCI bus)" );
    printk( "\n" );
 }
 
@@ -444,8 +456,6 @@ inline static void fdomain_make_bus_idle( void )
 
 static int fdomain_is_valid_port( int port )
 {
-   int options;
-
 #if DEBUG_DETECT 
    printk( " (%x%x),",
           inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
@@ -473,9 +483,9 @@ static int fdomain_is_valid_port( int port )
                                   we'll use the other method.) */
 
       outb( 0x80, port + IO_Control );
-      if (inb( port + Configuration2 ) & 0x80 == 0x80) {
+      if ((inb( port + Configuration2 ) & 0x80) == 0x80) {
         outb( 0x00, port + IO_Control );
-        if (inb( port + Configuration2 ) & 0x80 == 0x00) {
+        if ((inb( port + Configuration2 ) & 0x80) == 0x00) {
            chip = tmc18c30;
            FIFO_Size = 0x800;  /* 2k FIFO */
         }
@@ -494,31 +504,6 @@ static int fdomain_is_valid_port( int port )
                                /* If that failed, we are an 18c50. */
    }
 
-   /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
-      Now, check to be sure the bios_base matches these ports.  If someone
-      was unlucky enough to have purchased more than one Future Domain
-      board, then they will have to modify this code, as we only detect one
-      board here.  [The one with the lowest bios_base.]  */
-
-   options = inb( port + Configuration1 );
-
-#if DEBUG_DETECT
-   printk( " Options = %x\n", options );
-#endif
-
-                               /* Check for board with lowest bios_base --
-                                  this isn't valid for the 18c30 or for
-                                  boards on the PCI bus, so just assume we
-                                  have the right board. */
-
-   if (chip != tmc18c30
-       && !PCI_bus
-       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
-
-                               /* Get the IRQ from the options. */
-
-   interrupt_level = ints[ (options & 0x0e) >> 1 ];
-
    return 1;
 }
 
@@ -536,48 +521,45 @@ static int fdomain_test_loopback( void )
    return 0;
 }
 
-int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
+/* fdomain_get_irq assumes that we have a valid MCA ID for a
+   TMC-1660/TMC-1680 Future Domain board.  Now, check to be sure the
+   bios_base matches these ports.  If someone was unlucky enough to have
+   purchased more than one Future Domain board, then they will have to
+   modify this code, as we only detect one board here.  [The one with the
+   lowest bios_base.]
+
+   Note that this routine is only used for systems without a PCI BIOS32
+   (e.g., ISA bus).  For PCI bus systems, this routine will likely fail
+   unless one of the IRQs listed in the ints array is used by the board.
+   Sometimes it is possible to use the computer's BIOS setup screen to
+   configure a PCI system so that one of these IRQs will be used by the
+   Future Domain card. */
+
+static int fdomain_get_irq( int base )
 {
-   int              i, j;
-   int              flag = 0;
-   int              retcode;
-   struct Scsi_Host *shpnt;
-#if DO_DETECT
-   const int        buflen = 255;
-   Scsi_Cmnd        SCinit;
-   unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
-   unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
-   unsigned char    do_read_capacity[] = { READ_CAPACITY,
-                                          0, 0, 0, 0, 0, 0, 0, 0, 0 };
-   unsigned char    buf[buflen];
-#endif
+   int options = inb( base + Configuration1 );
 
 #if DEBUG_DETECT
-   printk( "fdomain_16x0_detect()," );
+   printk( " Options = %x\n", options );
 #endif
+   
+                               /* Check for board with lowest bios_base --
+                                  this isn't valid for the 18c30 or for
+                                  boards on the PCI bus, so just assume we
+                                  have the right board. */
 
-   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
-#if DEBUG_DETECT
-      printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
-#endif
-      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
-        if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
-                     signatures[j].signature, signatures[j].sig_length )) {
-           bios_major = signatures[j].major_bios_version;
-           bios_minor = signatures[j].minor_bios_version;
-           PCI_bus    = (signatures[j].flag == 1);
-           Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
-           bios_base  = addresses[i];
-        }
-      }
-   }
+   if (chip != tmc18c30
+       && !PCI_bus
+       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
 
-   if (!bios_base) {
-#if DEBUG_DETECT
-      printk( " FAILED: NO BIOS\n" );
-#endif
-      return 0;
-   }
+   return ints[ (options & 0x0e) >> 1 ];
+}
+
+static int fdomain_isa_detect( int *irq, int *iobase )
+{
+   int i;
+   int base;
+   int flag = 0;
 
    if (bios_major == 2) {
       /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
@@ -591,95 +573,299 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
       switch (Quantum) {
       case 2:                  /* ISA_200S */
       case 3:                  /* ISA_250MG */
-        port_base = *((char *)bios_base + 0x1fa2)
+        base = *((char *)bios_base + 0x1fa2)
               + (*((char *)bios_base + 0x1fa3) << 8);
         break;
       case 4:                  /* ISA_200S (another one) */
-        port_base = *((char *)bios_base + 0x1fa3)
+        base = *((char *)bios_base + 0x1fa3)
               + (*((char *)bios_base + 0x1fa4) << 8);
         break;
       default:
-        port_base = *((char *)bios_base + 0x1fcc)
+        base = *((char *)bios_base + 0x1fcc)
               + (*((char *)bios_base + 0x1fcd) << 8);
         break;
       }
    
 #if DEBUG_DETECT
-      printk( " %x,", port_base );
+      printk( " %x,", base );
 #endif
 
       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
-        if (port_base == ports[i])
+        if (base == ports[i])
               ++flag;
       }
 
-      if (flag)
-           flag = fdomain_is_valid_port( port_base );
-   }
-
-   if (!flag) {                        /* Cannot get port base from BIOS RAM */
+      if (flag && fdomain_is_valid_port( base )) {
+        *irq    = fdomain_get_irq( base );
+        *iobase = base;
+        return 1;
+      }
       
       /* This is a bad sign.  It usually means that someone patched the
         BIOS signature list (the signatures variable) to contain a BIOS
-        signature for a board *OTHER THAN* the TMC-1660/TMC-1680.  It
-        also means that we don't have a Version 2.0 BIOS :-)
-       */
+        signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */
       
 #if DEBUG_DETECT
-      if (bios_major != 2) printk( " RAM FAILED, " );
+      printk( " RAM FAILED, " );
 #endif
+   }
 
-      /* Anyway, the alternative to finding the address in the RAM is to
-        just search through every possible port address for one that is
-        attached to the Future Domain card.  Don't panic, though, about
-        reading all these random port addresses -- there are rumors that
-        the Future Domain BIOS does something very similar.
+   /* Anyway, the alternative to finding the address in the RAM is to just
+      search through every possible port address for one that is attached
+      to the Future Domain card.  Don't panic, though, about reading all
+      these random port addresses -- there are rumors that the Future
+      Domain BIOS does something very similar.
 
-        Do not, however, check ports which the kernel knows are being used
-        by another driver. */
+      Do not, however, check ports which the kernel knows are being used by
+      another driver. */
 
-      if (!PCI_bus) {
-        for (i = 0; !flag && i < PORT_COUNT; i++) {
-           port_base = ports[i];
-           if (check_region( port_base, 0x10 )) {
+   for (i = 0; i < PORT_COUNT; i++) {
+      base = ports[i];
+      if (check_region( base, 0x10 )) {
 #if DEBUG_DETECT
-              printk( " (%x inuse),", port_base );
+        printk( " (%x inuse),", base );
 #endif
-              continue;
-           }
+        continue;
+      }
+#if DEBUG_DETECT
+      printk( " %x,", base );
+#endif
+      if ((flag = fdomain_is_valid_port( base ))) break;
+   }
+
+   if (!flag) return 0;                /* iobase not found */
+
+   *irq    = fdomain_get_irq( base );
+   *iobase = base;
+
+   return 1;                   /* success */
+}
+
+static int fdomain_pci_nobios_detect( int *irq, int *iobase )
+{
+   int i;
+   int flag = 0;
+
+   /* The proper way of doing this is to use ask the PCI bus for the device
+      IRQ and interrupt level.  But we can't do that if PCI BIOS32 support
+      isn't compiled into the kernel, or if a PCI BIOS32 isn't present.
+
+      Instead, we scan down a bunch of addresses (Future Domain tech
+      support says we will probably find the address before we get to
+      0xf800).  This works fine on some systems -- other systems may have
+      to scan more addresses.  If you have to modify this section for your
+      installation, please send mail to faith@cs.unc.edu. */
+
+   for (i = 0xfff8; i > 0xe000; i -= 8) {
+      if (check_region( i, 0x10 )) {
 #if DEBUG_DETECT
-           printk( " %x,", port_base );
+        printk( " (%x inuse)," , i );
 #endif
-           flag = fdomain_is_valid_port( port_base );
+        continue;
+      }
+      if ((flag = fdomain_is_valid_port( i ))) break;
+   }
+
+   if (!flag) return 0;                /* iobase not found */
+
+   *irq    = fdomain_get_irq( i );
+   *iobase = i;
+
+   return 1;                   /* success */
+}
+
+/* PCI detection function: int fdomain_36c70_detect(int* irq, int* iobase)
+   This function gets the Interrupt Level and I/O base address from the PCI
+   configuration registers.  The I/O base address is masked with 0xfff8
+   since on my card the address read from the PCI config registers is off
+   by one from the actual I/O base address necessary for accessing the
+   status and control registers on the card (PCI config register gives
+   0xf801, actual address is 0xf800).  This is likely a bug in the FD
+   config code that writes to the PCI registers, however using a mask
+   should be safe since I think the scan done by the card to determine the
+   I/O base is done in increments of 8 (i.e., 0xf800, 0xf808, ...), at
+   least the old scan code we used to use to get the I/O base did...  Also,
+   the device ID from the PCI config registers is 0x0 and should be 0x60e9
+   as it is in the status registers (offset 5 from I/O base).  If this is
+   changed in future hardware/BIOS changes it will need to be fixed in this
+   detection function.  Comments, bug reports, etc... on this function
+   should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley.  */
+
+#ifdef PCI_CONFIG
+static int fdomain_36c70_detect( int *irq, int *iobase )
+{
+   int              error;
+   unsigned char    pci_bus, pci_dev_fn;    /* PCI bus & device function */
+   unsigned char    pci_irq;                /* PCI interrupt line */
+   unsigned long    pci_base;               /* PCI I/O base address */
+   unsigned short   pci_vendor, pci_device; /* PCI vendor & device IDs */
+
+   /* If the PCI BIOS doesn't exist, use the old-style detection routines.
+      Otherwise, get the I/O base address and interrupt from the PCI config
+      registers. */
+   
+   if (!pcibios_present()) return fdomain_pci_detect( irq, iobase );
+
+#if DEBUG_DETECT
+   /* Tell how to print a list of the known PCI devices from bios32 and
+      list vendor and device IDs being used if in debug mode.  */
+      
+   printk( "\nINFO: cat /proc/pci to see list of PCI devices from bios32\n" );
+   printk( "\nTMC-3260 detect:"
+          " Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n",
+          PCI_VENDOR_ID_FD, 
+          PCI_DEVICE_ID_FD_36C70 );
+#endif 
+
+   /* We will have to change this if more than 1 PCI bus is present and the
+      FD scsi host is not on the first bus (i.e., a PCI to PCI bridge,
+      which is not supported by bios32 right now anyway).  This should
+      probably be done by a call to pcibios_find_device but I can't get it
+      to work...  Also the device ID reported from the PCI config registers
+      does not match the device ID quoted in the tech manual or available
+      from offset 5 from the I/O base address.  It should be 0x60E9, but it
+      is 0x0 if read from the PCI config registers.  I guess the FD folks
+      neglected to write it to the PCI registers...  This loop is necessary
+      to get the device function (at least until someone can get
+      pcibios_find_device to work, I cannot but 53c7,8xx.c uses it...). */
+    
+   pci_bus = 0;
+
+   for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++) {
+      pcibios_read_config_word( pci_bus,
+                               pci_dev_fn,
+                               PCI_VENDOR_ID,
+                               &pci_vendor );
+
+      if (pci_vendor == PCI_VENDOR_ID_FD) {
+        pcibios_read_config_word( pci_bus,
+                                  pci_dev_fn,
+                                  PCI_DEVICE_ID,
+                                  &pci_device );
+
+        if (pci_device == PCI_DEVICE_ID_FD_36C70) {
+           /* Break out once we have the correct device.  If other FD
+              PCI devices are added to this driver we will need to add
+              an or of the other PCI_DEVICE_ID_FD_XXXXX's here. */
+           break;
+        } else {
+           /* If we can't find an FD scsi card we give up. */
+           return 0;
         }
-      } else {
+      }
+   }
+       
+#if DEBUG_DETECT
+   printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n",
+          pci_bus,
+          (pci_dev_fn & 0xf8) >> 3, 
+          pci_dev_fn & 7 );
+#endif
+
+   /* We now have the appropriate device function for the FD board so we
+      just read the PCI config info from the registers.  */
+
+   if ((error = pcibios_read_config_dword( pci_bus,
+                                          pci_dev_fn, 
+                                          PCI_BASE_ADDRESS_0,
+                                          &pci_base ))
+       || (error = pcibios_read_config_byte( pci_bus,
+                                            pci_dev_fn, 
+                                            PCI_INTERRUPT_LINE,
+                                            &pci_irq ))) {
+      printk ( "PCI ERROR: Future Domain 36C70 not initializing"
+              " due to error reading configuration space\n" );
+      return 0;
+   } else {
+#if DEBUG_DETECT
+      printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n", 
+             pci_irq, pci_base );
+#endif
 
-        /* The proper way of doing this is to use ask the PCI bus for the
-            device IRQ and interrupt level.
+      /* Now we have the I/O base address and interrupt from the PCI
+        configuration registers.  Unfortunately it seems that the I/O base
+        address is off by one on my card so I mask it with 0xfff8.  This
+        must be some kind of goof in the FD code that does the autoconfig
+        and writes to the PCI registers (or maybe I just don't understand
+        something).  If they fix it in later versions of the card or BIOS
+        we may have to adjust the address based on the signature or
+        something...  */
 
-           Until the Linux kernel supports this sort of PCI bus query, we
-           scan down a bunch of addresses (Future Domain tech support says
-           we will probably find the address before we get to 0xf800).
-           This works fine on some systems -- other systems may have to
-           scan more addresses.  If you have to modify this section for
-           your installation, please send mail to faith@cs.unc.edu. */
+      *irq    = pci_irq;
+      *iobase = (pci_base & 0xfff8);
 
-        for (i = 0xfff8; !flag && i > 0xe000; i -= 8) {
-           port_base = i;
-           if (check_region( port_base, 0x10 )) {
 #if DEBUG_DETECT
-              printk( " (%x inuse)," , port_base );
+      printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" ); 
+      printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );
 #endif
-              continue;
-           }
-           flag = fdomain_is_valid_port( port_base );
+
+      if (!fdomain_is_valid_port( *iobase )) return 0;
+      return 1;
+   }
+   return 0;
+}
+#endif
+
+int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
+{
+   int              i, j;
+   int              flag = 0;
+   int              retcode;
+   struct Scsi_Host *shpnt;
+#if DO_DETECT
+   const int        buflen = 255;
+   Scsi_Cmnd        SCinit;
+   unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
+   unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
+   unsigned char    do_read_capacity[] = { READ_CAPACITY,
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0 };
+   unsigned char    buf[buflen];
+#endif
+
+#if DEBUG_DETECT
+   printk( "fdomain_16x0_detect()," );
+#endif
+
+   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
+#if DEBUG_DETECT
+      printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
+#endif
+      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
+        if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
+                     signatures[j].signature, signatures[j].sig_length )) {
+           bios_major = signatures[j].major_bios_version;
+           bios_minor = signatures[j].minor_bios_version;
+           PCI_bus    = (signatures[j].flag == 1);
+           Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
+           bios_base  = addresses[i];
         }
       }
    }
 
+   if (!bios_base) {
+#if DEBUG_DETECT
+      printk( " FAILED: NO BIOS\n" );
+#endif
+      return 0;
+   }
+
+   if (!PCI_bus) {
+      flag = fdomain_isa_detect( &interrupt_level, &port_base );
+   } else {
+#ifdef PCI_CONFIG
+      flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );
+#else
+      flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base );
+#endif
+   }
+        
    if (!flag) {
 #if DEBUG_DETECT
       printk( " FAILED: NO PORT\n" );
+#endif
+#ifdef PCI_CONFIG
+      printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" );
+      printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" );
 #endif
       return 0;                /* Cannot find valid set of ports */
    }
index eb7ba378942062d5ec3dbb8e500ded6ec8c573bb..862f0a5abb1146d8b85aae4fa04391e50336322b 100644 (file)
@@ -44,8 +44,8 @@
 #include "aha1740.h"
 #endif
 
-#ifdef CONFIG_SCSI_AHA274X
-#include "aha274x.h"
+#ifdef CONFIG_SCSI_AIC7XXX
+#include "aic7xxx.h"
 #endif
 
 #ifdef CONFIG_SCSI_BUSLOGIC
@@ -160,8 +160,8 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_AHA1740
        AHA1740,
 #endif
-#ifdef CONFIG_SCSI_AHA274X
-       AHA274X,
+#ifdef CONFIG_SCSI_AIC7XXX
+       AIC7XXX,
 #endif
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
        FDOMAIN_16X0,
index f1e739d98d57e0880e4a1a3739d69a9380d50090..2599a966e37db98887973771543ba6b153e0bb8c 100644 (file)
@@ -763,6 +763,8 @@ if ($#undefined >= 0) {
 
 @label_patches = ();
 
+@external_patches = ();
+
 @absolute = sort @absolute;
 
 foreach $i (@absolute) {
@@ -854,7 +856,7 @@ foreach $label (@label) {
 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
 
-print OUTPUT "unsigned long ".$prefix."SCRIPT[] = {\n";
+print OUTPUT "u32 ".$prefix."SCRIPT[] = {\n";
 $instructions = 0;
 for ($i = 0; $i < $#code; ) {
     if ($list_in_array) {
@@ -863,14 +865,16 @@ for ($i = 0; $i < $#code; ) {
     printf OUTPUT "\t0x%08x,", $code[$i];
     printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
     if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
-       printf OUTPUT "((unsigned long)&%s)%s,", $1, $2
+       push (@external_patches, $i+1, $1);
+       printf OUTPUT "0%s,", $2
     } else {
        printf OUTPUT "0x%08x,",$code[$i+1];
     }
 
     if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
        if ($code[$i + 2] =~ /$identifier/) {
-           printf OUTPUT "(unsigned long)&%s,\n",$code[$i+2];
+           push (@external_patches, $i+2, $code[$i+2]);
+           printf OUTPUT "0,\n";
        } else {
            printf OUTPUT "0x%08x,\n",$code[$i+2];
        }
@@ -891,7 +895,7 @@ foreach $i (@absolute) {
     }
     printf OUTPUTU "#undef A_$i\n";
 
-    printf OUTPUT "unsigned long A_".$i."_used\[\] = {\n";
+    printf OUTPUT "u32 A_".$i."_used\[\] = {\n";
 printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
     foreach $j (split (/\s+/,$symbol_references{$i})) {
        $j =~ /(ABS|REL),(.*),(.*)/;
@@ -913,15 +917,27 @@ foreach $i (sort @entry) {
 # NCR assembler outputs label patches in the form of indices into 
 # the code.
 #
-printf OUTPUT "unsigned long ".$prefix."LABELPATCHES[] = {\n";
+printf OUTPUT "u32 ".$prefix."LABELPATCHES[] = {\n";
 for $patch (sort {$a <=> $b} @label_patches) {
     printf OUTPUT "\t0x%08x,\n", $patch;
 }
 printf OUTPUT "};\n\n";
 
-printf OUTPUT "unsigned long ".$prefix."INSTRUCTIONS\t= 0x%08x;\n", 
+$num_external_patches = 0;
+printf OUTPUT "struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
+    "} ".$prefix."EXTERNAL_PATCHES[] = {\n";
+while ($ident = pop(@external_patches)) {
+    $off = pop(@external_patches);
+    printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
+    ++$num_external_patches;
+}
+printf OUTPUT "};\n\n";
+
+printf OUTPUT "u32 ".$prefix."INSTRUCTIONS\t= %d;\n", 
     $instructions;
-printf OUTPUT "unsigned long ".$prefix."PATCHES\t= 0x%08x;\n", 
+printf OUTPUT "u32 ".$prefix."PATCHES\t= %d;\n", 
     $#label_patches+1;
+printf OUTPUT "u32 ".$prefix."EXTERNAL_PATCHES_LEN\t= %d;\n",
+    $num_external_patches;
 close OUTPUT;
 close OUTPUTU;
index fb815148f357ce047cbed254f14276a6f3e6399c..746a31b70ee71c90ad92474e0c593c17aeae0caa 100644 (file)
@@ -1900,7 +1900,7 @@ int scsi_free(void *obj, unsigned int len)
 
   save_flags(flags);
   cli();
-  if(dma_malloc_freelist[page] & (mask << sector) != (mask<<sector))
+  if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
     panic("Trying to free unused memory");
 
   dma_free_sectors += nbits;
index 69283efb2bd7e439388f3f4e65b1d7f058c6c1df..f3e7dc3bf681960fb110e5a80ee0f65f3508bfe2 100644 (file)
@@ -349,7 +349,11 @@ struct scatterlist {
      unsigned int length;
      };
 
-#define ISA_DMA_THRESHOLD (0x00ffffff)
+#ifdef __alpha__
+# define ISA_DMA_THRESHOLD (~0UL)
+#else
+# define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
 #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
 
 
index 92f3eef3ece4128bfc55ac587e5b77a6fa080e6b..a5a5f56f0c144d2296de77d95d613497ab8705f5 100644 (file)
@@ -33,7 +33,7 @@ static int ioctl_probe(struct Scsi_Host * host, void *buffer)
        const char * string;
        
        if ((temp = host->hostt->present) && buffer) {
-               len = get_fs_long ((unsigned long *) buffer);
+               len = get_user ((unsigned int *) buffer);
                if(host->hostt->info)
                  string = host->hostt->info(host);
                else 
@@ -157,11 +157,11 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
        if (!buffer)
                return -EINVAL;
        
-       inlen = get_fs_long((unsigned long *) buffer);
-       outlen = get_fs_long( ((unsigned long *) buffer) + 1);
+       inlen = get_user((unsigned int *) buffer);
+       outlen = get_user( ((unsigned int *) buffer) + 1);
 
        cmd_in = (char *) ( ((int *)buffer) + 2);
-       opcode = get_fs_byte(cmd_in); 
+       opcode = get_user(cmd_in); 
 
        needed = buf_needed = (inlen > outlen ? inlen : outlen);
        if(buf_needed){
@@ -249,8 +249,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
        switch (cmd) {
                case SCSI_IOCTL_GET_IDLUN:
                        verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-                       put_fs_long(dev->id + (dev->lun << 8) + 
-                                   (dev->host->host_no << 16), (unsigned long *) arg);
+                       put_user(dev->id + (dev->lun << 8) + 
+                                (dev->host->host_no << 16), (unsigned int *) arg);
                        return 0;
                case SCSI_IOCTL_TAGGED_ENABLE:
                        if(!suser())  return -EACCES;
index 5ca3f63e91f176b67423d7c6295442509bbe0445..a97f793a3089e4d11745d6f482e6e6d5c93429dd 100644 (file)
@@ -37,22 +37,18 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
                              host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
                                                          dev,
                                                          &diskinfo[0]);
-                       put_fs_byte(diskinfo[0],
-                               (char *) &loc->heads);
-                       put_fs_byte(diskinfo[1],
-                               (char *) &loc->sectors);
-                       put_fs_word(diskinfo[2],
-                               (short *) &loc->cylinders);
-                       put_fs_long(sd[MINOR(inode->i_rdev)].start_sect,
-                               (long *) &loc->start);
+                       put_user(diskinfo[0], &loc->heads);
+                       put_user(diskinfo[1], &loc->sectors);
+                       put_user(diskinfo[2], &loc->cylinders);
+                       put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
                        return 0;
                case BLKGETSIZE:   /* Return device size */
                        if (!arg)  return -EINVAL;
                        error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
                        if (error)
                                return error;
-                       put_fs_long(sd[MINOR(inode->i_rdev)].nr_sects,
-                               (long *) arg);
+                       put_user(sd[MINOR(inode->i_rdev)].nr_sects,
+                                (long *) arg);
                        return 0;
                case BLKRASET:
                        if(!suser())  return -EACCES;
index 9224533c169283815c7db23c7ff0cd45b45c7d54..cfd0706cdda457703932944e3a28906aab46ffe1 100644 (file)
@@ -71,7 +71,7 @@ static int sg_ioctl(struct inode * inode,struct file * file,
   switch(cmd_in)
    {
     case SG_SET_TIMEOUT:
-     scsi_generics[dev].timeout=get_fs_long((int *) arg);
+     scsi_generics[dev].timeout=get_user((int *) arg);
      return 0;
     case SG_GET_TIMEOUT:
      return scsi_generics[dev].timeout;
@@ -289,7 +289,7 @@ static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
   /* now issue command */
   SCpnt->request.dev=dev;
   SCpnt->sense_buffer[0]=0;
-  opcode = get_fs_byte(buf);
+  opcode = get_user(buf);
   size=COMMAND_SIZE(opcode);
   if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
   SCpnt->cmd_len = size;
index a5839a2b11820b1db622b69fb38ddaaaf4a7b5e5..f28d2ce0a2d28d5136e571a38d3cf5380f1322a7 100644 (file)
@@ -261,9 +261,10 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
                        return result;
 
                case CDROMEJECT:
-                       if (scsi_CDs[target].device -> access_count == 1)
-                         sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+                       if (scsi_CDs[target].device -> access_count != 1)
+                               return -EBUSY;
 
+                       sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
                        sr_cmd[0] = START_STOP;
                        sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
                        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
index 8c11a23fe48945d6658cfb82771b0942c6a76269..9a46fb9e309182396f83e79400d4f979afbd3715 100644 (file)
@@ -65,15 +65,16 @@ struct linux_binfmt elf_format = {
 
 static void padzero(unsigned long elf_bss)
 {
-       unsigned long fpnt, nbyte;
+       unsigned long nbyte;
+       char * fpnt;
   
        nbyte = elf_bss & (PAGE_SIZE-1);
        if (nbyte) {
                nbyte = PAGE_SIZE - nbyte;
                verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-               fpnt = elf_bss;
+               fpnt = (char *) elf_bss;
                do {
-                       put_fs_byte(0, fpnt++);
+                       put_user(0, fpnt++);
                } while (--nbyte);
        }
 }
@@ -115,8 +116,8 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
        sp -= argc+1;
        argv = sp;
        if (!ibcs) {
-               put_fs_long((unsigned long)envp,--sp);
-               put_fs_long((unsigned long)argv,--sp);
+               put_user(envp,--sp);
+               put_user(argv,--sp);
        }
 
        /* The constant numbers (0-9) that we are writing here are
@@ -125,29 +126,29 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
        if(exec) { /* Put this here for an ELF program interpreter */
          struct elf_phdr * eppnt;
          eppnt = (struct elf_phdr *) exec->e_phoff;
-         put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
-         put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
-         put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
-         put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
-         put_fs_long(7,dlinfo++); put_fs_long(interp_load_addr,dlinfo++);
-         put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
-         put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
-         put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
+         put_user(3,dlinfo++); put_user(load_addr + exec->e_phoff,dlinfo++);
+         put_user(4,dlinfo++); put_user(sizeof(struct elf_phdr),dlinfo++);
+         put_user(5,dlinfo++); put_user(exec->e_phnum,dlinfo++);
+         put_user(9,dlinfo++); put_user((unsigned long) exec->e_entry,dlinfo++);
+         put_user(7,dlinfo++); put_user(interp_load_addr,dlinfo++);
+         put_user(8,dlinfo++); put_user(0,dlinfo++);
+         put_user(6,dlinfo++); put_user(PAGE_SIZE,dlinfo++);
+         put_user(0,dlinfo++); put_user(0,dlinfo++);
        }
 
-       put_fs_long((unsigned long)argc,--sp);
+       put_user((unsigned long)argc,--sp);
        current->mm->arg_start = (unsigned long) p;
        while (argc-->0) {
-               put_fs_long((unsigned long) p,argv++);
-               while (get_fs_byte(p++)) /* nothing */ ;
+               put_user(p,argv++);
+               while (get_user(p++)) /* nothing */ ;
        }
-       put_fs_long(0,argv);
+       put_user(0,argv);
        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
        while (envc-->0) {
-               put_fs_long((unsigned long) p,envp++);
-               while (get_fs_byte(p++)) /* nothing */ ;
+               put_user(p,envp++);
+               while (get_user(p++)) /* nothing */ ;
        }
-       put_fs_long(0,envp);
+       put_user(0,envp);
        current->mm->env_end = (unsigned long) p;
        return sp;
 }
@@ -739,7 +740,7 @@ load_elf_library(int fd){
        if(k > elf_bss) elf_bss = k;
        
        SYS(close)(fd);
-       if (error != elf_phdata->p_vaddr & 0xfffff000) {
+       if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
                kfree(elf_phdata);
                MOD_DEC_USE_COUNT;
                return error;
index 9d54d03c7d7d782ef5d033e6582e13261a6f163d..34e4b8e91cfbdda4826264f06e4b52a1db455f2f 100644 (file)
@@ -289,8 +289,8 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
                                brelse(*bhe);
                                buf += chars;
                        } else {
-                               while (chars-->0)
-                                       put_fs_byte(0,buf++);
+                               while (chars-- > 0)
+                                       put_user(0,buf++);
                        }
                        offset = 0;
                        if (++bhe == &buflist[NBUF])
index e9543a1b0a0a97f47526fde0772fffddec97e56c..06b4d22489b4db3b26a47cb613311e6632137c60 100644 (file)
@@ -1340,8 +1340,12 @@ static int maybe_shrink_lav_buffers(int size)
  * Priority tells the routine how hard to try to shrink the
  * buffers: 3 means "don't bother too much", while a value
  * of 0 means "we'd better get some free pages now".
+ *
+ * "limit" is meant to limit the shrink-action only to pages
+ * that are in the 0 - limit address range, for DMA re-allocations.
+ * We ignore that right now.
  */
-int shrink_buffers(unsigned int priority)
+int shrink_buffers(unsigned int priority, unsigned long limit)
 {
        if (priority < 2) {
                sync_buffers(0,0);
index 9ad98356018b3f4b775455ade953df103dc74efb..b90ffb3229ed08929723c1a717e7fdc766257ce9 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -330,13 +330,13 @@ unsigned long * create_tables(char * p, struct linux_binprm * bprm, int ibcs)
        current->mm->arg_start = (unsigned long) p;
        while (argc-->0) {
                put_user(p,argv++);
-               while (get_fs_byte(p++)) /* nothing */ ;
+               while (get_user(p++)) /* nothing */ ;
        }
        put_user(NULL,argv);
        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
        while (envc-->0) {
                put_user(p,envp++);
-               while (get_fs_byte(p++)) /* nothing */ ;
+               while (get_user(p++)) /* nothing */ ;
        }
        put_user(NULL,envp);
        current->mm->env_end = (unsigned long) p;
@@ -358,7 +358,7 @@ static int count(char ** argv)
                error = verify_area(VERIFY_READ, tmp, sizeof(char *));
                if (error)
                        return error;
-               while ((p = (char *) get_user(tmp++)) != NULL) {
+               while ((p = get_user(tmp++)) != NULL) {
                        i++;
                        error = verify_area(VERIFY_READ, p, 1);
                        if (error)
@@ -401,14 +401,14 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
        while (argc-- > 0) {
                if (from_kmem == 1)
                        set_fs(new_fs);
-               if (!(tmp = (char *)get_user(argv+argc)))
+               if (!(tmp = get_user(argv+argc)))
                        panic("VFS: argc is wrong");
                if (from_kmem == 1)
                        set_fs(old_fs);
                len=0;          /* remember zero-padding */
                do {
                        len++;
-               } while (get_fs_byte(tmp++));
+               } while (get_user(tmp++));
                if (p < len) {  /* this shouldn't happen - 128kB */
                        set_fs(old_fs);
                        return 0;
@@ -427,7 +427,7 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
                                        set_fs(new_fs);
 
                        }
-                       *(pag + offset) = get_fs_byte(tmp);
+                       *(pag + offset) = get_user(tmp);
                }
        }
        if (from_kmem==2)
index f32cdd8982ecd62b8928d91ba8a59f532ca3c151..4f448c5e1c00ba09c2d37160195cfac1ee222e22 100644 (file)
@@ -170,7 +170,7 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
                                buf += chars;
                        } else {
                                while (chars-->0)
-                                       put_fs_byte(0,buf++);
+                                       put_user(0,buf++);
                        }
                        offset = 0;
                        if (++bhe == &buflist[NBUF])
index 8c84bc622979dea07f8ea749f7791cb51cccd596..658fdbc79df592df415c913d61e89673c67043f5 100644 (file)
@@ -101,7 +101,7 @@ static int ext_readlink(struct inode * inode, char * buffer, int buflen)
        i = 0;
        while (i<buflen && (c = bh->b_data[i])) {
                i++;
-               put_fs_byte(c,buffer++);
+               put_user(c,buffer++);
        }
        brelse(bh);
        return i;
index 29d5970be83983e7e8f40c3da5128e4f7e1697bc..da47123f848b2996d2893b915fb253a571c4ec9d 100644 (file)
@@ -202,7 +202,7 @@ static int ext2_file_read (struct inode * inode, struct file * filp,
                                buf += chars;
                        } else {
                                while (chars-- > 0)
-                                       put_fs_byte (0, buf++);
+                                       put_user (0, buf++);
                        }
                        offset = 0;
                        if (++bhe == &buflist[NBUF])
index 66d4ab860a44b080ab426c340207d261f9683136..3226477d8e43f405497b505943a35966efdfee5e 100644 (file)
@@ -119,7 +119,7 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
        i = 0;
        while (i < buflen && (c = link[i])) {
                i++;
-               put_fs_byte (c, buffer++);
+               put_user (c, buffer++);
        }
        iput (inode);
        if (bh)
index ec16d8af3b93ab9cbd63a17965f663aa08c12193..966302963417487a5a6a6337a703db8f8cc3544c 100644 (file)
@@ -981,7 +981,7 @@ static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
                unsigned c = *in++;
                if (c == '\r' && (len == 0 || *in == '\n'));
                else
-                       put_fs_byte(c, out++);
+                       put_user(c, out++);
        }
 
        return out - start;
index 831bfeaf4d3406e6082fd136b50f719d79480c6f..f2626b717ccfeac2ff69c5ba9f0fd0e4e2d2a07d 100644 (file)
@@ -88,7 +88,7 @@ static inline void unixify_to_fs(char * outbuf, char * buffer, int chars,
                        if(mode == ISOFS_FILE_TEXT_M) outchar = 0x0a;
                        if(mode == ISOFS_FILE_TEXT) outchar = ' ';
                }
-               put_fs_byte(outchar, outbuf++);
+               put_user(outchar, outbuf++);
                buffer++;
        }
 }
@@ -240,7 +240,7 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
                    buf += chars;
                  } else {
                    while (chars-->0)
-                     put_fs_byte(0,buf++);
+                     put_user(0,buf++);
                  }
                  offset = 0;
                  if (++bhe == &buflist[NBUF])
index d159e424fe640e434c3301ac003e311201b5cdbb..4b43418604913f8df6d746a576b77f177debd881 100644 (file)
@@ -103,7 +103,7 @@ static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
 
        while (i<buflen && (c = pnt[i])) {
                i++;
-               put_fs_byte(c,buffer++);
+               put_user(c,buffer++);
        }
        kfree(pnt);
        return i;
index db3097c37c061baa31e69cf14439255b91742fe5..5372b2e6622a8386ba4362db90afec17cd00a22c 100644 (file)
@@ -168,7 +168,7 @@ static int minix_file_read(struct inode * inode, struct file * filp, char * buf,
                                buf += chars;
                        } else {
                                while (chars-->0)
-                                       put_fs_byte(0,buf++);
+                                       put_user(0,buf++);
                        }
                        offset = 0;
                        if (++bhe == &buflist[NBUF])
index 86dabf9363e5ea0f22b384ee9281913471fe7d47..c390bb359c84023188af96626702b113aaa31bcb 100644 (file)
@@ -99,7 +99,7 @@ static int minix_readlink(struct inode * inode, char * buffer, int buflen)
        i = 0;
        while (i<buflen && (c = bh->b_data[i])) {
                i++;
-               put_fs_byte(c,buffer++);
+               put_user(c,buffer++);
        }
        brelse(bh);
        return i;
index 7fd17483e5c3a78bb94091f6ee3ee5fa91e0253f..4654eb005251719922f7238ae4e4f43fc1f2b28d 100644 (file)
@@ -89,7 +89,8 @@ int msdos_readdir(
                return -ENOENT;
        bh = NULL;
        while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
-               if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
+               if (!IS_FREE(de->name)
+                       && !(de->attr & (ATTR_VOLUME|ATTR_SYS|ATTR_HIDDEN))) {
                        char bufname[12];
                        char *ptname = bufname;
                        for (i = last = 0; i < 8; i++) {
index 491084a71b979c70312ee12815cf34922143abc7..931b7f2f1498ebe2acef2d7382c941d34b67a0b3 100644 (file)
@@ -247,7 +247,7 @@ int msdos_file_read(
                                        filp->f_pos = inode->i_size;
                                        break;
                                }else if (ch != '\r'){
-                                       put_fs_byte(ch,buf++);
+                                       put_user(ch,buf++);
                                }
                        }
                }
@@ -330,7 +330,7 @@ int msdos_file_write(
                                carry = 0;
                        }
                        for (size = 0; size < count && left; size++) {
-                               if ((ch = get_fs_byte(buf++)) == '\n') {
+                               if ((ch = get_user(buf++)) == '\n') {
                                        *to++ = '\r';
                                        left--;
                                }
index b5bf435fba582d419e0bbfbbaad9043c352d2d83..523d6df671bfd1e5be5dcc046ee4d183b58c68c4 100644 (file)
@@ -65,7 +65,7 @@ int getname(const char * filename, char **result)
                error = -ENAMETOOLONG;
                i = PAGE_SIZE;
        }
-       c = get_fs_byte(filename++);
+       c = get_user(filename++);
        if (!c)
                return -ENOENT;
        if(!(page = __get_free_page(GFP_KERNEL)))
@@ -73,7 +73,7 @@ int getname(const char * filename, char **result)
        *result = tmp = (char *) page;
        while (--i) {
                *(tmp++) = c;
-               c = get_fs_byte(filename++);
+               c = get_user(filename++);
                if (!c) {
                        *tmp = '\0';
                        return 0;
index 85c40b495143b4c04a38ff5e43e92bb3ca998bc2..13ce639d4a1acac186b2b42c6294e5b84412a5e8 100644 (file)
@@ -112,7 +112,7 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
        iput(inode);
        if (! error) {
                memcpy_tofs(buffer, res, len);
-               put_fs_byte('\0', buffer + len);
+               put_user('\0', buffer + len);
                error = len;
        }
        kfree(mem);
index 4b47c840812700f2a76c3a142f13cecd664c6298..bc9d83c5b4dc63ff6e49241d1c07fcb002b581ca 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -157,8 +157,8 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times)
                        iput(inode);
                        return error;
                }
-               actime = get_fs_long((unsigned long *) &times->actime);
-               modtime = get_fs_long((unsigned long *) &times->modtime);
+               actime = get_user(&times->actime);
+               modtime = get_user(&times->modtime);
                newattrs.ia_ctime = CURRENT_TIME;
                flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
        } else {
index e50c83b21936b2d84d12f8e2f60677096f3e4299..ce2a252ef81b043ff937c5cf44ac0c8e9b7758b8 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -135,7 +135,7 @@ static int pipe_ioctl(struct inode *pino, struct file * filp,
                case FIONREAD:
                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
                        if (!error)
-                               put_fs_long(PIPE_SIZE(*pino),(int *) arg);
+                               put_user(PIPE_SIZE(*pino),(int *) arg);
                        return error;
                default:
                        return -EINVAL;
index dad91d707fab6a7dbac693d448b6b03b7a68dddd..6a114b4812e1fefc79e9f052898dae2862e9eb4d 100644 (file)
@@ -87,7 +87,7 @@ static int read_core(struct inode * inode, struct file * file,char * buf, int co
        }
 
        while (p < 2*PAGE_SIZE && count > 0) {
-               put_fs_byte(0,buf);
+               put_user(0,buf);
                buf++;
                p++;
                count--;
@@ -135,7 +135,7 @@ static int read_profile(struct inode *inode, struct file *file, char *buf, int c
     read = 0;
 
     while (p < sizeof(unsigned long) && count > 0) {
-        put_fs_byte(*((char *)(&sample_step)+p),buf);
+        put_user(*((char *)(&sample_step)+p),buf);
                buf++; p++; count--; read++;
     }
     pnt = (char *)prof_buffer + p - sizeof(unsigned long);
index 58e49f721b286d3f26083e663e0e15e2449eb7cc..2daae4ab0fc67386e5d9c122891dd82a26c0ee71 100644 (file)
@@ -196,7 +196,7 @@ void proc_read_inode(struct inode * inode)
                return;
        }
        ino &= 0x0000ffff;
-       if (p->dumpable) {
+       if (p->dumpable && p->uid == p->euid && p->gid == p->egid) {
                inode->i_uid = p->uid;
                inode->i_gid = p->gid;
        }
index 2f940a275fb946420198efdaff72d0bd2d78a00d..ffd12b7aa0f6a4dc913e0c00c06bc78907c29b18 100644 (file)
@@ -191,6 +191,6 @@ static int proc_readlink(struct inode * inode, char * buffer, int buflen)
                buflen = i;
        i = 0;
        while (i < buflen)
-               put_fs_byte(buf[i++],buffer++);
+               put_user(buf[i++],buffer++);
        return i;
 }
index 1cd19d57aaff8bcfb7db5f1531ac779df26812c8..2d3c9cf2b1a37e12350b9e13d071727073467a3c 100644 (file)
@@ -65,7 +65,15 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
        if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
                return err;
        offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
-/* there is no fs specific llseek handler */
+
+       /* if there is a fs-specific handler, we can't just ignore it.. */
+       /* accept llseek() only for the signed long subset of long long */
+       if (file->f_op && file->f_op->lseek) {
+               if (offset != (long) offset)
+                       return -EINVAL;
+               return file->f_op->lseek(file->f_inode,file,offset,origin);
+       }
+
        switch (origin) {
                case 0:
                        tmp = offset;
@@ -81,9 +89,11 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
        }
        if (tmp < 0)
                return -EINVAL;
-       file->f_pos = tmp;
-       file->f_reada = 0;
-       file->f_version = ++event;
+       if (tmp != file->f_pos) {
+               file->f_pos = tmp;
+               file->f_reada = 0;
+               file->f_version = ++event;
+       }
        memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
        return 0;
 }
index 6490e7b4df99f0906e3d419e79e558931f4d983a..c22965d15b967d20a7b57921322b42cb4060582d 100644 (file)
@@ -36,7 +36,7 @@ struct readdir_callback {
        int count;
 };
 
-static int fillonedir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
        struct readdir_callback * buf = (struct readdir_callback *) __buf;
        struct old_linux_dirent * dirent;
@@ -92,7 +92,7 @@ struct getdents_callback {
        int error;
 };
 
-static int filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
        struct linux_dirent * dirent;
        struct getdents_callback * buf = (struct getdents_callback *) __buf;
index bba5cf340e590fc6a14f7536ccf957bc3071414a..84f87748ff2cd8195f4a1e99033fef04aaff08a1 100644 (file)
@@ -227,8 +227,8 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
                i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
                if (i)
                        return i;
-               timeout = ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ));
-               timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
+               timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ));
+               timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ;
                if (timeout)
                        timeout += jiffies + 1;
        }
@@ -239,10 +239,10 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
        if ((long) timeout < 0)
                timeout = 0;
        if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-               put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
+               put_user(timeout/HZ, &tvp->tv_sec);
                timeout %= HZ;
                timeout *= (1000000/HZ);
-               put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
+               put_user(timeout, &tvp->tv_usec);
        }
        if (i < 0)
                return i;
index f098af6b6a0d75e17948449a0dfde63c70ed7d7a..132b710ea58399cd47f79edc3384cf6109b47de8 100644 (file)
@@ -176,7 +176,7 @@ int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int cou
                                buf += chars;
                        } else {
                                while (chars-- > 0)
-                                       put_fs_byte(0,buf++);
+                                       put_user(0,buf++);
                        }
                        offset = 0;
                        if (++bhe == &buflist[NBUF])
index c4e7d5bf5e67d722df79446348980740183c015a..5bb2ae67ff65ad32ea73d1ff6c64f0fef9b73105 100644 (file)
@@ -107,7 +107,7 @@ static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
        i = 0;
        while (i<buflen && (c = bh_data[i])) {
                i++;
-               put_fs_byte(c,buffer++);
+               put_user(c,buffer++);
        }
        brelse(bh);
        return i;
index 990260a9264ecd254ac8d2d55e16f9c3bb1b4fb7..5a369176e072ca4f9efe27bab28261c3a188e748 100644 (file)
@@ -36,14 +36,43 @@ int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
 {
        return -EISDIR;
 }
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+
+struct UMSDOS_DIR_ONCE {
+       void *dirbuf;
+       filldir_t filldir;
+       int count;
+       int stop;
+};
+
+/*
+       Record a single entry the first call.
+       Return -EINVAL the next one.
+*/
+static int umsdos_dir_once(
+       void * buf,
+       char * name,
+       int name_len,
+       off_t offset,
+       ino_t ino)
+{
+       int ret = -EINVAL;
+       struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+       if (d->count == 0){
+               char zname[100];
+               memcpy (zname,name,name_len);
+               zname[name_len] = '\0';
+               PRINTK (("dir_once :%s: offset %ld\n",zname,offset));
+               ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
+               d->stop = ret < 0;
+               d->count = 1;
+       }
+       return ret;
+}
 
 /*
        Read count directory entries from directory filp
        Return a negative value from linux/errno.h.
-       Return > 0 if success (The amount of byte written in
-       dirent round_up to a word size (32 bits).
+       Return > 0 if success (The amount of byte written by filldir).
 
        This function is used by the normal readdir VFS entry point and by
        some function who try to find out info on a file from a pure MSDOS
@@ -52,19 +81,19 @@ int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
 static int umsdos_readdir_x(
        struct inode *dir,              /* Point to a description of the super block */
        struct file *filp,              /* Point to a directory which is read */
-    struct dirent *dirent,     /* Will hold count directory entry */
-       int dirent_in_fs,               /* dirent point in user's space ? */
-       int count,
+    void *dirbuf,                      /* Will hold count directory entry */
+                                                       /* but filled by the filldir function */
+       int internal_read,              /* Called for internal purpose */
        struct umsdos_dirent *u_entry,  /* Optional umsdos entry */
        int follow_hlink,
-       off_t *pt_f_pos)                /* will hold the offset of the entry in EMD */
+       filldir_t filldir)
 {
        int ret = 0;
        
        umsdos_startlookup(dir);        
        if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
                && dir == pseudo_root
-               && dirent_in_fs){
+               && !internal_read){
                /*
                        We don't need to simulate this pseudo directory
                        when umsdos_readdir_x is called for internal operation
@@ -75,13 +104,10 @@ static int umsdos_readdir_x(
                        linux root), it simulate a directory /DOS which points to
                        the real root of the file system.
                */
-               put_fs_long(dir->i_sb->s_mounted->i_ino,&dirent->d_ino);
-               memcpy_tofs (dirent->d_name,"DOS",3);
-               put_fs_byte(0,dirent->d_name+3);
-               put_fs_word (3,&dirent->d_reclen);
-               if (u_entry != NULL) u_entry->flags = 0;
-               ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1);
-               filp->f_pos++;
+               if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
+                       ,dir->i_sb->s_mounted->i_ino) == 0){
+                       filp->f_pos++;
+               }
        }else if (filp->f_pos < 2
                || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
                /* #Specification: readdir / . and ..
@@ -116,15 +142,26 @@ static int umsdos_readdir_x(
                        EMD, we are back at offset 64. So we set the offset
                        to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
                        .. entry from msdos.
+                       
+                       Now (linux 1.3), umsdos_readdir can read more than one
+                       entry even if we limit (umsdos_dir_once) to only one:
+                       It skips over hidden file. So we switch to
+                       UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
+                       the .. entry.
                */
-               ret = msdos_readdir(dir,filp,dirent,count);
-               if (filp->f_pos == 64) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
+               int last_f_pos = filp->f_pos;   
+               struct UMSDOS_DIR_ONCE bufk;
+               bufk.dirbuf = dirbuf;
+               bufk.filldir = filldir;
+               bufk.count = 0;
+               ret = msdos_readdir(dir,filp,&bufk,umsdos_dir_once);
+               if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
                if (u_entry != NULL) u_entry->flags = 0;
        }else{
                struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
                if (emd_dir != NULL){
                        if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
-                       PRINTK (("f_pos %ld i_size %d\n",filp->f_pos,emd_dir->i_size));
+                       PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
                        ret = 0;
                        while (filp->f_pos < emd_dir->i_size){
                                struct umsdos_dirent entry;
@@ -156,7 +193,6 @@ static int umsdos_readdir_x(
                                        int lret;
                                        umsdos_parse (entry.name,entry.name_len,&info);
                                        info.f_pos = cur_f_pos;
-                                       *pt_f_pos = cur_f_pos;
                                        umsdos_manglename (&info);
                                        lret = umsdos_real_lookup (dir,info.fake.fname
                                                ,info.fake.len,&inode);
@@ -177,29 +213,16 @@ static int umsdos_readdir_x(
                                                        infinite recursion /DOS/linux/DOS/linux while
                                                        walking the file system.
                                                */
-                                               if (inode != pseudo_root){
-                                                       PRINTK (("Trouve ino %d ",inode->i_ino));
-                                                       if (dirent_in_fs){
-                                                               put_fs_long(inode->i_ino,&dirent->d_ino);
-                                                               memcpy_tofs (dirent->d_name,entry.name
-                                                                       ,entry.name_len);
-                                                               put_fs_byte(0,dirent->d_name+entry.name_len);
-                                                               put_fs_word (entry.name_len
-                                                                       ,&dirent->d_reclen);
-                                                               /* In this case, the caller only needs */
-                                                               /* flags */
-                                                               if (u_entry != NULL){
-                                                                       u_entry->flags = entry.flags;
-                                                               }
-                                                       }else{
-                                                               dirent->d_ino = inode->i_ino;
-                                                               memcpy (dirent->d_name,entry.name
-                                                                       ,entry.name_len);
-                                                               dirent->d_name[entry.name_len] = '\0';
-                                                               dirent->d_reclen = entry.name_len;
-                                                               if (u_entry != NULL) *u_entry = entry;
+                                               if (inode != pseudo_root
+                                                       && (internal_read
+                                                               || !(entry.flags & UMSDOS_HIDDEN))){
+                                                       if (filldir (dirbuf 
+                                                               ,entry.name,entry.name_len
+                                                               ,cur_f_pos, inode->i_ino) < 0){
+                                                               filp->f_pos = cur_f_pos;
                                                        }
-                                                       ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1);
+                                                       PRINTK (("Trouve ino %ld ",inode->i_ino));
+                                                       if (u_entry != NULL) *u_entry = entry;
                                                        iput (inode);
                                                        break;
                                                }
@@ -217,11 +240,18 @@ static int umsdos_readdir_x(
                                        }
                                }
                        }
+                       /*
+                               If the fillbuf has failed, f_pos is back to 0.
+                               To avoid getting back into the . and .. state
+                               (see comments at the beginning), we put back
+                               the special offset.
+                       */
+                       if (filp->f_pos == 0) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
                        iput(emd_dir);
                }
        }
        umsdos_endlookup(dir);  
-       PRINTK (("read dir %p pos %d ret %d\n",dir,filp->f_pos,ret));
+       PRINTK (("read dir %p pos %lu ret %d\n",dir,filp->f_pos,ret));
        return ret;
 }
 /*
@@ -232,17 +262,26 @@ static int umsdos_readdir_x(
 static int UMSDOS_readdir(
        struct inode *dir,              /* Point to a description of the super block */
        struct file *filp,              /* Point to a directory which is read */
-    struct dirent *dirent,     /* Will hold count directory entry */
-       int count)
+       void *dirbuf,                   /* Will hold directory entries  */
+       filldir_t filldir)
 {
-       int ret = -ENOENT;
-       while (1){
+       int ret = 0;
+       int count = 0;
+       struct UMSDOS_DIR_ONCE bufk;
+       bufk.dirbuf = dirbuf;
+       bufk.filldir = filldir;
+       bufk.stop = 0;
+       PRINTK (("UMSDOS_readdir in\n"));
+       while (ret == 0 && bufk.stop == 0){
                struct umsdos_dirent entry;
-               off_t f_pos;
-               ret = umsdos_readdir_x (dir,filp,dirent,1,count,&entry,1,&f_pos);
-               if (ret <= 0 || !(entry.flags & UMSDOS_HIDDEN)) break;
+               bufk.count = 0;
+               ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
+               if (bufk.count == 0) break;
+               count += bufk.count;
        }
-       return ret;
+       PRINTK (("UMSDOS_readdir out %d count %d pos %lu\n",ret,count
+               ,filp->f_pos));
+       return count == 0 ? -ENOENT : ret;
 }
 /*
        Complete the inode content with info from the EMD file
@@ -331,6 +370,53 @@ void umsdos_lookup_patch (
 if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
        }
 }
+struct UMSDOS_DIRENT_K{
+       off_t f_pos; /* will hold the offset of the entry in EMD */
+       ino_t ino;
+};
+
+/*
+       Just to record the offset of one entry.
+*/
+static int umsdos_filldir_k(
+       void * buf,
+       char * name,
+       int name_len,
+       off_t offset,
+       ino_t ino)
+{
+       struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
+       d->f_pos = offset;
+       d->ino = ino;
+       return 0;
+}
+
+struct UMSDOS_DIR_SEARCH{
+       struct umsdos_dirent *entry;
+       int found;
+       ino_t search_ino;
+};
+
+static int umsdos_dir_search (
+       void * buf,
+       char * name,
+       int name_len,
+       off_t offset,
+       ino_t ino)
+{
+       int ret = 0;
+       struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
+       if (d->search_ino == ino){
+               d->found = 1;
+               memcpy (d->entry->name,name,name_len);
+               d->entry->name[name_len] = '\0';
+               d->entry->name_len = name_len;
+               ret = 1;        /* So msdos_readdir will terminate */
+       }
+       return ret;
+}
+
+
 /*
        Locate entry of an inode in a directory.
        Return 0 or a negative error code.
@@ -357,24 +443,18 @@ int umsdos_inode2entry (
                iput (emddir);
                if (emddir == NULL){
                        /* This is a DOS directory */
+                       struct UMSDOS_DIR_SEARCH bufk;
                        struct file filp;
                        filp.f_reada = 1;
                        filp.f_pos = 0;
-                       while (1){
-                               struct dirent dirent;
-                               if (umsdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
-                                       printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
-                                               ,inode->i_ino);
-                               }else if (dirent.d_ino == inode->i_ino){
-                                       ret = 0;
-                                       memcpy (entry->name,dirent.d_name,dirent.d_reclen);
-                                       entry->name[dirent.d_reclen] = '\0';
-                                       entry->name_len = dirent.d_reclen;
-                                       inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-                                       inode->u.umsdos_i.i_emd_owner = 0;
-                                       umsdos_setup_dir_inode(inode);
-                                       break;
-                               }
+                       bufk.entry = entry;
+                       bufk.search_ino = inode->i_ino;
+                       msdos_readdir (dir,&filp,&bufk,umsdos_dir_search);
+                       if (bufk.found){
+                               ret = 0;
+                               inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+                               inode->u.umsdos_i.i_emd_owner = 0;
+                               umsdos_setup_dir_inode(inode);
                        }
                }else{
                        /* skip . and .. see umsdos_readdir_x() */
@@ -382,16 +462,15 @@ int umsdos_inode2entry (
                        filp.f_reada = 1;
                        filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
                        while (1){
-                               struct dirent dirent;
-                               off_t f_pos;
-                               if (umsdos_readdir_x(dir,&filp,&dirent
-                                       ,0,1,entry,0,&f_pos) <= 0){
+                               struct UMSDOS_DIRENT_K bufk;
+                               if (umsdos_readdir_x(dir,&filp,&bufk
+                                       ,1,entry,0,umsdos_filldir_k) < 0){
                                        printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
                                                ,inode->i_ino);
                                        break;
-                               }else if (dirent.d_ino == inode->i_ino){
+                               }else if (bufk.ino == inode->i_ino){
                                        ret = 0;
-                                       umsdos_lookup_patch (dir,inode,entry,f_pos);
+                                       umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
                                        break;
                                }
                        }
@@ -411,7 +490,7 @@ static int umsdos_locate_ancestor (
        int ret;
        umsdos_patch_inode (dir,NULL,0);
        ret = umsdos_real_lookup (dir,"..",2,result);
-       PRINTK (("result %d %x ",ret,*result));
+       PRINTK (("result %d %p ",ret,*result));
        if (ret == 0){
                struct inode *adir = *result;
                ret = umsdos_inode2entry (adir,dir,entry);
@@ -560,7 +639,7 @@ static int umsdos_lookup_x (
                struct umsdos_info info;
                ret = umsdos_parse (name,len,&info);
                if (ret == 0) ret = umsdos_findentry (dir,&info,0);
-               PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
+               PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
                        ,info.fake.len));
                if (ret == 0){
                        /* #Specification: umsdos / lookup
@@ -581,7 +660,7 @@ static int umsdos_lookup_x (
                                umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
                        }else{
                                umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-                               PRINTK (("lookup ino %d flags %d\n",inode->i_ino
+                               PRINTK (("lookup ino %ld flags %d\n",inode->i_ino
                                        ,info.entry.flags));
                                if (info.entry.flags & UMSDOS_HLINK){
                                        ret = umsdos_hlink2inode (inode,result);
index b1ec47bf678809cf756993ea5f5b1df8af47a367..b0db9f45129dd36dad93c76e4abe5a84af277675 100644 (file)
 #define PRINTK(x)
 #define Printk(x) printk x
 
-int umsdos_readdir_kmem(
-       struct inode *inode,
-       struct file *filp,
-       struct dirent *dirent,
-       int count)
-{
-       int ret;
-       int old_fs = get_fs();
-       set_fs (KERNEL_DS);
-       ret = msdos_readdir(inode,filp,dirent,count);
-       set_fs (old_fs);
-       return ret;
-}
 /*
        Read a file into kernel space memory
 */
@@ -102,7 +89,8 @@ int umsdos_emd_dir_read (
        filp->f_flags = 0;
        sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);
        if (sizeread != count){
-               printk ("UMSDOS: problem with EMD file. Can't read\n");
+               printk ("UMSDOS: problem with EMD file. Can't read pos = %ld (%d != %d)\n"
+                       ,filp->f_pos,sizeread,count);
                ret = -EIO;
        }
        return ret;
index d766ef9390ad2d7a7783e62e55d19ff3fe6f20d2..49d54b50c403725488752946133ab65f57f71e77 100644 (file)
 #define PRINTK(x)
 #define Printk(x) printk x
 
+struct UMSDOS_DIR_ONCE {
+       struct dirent *ent;
+       int count;
+};
+
+/*
+       Record a single entry the first call.
+       Return -EINVAL the next one.
+*/
+static int umsdos_ioctl_fill(
+       void * buf,
+       char * name,
+       int name_len,
+       off_t offset,
+       ino_t ino)
+{
+       int ret = -EINVAL;
+       struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+       if (d->count == 0){
+               memcpy_tofs (d->ent->d_name,name,name_len);
+               put_user ('\0',d->ent->d_name+name_len);
+               put_user (name_len,&d->ent->d_reclen);
+               put_user (ino,&d->ent->d_ino);
+               put_user (offset,&d->ent->d_off);
+               d->count = 1;
+               ret = 0;
+       }
+       return ret;
+}
+
+
 /*
        Perform special function on a directory
 */
@@ -80,7 +111,11 @@ int UMSDOS_ioctl_dir (
 
                                Return > 0 if success.
                        */
-                       ret = msdos_readdir(dir,filp,&idata->dos_dirent,1);
+                       struct UMSDOS_DIR_ONCE bufk;
+                       bufk.count = 0;
+                       bufk.ent = &idata->dos_dirent;
+                       msdos_readdir(dir,filp,&bufk,umsdos_ioctl_fill);
+                       ret = bufk.count == 1 ? 1 : 0;
                }else if (cmd == UMSDOS_READDIR_EMD){
                        /* #Specification: ioctl / UMSDOS_READDIR_EMD
                                One entry is read from the EMD at the current
index d708709bde0c355b36044accb5fe51547474b52c..1b7bb4572dd2171bbbf4423211a0d32b3886edbd 100644 (file)
 
 extern struct inode *pseudo_root;
 
-static int UMSDOS_rreaddir (
-       struct inode *dir,
-       struct file *filp,
-    struct dirent *dirent,
-       int count)
+struct RDIR_FILLDIR {
+       void *dirbuf;
+       filldir_t filldir;
+       int real_root;
+};
+
+static int rdir_filldir(
+       void * buf,
+       char * name,
+       int name_len,
+       off_t offset,
+       ino_t ino)
 {
        int ret = 0;
-       while (1){
-               int len = -1;
-               ret = msdos_readdir(dir,filp,dirent,count);
-               if (ret > 0) len = get_fs_word(&dirent->d_reclen);
-               if (len == 5
-                       && pseudo_root != NULL
-                       && dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
-                       /*
-                               In pseudo root mode, we must eliminate logically
-                               the directory linux from the real root.
-                       */
-                       char name[5];
-                       memcpy_fromfs (name,dirent->d_name,5);
-                       if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
-               }else{
-                       if (pseudo_root != NULL
-                               && len == 2
-                               && dir == dir->i_sb->s_mounted
-                               && dir == pseudo_root->i_sb->s_mounted){
-                               char name[2];
-                               memcpy_fromfs (name,dirent->d_name,2);
-                               if (name[0] == '.' && name[1] == '.'){
-                                       put_fs_long (pseudo_root->i_ino,&dirent->d_ino);
-                               }
+       struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
+       if (d->real_root){
+               /* real root of a pseudo_rooted partition */
+               if (name_len != UMSDOS_PSDROOT_LEN
+                       || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
+                       /* So it is not the /linux directory */
+                       if (name_len == 2
+                               && name[0] == '.'
+                               && name[1] == '.'){
+                               /* Make sure the .. entry points back to the pseudo_root */
+                               ino = pseudo_root->i_ino;
                        }
-                       break;
+                       ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
                }
+       }else{
+               /* Any DOS directory */
+               ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
        }
        return ret;
 }
 
+
+static int UMSDOS_rreaddir (
+       struct inode *dir,
+       struct file *filp,
+    void *dirbuf,
+       filldir_t filldir)
+{
+       struct RDIR_FILLDIR bufk;
+       bufk.filldir = filldir;
+       bufk.dirbuf = dirbuf;
+       bufk.real_root = pseudo_root != NULL
+               && dir == dir->i_sb->s_mounted
+               && dir == pseudo_root->i_sb->s_mounted;
+       return msdos_readdir(dir,filp,&bufk,rdir_filldir);
+}
+
 /*
        Lookup into a non promoted directory.
        If the result is a directory, make sure we find out if it is
index c67daaed91eb6a001f864639ae0b0b591131e6dc..4c1a9b45f2182a00e59a232b160deaf578ddb554 100644 (file)
@@ -166,7 +166,7 @@ xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
                buf += chars;
            } else {
                while (chars-->0)
-                   put_fs_byte(0,buf++);
+                   put_user(0,buf++);
            }
            offset = 0;
            if (++bhe == &buflist[NBUF])
index 1c64ebc6dca11d2bf739dc05d1a0c44385e834e1..9f4d4e9b5121532abb854d7f1cf1c8b2f1379e5f 100644 (file)
@@ -69,9 +69,9 @@ static int xiafs_readlink(struct inode * inode, char * buffer, int buflen)
     if (!bh)
         return 0;
     for (i=0; i < buflen && (c=bh->b_data[i]); i++)
-      put_fs_byte(c, buffer++);
+      put_user(c, buffer++);
     if (i < buflen-1)
-      put_fs_byte((char)0, buffer);
+      put_user('\0', buffer);
     brelse(bh);
     return i;
 }
index 4b327266d7e9d526e6aafdfda4d3cc7516898a7e..745593ab40f089da4220c4afff7feefdd88d215e 100644 (file)
@@ -74,7 +74,7 @@
 #define MAX_DMA_CHANNELS       8
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS                0x1000000
+#define MAX_DMA_ADDRESS                (~0UL)
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
diff --git a/include/asm-alpha/pal.h b/include/asm-alpha/pal.h
new file mode 100644 (file)
index 0000000..a4ef2e3
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __ALPHA_PAL_H
+#define __ALPHA_PAL_H
+
+/*
+ * Common PAL-code
+ */
+#define PAL_halt         0
+#define PAL_cflush       1
+#define PAL_draina       2
+#define PAL_cobratt      9
+#define PAL_bpt                128
+#define PAL_bugchk     129
+#define PAL_chmk       131
+#define PAL_callsys    131
+#define PAL_imb                134
+#define PAL_rduniq     158
+#define PAL_wruniq     159
+#define PAL_gentrap    170
+#define PAL_nphalt     190
+
+/*
+ * VMS specific PAL-code
+ */
+#define PAL_swppal     10
+#define PAL_mfpr_vptb  41
+
+/*
+ * OSF specific PAL-code
+ */
+#define PAL_rdmces     16
+#define PAL_wrmces     17
+#define PAL_wrfen      43
+#define PAL_wrvptptr   45
+#define PAL_jtopal     46
+#define PAL_swpctx     48
+#define PAL_wrval      49
+#define PAL_rdval      50
+#define PAL_tbi                51
+#define PAL_wrent      52
+#define PAL_swpipl     53
+#define PAL_rdps       54
+#define PAL_wrkgp      55
+#define PAL_wrusp      56
+#define PAL_wrperfmon  57
+#define PAL_rdusp      58
+#define PAL_whami      60
+#define PAL_rtsys      61
+#define PAL_rti                63
+
+#endif /* __ALPHA_PAL_H */
index ed37706075580bc7158cf61f83d725a8c5b3e745..bbd9d603fe2c4aaba33a5e24a1dc4e9f498c9fdc 100644 (file)
@@ -9,7 +9,7 @@
  * pointer type..
  */
 #define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) __get_user((ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
 
 /*
  * This is a silly but good way to make sure that
@@ -40,7 +40,7 @@ static inline void __put_user(unsigned long x, void * y, int size)
 }
 
 /* I should make this use unaligned transfers etc.. */
-static inline unsigned long __get_user(void * y, int size)
+static inline unsigned long __get_user(const void * y, int size)
 {
        switch (size) {
                case 1:
index cbed1ded7dfbc875755b806ed5c2dcd635f2e7de..113f879d0fac755405be4efdda29098c6da1f417 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ALPHA_SYSTEM_H
 #define __ALPHA_SYSTEM_H
 
+#include <asm/pal.h>   /* for backwards compatibility... */
+
 /*
  * System defines.. Note that this is included both from .c and .S
  * files, so it does only defines, not any C code.
 #define START_ADDR     0xfffffc0000310000
 #define START_SIZE     (2*1024*1024)
 
-/*
- * Common PAL-code
- */
-#define PAL_halt         0
-#define PAL_cflush       1
-#define PAL_draina       2
-#define PAL_cobratt      9
-#define PAL_bpt                128
-#define PAL_bugchk     129
-#define PAL_chmk       131
-#define PAL_callsys    131
-#define PAL_imb                134
-#define PAL_rduniq     158
-#define PAL_wruniq     159
-#define PAL_gentrap    170
-#define PAL_nphalt     190
-
-/*
- * VMS specific PAL-code
- */
-#define PAL_swppal     10
-#define PAL_mfpr_vptb  41
-
-/*
- * OSF specific PAL-code
- */
-#define PAL_rdmces     16
-#define PAL_wrmces     17
-#define PAL_wrfen      43
-#define PAL_wrvptptr   45
-#define PAL_jtopal     46
-#define PAL_swpctx     48
-#define PAL_wrval      49
-#define PAL_rdval      50
-#define PAL_tbi                51
-#define PAL_wrent      52
-#define PAL_swpipl     53
-#define PAL_rdps       54
-#define PAL_wrkgp      55
-#define PAL_wrusp      56
-#define PAL_wrperfmon  57
-#define PAL_rdusp      58
-#define PAL_whami      60
-#define PAL_rtsys      61
-#define PAL_rti                63
-
 #ifndef __ASSEMBLY__
 
 extern void wrent(void *, unsigned long);
 extern void wrkgp(unsigned long);
 extern void wrusp(unsigned long);
 extern unsigned long rdusp(void);
+extern unsigned long rdmces (void);
+extern void wrmces (unsigned long);
 
 #define halt() __asm__ __volatile__(".long 0");
 
index 2c0f4e4919bb98cc0f6abdb9308504083b5a7ab6..003103b9aacb9a4e7ccd3a461d8865c13542f7c6 100644 (file)
@@ -60,6 +60,8 @@ struct ltchars {
 
 #define TIOCSWINSZ     _IOW('t', 103, struct winsize)
 #define TIOCGWINSZ     _IOR('t', 104, struct winsize)
+#define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
+#define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
 #define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
 
 #define TIOCGLTC       _IOR('t', 116, struct ltchars)
@@ -154,8 +156,8 @@ struct termios {
 #define VSTOP 13
 #define VLNEXT 14
 #define VDISCARD 15
-#define VTIME 17
 #define VMIN 16
+#define VTIME 17
 
 /*
  * ..and the same for c_cc in the termio structure.. 
@@ -173,13 +175,13 @@ struct termios {
 #define _VSWTC 7
 
 #ifdef __KERNEL__
-/*     intr=^C         quit=^|         erase=del       kill=^U
-       eof=^D          vtime=\0        vmin=\1         sxtc=\0
-       start=^Q        stop=^S         susp=^Z         eol=\0
-       reprint=^R      discard=^U      werase=^W       lnext=^V
-       eol2=\0
+/*     eof=^D          eol=\0          eol2=\0         erase=del
+       werase=^W       kill=^U         reprint=^R      sxtc=\0
+       intr=^C         quit=^\         susp=^Z         <OSF/1 VDSUSP>
+       start=^Q        stop=^S         lnext=^V        discard=^U
+       vmin=\1         vtime=\0
 */
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\000\001"
+#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
 #endif
 
 /* c_iflag bits */
index ee339bd646f2db807454fc5eb04c9aff01b07845..06ae3edac2e4f395672b7dbd65717ac797d263c0 100644 (file)
@@ -25,7 +25,7 @@ extern __inline__ int set_bit(int nr, void * addr)
 
        __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"r" (nr));
+               :"ir" (nr));
        return oldbit;
 }
 
@@ -35,7 +35,7 @@ extern __inline__ int clear_bit(int nr, void * addr)
 
        __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"r" (nr));
+               :"ir" (nr));
        return oldbit;
 }
 
@@ -45,7 +45,7 @@ extern __inline__ int change_bit(int nr, void * addr)
 
        __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"r" (nr));
+               :"ir" (nr));
        return oldbit;
 }
 
@@ -59,7 +59,7 @@ extern __inline__ int test_bit(int nr, void * addr)
 
        __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit)
-               :"m" (ADDR),"r" (nr));
+               :"m" (ADDR),"ir" (nr));
        return oldbit;
 }
 
@@ -75,20 +75,18 @@ extern inline int find_first_zero_bit(void * addr, unsigned size)
        __asm__("
                cld
                movl $-1,%%eax
+               xorl %%edx,%%edx
                repe; scasl
                je 1f
+               xorl -4(%%edi),%%eax
                subl $4,%%edi
-               movl (%%edi),%%eax
-               notl %%eax
                bsfl %%eax,%%edx
-               jmp 2f
-1:             xorl %%edx,%%edx
-2:             subl %%ebx,%%edi
+1:             subl %%ebx,%%edi
                shll $3,%%edi
                addl %%edi,%%edx"
                :"=d" (res)
                :"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
-               :"ax", "bx", "cx", "di");
+               :"ax", "cx", "di");
        return res;
 }
 
index 4b716359210a575efae1b560877f9ffdfacbede7..f7d2b8380a794cee5abb59903bb7125f6e46058b 100644 (file)
@@ -59,6 +59,34 @@ extern inline void * phys_to_virt(unsigned long address)
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+extern inline unsigned long readb(unsigned long addr)
+{ return *(unsigned char *) addr; }
+
+extern inline unsigned long readw(unsigned long addr)
+{ return *(unsigned short *) addr; }
+
+extern inline unsigned long readl(unsigned long addr)
+{ return *(unsigned int *) addr; }
+
+extern inline void writeb(unsigned char b, unsigned long addr)
+{ *(unsigned char *) addr = b; }
+
+extern inline void writew(unsigned short b, unsigned long addr)
+{ *(unsigned short *) addr = b; }
+
+extern inline void writel(unsigned int b, unsigned long addr)
+{ *(unsigned int *) addr = b; }
+
+#define memset_io(a,b,c)       memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
+
 /*
  * Talk about misusing macros..
  */
index 9c6740a937b84ba2a36f5ce85adde68649aea6e7..e9992ef6dd88469975f65791b0c3eb2cc4eb2b77 100644 (file)
@@ -15,7 +15,7 @@
  * pointer type..
  */
 #define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) __get_user((ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
 
 /*
  * This is a silly but good way to make sure that
@@ -127,21 +127,27 @@ static inline void put_user_long(unsigned long val,int * addr)
 
 static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
 {
-__asm__("cld\n\t"
-       "push %%es\n\t"
-       "push %%fs\n\t"
-       "pop %%es\n\t"
-       "testb $1,%%cl\n\t"
-       "je 1f\n\t"
-       "movsb\n"
-       "1:\ttestb $2,%%cl\n\t"
-       "je 2f\n\t"
-       "movsw\n"
-       "2:\tshrl $2,%%ecx\n\t"
-       "rep ; movsl\n\t"
-       "pop %%es"
-       : /* no outputs */
-       :"c" (n),"D" ((long) to),"S" ((long) from)
+    __asm__ volatile
+       ("      cld
+               push %%es
+               movw %%fs,%%cx
+               movw %%cx,%%es
+               cmpl $3,%0
+               jbe 1f
+               movl %%edi,%%ecx
+               negl %%ecx
+               andl $3,%%ecx
+               subl %%ecx,%0
+               rep; movsb
+               movl %0,%%ecx
+               shrl $2,%%ecx
+               rep; movsl
+               andl $3,%0
+       1:      movl %0,%%ecx
+               rep; movsb
+               pop %%es"
+       :"=abd" (n)
+       :"0" (n),"D" ((long) to),"S" ((long) from)
        :"cx","di","si");
 }
 
@@ -210,18 +216,24 @@ __asm__("cld\n\t" \
 
 static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
-__asm__("cld\n\t"
-       "testb $1,%%cl\n\t"
-       "je 1f\n\t"
-       "fs ; movsb\n"
-       "1:\ttestb $2,%%cl\n\t"
-       "je 2f\n\t"
-       "fs ; movsw\n"
-       "2:\tshrl $2,%%ecx\n\t"
-       "rep ; fs ; movsl"
-       : /* no outputs */
-       :"c" (n),"D" ((long) to),"S" ((long) from)
-       :"cx","di","si","memory");
+    __asm__ volatile
+       ("      cld
+               cmpl $3,%0
+               jbe 1f
+               movl %%edi,%%ecx
+               negl %%ecx
+               andl $3,%%ecx
+               subl %%ecx,%0
+               fs; rep; movsb
+               movl %0,%%ecx
+               shrl $2,%%ecx
+               fs; rep; movsl
+               andl $3,%0
+       1:      movl %0,%%ecx
+               fs; rep; movsb"
+       :"=abd" (n)
+       :"0" (n),"D" ((long) to),"S" ((long) from)
+       :"cx","di","si", "memory");
 }
 
 static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
index 0f721576ef5ae95141722165aaa327f25955cb9e..5a1982dc0065f806520eaaacc362dfa72f0c65aa 100644 (file)
@@ -342,15 +342,15 @@ extern inline void * __memcpy(void * to, const void * from, size_t n)
 __asm__ __volatile__(
        "cld\n\t"
        "rep ; movsl\n\t"
-       "testb $2,%%dl\n\t"
+       "testb $2,%b1\n\t"
        "je 1f\n\t"
        "movsw\n"
-       "1:\ttestb $1,%%dl\n\t"
+       "1:\ttestb $1,%b1\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
        : /* no output */
-       :"c" (n/4), "d" (n),"D" ((long) to),"S" ((long) from)
+       :"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
        : "cx","di","si","memory");
 return (to);
 }
@@ -424,21 +424,7 @@ __asm__ __volatile__(
 return dest;
 }
 
-extern inline int memcmp(const void * cs,const void * ct,size_t count)
-{
-register int __res;
-__asm__ __volatile__(
-       "cld\n\t"
-       "repe\n\t"
-       "cmpsb\n\t"
-       "je 1f\n\t"
-       "sbbl %%eax,%%eax\n\t"
-       "orb $1,%%al\n"
-       "1:"
-       :"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
-       :"si","di","cx");
-return __res;
-}
+#define memcmp __builtin_memcmp
 
 extern inline void * memchr(const void * cs,int c,size_t count)
 {
@@ -482,15 +468,15 @@ extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count
 __asm__ __volatile__(
        "cld\n\t"
        "rep ; stosl\n\t"
-       "testb $2,%%dl\n\t"
+       "testb $2,%b1\n\t"
        "je 1f\n\t"
        "stosw\n"
-       "1:\ttestb $1,%%dl\n\t"
+       "1:\ttestb $1,%b1\n\t"
        "je 2f\n\t"
        "stosb\n"
        "2:"
        : /* no output */
-       :"a" (c), "d" (count), "c" (count/4), "D" ((long) s)
+       :"a" (c), "q" (count), "c" (count/4), "D" ((long) s)
        :"cx","di","memory");
 return (s);    
 }
index d6b1e95f5e04325da3d5b051b8fdd596d59aaa52..a4c82ae8aabe0232667d971ec4e5a4c3984d56d7 100644 (file)
@@ -48,8 +48,8 @@ typedef unsigned char __u8;
 typedef __signed__ short __s16;
 typedef unsigned short __u16;
 
-typedef __signed__ long __s32;
-typedef unsigned long __u32;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
 
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __signed__ long long __s64;
@@ -67,8 +67,8 @@ typedef unsigned char u8;
 typedef signed short s16;
 typedef unsigned short u16;
 
-typedef signed long s32;
-typedef unsigned long u32;
+typedef signed int s32;
+typedef unsigned int u32;
 
 typedef signed long long s64;
 typedef unsigned long long u64;
index 4a404573d6ee01bf3d820a7684b1730e29f45fb6..3955f6639ad346ebc5faab7447f32872f4b0a083 100644 (file)
@@ -2,18 +2,18 @@
 #define _SPARC_ASI_H
 
 /* asi.h:  Address Space Identifier values for the sparc.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au)
+ * Joint edition for sun4c+sun4m: Pete A. Zaitcev <zaitcev@ipmce.su>
+ */
 
 /* These are sun4c, beware on other architectures. Although things should
  * be similar under regular sun4's.
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_SUN4M
-#include "asi4m.h"
-#else
 
 #define ASI_NULL1        0x0
 #define ASI_NULL2        0x1
@@ -24,6 +24,7 @@
 #define ASI_PTE              0x4
 #define ASI_HWFLUSHSEG       0x5      /* These are to initiate hw flushes of the cache */
 #define ASI_HWFLUSHPAGE      0x6
+#define ASI_REGMAP           0x6      /* Top level segmaps on Sun4's with MUTANT MMU */
 #define ASI_HWFLUSHCONTEXT   0x7
 
 
 #define ASI_FLUSHPG      0xd
 #define ASI_FLUSHCTX     0xe
 
+/* The following are now not so SS5 specific any more, it is pretty
+ * much a complete generic sun4m/V8 ASI assignment listing now.
+ *
+ * -- davem@caip.rutgers.edu
+ */
+
+/* SPARCstation-5: only 6 bits are decoded. */
+/* wo = Write Only, rw = Read Write;        */
+/* ss = Single Size, as = All Sizes;        */
+#define ASI_M_RES00         0x00   /* Don't touch... */
+#define ASI_M_UNA01         0x01   /* Same here... */
+#define ASI_M_MXCC          0x02   /* Access to TI VIKING MXCC registers */
+#define ASI_M_FLUSH_PROBE   0x03   /* Reference MMU Flush/Probe; rw, ss */
+#define ASI_M_MMUREGS       0x04   /* MMU Registers; rw, ss */
+#define ASI_M_TLBDIAG       0x05   /* MMU TLB only Diagnostics */
+#define ASI_M_DIAGS         0x06   /* Reference MMU Diagnostics */
+#define ASI_M_IODIAG        0x07   /* MMU I/O TLB only Diagnostics */
+#define ASI_M_USERTXT       0x08   /* Same as ASI_USERTXT; rw, as */
+#define ASI_M_KERNELTXT     0x09   /* Same as ASI_KERNELTXT; rw, as */
+#define ASI_M_USERDATA      0x0A   /* Same as ASI_USERDATA; rw, as */
+#define ASI_M_KERNELDATA    0x0B   /* Same as ASI_KERNELDATA; rw, as */
+#define ASI_M_TXTC_TAG      0x0C   /* Instruction Cache Tag; rw, ss */
+#define ASI_M_TXTC_DATA     0x0D   /* Instruction Cache Data; rw, ss */
+#define ASI_M_DATAC_TAG     0x0E   /* Data Cache Tag; rw, ss */
+#define ASI_M_DATAC_DATA    0x0F   /* Data Cache Data; rw, ss */
+
+/* The following cache flushing ASIs work only with the 'sta'
+ * instruction results are unpredictable for 'swap' and 'ldstuba' etc.
+ * So don't do it.
+ */
+
+/* These ASI flushes affect external caches too. */
+#define ASI_M_FLUSH_PAGE    0x10   /* Flush I&D Cache Line (page); wo, ss */
+#define ASI_M_FLUSH_SEG     0x11   /* Flush I&D Cache Line (seg); wo, ss */
+#define ASI_M_FLUSH_REGION  0x12   /* Flush I&D Cache Line (region); wo, ss */
+#define ASI_M_FLUSH_CTX     0x13   /* Flush I&D Cache Line (context); wo, ss */
+#define ASI_M_FLUSH_USER    0x14   /* Flush I&D Cache Line (user); wo, ss */
+
+/* Block-copy operations are available on certain V8 cpus */
+#define ASI_M_BCOPY         0x17   /* Block copy */
+
+/* These affect only the ICACHE and are Ross HyperSparc specific. */
+#define ASI_M_IFLUSH_PAGE   0x18   /* Flush I Cache Line (page); wo, ss */
+#define ASI_M_IFLUSH_SEG    0x19   /* Flush I Cache Line (seg); wo, ss */
+#define ASI_M_IFLUSH_REGION 0x1A   /* Flush I Cache Line (region); wo, ss */
+#define ASI_M_IFLUSH_CTX    0x1B   /* Flush I Cache Line (context); wo, ss */
+#define ASI_M_IFLUSH_USER   0x1C   /* Flush I Cache Line (user); wo, ss */
+
+/* Block-fill operations are available on certain V8 cpus */
+#define ASI_M_BFILL         0x1F
+
+/* This allows direct access to main memory, actually 0x20 to 0x2f are
+ * the available ASI's for physical ram pass-through, but I don't have
+ * any idea what the other ones do....
+ */
+
+#define ASI_M_BYPASS       0x20   /* Reference MMU bypass; rw, as */
+#define ASI_M_FBMEM        0x29   /* Graphics card frame buffer access */
+#define ASI_M_VMEUS        0x2A   /* VME user 16-bit access */
+#define ASI_M_VMEPS        0x2B   /* VME priv 16-bit access */
+#define ASI_M_VMEUT        0x2C   /* VME user 32-bit access */
+#define ASI_M_VMEPT        0x2D   /* VME priv 32-bit access */
+#define ASI_M_SBUS         0x2E   /* Direct SBus access */
+#define ASI_M_CTL          0x2F   /* Control Space (ECC and MXCC are here) */
+
+
+/* This is ROSS HyperSparc only. */
+#define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
+
+#define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Registerl rw, ss */
+
+/* Sparc V9 TI UltraSparc ASI's */
+
+/* ASIs 0x0-0x7f are Supervisor Only.  0x80-0xff are for anyone. */
+
+/* You will notice that there are a lot of places where if a normal
+ * ASI is available on the V9, there is also a little-endian version.
+ */
+
+#define ASI_V9_RESV0       0x00   /* Don't touch... */
+#define ASI_V9_RESV1       0x01   /* Not here */
+#define ASI_V9_RESV2       0x02   /* Or here */
+#define ASI_V9_RESV3       0x03   /* nor here. */
+#define ASI_V9_NUCLEUS     0x04   /* Impl-dep extra virtual access context */
+#define ASI_V9_NUCLEUSL    0x0C   /* Nucleus context, little-endian */
+#define ASI_V9_USER_PRIM   0x10   /* User primary address space */
+#define ASI_V9_USER_SEC    0x11   /* User secondary address space */
+
+#define ASI_V9_MMUPASS     0x14   /* OBMEM (external cache, no data cache) */
+#define ASI_V9_IOPASS      0x15   /* Like MMUPASS but for I/O areas (uncached) */
+#define ASI_V9_USER_PRIML  0x18   /* User primary address space, little-endian. */
+#define ASI_V9_USER_SECL   0x19   /* User secondary address space, little-endian. */
+#define ASI_V9_MMUPASSL    0x1C   /* OBMEM little-endian */
+#define ASI_V9_IOPASSL     0x1D   /* Like IOPASS but little-endian */
+#define ASI_V9_ATOMICQ     0x24   /* Atomic 128-bit load address space */
+#define ASI_V9_ATOMICQL    0x2C   /* Atomic 128-bit load little-endian */
+#define ASI_V9_LSTORECTL   0x45   /* ld/st control unit */
+#define ASI_V9_DCACHE_ENT  0x46   /* Data cache entries */
+#define ASI_V9_DCACHE_TAG  0x47   /* Data cache tags */
+#define ASI_V9_IRQDISPS    0x48   /* IRQ dispatch status registers */
+#define ASI_V9_IRQRECVS    0x49   /* IRQ receive status registers */
+#define ASI_V9_MMUREGS     0x4A   /* Spitfire MMU control register */
+#define ASI_V9_ESTATE      0x4B   /* Error state enable register */
+#define ASI_V9_ASYNC_FSR   0x4C   /* Asynchronous Fault Status reg */
+#define ASI_V9_ASYNC_FAR   0x4D   /* Asynchronous Fault Address reg */
+
+#define ASI_V9_ECACHE_DIAG 0x4E   /* External Cache diagnostics */
+
+#define ASI_V9_TXTMMU      0x50   /* MMU for program text */
+#define ASI_V9_TXTMMU_D1   0x51   /* XXX */
+#define ASI_V9_TXTMMU_D2   0x52   /* XXX */
+#define ASI_V9_TXTMMU_TDI  0x54   /* Text MMU TLB data in */
+#define ASI_V9_TXTMMU_TDA  0x55   /* Text MMU TLB data access */
+#define ASI_V9_TXTMMU_TTR  0x56   /* Text MMU TLB tag read */
+#define ASI_V9_TXTMMU_TDM  0x57   /* Text MMU TLB de-map */
+
+#define ASI_V9_DATAMMU     0x58   /* MMU for program data */
+#define ASI_V9_DATAMMU_D1  0x59   /* XXX */
+#define ASI_V9_DATAMMU_D2  0x5A   /* XXX */
+#define ASI_V9_DATAMMU_DD  0x5B   /* XXX */
+#define ASI_V9_DATAMMU_TDI 0x5C   /* Data MMU TLB data in */
+#define ASI_V9_DATAMMU_TDA 0x5D   /* Data MMU TLB data access */
+#define ASI_V9_DATAMMU_TTR 0x5E   /* Data MMU TLB tag read */
+#define ASI_V9_DATAMMU_TDM 0x5F   /* Data MMU TLB de-map */
+
+#define ASI_V9_ICACHE_D    0x66   /* Instruction cache data */
+#define ASI_V9_ICACHE_T    0x67   /* Instruction cache tags */
+#define ASI_V9_ICACHE_DEC  0x6E   /* Instruction cache decode */
+#define ASI_V9_ICACHE_NXT  0x6F   /* Instruction cache next ent */
+
+#define ASI_V9_HUH1        0x70   /* XXX */
+#define ASI_V9_HUH2        0x71   /* XXX */
+
+#define ASI_V9_ECACHE_ACC  0x76   /* External cache registers */
+
+#define ASI_V9_INTR_DISP   0x77   /* Interrupt dispatch registers */
+#define ASI_V9_HUH1L       0x78   /* XXX */
+#define ASI_V9_HUH2L       0x79   /* XXX */
+#define ASI_V9_INTR_RECV   0x7f   /* Interrupt Receive registers */
+
+#define ASI_V9_PRIMARY      0x80   /* Primary address space */
+#define ASI_V9_SECONDARY    0x81   /* Secondary address space */
+#define ASI_V9_PRIMARY_NF   0x82   /* Primary address space -- No Fault */
+#define ASI_V9_SECONDARY_NF 0x83   /* Secondary address space -- No Fault */
+
+#define ASI_V9_PRIMARYL      0x80   /* Primary address space, little-endian */
+#define ASI_V9_SECONDARYL    0x81   /* Secondary address space, little-endian  */
+#define ASI_V9_PRIMARY_NFL   0x82   /* Primary address space, No Fault, l-endian  */
+#define ASI_V9_SECONDARY_NFL 0x83   /* Secondary address space, No Fault, l-endian  */
+
+#define ASI_V9_XXX1        0xC0   /* XXX */
+#define ASI_V9_XXX2        0xC1   /* XXX */
+#define ASI_V9_XXX3        0xC2   /* XXX */
+#define ASI_V9_XXX4        0xC3   /* XXX */
+#define ASI_V9_XXX5        0xC4   /* XXX */
+#define ASI_V9_XXX6        0xC5   /* XXX */
+#define ASI_V9_XXX7        0xC8   /* XXX */
+#define ASI_V9_XXX8        0xC9   /* XXX */
+#define ASI_V9_XXX9        0xCA   /* XXX */
+#define ASI_V9_XXX10       0xCB   /* XXX */
+#define ASI_V9_XXX11       0xCC   /* XXX */
+#define ASI_V9_XXX12       0xCD   /* XXX */
+
+#define ASI_V9_XXX13       0xD0   /* XXX */
+#define ASI_V9_XXX14       0xD1   /* XXX */
+#define ASI_V9_XXX15       0xD2   /* XXX */
+#define ASI_V9_XXX16       0xD3   /* XXX */
+#define ASI_V9_XXX17       0xD8   /* XXX */
+#define ASI_V9_XXX18       0xD9   /* XXX */
+#define ASI_V9_XXX19       0xDA   /* XXX */
+#define ASI_V9_XXX20       0xDB   /* XXX */
+
+#define ASI_V9_XXX21       0xE0   /* XXX */
+#define ASI_V9_XXX22       0xE1   /* XXX */
+#define ASI_V9_XXX23       0xF0   /* XXX */
+#define ASI_V9_XXX24       0xF1   /* XXX */
+#define ASI_V9_XXX25       0xF8   /* XXX */
+#define ASI_V9_XXX26       0xF9   /* XXX */
+
+#ifndef __ASSEMBLY__
+
+/* Better to do these inline with gcc __asm__ statements. */
+
+/* The following allow you to access physical memory directly without
+ * translation by the SRMMU.  The only other way to do this is to
+ * turn off the SRMMU completely, and well... thats not good.
+ *
+ * TODO: For non-MBus SRMMU units we have to perform the following
+ *       using this sequence.
+ * 1) Turn off traps
+ * 2) Turn on AC bit in SRMMU control register
+ * 3) Do our direct physical memory access
+ * 4) Restore old SRMMU control register value
+ * 5) Restore old %psr value 
+ */
+
+extern __inline__ unsigned int
+ldb_sun4m_bypass(unsigned int addr)
+{
+  unsigned int retval;
+
+  __asm__("lduba [%2] %1, %0\n\t" :
+          "=r" (retval) :
+          "i" (ASI_M_BYPASS), "r" (addr));
+
+  return retval;
+}
+
+extern __inline__ unsigned int
+ldw_sun4m_bypass(unsigned int addr)
+{
+  unsigned int retval;
+
+  __asm__("lda [%2] %1, %0\n\t" :
+          "=r" (retval) :
+          "i" (ASI_M_BYPASS), "r" (addr));
+
+  return retval;
+}
+
+extern __inline__ void
+stb_sun4m_bypass(unsigned char value, unsigned int addr)
+{
+  __asm__("stba %0, [%2] %1\n\t" : :
+          "r" (value), "i" (ASI_M_BYPASS), "r" (addr) :
+         "memory");
+}
+
+extern __inline__ void
+stw_sun4m_bypass(unsigned int value, unsigned int addr)
+{
+  __asm__("sta %0, [%2] %1\n\t" : :
+          "r" (value), "i" (ASI_M_BYPASS), "r" (addr) :
+         "memory");
+}
+
+#endif /* !(__ASSEMBLY__) */
+
 
-#endif /* CONFIG_SUN4M */
 #endif /* _SPARC_ASI_H */
diff --git a/include/asm-sparc/auxio.h b/include/asm-sparc/auxio.h
new file mode 100644 (file)
index 0000000..1fa75e7
--- /dev/null
@@ -0,0 +1,35 @@
+/* auxio.h:  Definitons and code for the Auxiliary I/O register.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_AUXIO_H
+#define _SPARC_AUXIO_H
+
+/* This defines the register as I know it on the Sun4c, it may be
+ * different or not exist at all on sun4m's.
+ */
+
+#define AUXIO_IOADDR  0xf7400000  /* Physical address is IO space */
+
+/* This register is an unsigned char in IO space.  It does two things.
+ * First, it is used to control the front panel LED light on machines
+ * that have it (good for testing entry points to trap handlers and irq's)
+ * Secondly, it controls various floppy drive parameters on machines that
+ * have a drive.
+ */
+
+#define AUXIO_ORMEIN      0xf0    /* All writes must set these bits. */
+#define AUXIO_FLPY_DENS   0x20    /* Floppy density, high if set. */
+#define AUXIO_FLPY_DCHG   0x10    /* A disk change occurred. */
+#define AUXIO_FLPY_DSEL   0x08    /* Drive select, 0 'a drive' 1 'b drive'. */
+#define AUXIO_FLPY_TCNT   0x04    /* Floppy terminal count... ??? */
+#define AUXIO_FLPY_EJCT   0x02    /* Eject floppy disk. */
+#define AUXIO_LED         0x01    /* On if set, off if unset. */
+
+#define AUXREG ((volatile unsigned char *)(AUXIO_VADDR + 3))
+
+#define TURN_ON_LED  *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT | AUXIO_LED
+#define TURN_OFF_LED *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT
+#define FLIP_LED     *AUXREG = (*AUXREG | AUXIO_ORMEIN) ^ AUXIO_LED
+
+#endif /* !(_SPARC_AUXIO_H) */
index 241e5e8c1ec83c71680cd03af83865f9a48590c2..b785c25f0f05ac2c3632b746af8a16720c0c0123 100644 (file)
@@ -1,8 +1,11 @@
 #ifndef _SPARC_BITOPS_H
 #define _SPARC_BITOPS_H
 
+#include <linux/kernel.h>
+#include <asm/system.h>
+
 /*
- * Copyright 1994, David S. Miller (davem@caip.rutgers.edu).
+ * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
  */
 
 
  * for sun4m (ie. SMP) no doubt.
  */
 
-extern __inline__ unsigned int set_bit(unsigned int nr, void *addr)
+/* These routines now do things in little endian byte order. */
+
+/* Our unsigned long accesses on the Sparc look like this:
+ * Big Endian:
+ *    byte 0    byte 1      byte 2    byte 3
+ *  0000 0000  0000 0000  0000 0000  0000 0000
+ *  31     24  23     16  15      8  7       0
+ *
+ * We want to set the bits in a little-endian fashion:
+ * Little Endian:
+ *    byte 3    byte 2      byte 1    byte 0
+ *  0000 0000  0000 0000  0000 0000  0000 0000
+ *  31     24  23     16  15      8  7       0
+ */
+
+/* #define LITTLE_ENDIAN_BITOPS */
+
+extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
-
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"     /* produce the mask */
-                      "sll %3, %4, %3\n\t"
-                      "rd %%psr, %5\n\t"         /* read the psr */
-                      "wr %5, 0x20, %%psr\n\t"   /* traps disabled */
-                      "ld [%1], %2\n\t"          /* critical section */
-                      "and %3, %2, %0\n\t"
-                      "or  %3, %2, %2\n\t"
-                      "st  %2, [%1]\n\t"
-                      "wr %5, 0x0, %%psr\n\t" :  /* re-enable traps */
-                       "=r" (retval) :
-                       "r" (addr), "r" (tmp=0), "r" (mask=0),
-                       "r" (nr), "r" (psr=0));
-
-  return retval; /* confuse gcc :-) */
 
+
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+       unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 0x7);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr |= mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+        return retval;
+
+#else  /* BIG ENDIAN BITOPS */
+
+
+       int retval;
+       unsigned long *addr = vaddr;
+       unsigned long mask;
+#ifndef TEST_BITOPS
+       unsigned long flags;
+#endif
+
+       addr += nr>>5;
+       mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+       retval = (mask & *addr) != 0;
+       *addr |= mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+       return retval;
+
+
+#endif
 }
 
-extern __inline__ unsigned int clear_bit(unsigned int nr, void *addr)
+extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
-
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
-                      "sll %3, %4, %3\n\t"
-                      "rd %%psr, %5\n\t"
-                      "wr %5, 0x20, %%psr\n\t"   /* disable traps */
-                       "ld [%1], %2\n\t"
-                      "and %2, %3, %0\n\t"       /* get old bit */
-                      "andn %2, %3, %2\n\t"      /* set new val */
-                      "st  %2, [%1]\n\t"
-                      "wr %5, 0x0, %%psr\n\t" :  /* enable traps */
-                      "=r" (retval) :
-                      "r" (addr), "r" (tmp=0), "r" (mask=0),
-                      "r" (nr), "r" (psr=0));
-
-  return retval; /* confuse gcc ;-) */
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+       unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr &= ~mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+        return retval;
+
+
+#else   /* BIG ENDIAN BITOPS */
 
+
+       int retval;
+       unsigned long *addr = vaddr;
+       unsigned long mask;
+#ifndef TEST_BITOPS
+       unsigned long flags;
+#endif
+
+       addr += nr>>5;
+       mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+       retval = (mask & *addr) != 0;
+       *addr &= ~mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+       return retval;
+
+
+#endif
 }
 
-extern __inline__ unsigned int change_bit(unsigned int nr, void *addr)
+extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
-
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
-                      "sll %3, %4, %3\n\t"
-                      "rd %%psr, %5\n\t"
-                      "wr %5, 0x20, %%psr\n\t"   /* disable traps */
-                       "ld [%1], %2\n\t"
-                      "and %3, %2, %0\n\t"       /* get old bit val */
-                      "xor %3, %2, %2\n\t"       /* set new val */
-                      "st  %2, [%1]\n\t"
-                      "wr %5, 0x0, %%psr\n\t" :  /* enable traps */
-                      "=r" (retval) :
-                      "r" (addr), "r" (tmp=0), "r" (mask=0),
-                      "r" (nr), "r" (psr=0));
-
-  return retval; /* confuse gcc ;-) */
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+       unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr ^= mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+        return retval;
 
+
+#else   /* BIG ENDIAN BITOPS */
+
+
+       int retval;
+       unsigned long *addr = vaddr;
+       unsigned long mask;
+#ifndef TEST_BITOPS
+       unsigned long flags;
+#endif
+
+       addr += nr>>5;
+       mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+       save_flags(flags);
+       cli();
+#endif
+
+       retval = (mask & *addr) != 0;
+       *addr ^= mask;
+
+#ifndef TEST_BITOPS
+       restore_flags(flags);
+#endif
+
+       return retval;
+
+
+#endif
 }
 
 /* The following routine need not be atomic. */
 
-extern __inline__ unsigned int test_bit(int nr, void *addr)
+extern __inline__ unsigned int test_bit(int nr, void *vaddr)
 {
-  register unsigned long retval, tmp;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+        unsigned char mask;
+        unsigned char *addr = (unsigned char *)vaddr;
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+        return ((mask & *addr) != 0);
 
-  __asm__ __volatile__("ld [%1], %2\n\t"
-                      "or %%g0, 0x1, %0\n\t"
-                      "sll %0, %3, %0\n\t"
-                      "and %0, %2, %0\n\t" :
-                      "=r" (retval) :
-                      "r" (addr), "r" (tmp=0),
-                      "r" (nr));
+#else   /* BIG ENDIAN BITOPS */
 
-  return retval; /* confuse gcc :> */
+       unsigned long mask;
+       unsigned long *addr = vaddr;
 
+       addr += (nr>>5);
+       mask = 1 << (nr&31);
+       return ((mask & *addr) != 0);
+
+#endif
 }
 
 /* There has to be a faster way to do this, sigh... */
 
 extern __inline__ unsigned long ffz(unsigned long word)
 {
-  register unsigned long cnt, tmp, tmp2;
+  register unsigned long cnt;
 
   cnt = 0;
 
-  __asm__("or %%g0, %3, %2\n\t"
-         "1: and %2, 0x1, %1\n\t"
-         "srl %2, 0x1, %2\n\t"
-         "cmp %1, 0\n\t"
-         "bne,a 1b\n\t"
-         "add %0, 0x1, %0\n\t" :
-         "=r" (cnt) :
-         "r" (tmp=0), "r" (tmp2=0), "r" (word));
-
+#ifdef LITTLE_ENDIAN_BITOPS
+
+  for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8)
+         for(int bit = 0; bit<8; bit++)
+                 if((word>>(byte_bit+bit))&1)
+                         cnt++;
+                 else
+                         return cnt;
+
+#else /* BIT ENDIAN BITOPS */
+  while(cnt<32) {
+         if(!((word>>cnt)&1))
+                 return cnt;
+         else
+                 cnt++;
+  }
   return cnt;
+#endif
+
 }
 
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
@@ -123,42 +280,49 @@ extern __inline__ unsigned long ffz(unsigned long word)
  * on Linus's ALPHA routines, which are pretty portable BTW.
  */
 
-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 long *p = ((unsigned long *) addr) + (offset >> 6);
-  unsigned long result = offset & ~31UL;
-  unsigned long tmp;
-
-  if (offset >= size)
-    return size;
-  size -= result;
-  offset &= 31UL;
-  if (offset) 
-    {
-      tmp = *(p++);
-      tmp |= ~0UL >> (32-offset);
-      if (size < 32)
-       goto found_first;
-      if (~tmp)
-       goto found_middle;
-      size -= 32;
-      result += 32;
-    }
-  while (size & ~32UL) 
-    {
-      if (~(tmp = *(p++)))
-       goto found_middle;
-      result += 32;
-      size -= 32;
-    }
-  if (!size)
-    return result;
-  tmp = *p;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+       /* FOO, needs to be written */
+
+#else   /* BIG ENDIAN BITOPS */
+       unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+       unsigned long result = offset & ~31UL;
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) 
+       {
+               tmp = *(p++);
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size & ~32UL) 
+       {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
 
 found_first:
-  tmp |= ~0UL << size;
+       tmp |= ~0UL << size;
 found_middle:
-  return result + ffz(tmp);
+       return result + ffz(tmp);
+#endif
 }
 
 /* Linus sez that gcc can optimize the following correctly, we'll see if this
index 55f5434ad388655568f9a1b6c3282400a931426d..954a9f05fb53a054beef184264f1f17effbf9b3e 100644 (file)
@@ -13,9 +13,9 @@
 #define CONFIG_BUGSPARC
 
 #include <asm/openprom.h>
+#include <asm/page.h>
 
-extern struct linux_romvec *romvec;
-extern int tbase_needs_unmapping;   /* We do the bug workaround in pagetables.c */
+extern pgd_t swapper_pg_dir[16384];
 
 static void check_mmu(void)
 {
@@ -26,15 +26,16 @@ static void check_mmu(void)
   lvec = romvec;
 
   root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-  tbase_needs_unmapping=0;
 
   present = 0;
   (*(romvec->pv_nodeops->no_getprop))(root_node, "buserr-type", 
                                      (char *) &present);
   if(present == 1)
     {
-      tbase_needs_unmapping=1;
-      printk("MMU bug found: not allowing trapbase to be cached\n");
+      printk("MMU bug found: uncaching trap table\n");
+      for(present = (unsigned long) &trapbase; present < (unsigned long)
+         &swapper_pg_dir; present+=PAGE_SIZE)
+             put_pte(present, (get_pte(present) | PTE_NC));
     }
 
   return;
diff --git a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h
new file mode 100644 (file)
index 0000000..3f94478
--- /dev/null
@@ -0,0 +1,128 @@
+/* cache.h:  Cache specific code for the Sparc.  These include flushing
+ *           and direct tag/data line access.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_CACHE_H
+#define _SPARC_CACHE_H
+
+#include <asm/asi.h>
+
+/* Direct access to the instruction cache is provided through and
+ * alternate address space.  The IDC bit must be off in the ICCR on
+ * HyperSparcs for these accesses to work.  The code below does not do
+ * any checking, the caller must do so.  These routines are for
+ * diagnostics only, but coule end up being useful.  Use with care.
+ * Also, you are asking for trouble if you execute these in one of the
+ * three instructions following a %asr/%psr access or modification.
+ */
+
+/* First, cache-tag access. */
+extern inline unsigned int get_icache_tag(int setnum, int tagnum)
+{
+       unsigned int vaddr, retval;
+
+       vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5);
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (vaddr), "i" (ASI_M_TXTC_TAG));
+       return retval;
+}
+
+extern inline void put_icache_tag(int setnum, int tagnum, unsigned int entry)
+{
+       unsigned int vaddr;
+
+       vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5);
+       __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+                            "r" (entry), "r" (vaddr), "i" (ASI_M_TXTC_TAG) :
+                            "memory");
+       return;
+}
+
+/* Second cache-data access.  The data is returned two-32bit quantities
+ * at a time.
+ */
+extern inline void get_icache_data(int setnum, int tagnum, int subblock,
+                             unsigned int *data)
+{
+       unsigned int value1, value2, vaddr;
+
+       vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3);
+       __asm__ __volatile__("ldda [%2] %3, %%g2\n\t"
+                            "or %%g0, %%g2, %0\n\t"
+                            "or %%g0, %%g3, %1\n\t" :
+                            "=r" (value1), "=r" (value2) :
+                            "r" (vaddr), "i" (ASI_M_TXTC_DATA) :
+                            "g2", "g3");
+       data[0] = value1; data[1] = value2;
+       return;
+}
+
+extern inline void put_icache_data(int setnum, int tagnum, int subblock,
+                             unsigned int *data)
+{
+       unsigned int value1, value2, vaddr;
+
+       vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3);
+       value1 = data[0]; value2 = data[1];
+       __asm__ __volatile__("or %%g0, %0, %%g2\n\t"
+                            "or %%g0, %1, %%g3\n\t"
+                            "stda %%g2, [%2] %3\n\t" : :
+                            "r" (value1), "r" (value2), 
+                            "r" (vaddr), "i" (ASI_M_TXTC_DATA) :
+                            "g2", "g3", "memory" /* no joke */);
+       return;
+}
+
+/* Different types of flushes with the ICACHE.  Some of the flushes
+ * affect both the ICACHE and the external cache.  Others only clear
+ * the ICACHE entries on the cpu itself.  V8's (most) allow
+ * granularity of flushes on the packet (element in line), whole line,
+ * and entire cache (ie. all lines) level.  The ICACHE only flushes are
+ * ROSS HyperSparc specific and are in ross.h
+ */
+
+/* Flushes which clear out both the on-chip and external caches */
+extern inline void flush_ei_page(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_PAGE) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_ei_seg(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_SEG) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_ei_region(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_REGION) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_ei_ctx(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_CTX) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_ei_user(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_USER) :
+                            "memory");
+       return;
+}
+
+#endif /* !(_SPARC_CACHE_H) */
index ce5ce6762356187d296f33a32639b46fc1609456..fbcf9f367499240e0f64c1ea3f8a07a655018099 100644 (file)
@@ -1,53 +1,10 @@
-/* clock.h:  Definitions for the clock/timer chips on the Sparc.
+/* clock.h:  Definitions for clock operations on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
+#ifndef _SPARC_CLOCK_H
+#define _SPARC_CLOCK_H
 
-/* Clock timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one.  Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10.  There is another one available that can fire at
- * IRQ 14. If I can think of some creative uses for it this may
- * change. It might make a nice kernel/user profiler etc.
- */
-
-struct sparc_timer_info {
-  unsigned int cur_count10;
-  unsigned int timer_limit10;
-  unsigned int cur_count14;
-  unsigned int timer_limit14;
-};
-
-struct sparc_clock_info {
-  unsigned char hsec;
-  unsigned char hr;
-  unsigned char min;
-  unsigned char sec;
-  unsigned char mon;
-  unsigned char day;
-  unsigned char yr;
-  unsigned char wkday;
-  unsigned char ram_hsec;
-  unsigned char ram_hr;
-  unsigned char ram_min;
-  unsigned char ram_sec;
-  unsigned char ram_mon;
-  unsigned char ram_day;
-  unsigned char ram_year;
-  unsigned char ram_wkday;
-  unsigned char intr_reg;
-  unsigned char cmd_reg;
-  unsigned char foo[14];
-};
-
-#define TIMER_PHYSADDR   0xf3000000
-
-/* YUCK YUCK YUCK, grrr... */
-#define  TIMER_STRUCT  ((struct sparc_timer_info *)((struct sparc_clock_info *) TIMER_VADDR))
+/* Foo for now. */
 
+#endif /* !(_SPARC_CLOCK_H) */
index 326e888ff08754b4f069d6c09f8b84b9ad72092a..2f50fcb81e478e377569e3ad986c1ae9d9dc5e4b 100644 (file)
@@ -2,18 +2,48 @@
 #define _SPARC_CONTREGS_H
 
 /* contregs.h:  Addresses of registers in the ASI_CONTROL alternate address
-                space. These are for the mmu's context register, etc.
+ *              space. These are for the mmu's context register, etc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+/* 4 = sun4 (as in sun4 sysmaint student book), c = sun4c (according to davem) */
 
-#define AC_CONTEXT    0x30000000    /* current mmu-context, handy for invalidate()'s ;-)   */
-#define AC_SENABLE    0x40000000    /* system dvma/cache enable, plus special reset poking */
-#define AC_CACHETAGS  0x80000000    /* direct access to the VAC cache, unused...          */
-#define AC_SYNC_ERR   0x60000000    /* what type of synchronous memory error happened      */
-#define AC_SYNC_VA    0x60000004    /* what virtual address caused the error to occur      */
-#define AC_ASYNC_ERR  0x60000008    /* what type of asynchronous mem-error happened        */
-#define AC_ASYNC_VA   0x6000000c    /* what virtual address caused the async-err to happen */
-#define AC_CACHEDDATA 0x90000000    /* where the actual VAC cached data sits               */
+#define AC_IDPROM     0x00000000    /* 4  ID PROM, R/O, byte, 32 bytes                        */
+#define AC_CONTEXT    0x30000000    /* 4c current mmu-context, handy for invalidate()'s ;-)   */
+#define AC_SENABLE    0x40000000    /* 4c system dvma/cache enable, plus special reset poking */
+#define AC_UDVMA_ENB  0x50000000    /* 4  Not used on Sun boards, byte                        */
+#define AC_BUS_ERROR  0x60000000    /* 4  Cleared on read, byte. Probably same as sun4c.      */
+#define AC_SYNC_ERR   0x60000000    /*  c what type of synchronous memory error happened      */
+#define AC_SYNC_VA    0x60000004    /*  c what virtual address caused the error to occur      */
+#define AC_ASYNC_ERR  0x60000008    /*  c what type of asynchronous mem-error happened        */
+#define AC_ASYNC_VA   0x6000000c    /*  c what virtual address caused the async-err to happen */
+#define AC_LEDS       0x70000000    /* 4  Zero turns on LEDs, byte                            */
+#define AC_CACHETAGS  0x80000000    /* 4c direct access to the VAC cache, unused...           */
+#define AC_CACHEDDATA 0x90000000    /*  c where the actual VAC cached data sits               */
+#define AC_UDVMA_MAP  0xD0000000    /* 4  Not used on Sun boards, byte                        */
+#define AC_VME_VECTOR 0xE0000000    /* 4  For non-Autovector VME, byte                        */
+#define AC_BOOT_SCC   0xF0000000    /* 4  To bypass MMU and access Zilog 8530 on boot. byte.  */
+
+/* SPARCstation-5. I changed Paul's names to the hardware guy's ones. --P3 */
+#define AC_M_PCR      0x0000        /* 5  Processor Control Register */
+#define AC_M_CTPR     0x0100        /* 5  Context Table Pointer Register  */
+#define AC_M_CXR      0x0200        /* 5  Context Register */
+#define AC_M_SFSR     0x0300        /* 5  Synchronous Fault Status Register */
+#define AC_M_SFAR     0x0400        /* 5  Synchronous Fault Address Register */
+#define AC_M_AFSR     0x0500        /* 5  Asynchronous Fault Status Register */
+#define AC_M_AFAR     0x0600        /* 5  Asynchronous Fault Address Register */
+#define AC_M_RESET    0x0700        /* 5  Reset Register  Aieee! */
+#define AC_M_RPR      0x1000        /* 5  Root Pointer Register */
+#define AC_M_TSUTRCR  0x1000        /* 5  TLB Replacement Control Reg on Tsunami */
+#define AC_M_IAPTP    0x1100        /* 5  Instruction Access PTP */
+#define AC_M_DAPTP    0x1200        /* 5  Data Access PTP */
+#define AC_M_ITR      0x1300        /* 5  Index Tag Register */
+#define AC_M_TRCR     0x1400        /* 5  TLB Replacement Control Register */
+
+/* The following are Ross HyperSparc only. */
+#define AC_M_RPR1     0x1500        /* 5  Root Pointer Register (entry 2) */
+#define AC_M_IAPTP1   0x1600        /* 5  Instruction Access PTP (entry 2) */
+#define AC_M_DAPTP1   0x1700        /* 5  Data Access PTP (entry 2) */
 
 #endif /* _SPARC_CONTREGS_H */
diff --git a/include/asm-sparc/cypress.h b/include/asm-sparc/cypress.h
new file mode 100644 (file)
index 0000000..0481192
--- /dev/null
@@ -0,0 +1,51 @@
+/* cypress.h: Cypress module specific definitions and defines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_CYPRESS_H
+#define _SPARC_CYPRESS_H
+
+/* Cypress chips have %psr 'impl' of '0001' and 'vers' of '0001'. */
+
+/* The MMU control register fields on the Sparc Cypress 604/605 MMU's.
+ *
+ * ---------------------------------------------------------------
+ * |implvers| MCA | MCM |MV| MID |BM| C|RSV|MR|CM|CL|CE|RSV|NF|ME|
+ * ---------------------------------------------------------------
+ *  31    24 23-22 21-20 19 18-15 14 13  12 11 10  9  8 7-2  1  0
+ *
+ * MCA: MultiChip Access -- Used for configuration of multiple
+ *      CY7C604/605 cache units.
+ * MCM: MultiChip Mask -- Again, for multiple cache unit config.
+ * MV: MultiChip Valid -- Indicates MCM and MCA have valid settings.
+ * MID: ModuleID -- Unique processor ID for MBus transactions. (605 only)
+ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode
+ * C: Cacheable -- Indicates whether accesses are cacheable while
+ *    the MMU is off.  0=no 1=yes
+ * MR: MemoryReflection -- Indicates whether the bus attacted to the
+ *     MBus supports memory reflection. 0=no 1=yes (605 only)
+ * CM: CacheMode -- Indicates whether the cache is operating in write
+ *     through or copy-back mode. 0=write-through 1=copy-back
+ * CL: CacheLock -- Indicates if the entire cache is locked or not.
+ *     0=not-locked 1=locked  (604 only)
+ * CE: CacheEnable -- Is the virtual cache on? 0=no 1=yes
+ * NF: NoFault -- Do faults generate traps? 0=yes 1=no
+ * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes
+ */
+
+/* NEEDS TO BE FIXED */
+#define CYPRESS_MCABITS   0x01800000
+#define CYPRESS_MCMBITS   0x00600000
+#define CYPRESS_MVALID    0x00040000
+#define CYPRESS_MIDMASK   0x0003c000   /* Only on 605 */
+#define CYPRESS_BMODE     0x00002000
+#define CYPRESS_ACENABLE  0x00001000
+#define CYPRESS_MRFLCT    0x00000800   /* Only on 605 */
+#define CYPRESS_CMODE     0x00000400
+#define CYPRESS_CLOCK     0x00000200   /* Only on 604 */
+#define CYPRESS_CENABLE   0x00000100
+#define CYPRESS_NFAULT    0x00000002
+#define CYPRESS_MENABLE   0x00000001
+
+#endif /* !(_SPARC_CYPRESS_H) */
index d6c4b360e205dc94db202555e22e2256f33754e5..74caed5a79f63a35837cd19f6de18cf31e6ae608 100644 (file)
@@ -23,10 +23,8 @@ extern __inline__ void udelay(unsigned int usecs)
 {
   usecs *= 0x000010c6;         /* Sparc is 32-bit just like ix86 */
 
-  __asm__("sethi %hi(_loops_per_sec), %o1\n\t"
-         "ld [%o1 + %lo(_loops_per_sec)], %o1\n\t"
-         "call ___delay\n\t"
-         "umul %o1, %o0, %o0\n\t");
+  __delay(loops_per_sec*usecs);
+
 }
 
 /* calibrate_delay() wants this... */
index 138e7a445b16396af41ee9f53e4733e36f9e1453..f8db8280451efde67ed1fb4f55e9251bb3efb8a7 100644 (file)
  * on the Sparc. It may end up being real hairy to plug
  * into this code, maybe not, we'll see.
  *
- * Copyright (C) David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
  */
 
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
 #include <asm/vac-ops.h>  /* for invalidate's, etc. */
+#include <asm/sbus.h>
+#include <asm/delay.h>
+#include <asm/oplib.h>
+
+/* DMA probing routine */
+extern unsigned long probe_dma(unsigned long);
 
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
 #define MAX_DMA_CHANNELS 8
 #define MAX_DMA_ADDRESS  0x0
 
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  volatile unsigned long cond_reg;   /* DMA condition register */
+  volatile char * st_addr;           /* Start address of this transfer */
+  volatile unsigned long cnt;        /* How many bytes to transfer */
+  volatile unsigned long dma_test;   /* DMA test register */
+};
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+  struct linux_sbus_device *SBus_dev;   /* pointer to sbus device struct */
+  struct sparc_dma_registers *DMA_regs; /* Pointer to DMA regs in IO space */
+
+  /* Status, misc info */
+  int node;                /* Prom node for this DMA device */
+  int dma_running;         /* Are we using the DMA now? */
+
+  /* DMA revision: 0=REV0 1=REV1 2=REV2 3=DMA_PLUS */
+  int dma_rev;
+};
+
+extern struct Linux_SBus_DMA Sparc_DMA;
+
+/* Main routines in dma.c */
+extern void dump_dma_regs(struct sparc_dma_registers *);
+extern unsigned long probe_dma(unsigned long);
+extern void sparc_dma_init_transfer(struct sparc_dma_registers *,
+                                   unsigned long, int, int);
+extern int sparc_dma_interrupt(struct sparc_dma_registers *);
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An interrupt needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take care of an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_ST_WRITE     0x00000100        /* If set, write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Read is pending */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_BRST_SZ      0x000c0000        /* SBUS transfer r/w burst size */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer equals 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer equals 3 clock ticks */
+#define DMA_CNTR_DISAB   0x00800000        /* No intr's when DMA_TERM_CNTR is set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto next address" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Only 24-bits of the byte count are significant */
+#define DMA_BYTE_CNT_MASK  0x00ffffff
+
+/* Pause until counter runs out or BIT isn't set in the DMA condition
+ * register.
+ */
+extern inline void sparc_dma_pause(struct sparc_dma_registers *dma_regs,
+                                  unsigned long bit)
+{
+  int ctr = 50000;   /* Let's find some bugs ;) */
+
+  /* Busy wait until the bit is not set any more */
+  while((dma_regs->cond_reg&bit) && (ctr>0)) {
+    ctr--;
+    __delay(1);
+  }
+
+  /* Check for bogus outcome. */
+  if(ctr==0) {
+    printk("DMA Grrr:  I tried for wait for the assertion of bit %08xl to clear",
+          (unsigned int) bit);
+    printk("           in the DMA condition register and it did not!\n");
+    printk("Cannot continue, halting...\n");
+    prom_halt();
+  }
+
+  return;
+}
+
+/* Enable DMA interrupts */
+extern inline void sparc_dma_enable_interrupts(struct sparc_dma_registers *dma_regs)
+{
+  dma_regs->cond_reg |= DMA_INT_ENAB;
+}
+
+/* Disable DMA interrupts from coming in */
+extern inline void sparc_dma_disable_interrupts(struct sparc_dma_registers *dma_regs)
+{
+  dma_regs->cond_reg &= ~(DMA_INT_ENAB);
+}
+
+/* Reset the DMA module. */
+extern inline void sparc_dma_reset(struct sparc_dma_registers *dma_regs)
+{
+  /* Let the current FIFO drain itself */
+  sparc_dma_pause(dma_regs, (DMA_FIFO_ISDRAIN));
+
+  /* Reset the logic */
+  dma_regs->cond_reg |= (DMA_RST_SCSI);     /* assert */
+  __delay(400);                             /* let the bits set ;) */
+  dma_regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */
+
+  sparc_dma_enable_interrupts(dma_regs);    /* Re-enable interrupts */
+
+  /* Enable FAST transfers if available */
+  if(Sparc_DMA.dma_rev>1) { dma_regs->cond_reg |= DMA_3CLKS; }
+  Sparc_DMA.dma_running = 0;
 
+  return;
+}
 
 #endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/include/asm-sparc/ecc.h b/include/asm-sparc/ecc.h
new file mode 100644 (file)
index 0000000..3e140fb
--- /dev/null
@@ -0,0 +1,121 @@
+/* ecc.h: Definitions and defines for the external cache/memory
+ *        controller on the sun4m.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ECC_H
+#define _SPARC_ECC_H
+
+/* These registers are accessed through the SRMMU passthrough ASI 0x20 */
+#define ECC_ENABLE     0x00000000       /* ECC enable register */
+#define ECC_FSTATUS    0x00000008       /* ECC fault status register */
+#define ECC_FADDR      0x00000010       /* ECC fault address register */
+#define ECC_DIGNOSTIC  0x00000018       /* ECC diagnostics register */
+#define ECC_MBAENAB    0x00000020       /* MBus arbiter enable register */
+#define ECC_DMESG      0x00001000       /* Diagnostic message passing area */
+
+/* ECC MBus Arbiter Enable register:
+ *
+ * ----------------------------------------
+ * |              |SBUS|MOD3|MOD2|MOD1|RSV|
+ * ----------------------------------------
+ *  31           5   4   3    2    1    0
+ *
+ * SBUS: Enable MBus Arbiter on the SBus 0=off 1=on
+ * MOD3: Enable MBus Arbiter on MBus module 3  0=off 1=on
+ * MOD2: Enable MBus Arbiter on MBus module 2  0=off 1=on
+ * MOD1: Enable MBus Arbiter on MBus module 1  0=off 1=on
+ */
+
+#define ECC_MBAE_SBUS     0x00000010
+#define ECC_MBAE_MOD3     0x00000008
+#define ECC_MBAE_MOD2     0x00000004
+#define ECC_MBAE_MOD1     0x00000002 
+
+/* ECC Fault Control Register layout:
+ *
+ * -----------------------------
+ * |    RESV   | ECHECK | EINT |
+ * -----------------------------
+ *  31        2     1       0
+ *
+ * ECHECK:  Enable ECC checking.  0=off 1=on
+ * EINT:  Enable Interrupts for correctable errors. 0=off 1=on
+ */ 
+#define ECC_FCR_CHECK    0x00000002
+#define ECC_FCR_INTENAB  0x00000001
+
+/* ECC Fault Address Register Zero layout:
+ *
+ * -----------------------------------------------------
+ * | MID | S | RSV |  VA   | BM |AT| C| SZ |TYP| PADDR |
+ * -----------------------------------------------------
+ *  31-28  27 26-22  21-14   13  12 11 10-8 7-4   3-0
+ *
+ * MID: ModuleID of the faulting processor. ie. who did it?
+ * S: Supervisor/Privileged access? 0=no 1=yes
+ * VA: Bits 19-12 of the virtual faulting address, these are the
+ *     superset bits in the virtual cache and can be used for
+ *     a flush operation if necessary.
+ * BM: Boot mode? 0=no 1=yes  This is just like the SRMMU boot
+ *     mode bit.
+ * AT: Did this fault happen during an atomic instruction? 0=no
+ *     1=yes.  This means either an 'ldstub' or 'swap' instruction
+ *     was in progress (but not finished) when this fault happened.
+ *     This indicated whether the bus was locked when the fault
+ *     occurred.
+ * C: Did the pte for this access indicate that it was cacheable?
+ *    0=no 1=yes
+ * SZ: The size of the transaction.
+ * TYP: The transaction type.
+ * PADDR: Bits 35-32 of the physical address for the fault.
+ */
+#define ECC_FADDR0_MIDMASK   0xf0000000
+#define ECC_FADDR0_S         0x08000000
+#define ECC_FADDR0_VADDR     0x003fc000
+#define ECC_FADDR0_BMODE     0x00002000
+#define ECC_FADDR0_ATOMIC    0x00001000
+#define ECC_FADDR0_CACHE     0x00000800
+#define ECC_FADDR0_SIZE      0x00000700
+#define ECC_FADDR0_TYPE      0x000000f0
+#define ECC_FADDR0_PADDR     0x0000000f
+
+/* ECC Fault Address Register One layout:
+ *
+ * -------------------------------------
+ * |          Physical Address 31-0    |
+ * -------------------------------------
+ *  31                               0
+ *
+ * You get the upper 4 bits of the physical address from the
+ * PADDR field in ECC Fault Address Zero register.
+ */
+
+/* ECC Fault Status Register layout:
+ *
+ * ----------------------------------------------
+ * | RESV|C2E|MULT|SYNDROME|DWORD|UNC|TIMEO|BS|C|
+ * ----------------------------------------------
+ *  31-18  17  16    15-8    7-4   3    2    1 0
+ *
+ * C2E: A C2 graphics error occurred. 0=no 1=yes (SS10 only)
+ * MULT: Multiple errors occurres ;-O 0=no 1=prom_panic(yes)
+ * SYNDROME: Controller is mentally unstable.
+ * DWORD:
+ * UNC: Uncorrectable error.  0=no 1=yes
+ * TIMEO: Timeout occurred. 0=no 1=yes
+ * BS: C2 graphics bad slot access. 0=no 1=yes (SS10 only)
+ * C: Correctable error? 0=no 1=yes
+ */
+
+#define ECC_FSR_C2ERR    0x00020000
+#define ECC_FSR_MULT     0x00010000
+#define ECC_FSR_SYND     0x0000ff00
+#define ECC_FSR_DWORD    0x000000f0
+#define ECC_FSR_UNC      0x00000008
+#define ECC_FSR_TIMEO    0x00000004
+#define ECC_FSR_BADSLOT  0x00000002
+#define ECC_FSR_C        0x00000001
+
+#endif /* !(_SPARC_ECC_H) */
diff --git a/include/asm-sparc/eeprom.h b/include/asm-sparc/eeprom.h
new file mode 100644 (file)
index 0000000..4f9638f
--- /dev/null
@@ -0,0 +1,8 @@
+/* eeprom.h:  Definitions for the Sun eeprom.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* The EEPROM and the Mostek Mk48t02 use the same IO address space
+ * for their registers/data areas.  The IDPROM lives here too.
+ */
index b26067623fd2c8a348da3fdbd01ec49a8fd18103..49ee8ffa6fed0f051cdb27d8748fc51add82c182 100644 (file)
@@ -1,61 +1,75 @@
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
-#define KERNSIZE       134217728   /* this is how much of a mapping the prom promises */
-#define PAGESIZE       4096        /* luckily this is the same on sun4c's and sun4m's */
-#define PAGESHIFT       12
-#define PROM_BASE      -1568768    /* casa 'de PROM */
-#define LOAD_ADDR       0x4000      /* prom jumps to us here */
+#define KERNBASE        0xf0000000  /* First address the kernel will eventually be */
+#define LOAD_ADDR       0x4000      /* prom jumps to us here unless this is elf /boot */
 #define C_STACK         96
 #define SUN4C_SEGSZ     (1 << 18)
-#define USRSTACK        0x0         /* no joke, this is temporary, trust me */
-#define INT_ENABLE_REG_PHYSADR      0xf5000000
-#define INTS_ENAB   0x01
+#define SRMMU_L1_KBASE_OFFSET ((KERNBASE>>24)<<2)  /* Used in boot remapping. */
+#define INTS_ENAB   0x01            /* entry.S uses this. */
 
-#define BOOT_MSG_LEN    61
-#define BOOT_MSG2_LEN   50
+#define NCPUS           4            /* Architectual limit of sun4m. */
 
+#define  SUN4_PROM_VECTOR   0xFFE81000    /* To safely die on a SUN4 */
+#define  SUN4_PRINTF   0x84               /* Offset into SUN4_PROM_VECTOR */
 
 #define WRITE_PAUSE     nop; nop; nop;
 
-#define PAGE_SIZE       4096
+#define NOP_INSN        0x01000000        /* Used to patch sparc_save_state */
 
 /* Here are some trap goodies */
 
-
 /* Generic trap entry. */
-
 #define TRAP_ENTRY(type, label) \
        mov (type), %l3; b label; rd %psr, %l0; nop;
 
+/* Notice that for the system calls we pull a trick.  We load up a
+ * different pointer to the system call vector table in %l7, but call
+ * the same generic system call low-level entry point.  The trap table
+ * entry sequences are also HyperSparc pipeline friendly ;-)
+ */
+
+/* Software trap for Linux system calls. */
+#define LINUX_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for SunOS4.1.x system calls. */
+#define SUNOS_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for Slowaris system calls. */
+#define SOLARIS_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for Sparc-netbsd system calls. */
+#define NETBSD_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* The Get Condition Codes software trap for userland. */
+#define GETCC_TRAP \
+        b getcc_trap_handler; mov %psr, %l0; nop; nop
+
+/* The Set Condition Codes software trap for userland. */
+#define SETCC_TRAP \
+        b setcc_trap_handler; mov %psr, %l0; nop; nop
+
 /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and
  * gets handled with another macro.
  */
-
 #define TRAP_ENTRY_INTERRUPT(int_level) \
-        mov int_level, %l3; b stray_irq_entry; rd %psr, %l0; nop;
+        mov int_level, %l3; b real_irq_entry; rd %psr, %l0; nop;
 
-/* Here is the macro for soft interrupts (ie. not as urgent as hard ones)
- * which need to jump to a different handler.
+/* NMI's (Non Maskable Interrupts) are special, you can't keep them
+ * from coming in, and basically if you get one, the shows over. ;(
  */
-
-#define TRAP_ENTRY_INTERRUPT_SOFT(int_level, ident) \
-        mov int_level, %l3; rd %psr, %l0; b stray_irq_entry; mov ident, %l4;
+#define NMI_TRAP \
+        b linux_trap_nmi; mov %psr, %l0; nop; nop
 
 /* The above two macros are for generic traps. The following is made
  * especially for timer interrupts at IRQ level 14.
  */
-
 #define TRAP_ENTRY_TIMER \
-        mov 10, %l3; rd %psr, %l0; b sparc_timer; nop;
-
-/* Non-maskable interrupt entry macro. You have to turn off all interrupts
- * to not receive this. This is usually due to a asynchronous memory error.
- * All we can really do is stop the show. :-(
- */
-
-#define TRAP_ENTRY_INTERRUPT_NMI(t_type, jmp_to) \
-        mov t_type, %l3; b jmp_to; rd %psr, %l0; nop;
+        rd %psr, %l0; b sparc_timer; nop; nop;
 
 /* Trap entry code in entry.S needs the offsets into task_struct
  * to get at the thread_struct goodies during window craziness.
  *       See TRAP_WIN_CLEAN in entry.S for details.
  */
 
-#define THREAD_UWINDOWS 0x3bc
-#define THREAD_WIM 0x3c0
-#define THREAD_W_SAVED 0x3c4
-#define THREAD_KSP 0x3c8
-#define THREAD_USP 0x3cc
-#define THREAD_REG_WINDOW 0x3d4
+/* First generic task_struct offsets */
+#define TASK_STATE        0x000
+#define TASK_PRI          0x008
+#define TASK_KSTACK_PG    0x250
+
+#define THREAD_UWINDOWS   0x3b8
+#define THREAD_WIM        0x3bc
+#define THREAD_W_SAVED    0x3c0
+#define THREAD_KSP        0x3c4
+#define THREAD_USP        0x3c8
+#define THREAD_PSR        0x3cc
+#define THREAD_PC         0x3d0
+#define THREAD_NPC        0x3d4
+#define THREAD_Y          0x3d8
+#define THREAD_REG_WINDOW 0x3e0
+
+/* More fun offset macros. These are for pt_regs. */
+
+#define PT_PSR    0x0
+#define PT_PC     0x4
+#define PT_NPC    0x8
+#define PT_Y      0xc
+#define PT_G0     0x10
+#define PT_G1     0x14
+#define PT_G2     0x18
+#define PT_G3     0x1c
+#define PT_G4     0x20
+#define PT_G5     0x24
+#define PT_G6     0x28
+#define PT_G7     0x2c
+#define PT_I0     0x30
+#define PT_I1     0x34
+#define PT_I2     0x38
+#define PT_I3     0x3c
+#define PT_I4     0x40
+#define PT_I5     0x44
+#define PT_I6     0x48
+#define PT_I7     0x4c
 
 #endif __SPARC_HEAD_H
index e7a1368912dd33e3eb71c30c3280b3edb3504848..822418610daf4674576fd64c6d7b6152477f7691 100644 (file)
@@ -3,10 +3,17 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#ifndef _SPARC_IDPROM_H
+#define _SPARC_IDPROM_H
+
 extern struct linux_romvec *romvec;
 
-#define IDPROM_ADDR  (0xffd04000 + 0x7d8)
-#define IDPROM_SIZE  36
+/* Offset into the EEPROM where the id PROM is located on the 4c */
+#define IDPROM_OFFSET  0x7d8
+
+/* On sun4m; physical. */
+/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
+#define IDPROM_OFFSET_M  0xfd8
 
 struct idp_struct
 {
@@ -19,3 +26,8 @@ struct idp_struct
   unsigned char dummy[16];    /* XXX */
 };
 
+extern struct idp_struct *idprom;
+
+#define IDPROM_SIZE  (sizeof(struct idp_struct))
+
+#endif /* !(_SPARC_IDPROM_H) */
index 5aa1a3fac8cb6dfbf05f7579da8caa609b104480..7a1ca117d6d6586845cdf41f1213aa91d805c720 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
+#include <linux/kernel.h>
+
 #include <asm/page.h>      /* IO address mapping routines need this */
+#include <asm/system.h>
 
 /*
  * Defines for io operations on the Sparc. Whether a memory access is going
@@ -86,15 +89,31 @@ extern inline void writel(unsigned int b, unsigned long addr)
 #define inb_p inb
 #define outb_p outb
 
-extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr)
-{
-  unsigned long page_entry;
-
-  page_entry = physaddr >> PAGE_SHIFT;
-  page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO);  /* kernel io addr */
+extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
+extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
 
-  put_pte(virt_addr, page_entry);
-  return;
+extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+                            int bus, int rdonly)
+{
+       switch(sparc_cpu_model) {
+       case sun4c:
+               sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly);
+               break;
+       case sun4m:
+       case sun4d:
+       case sun4e:
+               srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly);
+               break;
+       default:
+               printk("mapioaddr: Trying to map IO space for unsupported machine.\n");
+               printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model);
+               printk("mapioaddr: Halting...\n");
+               halt();
+       };
+       return;
 }
 
+extern void *sparc_alloc_io (void *, void *, int, char *, int, int);
+extern void *sparc_dvma_malloc (int, char *);
+
 #endif /* !(__SPARC_IO_H) */
diff --git a/include/asm-sparc/ipsum.h b/include/asm-sparc/ipsum.h
new file mode 100644 (file)
index 0000000..92b203e
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __SPARC_IPSUM_H
+#define __SPARC_IPSUM_H
+/*  ipsum.h:  IP/UDP/TCP checksum routines on the Sparc.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ *      This routine computes a UDP checksum. 
+ */
+extern inline unsigned short udp_check(struct udphdr *uh, int len, u32 saddr, u32 daddr)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+/*
+ *      This routine computes a TCP checksum. 
+ */
+extern inline unsigned short tcp_check(struct tcphdr *th, int len, u32 saddr, u32 daddr)
+{     
+        /* uhh.. eventually */
+        return 0;
+}
+
+
+/*
+ * This routine does all the checksum computations that don't
+ * require anything special (like copying or special headers).
+ */
+
+extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+/*
+ *      This is a version of ip_compute_csum() optimized for IP headers, which
+ *      always checksum on 4 octet boundaries.
+ */
+
+static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+#endif /* !(__SPARC_IPSUM_H) */
index 0e96ffb8c8f1e132a75e1ec7d5df7c6edfd5c82f..2f1903eeb45abdce94913968323a8a27e820b0ab 100644 (file)
@@ -4,14 +4,70 @@
 /*
  *     linux/include/asm-sparc/irq.h
  *
- *     Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ *     Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/linkage.h>
 
+#include <asm/system.h>     /* For NCPUS */
+
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+/* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+ */
+
+/* These registers are used for sending/receiving irqs from/to
+ * different cpu's.   
+ */
+struct sun4m_intreg_percpu {
+       unsigned int tbt;        /* Interrupts still pending for this cpu. */
+
+       /* These next two registers are WRITE-ONLY and are only
+        * "on bit" sensitive, "off bits" written have NO affect.
+        */
+       unsigned int clear;  /* Clear this cpus irqs here. */
+       unsigned int set;    /* Set this cpus irqs here. */
+       unsigned char space[PAGE_SIZE - 12];
+};
+
+struct sun4m_intregs {
+       struct sun4m_intreg_percpu cpu_intregs[NCPUS];
+       unsigned int tbt;                /* IRQ's that are still pending. */
+       unsigned int irqs;               /* Master IRQ bits. */
+
+       /* Again, like the above, two these registers are WRITE-ONLY. */
+       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
+       unsigned int set;                /* Set master IRQ's by setting bits here. */
+
+       /* This register is both READ and WRITE. */
+       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+};
+
+extern struct sun4m_intregs *sun4m_interrupts;
+
+/* Bit field defines for the interrupt registers on various
+ * Sparc machines.
+ */
+
+/* The sun4c interrupt register. */
+#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
+#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
+#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
+#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
+#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
+#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
+#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
+
+/* The sun4m interrupt registers.  MUST RESEARCH THESE SOME MORE XXX */
+#define SUN4M_INT_ENABLE  0x80000000
+#define SUN4M_INT_E14     0x00000080
+#define SUN4M_INT_E10     0x00080000
+
+#if 0 /* These aren't used on the Sparc (yet), but kept for
+       * future reference, they could come in handy.
+       */
 #define __STR(x) #x
 #define STR(x) __STR(x)
  
@@ -39,5 +95,6 @@ asmlinkage void IRQ_NAME(nr); \
 asmlinkage void FAST_IRQ_NAME(nr); \
 asmlinkage void BAD_IRQ_NAME(nr); \
 asm code comes here
+#endif
 
 #endif
diff --git a/include/asm-sparc/kdebug.h b/include/asm-sparc/kdebug.h
new file mode 100644 (file)
index 0000000..d4fa50f
--- /dev/null
@@ -0,0 +1,75 @@
+/* kdebug.h:  Defines and definitions for debugging the Linux kernel
+ *            under various kernel debuggers.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_KDEBUG_H
+#define _SPARC_KDEBUG_H
+
+#include <asm/openprom.h>
+
+/* The debugger lives in 1MB of virtual address space right underneath
+ * the boot prom.
+ */
+
+#define DEBUG_FIRSTVADDR       0xffc00000
+#define DEBUG_LASTVADDR       LINUX_OPPROM_BEGVM
+
+/* Breakpoints are enter through trap table entry 126.  So in sparc assembly
+ * if you want to drop into the debugger you do:
+ *
+ * t DEBUG_BP_TRAP
+ */
+
+#define DEBUG_BP_TRAP     126
+
+#ifndef __ASSEMBLY__
+/* The debug vector is passed in %o1 at boot time.  It is a pointer to
+ * a structure in the debuggers address space.  Here is it's format.
+ */
+
+typedef unsigned int (*debugger_funct)(void);
+
+struct kernel_debug {
+       /* First the entry point into the debugger.  You jump here
+        * to give control over to the debugger.
+        */
+       unsigned long kdebug_entry;
+       unsigned long kdebug_trapme;   /* Figure out later... */
+       /* The following is the number of pages that the debugger has
+        * taken from to total pool.
+        */
+       unsigned long *kdebug_stolen_pages;
+       /* Ok, after you remap yourself and/or change the trap table
+        * from what you were left with at boot time you have to call
+        * this synchronization function so the debugger can check out
+        * what you have done.
+        */
+       debugger_funct teach_debugger;
+}; /* I think that is it... */
+
+extern struct kernel_debug *linux_dbvec;
+
+/* Use this macro in C-code to enter the debugger. */
+extern __inline__ void sp_enter_debugger(void)
+{
+       printk("Entering debugger in file %s line %d\n", __FILE__, __LINE__);
+       __asm__ __volatile__("jmpl %0, %%o7\n\t"
+                            "nop\n\t" : :
+                            "r" (linux_dbvec) : "o7", "memory");
+}
+
+#define SP_ENTER_DEBUGGER do { \
+            if((linux_dbvec!=0) && ((*(short *)linux_dbvec)!=-1)) \
+              sp_enter_debugger(); \
+                      } while(0)
+
+#endif /* !(__ASSEMBLY__) */
+
+/* Some nice offset defines for assembler code. */
+#define KDEBUG_ENTRY_OFF    0x0
+#define KDEBUG_DUNNO_OFF    0x4
+#define KDEBUG_DUNNO2_OFF   0x8
+#define KDEBUG_TEACH_OFF    0xc
+
+#endif /* !(_SPARC_KDEBUG_H) */
diff --git a/include/asm-sparc/machines.h b/include/asm-sparc/machines.h
new file mode 100644 (file)
index 0000000..fc7cb08
--- /dev/null
@@ -0,0 +1,68 @@
+/* machines.h:  Defines for taking apart the machine type value in the
+ *              idprom and determining the kind of machine we are on.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MACHINES_H
+#define _SPARC_MACHINES_H
+
+struct Sun_Machine_Models {
+       char *name;
+       unsigned char id_machtype;
+};
+
+/* Current number of machines we know about that has an IDPROM
+ * machtype entry including one entry for the 0x80 OBP machines.
+ */
+#define NUM_SUN_MACHINES   15
+
+extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
+
+/* The machine type in the idprom area looks like this:
+ *
+ * ---------------
+ * | ARCH | MACH |
+ * ---------------
+ *  7    4 3    0
+ *
+ * The ARCH field determines the architecture line (sun4, sun4c, etc).
+ * The MACH field determines the machine make within that architecture.
+ */
+
+#define SM_ARCH_MASK  0xf0
+#define SM_SUN4       0x20
+#define SM_SUN4C      0x50
+#define SM_SUN4M      0x70
+#define SM_SUN4M_OBP  0x80
+
+#define SM_TYP_MASK   0x0f
+/* Sun4 machines */
+#define SM_4_260      0x01    /* Sun 4/200 series */
+#define SM_4_110      0x02    /* Sun 4/100 series */
+#define SM_4_330      0x03    /* Sun 4/300 series */
+#define SM_4_470      0x04    /* Sun 4/400 series */
+
+/* Sun4c machines                Full Name              - PROM NAME */
+#define SM_4C_SS1     0x01    /* Sun4c SparcStation 1   - Sun 4/60  */
+#define SM_4C_IPC     0x02    /* Sun4c SparcStation IPC - Sun 4/40  */
+#define SM_4C_SS1PLUS 0x03    /* Sun4c SparcStation 1+  - Sun 4/65  */
+#define SM_4C_SLC     0x04    /* Sun4c SparcStation SLC - Sun 4/20  */
+#define SM_4C_SS2     0x05    /* Sun4c SparcStation 2   - Sun 4/75  */
+#define SM_4C_ELC     0x06    /* Sun4c SparcStation ELC - Sun 4/25  */
+#define SM_4C_IPX     0x07    /* Sun4c SparcStation IPX - Sun 4/50  */
+
+/* Sun4m machines, these predate the OpenBoot.  These values only mean
+ * something if the value in the ARCH field is SM_SUN4M, if it is
+ * SM_SUN4M_OBP then you have the following situation:
+ * 1) You either have a sun4d, a sun4e, or a recently made sun4m.
+ * 2) You have to consult OpenBoot to determine which machine this is.
+ */
+#define SM_4M_SS60    0x01    /* Sun4m SparcSystem 600                  */
+#define SM_4M_SS50    0x02    /* Sun4m SparcStation 10                  */
+#define SM_4M_SS40    0x03    /* Sun4m SparcStation 5                   */
+
+/* Sun4d machines -- N/A */
+/* Sun4e machines -- N/A */
+/* Sun4u machines -- N/A */
+
+#endif /* !(_SPARC_MACHINES_H) */
diff --git a/include/asm-sparc/mbus.h b/include/asm-sparc/mbus.h
new file mode 100644 (file)
index 0000000..087329c
--- /dev/null
@@ -0,0 +1,99 @@
+/* mbus.h:  Various defines for MBUS modules.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MBUS_H
+#define _SPARC_MBUS_H
+
+#include <asm/ross.h>    /* HyperSparc stuff */
+#include <asm/cypress.h> /* Cypress Chips */
+#include <asm/viking.h>  /* Ugh, bug city... */
+
+enum mbus_module {
+       HyperSparc        = 0,
+       Cypress           = 1,
+       Cypress_vE        = 2,
+       Cypress_vD        = 3,
+       Swift_ok          = 4,
+       Swift_bad_c       = 5,
+       Swift_lots_o_bugs = 6,
+       Tsunami           = 7,
+       Viking_12         = 8,
+       Viking_2x         = 9,
+       Viking_30         = 10,
+       Viking_35         = 11,
+       Viking_new        = 12,
+       SRMMU_INVAL_MOD   = 13,
+};
+
+extern enum mbus_module srmmu_modtype;
+extern unsigned int viking_rev, swift_rev, cypress_rev;
+
+/* HW Mbus module bugs we have to deal with */
+#define HWBUG_COPYBACK_BROKEN        0x00000001
+#define HWBUG_ASIFLUSH_BROKEN        0x00000002
+#define HWBUG_VACFLUSH_BITROT        0x00000004
+#define HWBUG_KERN_ACCBROKEN         0x00000008
+#define HWBUG_KERN_CBITBROKEN        0x00000010
+#define HWBUG_MODIFIED_BITROT        0x00000020
+#define HWBUG_PC_BADFAULT_ADDR       0x00000040
+#define HWBUG_SUPERSCALAR_BAD        0x00000080
+#define HWBUG_PACINIT_BITROT         0x00000100
+
+extern unsigned int hwbug_bitmask;
+
+/* First the module type values. To find out which you have, just load
+ * the mmu control register from ASI_M_MMUREG alternate adress space and
+ * shift the value right 28 bits.
+ */
+/* IMPL field means the company which produced the chip. */
+#define MBUS_VIKING        0x4   /* bleech, Texas Instruments Module */
+#define MBUS_LSI           0x3   /* LSI Logics */
+#define MBUS_ROSS          0x1   /* Ross is nice */
+#define MBUS_FMI           0x0   /* Fujitsu Microelectronics/Swift */
+
+/* Ross Module versions */
+#define ROSS_604_REV_CDE        0x0   /* revisions c, d, and e */
+#define ROSS_604_REV_F          0x1   /* revision f */
+#define ROSS_605                0xf   /* revision a, a.1, and a.2 */
+#define ROSS_605_REV_B          0xe   /* revision b */
+
+/* TI Viking Module versions */
+#define VIKING_REV_12           0x1   /* Version 1.2 or SPARCclassic's CPU */
+#define VIKING_REV_2            0x2   /* Version 2.1, 2.2, 2.3, and 2.4 */
+#define VIKING_REV_30           0x3   /* Version 3.0 */
+#define VIKING_REV_35           0x4   /* Version 3.5 */
+
+/* LSI Logics. */
+#define LSI_L64815             0x0
+
+/* Fujitsu */
+#define FMI_AURORA             0x4   /* MB8690x, a Swift module... */
+
+/* For multiprocessor support we need to be able to obtain the CPU id and
+ * the MBUS Module id.
+ */
+
+/* The CPU ID is encoded in the trap base register, 20 bits to the left of
+ * bit zero, with 2 bits being significant.
+ */
+#define TBR_ID_SHIFT            0x20
+
+extern inline int get_cpuid(void)
+{
+       register int retval;
+       __asm__ __volatile__("rd %%tbr, %0\n\t"
+                            "srl %0, %1, %0\n\t" :
+                            "=r" (retval) :
+                            "i" (TBR_ID_SHIFT));
+       return (retval & 3);
+}
+
+extern inline int get_modid(void)
+{
+       return (get_cpuid() | 0x8);
+}
+
+       
+#endif /* !(_SPARC_MBUS_H) */
index cd0ca32640d9714fb39df05bd8c9190c71cfc718..cbb8ec55bcf98c3c808d597be8221439ac58e70e 100644 (file)
@@ -2,11 +2,11 @@
 #define _SPARC_MEMERR_H
 
 /* memerr.h:  Bit fields in the asynchronous and synchronous memory error
             registers used to determine what 'type' of error has just
            induced a trap.
-
  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
*            registers used to determine what 'type' of error has just
*           induced a trap.
+ *
* Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 /* synchronous error register fields come first... */
 
diff --git a/include/asm-sparc/memreg.h b/include/asm-sparc/memreg.h
new file mode 100644 (file)
index 0000000..4642067
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _SPARC_MEMREG_H
+#define _SPARC_MEMREG_H
+/* memreg.h:  Definitions of the values found in the synchronous
+ *            and asynchronous memory error registers when a fault
+ *            occurs on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* First the synchronous error codes, these are usually just
+ * normal page faults.
+ */
+
+#define SUN4C_SYNC_WDRESET   0x1  /* watchdog reset, only the prom sees this */
+#define SUN4C_SYNC_SIZE      0x2  /* bad access size? whuz this? */
+#define SUN4C_SYNC_PARITY    0x8  /* bad ram chips caused a parity error */
+#define SUN4C_SYNC_SBUS      0x10 /* the SBUS had some problems... */
+#define SUN4C_SYNC_NOMEM     0x20 /* translation pointed to non-existant ram */
+#define SUN4C_SYNC_PROT      0x40 /* access violated pte protection settings */
+#define SUN4C_SYNC_NPRESENT  0x80 /* pte said that page was not present */
+#define SUN4C_SYNC_BADWRITE  0x8000  /* while writing something went bogus */
+
+/* Now the asynchronous error codes, these are almost always produced
+ * by the cache writing things back to memory and getting a bad translation.
+ * Bad DVMA transactions can cause these faults too.
+ */
+
+#define SUN4C_ASYNC_BADDVMA  0x10 /* error during DVMA access */
+#define SUN4C_ASYNC_NOMEM    0x20 /* write back pointed to bad phys addr */
+#define SUN4C_ASYNC_BADWB    0x80 /* write back points to non-present page */
+
+/* These are the values passed as the first arguement to the fault
+ * entry c-code from the assembly entry points.
+ */
+#define FAULT_ASYNC          0x0
+#define FAULT_SYNC           0x1
+
+#endif /* !(_SPARC_MEMREG_H) */
diff --git a/include/asm-sparc/mostek.h b/include/asm-sparc/mostek.h
new file mode 100644 (file)
index 0000000..b4e3d37
--- /dev/null
@@ -0,0 +1,74 @@
+/* mostek.h:  Describes the various Mostek time of day clock registers.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MOSTEK_H
+#define _SPARC_MOSTEK_H
+
+#include <asm/idprom.h>
+
+/* First the Mostek 48t02 clock chip.  The registers other than the
+ * control register are in binary coded decimal.
+ */
+struct mostek48t02 {
+       char eeprom[2008];            /* This is the eeprom, don't touch! */
+       struct idp_struct idprom;     /* The idprom lives here. */
+       volatile unsigned char creg;  /* Control register */
+       volatile unsigned char sec;   /* Seconds (0-59) */
+       volatile unsigned char min;   /* Minutes (0-59) */
+       volatile unsigned char hour;  /* Hour (0-23) */
+       volatile unsigned char dow;   /* Day of the week (1-7) */
+       volatile unsigned char dom;   /* Day of the month (1-31) */
+       volatile unsigned char mnth;  /* Month of year (1-12) */
+       volatile unsigned char yr;    /* Year (0-99) */
+};
+
+extern struct mostek48t02 *mstk48t02_regs;
+
+/* Control register values. */
+#define MSTK_CREG_WRITE    0x80   /* Must set this before placing values. */
+#define MSTK_CREG_READ     0x40   /* Stop the clock, I want to fetch values. */
+#define MSTK_CREG_SIGN     0x20   /* Grrr... whats this??? */
+
+#define MSTK_YR_ZERO       1968   /* If year reg has zero, it is 1968 */
+#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YR_ZERO)
+
+/* Fun with masks. */
+#define MSTK_SEC_MASK      0x7f
+#define MSTK_MIN_MASK      0x7f
+#define MSTK_HOUR_MASK     0x3f
+#define MSTK_DOW_MASK      0x07
+#define MSTK_DOM_MASK      0x3f
+#define MSTK_MNTH_MASK     0x1f
+#define MSTK_YR_MASK       0xff
+
+/* Conversion routines. */
+#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0xf) + 0xa * ((x) >> 0x4))
+#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0xa) << 0x4) + ((x) % 0xa))
+
+/* Macros to make register access easier on our fingers. These give you
+ * the decimal value of the register requested if applicable.  You pass
+ * the a pointer to a 'struct mostek48t02'.
+ */
+#define MSTK_REG_CREG(ptr)  (ptr->creg)
+#define MSTK_REG_SEC(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->sec & MSTK_SEC_MASK)))
+#define MSTK_REG_MIN(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->min & MSTK_MIN_MASK)))
+#define MSTK_REG_HOUR(ptr)  (MSTK_REGVAL_TO_DECIMAL((ptr->hour & MSTK_HOUR_MASK)))
+#define MSTK_REG_DOW(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->dow & MSTK_DOW_MASK)))
+#define MSTK_REG_DOM(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->dom & MSTK_DOM_MASK)))
+#define MSTK_REG_MNTH(ptr)  (MSTK_REGVAL_TO_DECIMAL((ptr->mnth & MSTK_MNTH_MASK)))
+#define MSTK_REG_YR(ptr)    (MSTK_REGVAL_TO_DECIMAL((ptr->yr & MSTK_YR_MASK)))
+
+/* The Mostek 48t02 clock chip.  Found on Sun4m's I think.  It has the
+ * same (basically) layout of the 48t02 chip.
+ */
+struct mostek48t08 {
+       char offset[6*1024];         /* Magic things may be here, who knows? */
+       struct mostek48t02 regs;     /* Here is what we are interested in.   */
+};
+extern struct mostek48t08 *mstk48t08_regs;
+
+enum sparc_clock_type {        MSTK48T02, MSTK48T08, MSTK_INVALID };
+extern enum sparc_clock_type sp_clock_typ;
+
+#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/include/asm-sparc/mp.h b/include/asm-sparc/mp.h
new file mode 100644 (file)
index 0000000..6305e8b
--- /dev/null
@@ -0,0 +1,33 @@
+/* mp.h:  Multiprocessing definitions for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MP_H
+#define _SPARC_MP_H
+
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/vaddrs.h>
+
+extern int linux_smp_still_initting;
+
+struct sparc_percpu {
+       struct tt_entry trap_table[NUM_SPARC_TRAPS];  /* One page */
+       unsigned int kernel_stack[PAGE_SIZE/4];       /* One page */
+       int cpuid;          /* Who am I? */
+       int cpu_is_alive;   /* Linux has fired it up. */
+       int cpu_is_idling;  /* Is sitting in the idle loop. */
+       /* More to come... */
+       char filler[PERCPU_ENTSIZE-(PAGE_SIZE*2)-0xc];
+};
+
+extern struct sparc_percpu *percpu_table;
+
+struct prom_cpuinfo {
+       int prom_node;
+       int mid;
+};
+
+extern struct prom_cpuinfo linux_cpus[NCPUS];
+
+#endif /* !(_SPARC_MP_H) */
diff --git a/include/asm-sparc/mpmbox.h b/include/asm-sparc/mpmbox.h
new file mode 100644 (file)
index 0000000..b4e3f29
--- /dev/null
@@ -0,0 +1,66 @@
+/* mpmbox.h:  Interface and defines for the OpenProm mailbox
+ *               facilities for MP machines under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MPMBOX_H
+#define _SPARC_MPMBOX_H
+
+/* The prom allocates, for each CPU on the machine an unsigned
+ * byte in physical ram.  You probe the device tree prom nodes
+ * for these values.  The purpose of this byte is to be able to
+ * pass messages from one cpu to another.
+ */
+
+/* These are the main message types we have to look for in our
+ * Cpu mailboxes, based upon these values we decide what course
+ * of action to take.
+ */
+
+/* The CPU is executing code in the kernel. */
+#define MAILBOX_ISRUNNING     0xf0
+
+/* Another CPU called romvec->pv_exit(), you should call
+ * prom_stopcpu() when you see this in your mailbox.
+ */
+#define MAILBOX_EXIT          0xfb
+
+/* Another CPU called romvec->pv_enter(), you should call
+ * prom_cpuidle() when this is seen.
+ */
+#define MAILBOX_GOSPIN        0xfc
+
+/* Another CPU has hit a breakpoint either into kadb or the prom
+ * itself.  Just like MAILBOX_GOSPIN, you should call prom_cpuidle()
+ * at this point.
+ */
+#define MAILBOX_BPT_SPIN      0xfd
+
+/* Oh geese, some other nitwit got a damn watchdog reset.  The partys
+ * over so go call prom_stopcpu().
+ */
+#define MAILBOX_WDOG_STOP     0xfe
+
+#ifndef __ASSEMBLY__
+
+/* Handy macro's to determine a cpu's state. */
+
+/* Is the cpu still in Power On Self Test? */
+#define MBOX_POST_P(letter)  ((letter) >= 0x00 && (letter) <= 0x7f)
+
+/* Is the cpu at the 'ok' prompt of the PROM? */
+#define MBOX_PROMPROMPT_P(letter) ((letter) >= 0x80 && (letter) <= 0x8f)
+
+/* Is the cpu spinning in the PROM? */
+#define MBOX_PROMSPIN_P(letter) ((letter) >= 0x90 && (letter) <= 0xef)
+
+/* Sanity check... This is junk mail, throw it out. */
+#define MBOX_BOGON_P(letter) ((letter) >= 0xf1 && (letter) <= 0xfa)
+
+/* Is the cpu actively running an application/kernel-code? */
+#define MBOX_RUNNING_P(letter) ((letter) == MAILBOX_ISRUNNING)
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* !(_SPARC_MPMBOX_H) */
diff --git a/include/asm-sparc/mxcc.h b/include/asm-sparc/mxcc.h
new file mode 100644 (file)
index 0000000..17128a4
--- /dev/null
@@ -0,0 +1,82 @@
+/* mxcc.h:  Definitions of the Viking MXCC registers
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MXCC_H
+#define _SPARC_MXCC_H
+
+/* These registers are accessed through ASI 0x2. */
+#define MXCC_DATSTREAM       0x1C00000  /* Data stream register */
+#define MXCC_SRCSTREAM       0x1C00100  /* Source stream register */
+#define MXCC_DESSTREAM       0x1C00200  /* Destination stream register */
+#define MXCC_RMCOUNT         0x1C00300  /* Count of references and misses */
+#define MXCC_STEST           0x1C00804  /* Internal self-test */
+#define MXCC_CREG            0x1C00A04  /* Control register */
+#define MXCC_SREG            0x1C00B00  /* Status register */
+#define MXCC_RREG            0x1C00C04  /* Reset register */
+#define MXCC_EREG            0x1C00E00  /* Error code register */
+#define MXCC_PREG            0x1C00F04  /* Address port register */
+
+/* The MXCC Control Register:
+ *
+ * ----------------------------------------------------------------------
+ * |                                   | RRC | RSV |PRE|MCE|PARE|ECE|RSV|
+ * ----------------------------------------------------------------------
+ *  31                              10    9    8-6   5   4    3   2  1-0
+ *
+ * RRC: Controls what you read from MXCC_RMCOUNT reg.
+ *      0=Misses 1=References
+ * PRE: Prefetch enable
+ * MCE: Multiple Command Enable
+ * PARE: Parity enable
+ * ECE: External cache enable
+ */
+
+#define MXCC_CTL_RRC   0x00000200
+#define MXCC_CTL_PRE   0x00000020
+#define MXCC_CTL_MCE   0x00000010
+#define MXCC_CTL_PARE  0x00000008
+#define MXCC_CTL_ECE   0x00000004
+
+/* The MXCC Error Register:
+ *
+ * --------------------------------------------------------
+ * |ME| RSV|CE|PEW|PEE|ASE|EIV| MOPC|ECODE|PRIV|RSV|HPADDR|
+ * --------------------------------------------------------
+ *  31   30 29  28  27  26  25 24-15  14-7   6  5-3   2-0
+ *
+ * ME: Multiple Errors have occurred
+ * CE: Cache consistancy Error
+ * PEW: Parity Error during a Write operation
+ * PEE: Parity Error involving the External cache
+ * ASE: ASynchronous Error
+ * EIV: This register is toast
+ * MOPC: MXCC Operation Code for instance causing error
+ * ECODE: The Error CODE
+ * PRIV: A privileged mode error? 0=no 1=yes
+ * HPADDR: High PhysicalADDRess bits (35-32)
+ */
+
+#define MXCC_ERR_ME     0x80000000
+#define MXCC_ERR_CE     0x20000000
+#define MXCC_ERR_PEW    0x10000000
+#define MXCC_ERR_PEE    0x08000000
+#define MXCC_ERR_ASE    0x04000000
+#define MXCC_ERR_EIV    0x02000000
+#define MXCC_ERR_MOPC   0x01FF8000
+#define MXCC_ERR_ECODE  0x00007F80
+#define MXCC_ERR_PRIV   0x00000040
+#define MXCC_ERR_HPADDR 0x0000000f
+
+/* The MXCC Port register:
+ *
+ * -----------------------------------------------------
+ * |                | MID |                            |
+ * -----------------------------------------------------
+ *  31            21 20-18 17                         0
+ *
+ * MID: The moduleID of the cpu your read this from.
+ */
+
+#endif /* !(_SPARC_MXCC_H) */
index ca6d9e36d09aa1af0a48316c6799a8a930b19d8f..a38ab7a39b755d626100c3614352a19d15c4813b 100644 (file)
@@ -2,33 +2,37 @@
 #define __SPARC_OPENPROM_H
 
 /* openprom.h:  Prom structures and defines for access to the OPENBOOT
               prom routines and data areas.
-
  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
*              prom routines and data areas.
+ *
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 /* In the v0 interface of the openboot prom we could traverse a nice
-   little list structure to figure out where in vm-space the prom had
-   mapped itself and how much space it was taking up. In the v2 prom
-   interface we have to rely on 'magic' values. :-( Most of the machines
-   I have checked on have the prom mapped here all the time though.
-*/
+ * little list structure to figure out where in vm-space the prom had
+ * mapped itself and how much space it was taking up. In the v2 prom
+ * interface we have to rely on 'magic' values. :-( Most of the machines
+ * I have checked on have the prom mapped here all the time though.
+ */
+
+#define KADB_DEBUGGER_BEGVM     0xffc00000    /* Where kern debugger is in virt-mem */
+
 #define        LINUX_OPPROM_BEGVM      0xffd00000
 #define        LINUX_OPPROM_ENDVM      0xfff00000
 
 #define        LINUX_OPPROM_MAGIC      0x10010407
 
+#ifndef __ASSEMBLY__
 /* The device functions structure for the v0 prom. Nice and neat, open,
  close, read & write divvied up between net + block + char devices. We
  also have a seek routine only usable for block devices. The divide
  and conquer strategy of this struct becomes unnecessary for v2.
-
  V0 device names are limited to two characters, 'sd' for scsi-disk,
  'le' for local-ethernet, etc. Note that it is technically possible
  to boot a kernel off of a tape drive and use the tape as the root
  partition! In order to do this you have to have 'magic' formatted
  tapes from Sun supposedly :-)
-*/
* close, read & write divvied up between net + block + char devices. We
* also have a seek routine only usable for block devices. The divide
* and conquer strategy of this struct becomes unnecessary for v2.
+ *
* V0 device names are limited to two characters, 'sd' for scsi-disk,
* 'le' for local-ethernet, etc. Note that it is technically possible
* to boot a kernel off of a tape drive and use the tape as the root
* partition! In order to do this you have to have 'magic' formatted
* tapes from Sun supposedly :-)
+ */
 
 struct linux_dev_v0_funcs {
        int     (*v0_devopen)(char *device_str);
@@ -43,32 +47,32 @@ struct linux_dev_v0_funcs {
 };
 
 /* The OpenBoot Prom device operations for version-2 interfaces are both
  good and bad. They now allow you to address ANY device whatsoever
  that is in the machine via these funny "device paths". They look like
  this:
-
    "/sbus/esp@0,0xf004002c/sd@3,1"
-
  You can basically reference any device on the machine this way, and
  you pass this string to the v2 dev_ops. Producing these strings all
  the time can be a pain in the rear after a while. Why v2 has memory
  allocations in here are beyond me. Perhaps they figure that if you
  are going to use only the prom's device drivers then your memory
  management is either non-existent or pretty sad. :-)
-*/
* good and bad. They now allow you to address ANY device whatsoever
* that is in the machine via these funny "device paths". They look like
* this:
+ *
*   "/sbus/esp@0,0xf004002c/sd@3,1"
+ *
* You can basically reference any device on the machine this way, and
* you pass this string to the v2 dev_ops. Producing these strings all
* the time can be a pain in the rear after a while. Why v2 has memory
* allocations in here are beyond me. Perhaps they figure that if you
* are going to use only the prom's device drivers then your memory
* management is either non-existent or pretty sad. :-)
+ */
 
 struct linux_dev_v2_funcs {
-       int     (*v2_aieee)(int d);     /* figure this out later... */
+       int     (*v2_inst2pkg)(int d);  /* Convert ihandle to phandle */
 
        /* "dumb" prom memory management routines, probably
-           only safe to use for mapping device address spaces...
-        */
+        *  only safe to use for mapping device address spaces...
+         */
 
        char*   (*v2_dumb_mem_alloc)(char*  va, unsigned sz);
        void    (*v2_dumb_mem_free)(char*  va, unsigned sz);
 
        /* "dumb" mmap() munmap(), copy on write? what's that? */
-       char*   (*v2_dumb_mmap)(char*  virta, int asi, unsigned prot, unsigned sz);
+       char*   (*v2_dumb_mmap)(char*  virta, int which_io, unsigned paddr, unsigned sz);
        void    (*v2_dumb_munmap)(char*  virta, unsigned size);
 
        /* Basic Operations, self-explanatory */
@@ -78,16 +82,16 @@ struct linux_dev_v2_funcs {
        int     (*v2_dev_write)(int d, char*  buf, int nbytes);
        void    (*v2_dev_seek)(int d, int hi, int lo);
 
-        /* huh? */
+       /* Never issued (multistage load support) */
        void    (*v2_wheee2)(void);
        void    (*v2_wheee3)(void);
 };
 
 /* Just like the device ops, they slightly screwed up the mem-list
  from v0 to v2. Probably easier on the prom-writer dude, sucks for
  us though. See above comment about prom-vm mapped address space
  magic numbers. :-(
-*/
* from v0 to v2. Probably easier on the prom-writer dude, sucks for
* us though. See above comment about prom-vm mapped address space
* magic numbers. :-(
+ */
 
 struct linux_mlist_v0 {
        struct  linux_mlist_v0 *theres_more;
@@ -95,11 +99,12 @@ struct linux_mlist_v0 {
        unsigned num_bytes;
 };
 
-/* The linux_mlist_v0's are pointer by this structure. One list
  per description. This means one list for total physical memory,
  one for prom's address mapping, and one for physical mem left after
  the kernel is loaded.
+/* The linux_mlist_v0's are pointed to by this structure. One list
* per description. This means one list for total physical memory,
* one for prom's address mapping, and one for physical mem left after
* the kernel is loaded.
  */
+
 struct linux_mem_v0 {
        struct  linux_mlist_v0 **v0_totphys;    /* all of physical */
        struct  linux_mlist_v0 **v0_prommap;    /* addresses map'd by prom */
@@ -120,9 +125,9 @@ struct linux_arguments_v0 {
 };
 
 /* Prom version-2 gives us the raw strings for boot arguments and
  boot device path. We also get the stdin and stdout file pseudo
  descriptors for use with the mungy v2 device functions.
-*/
* boot device path. We also get the stdin and stdout file pseudo
* descriptors for use with the mungy v2 device functions.
+ */
 struct linux_bootargs_v2 {
        char    **bootpath;             /* V2: Path to boot device */
        char    **bootargs;             /* V2: Boot args */
@@ -131,11 +136,12 @@ struct linux_bootargs_v2 {
 };
 
 /* This is the actual Prom Vector from which everything else is accessed
-   via struct and function pointers, etc. The prom when it loads us into
-   memory plops a pointer to this master structure in register %o0 before
-   it jumps to the kernel start address. I will update this soon to cover
-   the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-)
-*/
+ * via struct and function pointers, etc. The prom when it loads us into
+ * memory plops a pointer to this master structure in register %o0 before
+ * it jumps to the kernel start address. I will update this soon to cover
+ * the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-)
+ */
+
 struct linux_romvec {
        /* Version numbers. */
        unsigned int    pv_magic_cookie;      /* Magic Mushroom... */
@@ -200,7 +206,7 @@ struct linux_romvec {
        struct  linux_bootargs_v2 pv_v2bootargs;    /* V2: Boot args+std-in/out */
        struct  linux_dev_v2_funcs pv_v2devops;     /* V2: device operations */
 
-       int     whatzthis[15];       /* huh? */
+       int     filler[15];
 
        /*
         * The following is machine-dependent.
@@ -222,11 +228,9 @@ struct linux_romvec {
 
        /* v3_cpustart() will start the cpu 'whichcpu' in mmu-context
         * 'thiscontext' executing at address 'prog_counter'
-        *
-        * XXX Have to figure out what 'cancontext' means.
          */
 
-       int (*v3_cpustart)(unsigned int whichcpu, int cancontext,
+       int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr,
                           int thiscontext, char* prog_counter);
 
        /* v3_cpustop() will cause cpu 'whichcpu' to stop executing
@@ -277,11 +281,6 @@ struct linux_romvec {
  * are not in the openprom vectors but rather found by indirection from
  * there.  So the taste balances out.
  */
-struct linux_prom_addr {
-       int     oa_space;               /* address space (may be relative) */
-       unsigned int    oa_base;                /* address within space */
-       unsigned int    oa_size;                /* extent (number of bytes) */
-};
 
 struct linux_nodeops {
        /*
@@ -301,4 +300,31 @@ struct linux_nodeops {
        char*   (*no_nextprop)(int node, char*  name);
 };
 
+/* More fun PROM structures for device probing. */
+#define PROMREG_MAX     16
+#define PROMVADDR_MAX   16
+#define PROMINTR_MAX    15
+
+struct linux_prom_registers {
+  int which_io;         /* is this in OBIO space? */
+  char *phys_addr;      /* The physical address of this register */
+  int reg_size;         /* How many bytes does this register take up? */
+};
+
+struct linux_prom_irqs {
+  int pri;    /* IRQ priority */
+  int vector; /* This is foobar, what does it do? */
+};
+
+/* Element of the "ranges" vector */
+struct linux_prom_ranges {
+       unsigned int    ot_child_space;
+       unsigned int    ot_child_base;          /* Bus feels this */
+       unsigned int    ot_parent_space;
+       unsigned int    ot_parent_base;         /* CPU looks from here */
+       unsigned int    or_size;
+};
+
+#endif /* !(__ASSEMBLY__) */
+
 #endif /* !(__SPARC_OPENPROM_H) */
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
new file mode 100644 (file)
index 0000000..8b4a6e3
--- /dev/null
@@ -0,0 +1,260 @@
+/* oplib.h:  Describes the interface and available routines in the
+ *           Linux Prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_OPLIB_H
+#define __SPARC_OPLIB_H
+
+#include <asm/openprom.h>
+
+/* The master romvec pointer... */
+extern struct linux_romvec *romvec;
+
+/* Enumeration to describe the prom major version we have detected. */
+enum prom_major_version {
+       PROM_V0,      /* Origional sun4c V0 prom */
+       PROM_V2,      /* sun4c and early sun4m V2 prom */
+       PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
+       PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
+};
+
+extern enum prom_major_version prom_vers;
+/* Revision, and firmware revision. */
+extern unsigned int prom_rev, prom_prev;
+
+/* Root node of the prom device tree, this stays constant after
+ * initialization is complete.
+ */
+extern int prom_root_node;
+
+/* Pointer to prom structure containing the device tree traversal
+ * and usage utility functions.  Only prom-lib should use these,
+ * users use the interface defined by the library only!
+ */
+extern struct linux_nodeops *prom_nodeops;
+
+/* The functions... */
+
+/* You must call prom_init() before using any of the library services,
+ * preferably as early as possible.  Pass it the romvec pointer.
+ */
+extern int prom_init(struct linux_romvec *rom_ptr);
+
+/* Boot argument acquisition, returns the boot command line string. */
+extern char *prom_getbootargs(void);
+
+/* Device utilities. */
+
+/* Map and unmap devices in IO space at virtual addresses. Note that the
+ * virtual address you pass is a request and the prom may put your mappings
+ * somewhere else, so check your return value as that is where your new
+ * mappings really are!
+ *
+ * Another note, these are only available on V2 or higher proms!
+ */
+extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes);
+extern void prom_unmapio(char *virt_addr, unsigned int num_bytes);
+
+/* Device operations. */
+
+/* Open the device described by the passed string.  Note, that the format
+ * of the string is different on V0 vs. V2->higher proms.  The caller must
+ * know what he/she is doing!  Returns the device descriptor, an int.
+ */
+extern int prom_devopen(char *device_string);
+
+/* Close a previously opened device described by the passed integer
+ * descriptor.
+ */
+extern int prom_devclose(int device_handle);
+
+/* Do a seek operation on the device described by the passed integer
+ * descriptor.
+ */
+extern void prom_seek(int device_handle, unsigned int seek_hival,
+                     unsigned int seek_lowval);
+
+/* Machine memory configuration routine. */
+
+/* This function returns a V0 format memory descriptor table, it has three
+ * entries.  One for the total amount of physical ram on the machine, one
+ * for the amount of physical ram available, and one describing the virtual
+ * areas which are allocated by the prom.  So, in a sense the physical
+ * available is a calculation of the total physical minus the physcial mapped
+ * by the prom with virtual mappings.
+ *
+ * These lists are returned pre-sorted, this should make your life easier
+ * since the prom itself is way too lazy to do such nice things.
+ */
+extern struct linux_mem_v0 *prom_meminfo(void);
+
+/* Miscellaneous routines, don't really fit in any category per se. */
+
+/* Reboot the machine with the command line passed. */
+extern void prom_reboot(char *boot_command);
+
+/* Evaluate the forth string passed. */
+extern void prom_feval(char *forth_string);
+
+/* Enter the prom, with possibility of continuation with the 'go'
+ * command in newer proms.
+ */
+extern void prom_halt(void);
+
+/* Enter the prom, with no chance of continuation for the stand-alone
+ * which calls this.
+ */
+extern void prom_die(void);
+
+/* Set the PROM 'sync' callback function to the passed function pointer.
+ * When the user gives the 'sync' command at the prom prompt while the
+ * kernel is still active, the prom will call this routine.
+ *
+ * XXX The arguments are different on V0 vs. V2->higher proms, grrr! XXX
+ */
+typedef void (*sync_func_t)(void);
+extern void prom_setsync(sync_func_t func_ptr);
+
+/* Acquire the IDPROM of the root node in the prom device tree.  This
+ * gets passed a buffer where you would like it stuffed.  The return value
+ * is the format type of this idprom or 0xff on error.
+ */
+extern unsigned char prom_getidp(char *idp_buffer, int idpbuf_size);
+
+/* Get the prom major version. */
+extern int prom_version(void);
+
+/* Get the prom plugin revision. */
+extern int prom_getrev(void);
+
+/* Get the prom firmware revision. */
+extern int prom_getprev(void);
+
+/* Character operations to/from the console.... */
+
+/* Non-blocking get character from console. */
+extern int prom_nbgetchar(void);
+
+/* Non-blocking put character to console. */
+extern int prom_nbputchar(char character);
+
+/* Blocking get character from console. */
+extern char prom_getchar(void);
+
+/* Blocking put character to console. */
+extern void prom_putchar(char character);
+
+/* Prom's internal printf routine, don't use in kernel/boot code. */
+void prom_printf(char *fmt, ...);
+
+/* Multiprocessor operations... */
+
+/* Start the CPU with the given device tree node, context table, and context
+ * at the passed program counter.
+ */
+extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table,
+                        int context, char *program_counter);
+
+/* Stop the CPU with the passed device tree node. */
+extern int prom_stopcpu(int cpunode);
+
+/* Idle the CPU with the passed device tree node. */
+extern int prom_idlecpu(int cpunode);
+
+/* Re-Start the CPU with the passed device tree node. */
+extern int prom_restartcpu(int cpunode);
+
+/* PROM memory allocation facilities... */
+
+/* Allocated at possibly the given virtual address a chunk of the
+ * indicated size.
+ */
+extern char *prom_alloc(char *virt_hint, unsigned int size);
+
+/* Free a previously allocated chunk. */
+extern void prom_free(char *virt_addr, unsigned int size);
+
+/* Sun4/sun4c specific memory-management startup hook. */
+
+/* Map the passed segment in the given context at the passed
+ * virtual address.
+ */
+extern void prom_putsegment(int context, unsigned long virt_addr,
+                           int physical_segment);
+
+/* PROM device tree traversal functions... */
+
+/* Get the child node of the given node, or zero if no child exists. */
+extern int prom_getchild(int parent_node);
+
+/* Get the next sibling node of the given node, or zero if no further
+ * siblings exist.
+ */
+extern int prom_getsibling(int node);
+
+/* Get the length, at the passed node, of the given property type.
+ * Returns -1 on error (ie. no such property at this node).
+ */
+extern int prom_getproplen(int thisnode, char *property);
+
+/* Fetch the requested property using the given buffer.  Returns
+ * the number of bytes the prom put into your buffer or -1 on error.
+ */
+extern int prom_getproperty(int thisnode, char *property,
+                           char *prop_buffer, int propbuf_size);
+
+/* Acquire an integer property. */
+extern int prom_getint(int node, char *property);
+
+/* Acquire an integer property, with a default value. */
+extern int prom_getintdefault(int node, char *property, int defval);
+
+/* Acquire a boolean property, 0=FALSE 1=TRUE. */
+extern int prom_getbool(int node, char *prop);
+
+/* Acquire a string property, null string on error. */
+extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+
+/* Does the passed node have the given "name"? YES=1 NO=0 */
+extern int prom_nodematch(int thisnode, char *name);
+
+/* Search all siblings starting at the passed node for "name" matching
+ * the given string.  Returns the node on success, zero on failure.
+ */
+extern int prom_searchsiblings(int node_start, char *name);
+
+/* Return the first property type, as a string, for the given node.
+ * Returns a null string on error.
+ */
+extern char *prom_firstprop(int node);
+
+/* Returns the next property after the passed property for the given
+ * node.  Returns null string on failure.
+ */
+extern char *prom_nextprop(int node, char *prev_property);
+
+/* Set the indicated property at the given node with the passed value.
+ * Returns the number of bytes of your value that the prom took.
+ */
+extern int prom_setprop(int node, char *prop_name, char *prop_value,
+                       int value_size);
+
+/* Dorking with Bus ranges... */
+
+/* Adjust reg values with the passed ranges. */
+extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
+                            struct linux_prom_ranges *rangep, int nranges);
+
+/* Adjust child ranges with the passed parent ranges. */
+extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
+                              struct linux_prom_ranges *pranges, int npranges);
+
+/* Apply promlib probed OBIO ranges to registers. */
+extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
+
+/* Apply promlib probed SBUS ranges to registers. */
+extern void prom_apply_sbus_ranges(struct linux_prom_registers *sbusregs, int nregs);
+
+#endif /* !(__SPARC_OPLIB_H) */
index 9aea3e5157a6565582b775c154d1bfcf8f2a8f7d..39677f1a88873b96fb85c07e22c275194bd4a41b 100644 (file)
@@ -1,31 +1,32 @@
 /* page.h:  Various defines and such for MMU operations on the Sparc for
           the Linux kernel.
-
  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
*          the Linux kernel.
+ *
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
 #include <asm/asi.h>        /* for get/set segmap/pte routines */
 #include <asm/contregs.h>   /* for switch_to_context */
+#include <asm/head.h>       /* for KERNBASE */
 
 #define PAGE_SHIFT   12             /* This is the virtual page... */
-
-#ifndef __ASSEMBLY__
-#define PAGE_SIZE    (1UL << PAGE_SHIFT)
+#define PAGE_OFFSET    KERNBASE
+#define PAGE_SIZE    (1 << PAGE_SHIFT)
 
 /* to mask away the intra-page address bits */
 #define PAGE_MASK         (~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
+#ifndef __ASSEMBLY__
 
 /* The following structure is used to hold the physical
- * memory configuration of the machine.  This is filled
- * in probe_memory() and is later used by mem_init() to
- * set up mem_map[].  We statically allocate 14 of these
- * structs, this is arbitrary.  The entry after the last
- * valid one has num_bytes==0.
+ * memory configuration of the machine.  This is filled in
+ * probe_memory() and is later used by mem_init() to set up
+ * mem_map[].  We statically allocate SPARC_PHYS_BANKS of
+ * these structs, this is arbitrary.  The entry after the
+ * last valid one has num_bytes==0.
  */
 
 struct sparc_phys_banks {
@@ -33,6 +34,10 @@ struct sparc_phys_banks {
   unsigned long num_bytes;
 };
 
+#define SPARC_PHYS_BANKS 32
+
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
 #define CONFIG_STRICT_MM_TYPECHECKS
 
 #ifdef CONFIG_STRICT_MM_TYPECHECKS
@@ -76,16 +81,19 @@ typedef unsigned long pgprot_t;
 #endif
 
 /* The current va context is global and known, so all that is needed to
- * do an invalidate is flush the VAC.
+ * do an invalidate is flush the VAC on a sun4c or call the ASI flushing
+ * routines on a SRMMU.
  */
 
-#define invalidate() flush_vac_context()  /* how conveeeiiiiinnnient :> */
+extern void (*invalidate)(void);
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-#define PAGE_OFFSET    0
-#define MAP_NR(addr) (((unsigned long)(addr)) >> PAGE_SHIFT)
+/* We now put the free page pool mapped contiguously in high memory above
+ * the kernel.
+ */
+#define MAP_NR(addr) ((((unsigned long)addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED (1<<15)
 
 
@@ -114,21 +122,144 @@ typedef unsigned long pgprot_t;
 #define PTE_RESV  0x00f80000   /* reserved bits */
 #define PTE_PHYPG 0x0007ffff   /* phys pg number, sun4c only uses 16bits */
 
+/* SRMMU defines */
+/* The fields in an srmmu virtual address when it gets translated.
+ *
+ *  -------------------------------------------------------------
+ *  |   INDEX 1   |   INDEX 2   |   INDEX 3   |   PAGE OFFSET   |
+ *  -------------------------------------------------------------
+ *  31          24 23        18  17         12  11              0
+ */
+#define SRMMU_IDX1_SHIFT      24
+#define SRMMU_IDX1_MASK       0xff000000
+#define SRMMU_IDX2_SHIFT      18
+#define SRMMU_IDX2_MASK       0x00fc0000
+#define SRMMU_IDX3_SHIFT      12
+#define SRMMU_IDX3_MASK       0x0003f000
+
+#define SRMMU_PGOFFSET_MASK   0x00000fff
+/* The page table sizes for the various levels in bytes. */
+#define SRMMU_LV1_PTSIZE      1024
+#define SRMMU_LV2_PTSIZE      256
+#define SRMMU_LV3_PTSIZE      256
+
+/* Definition of the values in the ET field of PTD's and PTE's */
+#define SRMMU_ET_INVALID      0x0
+#define SRMMU_ET_PTD          0x1
+#define SRMMU_ET_PTE          0x2
+#define SRMMU_ET_RESV         0x3
+#define SRMMU_ET_PTDBAD       0x3   /* Upward compatability my butt. */
+
+/* Page table directory bits.
+ *
+ * ----------------
+ * |  PTP    | ET |
+ * ----------------
+ * 31       2 1  0
+ *
+ * PTP:  The physical page table pointer.  This value appears on
+ *       bits 35->6 on the physical address bus during translation.
+ *
+ * ET:   Entry type field.  Must be 1 for a PTD.
+ */
+
+#define SRMMU_PTD_PTP_SHIFT         0x2
+#define SRMMU_PTD_PTP_MASK          0xfffffffc
+#define SRMMU_PTD_PTP_PADDR_SHIFT   0x4
+#define SRMMU_PTD_ET_SHIFT          0x0
+#define SRMMU_PTD_ET_MASK           0x00000003
+
+/* Page table entry bits.
+ *
+ * -------------------------------------------------
+ * |  Physical Page Number  | C | M | R | ACC | ET |
+ * -------------------------------------------------
+ * 31                     8   7   6   5  4   2  1  0
+ *
+ * PPN: Physical page number, high order 24 bits of the 36-bit
+ *      physical address, thus is you mask off all the non
+ *      PPN bits you have the physical address of your page.
+ *      No shifting necessary.
+ *
+ * C:   Whether the page is cacheable in the mmu TLB or not.  If
+ *      not set the CPU cannot cache values to these addresses. For
+ *      IO space translations this bit should be clear.
+ *
+ * M:   Modified.  This tells whether the page has been written to
+ *      since the bit was last cleared.  NOTE: this does not include
+ *      accesses via the ASI physical page pass through since that does
+ *      not use the MMU.
+ *
+ * R:   References.  This tells whether the page has been referenced
+ *      in any way shape or form since the last clearing of the bit.
+ *      NOTE: this does not include accesses via the ASI physical page
+ *      pass through since that does not use the MMU.
+ *
+ * ACC: Access permissions for this page.  This is further explained below
+ *      with appropriate macros.
+ */
+
+#define SRMMU_PTE_PPN_SHIFT         0x8
+#define SRMMU_PTE_PPN_MASK          0xffffff00
+#define SRMMU_PTE_PPN_PADDR_SHIFT   0x4
+#define SRMMU_PTE_C_SHIFT           0x7
+#define SRMMU_PTE_C_MASK            0x00000080
+#define SRMMU_PTE_M_SHIFT           0x6
+#define SRMMU_PTE_M_MASK            0x00000040
+#define SRMMU_PTE_R_SHIFT           0x5
+#define SRMMU_PTE_R_MASK            0x00000020
+#define SRMMU_PTE_ACC_SHIFT         0x2
+#define SRMMU_PTE_ACC_MASK          0x0000001c
+#define SRMMU_PTE_ET_SHIFT          0x0
+#define SRMMU_PTE_ET_MASK           0x00000003
+
+/* SRMMU pte access bits.
+ *
+ * BIT    USER ACCESS          SUPERVISOR ACCESS
+ * ---    --------------       -----------------
+ * 0x0    read only            read only
+ * 0x1    read&write           read&write
+ * 0x2    read&execute         read&execute
+ * 0x3    read&write&execute   read&write&execute
+ * 0x4    execute only         execute only
+ * 0x5    read only            read&write
+ * 0x6    ACCESS DENIED        read&execute
+ * 0x7    ACCESS DENIED        read&write&execute
+ *
+ * All these values are shifted left two bits.
+ */
+
+#define SRMMU_ACC_US_RDONLY      0x00
+#define SRMMU_ACC_US_RDWR        0x04
+#define SRMMU_ACC_US_RDEXEC      0x08
+#define SRMMU_ACC_US_RDWREXEC    0x0c
+#define SRMMU_ACC_US_EXECONLY    0x10
+#define SRMMU_ACC_U_RDONLY       0x14
+#define SRMMU_ACC_S_RDWR         0x14
+#define SRMMU_ACC_U_ACCDENIED    0x18
+#define SRMMU_ACC_S_RDEXEC       0x18
+#define SRMMU_ACC_U_ACCDENIED2   0x1c
+#define SRMMU_ACC_S_RDWREXEC     0x1c
+
+#ifndef __ASSEMBLY__
+
+/* SUN4C pte, segmap, and context manipulation */
 extern __inline__ unsigned long get_segmap(unsigned long addr)
 {
   register unsigned long entry;
 
-  __asm__ __volatile__("lduba [%1] 0x3, %0" : 
+  __asm__ __volatile__("lduba [%1] %2, %0" : 
                       "=r" (entry) :
-                      "r" (addr));
+                      "r" (addr), "i" (ASI_SEGMAP));
 
-  return (entry&0x7f);
+  return (entry&0xff);
 }
 
 extern __inline__ void put_segmap(unsigned long addr, unsigned long entry)
 {
 
-  __asm__ __volatile__("stba %1, [%0] 0x3" : : "r" (addr), "r" (entry&0x7f));
+  __asm__ __volatile__("stba %1, [%0] %2" : : "r" (addr), "r" (entry&0xff),
+                      "i" (ASI_SEGMAP));
 
   return;
 }
@@ -137,43 +268,38 @@ extern __inline__ unsigned long get_pte(unsigned long addr)
 {
   register unsigned long entry;
 
-  __asm__ __volatile__("lda [%1] 0x4, %0" : 
+  __asm__ __volatile__("lda [%1] %2, %0" : 
                       "=r" (entry) :
-                      "r" (addr));
+                      "r" (addr), "i" (ASI_PTE));
   return entry;
 }
 
 extern __inline__ void put_pte(unsigned long addr, unsigned long entry)
 {
-  __asm__ __volatile__("sta %1, [%0] 0x4" : :
+  __asm__ __volatile__("sta %1, [%0] %2" : :
                       "r" (addr), 
-                      "r" (entry));
+                      "r" (entry), "i" (ASI_PTE));
 
   return;
 }
 
-extern __inline__ void switch_to_context(int context)
-{
-  __asm__ __volatile__("stba %0, [%1] 0x2" : :
-                      "r" (context),
-                      "r" (0x30000000));                      
-
-  return;
-}
+extern void (*switch_to_context)(int);
 
 extern __inline__ int get_context(void)
 {
   register int ctx;
 
-  __asm__ __volatile__("lduba [%1] 0x2, %0" :
+  __asm__ __volatile__("lduba [%1] %2, %0" :
                       "=r" (ctx) :
-                      "r" (0x30000000));
+                      "r" (AC_CONTEXT), "i" (ASI_CONTROL));
 
   return ctx;
 }
 
 typedef unsigned short mem_map_t;
 
+#endif /* __ASSEMBLY__ */
+
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_PAGE_H */
index 45b6521080414e8a31de2077d60136e988af816f..5d34edf8f7c5956c39c40467b1725f96b7957183 100644 (file)
@@ -7,76 +7,73 @@
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define PMD_SHIFT       18
-#define PMD_SIZE        (1UL << PMD_SHIFT)
-#define PMD_MASK        (~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT       18
-#define PGDIR_SIZE        (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK        (~(PGDIR_SIZE-1))
-#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&PGDIR_MASK)
+#include <linux/mm.h>
+#include <asm/asi.h>
+#include <asm/pgtsun4c.h>
+#include <asm/pgtsrmmu.h>
+
+extern void load_mmu(void);
+
+extern unsigned int pmd_shift;
+extern unsigned int pmd_size;
+extern unsigned int pmd_mask;
+extern unsigned int (*pmd_align)(unsigned int);
+
+extern unsigned int pgdir_shift;
+extern unsigned int pgdir_size;
+extern unsigned int pgdir_mask;
+extern unsigned int (*pgdir_align)(unsigned int);
+
+extern unsigned int ptrs_per_pte;
+extern unsigned int ptrs_per_pmd;
+extern unsigned int ptrs_per_pgd;
+
+extern unsigned int ptrs_per_page;
+
+extern unsigned long (*(vmalloc_start))(void);
+
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_START vmalloc_start()
+
+extern pgprot_t page_none;
+extern pgprot_t page_shared;
+extern pgprot_t page_copy;
+extern pgprot_t page_readonly;
+extern pgprot_t page_kernel;
+extern pgprot_t page_invalid;
+
+#define PMD_SHIFT      (pmd_shift)
+#define PMD_SIZE       (pmd_size)
+#define PMD_MASK       (pmd_mask)
+#define PMD_ALIGN      (pmd_align)
+#define PGDIR_SHIFT    (pgdir_shift)
+#define PGDIR_SIZE     (pgdir_size)
+#define PGDIR_MASK     (pgdir_mask)
+#define PGDIR_ALIGN    (pgdir_align)
+#define PTRS_PER_PTE   (ptrs_per_pte)
+#define PTRS_PER_PMD   (ptrs_per_pmd)
+#define PTRS_PER_PGD   (ptrs_per_pgd)
+
+#define PAGE_NONE      (page_none)
+#define PAGE_SHARED    (page_shared)
+#define PAGE_COPY      (page_copy)
+#define PAGE_READONLY  (page_readonly)
+#define PAGE_KERNEL    (page_kernel)
+#define PAGE_INVALID   (page_invalid)
+
+/* Top-level page directory */
+extern pgd_t swapper_pg_dir[1024];
 
-/*
- * Just following the i386 lead, because it works on the Sparc sun4c
- * machines.  Two-level, therefore there is no real PMD.
+/* Page table for 0-4MB for everybody, on the Sparc this
+ * holds the same as on the i386.
  */
+extern unsigned long pg0[1024];
 
-#define PTRS_PER_PTE    1024
-#define PTRS_PER_PMD    1
-#define PTRS_PER_PGD    1024
+extern unsigned long ptr_in_current_pgd;
 
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE   (PAGE_SIZE/sizeof(void*))
 
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET  (8*1024*1024)
-#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
-
-/*
- * Sparc page table fields.
- */
-
-#define _PAGE_VALID     0x80000000   /* valid page */
-#define _PAGE_WRITE     0x40000000   /* can be written to */
-#define _PAGE_PRIV      0x20000000   /* bit to signify privileged page */
-#define _PAGE_NOCACHE   0x10000000   /* non-cacheable page */
-#define _PAGE_REF       0x02000000   /* Page has been accessed/referenced */
-#define _PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
-#define _PAGE_COW       0x00800000   /* COW page, hardware ignores this bit (untested) */
-
-
-/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be
- * read in a load, and executed as code automatically. Although, the memory fault
- * hardware does make a distinction between date-read faults and insn-read faults
- * which is determined by which trap happened plus magic sync/async fault register
- * values which must be checked in the actual fault handler.
- */
-
-/* We want the swapper not to swap out page tables, thus dirty and writable
- * so that the kernel can change the entries as needed. Also valid for
- * obvious reasons.
- */
-#define _PAGE_TABLE     (_PAGE_VALID | _PAGE_WRITE | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_REF | _PAGE_DIRTY)
-
-#define PAGE_NONE       __pgprot(_PAGE_VALID | _PAGE_REF)
-#define PAGE_SHARED     __pgprot(_PAGE_VALID | _PAGE_WRITE | _PAGE_REF)
-#define PAGE_COPY       __pgprot(_PAGE_VALID | _PAGE_REF | _PAGE_COW)
-#define PAGE_READONLY   __pgprot(_PAGE_VALID | _PAGE_REF)
-#define PAGE_KERNEL     __pgprot(_PAGE_VALID | _PAGE_WRITE | _PAGE_NOCACHE | _PAGE_REF | _PAGE_PRIV)
-#define PAGE_INVALID    __pgprot(_PAGE_PRIV)
-
-#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | _PAGE_REF | (x))
-
 /* I define these like the i386 does because the check for text or data fault
  * is done at trap time by the low level handler. Maybe I can set these bits
  * then once determined. I leave them like this for now though.
 #define __S110 PAGE_SHARED
 #define __S111 PAGE_SHARED
 
+/* Contexts on the Sparc. */
+#define MAX_CTXS 256
+#define NO_CTX   0xffff     /* In tss.context means task has no context currently */
+extern struct task_struct * ctx_tasks[MAX_CTXS];
+extern int ctx_tasks_last_frd;
 
-extern unsigned long pg0[1024];
+extern int num_contexts;
+
+/* This routine allocates a new context.  And 'p' must not be 'current'! */
+extern inline int alloc_mmu_ctx(struct task_struct *p)
+{
+       int i;
+
+       for(i=0; i<num_contexts; i++)
+               if(ctx_tasks[i] == NULL) break;
+
+       if(i<num_contexts) {
+               p->tss.context = i;
+               ctx_tasks[i] = p;
+               return i;
+       }
+
+       /* Have to free one up */
+       ctx_tasks_last_frd++;
+       if(ctx_tasks_last_frd >= num_contexts) ctx_tasks_last_frd=0;
+       /* Right here is where we invalidate the user mappings that were
+        * present.  TODO
+        */
+        ctx_tasks[ctx_tasks_last_frd]->tss.context = NO_CTX;
+       ctx_tasks[ctx_tasks_last_frd] = p;
+       p->tss.context = ctx_tasks_last_frd;
+       return ctx_tasks_last_frd;
+}
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -120,7 +148,7 @@ extern unsigned long __zero_page(void);
 #define ZERO_PAGE __zero_page()
 
 /* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR      (8*sizeof(unsigned long))   /* better check this stuff */
+#define BITS_PER_PTR      (8*sizeof(unsigned long))
 
 /* to align the pointer to a pointer address */
 #define PTR_MASK          (~(sizeof(void*)-1))
@@ -128,6 +156,9 @@ extern unsigned long __zero_page(void);
 
 #define SIZEOF_PTR_LOG2   2
 
+extern unsigned long (*pte_page)(pte_t);
+extern unsigned long (*pmd_page)(pmd_t);
+extern unsigned long (*pgd_page)(pgd_t);
 
 /* to set the page-dir
  *
@@ -135,208 +166,187 @@ extern unsigned long __zero_page(void);
  * Therefore there is no global idea of 'the' page directory, although we
  * make a virtual one in kernel memory so that we can keep the stats on
  * all the pages since not all can be loaded at once in the mmu.
+ *
+ * Actually on the SRMMU things do work exactly like the i386, the
+ * page tables live in real physical ram, no funky TLB buisness.  But
+ * we have to do lots of flushing. And we have to update the root level
+ * page table pointer for this process if it has a context.
  */
 
-#define SET_PAGE_DIR(tsk,pgdir)
+extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 
+#define SET_PAGE_DIR(tsk,pgdir) \
+do { sparc_update_rootmmu_dir(tsk, pgdir); } while (0)
+       
 /* to find an entry in a page-table */
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
 extern unsigned long high_memory;
 
-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_VALID; }
-extern inline int pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] > 1; }
-extern inline void pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t *ptep)
-{
-  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
-    mem_map[MAP_NR(ptep)]++;
-}
-
-extern inline int pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)           { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
-extern inline int pmd_present(pmd_t pmd)       { return pmd_val(pmd) & _PAGE_VALID; }
-extern inline int pmd_inuse(pmd_t *pmdp)        { return 0; }
-extern inline void pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)      { }
-
-extern inline int pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)           { return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
-extern inline int pgd_present(pgd_t pgd)       { return pgd_val(pgd) & _PAGE_VALID; }
-extern inline int pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] > 1; }
-extern inline void pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
-extern inline void pgd_reuse(pgd_t *pgdp)
-{
-  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
-    mem_map[MAP_NR(pgdp)]++;
-}
+extern int (*pte_none)(pte_t);
+extern int (*pte_present)(pte_t);
+extern int (*pte_inuse)(pte_t *);
+extern void (*pte_clear)(pte_t *);
+extern void (*pte_reuse)(pte_t *);
+
+extern int (*pmd_none)(pmd_t);
+extern int (*pmd_bad)(pmd_t);
+extern int (*pmd_present)(pmd_t);
+extern int (*pmd_inuse)(pmd_t *);
+extern void (*pmd_clear)(pmd_t *);
+extern void (*pmd_reuse)(pmd_t *);
+
+extern int (*pgd_none)(pgd_t);
+extern int (*pgd_bad)(pgd_t);
+extern int (*pgd_present)(pgd_t);
+extern int (*pgd_inuse)(pgd_t *);
+extern void (*pgd_clear)(pgd_t *);
+extern void (*pgd_reuse)(pgd_t *);
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_read(pte_t pte)          { return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_WRITE; }
-extern inline int pte_exec(pte_t pte)          { return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_REF; }
-extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_REF; }
-extern inline int pte_cow(pte_t pte)           { return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_VALID; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_VALID; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_REF; return pte; }
-extern inline pte_t pte_uncow(pte_t pte)       { pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) |= _PAGE_VALID; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)      { pte_val(pte) |= _PAGE_VALID; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_REF; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)       { pte_val(pte) |= _PAGE_COW; return pte; }
+extern int (*pte_read)(pte_t);
+extern int (*pte_write)(pte_t);
+extern int (*pte_exec)(pte_t);
+extern int (*pte_dirty)(pte_t);
+extern int (*pte_young)(pte_t);
+extern int (*pte_cow)(pte_t);
+
+extern pte_t (*pte_wrprotect)(pte_t);
+extern pte_t (*pte_rdprotect)(pte_t);
+extern pte_t (*pte_exprotect)(pte_t);
+extern pte_t (*pte_mkclean)(pte_t);
+extern pte_t (*pte_mkold)(pte_t);
+extern pte_t (*pte_uncow)(pte_t);
+extern pte_t (*pte_mkwrite)(pte_t);
+extern pte_t (*pte_mkread)(pte_t);
+extern pte_t (*pte_mkexec)(pte_t);
+extern pte_t (*pte_mkdirty)(pte_t);
+extern pte_t (*pte_mkyoung)(pte_t);
+extern pte_t (*pte_mkcow)(pte_t);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)        { return pte_val(pte) & PAGE_MASK; }
-
-extern inline unsigned long pmd_page(pmd_t pmd) { return pmd_val(pmd) & PAGE_MASK; }
+extern pte_t (*mk_pte)(unsigned long, pgprot_t);
 
-extern inline unsigned long pgd_page(pgd_t pgd)        { return pgd_val(pgd) & PAGE_MASK; }
+extern void (*pgd_set)(pgd_t *, pte_t *);
 
-extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
-{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+extern pte_t (*pte_modify)(pte_t, pgprot_t);
 
 /* to find an entry in a page-table-directory */
-#define PAGE_DIR_OFFSET(tsk,address) \
-((((unsigned long)(address)) >> 22) + (pgd_t *) (tsk)->tss.cr3)
-
-/* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
-{
-       return (pgd_t *) tsk->tss.cr3 + (address >> PGDIR_SHIFT);
-}
+extern pgd_t * (*pgd_offset)(struct task_struct *, unsigned long);
 
 /* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
-{
-       return (pmd_t *) dir;
-}
+extern pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
 
 /* Find an entry in the third-level page table.. */ 
-extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-       return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
-
+extern pte_t * (*pte_offset)(pmd_t *, unsigned long);
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-extern inline void pte_free_kernel(pte_t * pte)
-{
-       mem_map[MAP_NR(pte)] = 1;
-       free_page((unsigned long) pte);
-}
+extern void (*pte_free_kernel)(pte_t *);
 
-extern inline pte_t * pte_alloc_kernel(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_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-                               mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
-                               return page + address;
-                       }
-                       pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-       if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + address;
-}
+extern pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-extern inline void pmd_free_kernel(pmd_t * pmd)
-{
-}
+extern void (*pmd_free_kernel)(pmd_t *);
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
-{
-       return (pmd_t *) pgd;
-}
+extern pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
 
-extern inline void pte_free(pte_t * pte)
-{
-       free_page((unsigned long) pte);
-}
+extern void (*pte_free)(pte_t *);
 
-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_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-                               return page + address;
-                       }
-                       pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-       if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + address;
-}
+extern pte_t * (*pte_alloc)(pmd_t *, unsigned long);
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
+extern void (*pmd_free)(pmd_t *);
+
+extern pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
+
+extern void (*pgd_free)(pgd_t *);
+
+/* A page directory on the sun4c needs 16k, thus we request an order of
+ * two.
+ *
+ * I need 16k for a sun4c page table, so I use kmalloc since kmalloc_init()
+ * is called before pgd_alloc ever is (I think).
+ */
+
+extern pgd_t * (*pgd_alloc)(void);
 
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+extern int invalid_segment;
+
+/* Sun4c specific routines.  They can stay inlined. */
+extern inline int alloc_sun4c_pseg(void)
 {
-       return (pmd_t *) pgd;
+       int oldseg, i;
+       /* First see if any are free already */
+       for(i=0; i<PSEG_ENTRIES; i++)
+               if(phys_seg_map[i]==PSEG_AVL) return i;
+
+       /* Uh-oh, gotta unallocate a TLB pseg */
+       oldseg=0;
+       for(i=0; i<PSEG_ENTRIES; i++) {
+               /* Can not touch PSEG_KERNEL and PSEG_RSV segmaps */
+               if(phys_seg_map[i]!=PSEG_USED) continue;
+               /* Ok, take a look at it's lifespan */
+               oldseg = (phys_seg_life[i]>oldseg) ? phys_seg_life[i] : oldseg;
+       }
+       phys_seg_life[oldseg]=PSEG_BORN;
+       return oldseg;
 }
 
-extern inline void pgd_free(pgd_t *pgd)
+/* Age all psegs except pseg_skip */
+extern inline void age_sun4c_psegs(int pseg_skip)
 {
-  free_page((unsigned long) pgd);
+       int i;
+
+       for(i=0; i<pseg_skip; i++) phys_seg_life[i]++;
+       i++;
+       while(i<PSEG_ENTRIES) phys_seg_life[i++]++;
+       return;
 }
-extern inline pgd_t *pgd_alloc(void)
+
+/*
+ * This is only ever called when the sun4c page fault routines run
+ * so we can keep this here as the srmmu code will never get to it.
+ */
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+       unsigned long address, pte_t pte)
 {
-  return (pgd_t *) get_free_page(GFP_KERNEL);
-}
+  unsigned long clr_addr;
+  int segmap;
+
+  segmap = (int) get_segmap(address & SUN4C_REAL_PGDIR_MASK);
+  if(segmap == invalid_segment) {
+    segmap = alloc_sun4c_pseg();
+    put_segmap((address & SUN4C_REAL_PGDIR_MASK), segmap);
+    phys_seg_map[segmap] = PSEG_USED;
+
+    /* We got a segmap, clear all the pte's in it. */
+    for(clr_addr=(address&SUN4C_REAL_PGDIR_MASK); clr_addr<((address&SUN4C_REAL_PGDIR_MASK) + SUN4C_REAL_PGDIR_SIZE); 
+       clr_addr+=PAGE_SIZE)
+           put_pte(clr_addr, 0);
+  }
+
+  /* Do aging */
+  age_sun4c_psegs(segmap);
+  put_pte((address & PAGE_MASK), pte_val(pte));
+  return;
 
-extern pgd_t swapper_pg_dir[1024];
+}
 
 #endif /* !(_SPARC_PGTABLE_H) */
diff --git a/include/asm-sparc/pgtsfmmu.h b/include/asm-sparc/pgtsfmmu.h
new file mode 100644 (file)
index 0000000..482effb
--- /dev/null
@@ -0,0 +1,29 @@
+/* pgtsfmmu.h:  Spitfire V9 MMU support goes here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_PGTSFMMU_H
+#define _SPARC_PGTSFMMU_H
+
+/* Spitfire is four-level.... I think... It also has a seperate TLB for
+ * data and instruction mappings.
+ */
+#define SFMMU_PMD_SHIFT       16
+#define SFMMU_PMD_SIZE        (1UL << SFMMU_PMD_SHIFT)
+#define SFMMU_PMD_MASK        (~(SFMMU_PMD_SIZE-1))
+#define SFMMU_PMD_ALIGN(addr) (((addr)+SFMMU_PMD_SIZE-1)&SFMMU_PMD_MASK)
+
+#define SFMMU_PGDIR_SHIFT     19
+#define SFMMU_PGDIR_SIZE        (1UL << SFMMU_PGDIR_SHIFT)
+#define SFMMU_PGDIR_MASK        (~(SFMMU_PGDIR_SIZE-1))
+#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK)
+
+#define SFMMU_PGMAP_SHIFT     22
+#define SFMMU_PGDIR_SIZE        (1UL << SFMMU_PGDIR_SHIFT)
+#define SFMMU_PGDIR_MASK        (~(SFMMU_PGDIR_SIZE-1))
+#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK)
+
+
+#endif /* !(_SPARC_PGTSFMMU_H) */
+
diff --git a/include/asm-sparc/pgtsrmmu.h b/include/asm-sparc/pgtsrmmu.h
new file mode 100644 (file)
index 0000000..bbffd9a
--- /dev/null
@@ -0,0 +1,424 @@
+/* pgtsrmmu.h:  SRMMU page table defines and code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/page.h>  /* just in case */
+
+#ifndef _SPARC_PGTSRMMU_H
+#define _SPARC_PGTSRMMU_H
+
+#define SRMMU_PAGE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PMD_TABLE_SIZE  0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PGD_TABLE_SIZE  0x400 /* 256 entries, 4 bytes a piece */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define SRMMU_PMD_SHIFT       18
+#define SRMMU_PMD_SIZE        (1UL << SRMMU_PMD_SHIFT)
+#define SRMMU_PMD_MASK        (~(SRMMU_PMD_SIZE-1))
+#define SRMMU_PMD_ALIGN(addr) (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define SRMMU_PGDIR_SHIFT       24
+#define SRMMU_PGDIR_SIZE        (1UL << SRMMU_PGDIR_SHIFT)
+#define SRMMU_PGDIR_MASK        (~(SRMMU_PGDIR_SIZE-1))
+#define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK)
+
+/*
+ * Three-level on SRMMU.
+ */
+
+#define SRMMU_PTRS_PER_PTE    64
+#define SRMMU_PTRS_PER_PMD    64
+#define SRMMU_PTRS_PER_PGD    256
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define SRMMU_VMALLOC_OFFSET  (8*1024*1024)
+#define SRMMU_VMALLOC_START ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1))
+
+/*
+ * Sparc SRMMU page table fields.
+ */
+
+#define _SRMMU_PAGE_VALID      (SRMMU_ET_PTE)
+#define _SRMMU_PMD_VALID       (SRMMU_ET_PTD)
+#define _SRMMU_PGD_VALID       (SRMMU_ET_PTD)
+#define _SRMMU_PAGE_WRITE_USR  (SRMMU_ACC_US_RDWR)
+#define _SRMMU_PAGE_WRITE_KERN (SRMMU_ACC_S_RDWR)
+#define _SRMMU_PAGE_EXEC       (SRMMU_ACC_US_RDEXEC)
+#define _SRMMU_PAGE_RDONLY     (SRMMU_ACC_US_RDONLY)
+#define _SRMMU_PAGE_NOREAD     (SRMMU_ACC_U_ACCDENIED)
+#define _SRMMU_PAGE_NOCACHE    (~SRMMU_PTE_C_MASK)
+#define _SRMMU_PAGE_PRIV       (SRMMU_ACC_S_RDWREXEC)
+#define _SRMMU_PAGE_REF        (SRMMU_PTE_R_MASK)
+#define _SRMMU_PAGE_DIRTY      (SRMMU_PTE_M_MASK)
+#define _SRMMU_PAGE_COW        (SRMMU_ACC_U_RDONLY)
+#define _SRMMU_PAGE_UNCOW      (SRMMU_ACC_US_RDWR)
+
+/* We want the swapper not to swap out page tables, thus dirty and writable
+ * so that the kernel can change the entries as needed. Also valid for
+ * obvious reasons.
+ */
+#define _SRMMU_PAGE_TABLE     (_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_KERN | _SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY)
+#define _SRMMU_PAGE_CHG_MASK  (_SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY | SRMMU_ET_PTE)
+#define _SRMMU_PMD_CHG_MASK   (SRMMU_ET_PTD)
+#define _SRMMU_PGD_CHG_MASK   (SRMMU_ET_PTD)
+
+#define SRMMU_PAGE_NONE       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF)
+#define SRMMU_PAGE_SHARED     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_USR | _SRMMU_PAGE_REF)
+#define SRMMU_PAGE_COPY       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | _SRMMU_PAGE_COW)
+#define SRMMU_PAGE_READONLY   __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | SRMMU_ACC_US_RDONLY)
+#define SRMMU_PAGE_KERNEL     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_PRIV | SRMMU_PTE_C_MASK)
+#define SRMMU_PAGE_INVALID    __pgprot(SRMMU_ET_INVALID)
+
+#define _SRMMU_PAGE_NORMAL(x) __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | (x))
+
+/* SRMMU Register addresses */
+#define SRMMU_CTRL_REG           0x00000000
+#define SRMMU_CTXTBL_PTR         0x00000100
+#define SRMMU_CTX_REG            0x00000200
+#define SRMMU_FAULT_STATUS       0x00000300
+#define SRMMU_FAULT_ADDR         0x00000400
+#define SRMMU_AFAULT_STATUS      0x00000500
+#define SRMMU_AFAULT_ADDR        0x00000600
+
+/* The SRMMU control register fields:
+ * -------------------------------------------------------------------
+ * | IMPL  |  VERS  |    SysControl | PSO | Resv | No Fault | Enable |
+ * -------------------------------------------------------------------
+ * 31    28 27    24 23            8   7    6   2      1        0
+ *
+ * IMPL:  Indicates the implementation of this SRMMU, read-only.
+ * VERS:  The version of this implementation, again read-only.
+ * SysControl:  This is an implementation specific field, the SRMMU
+ *              specification does not define anything for this field.
+ * PSO: This determines whether the memory model as seen by the CPU
+ *      is Partial Store Order (PSO=1) or Total Store Ordering (PSO=0).
+ * Resv: Don't touch these bits ;)
+ * No Fault: If zero, any fault acts as expected where the fault status
+ *           and address registers are updated and a trap hits the CPU.
+ *           When this bit is one, on any fault other than in ASI 9, the
+ *           MMU updates the status and address fault registers but does
+ *           not signal the CPU with a trap.  This is useful to beat
+ *           race conditions in low-level code when we have to throw
+ *           a register window onto the stack in a spill/fill handler
+ *           on multiprocessors.
+ * Enable: If one the MMU is doing translations, if zero the addresses
+ *         given to the bus are pure physical.
+ */
+
+#define SRMMU_CTREG_IMPL_MASK        0xf0000000
+#define SRMMU_CTREG_IMPL_SHIFT       28
+#define SRMMU_CTREG_VERS_MASK        0x0f000000
+#define SRMMU_CTREG_VERS_SHIFT       24
+#define SRMMU_CTREG_SYSCNTRL_MASK    0x00ffff00
+#define SRMMU_CTREG_SYSCNTRL_SHIFT   8
+#define SRMMU_CTREG_PSO_MASK         0x00000080
+#define SRMMU_CTREG_PSO_SHIFT        7
+#define SRMMU_CTREG_RESV_MASK        0x0000007c
+#define SRMMU_CTREG_RESV_SHIFT       2
+#define SRMMU_CTREG_NOFAULT_MASK     0x00000002
+#define SRMMU_CTREG_NOFAULT_SHIFT    1
+#define SRMMU_CTREG_ENABLE_MASK      0x00000001
+#define SRMMU_CTREG_ENABLE_SHIFT     0
+
+/* Get the MMU control register */
+extern inline unsigned int srmmu_get_mmureg(void)
+{
+        register unsigned int retval;
+       __asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
+                            "=r" (retval) :
+                            "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+/* Set the MMU control register */
+extern inline void srmmu_set_mmureg(unsigned long regval)
+{
+       __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
+                            "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
+
+       return;
+}
+
+/* The SRMMU Context Table Pointer Register:
+ * ---------------------------------
+ * |  Context Table Pointer | Resv |
+ * ---------------------------------
+ * 31                      2 1    0
+ *
+ * This is where the MMU goes to in physical RAM to fetch the
+ * elements in the context table.  The non-Resv bits of this
+ * address appear in bits 6-35 of the physical bus during miss
+ * processing, then indexed by the value in the Context Register.
+ * This table must be aligned on a boundary equal to the size of
+ * the table, we provide a nice macro for doing this based upon
+ * the significant bits in the context register.
+ */
+#define SRMMU_CTP_ADDR_MASK          0xfffffffc
+#define SRMMU_CTP_ADDR_PADDR_SHIFT   0x4
+#define SRMMU_CTP_RESV_MASK          0x00000003
+
+#define SRMMU_SIGBITS_TO_ALIGNMENT(numbits)  ((1 << (numbits + 2)))
+
+
+/* Set the address of the context table.  You pass this routine
+ * the physical address, we do the magic shifting for you.
+ */
+extern inline void srmmu_set_ctable_ptr(unsigned long paddr)
+{
+       unsigned long ctp;
+
+       ctp = (paddr >> SRMMU_CTP_ADDR_PADDR_SHIFT);
+       ctp &= SRMMU_CTP_ADDR_MASK;
+
+       __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+                            "r" (ctp), "r" (SRMMU_CTXTBL_PTR),
+                            "i" (ASI_M_MMUREGS) :
+                            "memory");
+       return;
+}
+
+
+/* Get the address of the context table.  We return the physical
+ * address of the table, again we do the shifting here.
+ */
+extern inline unsigned long srmmu_get_ctable_ptr(void)
+{
+       register unsigned int retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_CTXTBL_PTR),
+                            "i" (ASI_M_MMUREGS));
+
+       retval &= SRMMU_CTP_ADDR_MASK;
+       retval = (retval << SRMMU_CTP_ADDR_PADDR_SHIFT);
+       return retval;
+}
+
+/* Set the context on an SRMMU */
+extern inline void srmmu_set_context(int context)
+{
+       __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+                            "r" (context), "r" (SRMMU_CTX_REG),
+                            "i" (ASI_M_MMUREGS) : "memory");
+       return;
+}
+
+/* Get the context on an SRMMU */
+extern inline int srmmu_get_context(void)
+{
+       register int retval;
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_CTX_REG),
+                            "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+/* SRMMU diagnostic register:
+ * --------------------------------------------------------
+ * |   Virtual Address   |   PDC entry   | DiagReg | Resv |
+ * --------------------------------------------------------
+ * 31                  12 11            4 3       2 1    0
+ *
+ * An SRMMU implementation has the choice of providing this register
+ * and I don't know much about it.
+ */
+
+#define SRMMU_DIAG_VADDR_MASK        0xfffff000
+#define SRMMU_DIAG_PDC_MASK          0x00000ff0
+#define SRMMU_DIAG_REG_MASK          0x0000000c
+#define SRMMU_DIAG_RESV_MASK         0x00000003
+
+/* SRMMU Fault Status Register:
+ * -----------------------------------------------------------
+ * | Reserved          | EBE  |  L  |  AT  |  FT  | FAV | OW |
+ * -----------------------------------------------------------
+ *  31               18 17  10  9  8 7    5  4   2   1     0
+ *
+ * WARNING!!! On certain VERY BROKEN Viking Sun4d modules this register
+ * is complete TOAST!  During a fault you cannot trust the values
+ * contained in this register, you must calculate them yourself
+ * by first using the trap program counter to decode the
+ * instruction the code tried to execute (ie. load or store) and
+ * the address they tried to access.  I think the Fault Virtual
+ * Address register may be ok on these chips, but who knows. Grrr.
+ *
+ * Reserved:  These bits must be zero.
+ * EBE: External bus error bits, implementation dependant (at least
+ *      we know what the bits mean on sun4d Viking modules) ;)
+ * L: The level in tree traversal at which the fault occured. The
+ *    values are... 0 = context table
+ *                  1 = level-1 page table
+ *                  2 = level-2 page table
+ *                  3 = level-3 page table
+ * AT: Access type field. This is decoded as follows...
+ *     0 -- Load from user data space
+ *     1 -- Load from supervisor data space
+ *     2 -- Read/Execute from user instruction space
+ *     3 -- Read/Execute from supervisor instruction space
+ *     4 -- Store to user data space
+ *     5 -- Store to supervisor data space
+ *     6 -- Store to user instruction space
+ *     7 -- Store to supervisor instruction space (emacs does this)
+ *     On the Viking --  TOAST!
+ * FT:  This is the fault type field.  It is used to determine what was
+ *      wrong in the attempted translation. It can be one of...
+ *     0 -- None
+ *     1 -- Invalid address error
+ *     2 -- Protection violation error
+ *     3 -- Priviledge violation error
+ *     4 -- Translation error (your tables are fucked up)
+ *     5 -- Bus access error (you lose)
+ *     6 -- Internal error (might as well have a Viking)
+ *     7 -- Reserved (don't touch)
+ * FAV: Fault Address Valid bit.  When set to one the fault address
+ *      register contents are valid.  It need not be valid for text
+ *      faults as the trapped PC tells us this anyway.
+ * OW: The Overwrite Bit, if set to one, this register has been
+ *     written to more than once by the hardware since software did
+ *     a read.  This mean multiple faults have occurred and you have
+ *     to a manual page table tree traversal to continue the handling
+ *     of the first fault. And on the Viking module....
+ *
+ * The Fault Address Register is just a 32-bit register representing the
+ * virtual address which caused the fault.  It's validity is determined
+ * by the following equation:
+ * if(module==VIKING || FSR.FAV==0) forget_it();
+ * It's ok for the FAV to be invalid for a text fault because we can
+ * use the trapped program counter, however for a data fault we are SOL.
+ * I'll probably have to write a workaround for this situation too ;-(
+ */
+
+#define SRMMU_FSR_RESV_MASK      0xfffc0000  /* Reserved bits */
+#define SRMMU_FSR_EBE_MASK       0x0003fc00  /* External Bus Error bits */
+#define SRMMU_FSR_EBE_BERR       0x00000400  /* Bus Error */
+#define SRMMU_FSR_EBE_BTIMEO     0x00000800  /* Bus Time Out */
+#define SRMMU_FSR_EBE_UNCOR      0x00001000  /* Uncorrectable Error */
+#define SRMMU_FSR_EBE_UNDEF      0x00002000  /* Undefined Error */
+#define SRMMU_FSR_EBE_PARITY     0x00004000  /* Parity error */
+#define SRMMU_FSR_EBE_TPARITY    0x00006000  /* Tsunami parity error */
+#define SRMMU_FSR_EBE_SBUF       0x00008000  /* Store Buffer error */
+#define SRMMU_FSR_EBE_CSA        0x00010000  /* Control space access error (bad ASI) */
+#define SRMMU_FSR_EBE_EMRT       0x00020000  /* Viking Emergency Response Team */
+#define SRMMU_FSR_L_MASK         0x00000300  /* Fault level bits */
+#define SRMMU_FSR_L_CTABLE       0x00000000  /* Context table level flt/err */
+#define SRMMU_FSR_L_ONE          0x00000100  /* Level1 ptable flt/err */
+#define SRMMU_FSR_L_TWO          0x00000200  /* Level2 ptable flt/err */
+#define SRMMU_FSR_L_THREE        0x00000300  /* Level3 ptable flt/err */
+#define SRMMU_FSR_AT_MASK        0x000000e0  /* Access Type bits */
+#define SRMMU_FSR_AT_LUD         0x00000000  /* Load from User Data space */
+#define SRMMU_FSR_AT_LSD         0x00000020  /* What I'll need after writing this code */
+#define SRMMU_FSR_AT_RXUI        0x00000040  /* Read/Execute from user text */
+#define SRMMU_FSR_AT_RXSI        0x00000060  /* Read/Execute from supv text */
+#define SRMMU_FSR_AT_SUD         0x00000080  /* Store to user data space */
+#define SRMMU_FSR_AT_SSD         0x000000a0  /* Store to supv data space */
+#define SRMMU_FSR_AT_SUI         0x000000c0  /* Store to user text */
+#define SRMMU_FSR_AT_SSI         0x000000e0  /* Store to supv text */
+#define SRMMU_FSR_FT_MASK        0x0000001c  /* Fault Type bits */
+#define SRMMU_FSR_FT_NONE        0x00000000  /* No fault occurred */
+#define SRMMU_FSR_FT_IADDR       0x00000002  /* Invalid address */
+#define SRMMU_FSR_FT_PROT        0x00000004  /* Protection violation */
+#define SRMMU_FSR_FT_PRIV        0x00000008  /* Privilege violation */
+#define SRMMU_FSR_FT_TRANS       0x0000000a  /* Translation error */
+#define SRMMU_FSR_FT_BACC        0x0000000c  /* Bus Access error */
+#define SRMMU_FSR_FT_IACC        0x0000000e  /* Internal error */
+#define SRMMU_FSR_FT_RESV        0x00000010  /* Reserved, should not get this */
+#define SRMMU_FSR_FAV_MASK       0x00000002  /* Fault Address Valid bits */
+#define SRMMU_FSR_OW_MASK        0x00000001  /* SFSR OverWritten bits */
+
+/* Read the Fault Status Register on the SRMMU */
+extern inline unsigned int srmmu_get_fstatus(void)
+{
+       register unsigned int retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+/* Read the Fault Address Register on the SRMMU */
+extern inline unsigned int srmmu_get_faddr(void)
+{
+       register unsigned int retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_FAULT_ADDR), "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+/* SRMMU Asynchronous Fault Status Register:
+ * -----------------------------------------
+ * |  RESERVED |UCE|BTO|BERR|RSV|HFADDR|AFO|
+ * -----------------------------------------
+ *  31       13  12  11  10  9-8  7-4     0
+ *
+ * UCE: UnCorrectable Error
+ * BTO: Bus TimeOut
+ * BERR: Genreic Bus Error
+ * HFADDR: High 4 bits of the faulting address
+ * AFO: Asynchronous Fault Occurred
+ */
+#define SRMMU_AFSR_RESVMASK  0xffffe000
+#define SRMMU_AFSR_UCE       0x00001000
+#define SRMMU_AFSR_BTO       0x00000800
+#define SRMMU_AFSR_BERR      0x00000400
+#define SRMMU_AFSR_HFADDR    0x000000f0
+#define SRMMU_AFSR_AFO       0x00000001
+
+/* Read the asynchronous fault register */
+extern inline unsigned int srmmu_get_afstatus(void)
+{
+       register unsigned int retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_AFAULT_STATUS), "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+/* Read the Asynchronous Fault Address Register on the SRMMU */
+extern inline unsigned int srmmu_get_afaddr(void)
+{
+       register unsigned int retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (SRMMU_AFAULT_ADDR), "i" (ASI_M_MMUREGS));
+       return retval;
+}
+
+
+/* Flush the entire TLB cache on the SRMMU. */
+extern inline void srmmu_flush_whole_tlb(void)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+                            "r" (0x400),        /* Flush entire TLB!! */
+                            "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+       return;
+}
+
+/* Probe for an entry in the page-tables of the SRMMU. */
+extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
+{
+       unsigned long retval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (retval) :
+                            "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+
+       return retval;
+}
+
+#endif /* !(_SPARC_PGTSRMMU_H) */
diff --git a/include/asm-sparc/pgtsun4.h b/include/asm-sparc/pgtsun4.h
new file mode 100644 (file)
index 0000000..9547774
--- /dev/null
@@ -0,0 +1,9 @@
+/* pgtsun4.c:  Regular Sun4 MMU support goes in here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_PGTSUN4_H
+#define _SPARC_PGTSUN4_H
+
+#endif /* !(_SPARC_PGTSUN4_H) */
diff --git a/include/asm-sparc/pgtsun4c.h b/include/asm-sparc/pgtsun4c.h
new file mode 100644 (file)
index 0000000..ca6f2e5
--- /dev/null
@@ -0,0 +1,125 @@
+/* pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_PGTSUN4C_H
+#define _SPARC_PGTSUN4C_H
+
+#define SUN4C_PAGE_TABLE_SIZE 0x100   /* 64 entries, 4 bytes a piece */
+
+/* NOTE:  Now we put the free page pool and the page structures
+ *        up in high memory above the kernel image which itself
+ *        starts at KERNBASE.  Also note PAGE_OFFSET in page.h
+ *        This is just like what Linus does on the ALPHA.
+ */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define SUN4C_PMD_SHIFT       22
+#define SUN4C_PMD_SIZE        (1UL << SUN4C_PMD_SHIFT)
+#define SUN4C_PMD_MASK        (~(SUN4C_PMD_SIZE-1))
+#define SUN4C_PMD_ALIGN(addr) (((addr)+SUN4C_PMD_SIZE-1)&SUN4C_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define SUN4C_PGDIR_SHIFT       22
+#define SUN4C_PGDIR_SIZE        (1UL << SUN4C_PGDIR_SHIFT)
+#define SUN4C_PGDIR_MASK        (~(SUN4C_PGDIR_SIZE-1))
+#define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK)
+
+/* To make sun4c_paging_init() happy, I provide the following macros. */
+#define SUN4C_REAL_PGDIR_SHIFT  18
+#define SUN4C_REAL_PGDIR_SIZE        (1UL << SUN4C_REAL_PGDIR_SHIFT)
+#define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
+#define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
+
+/*
+ * To be efficient, and not have to worry about allocating such
+ * a huge pgd, we make the kernel sun4c tables each hold 1024
+ * entries and the pgd similarly.
+ */
+
+#define SUN4C_PTRS_PER_PTE    1024
+#define SUN4C_PTRS_PER_PMD    1
+#define SUN4C_PTRS_PER_PGD    1024
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define SUN4C_VMALLOC_OFFSET  (8*1024*1024)
+#define SUN4C_VMALLOC_START ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1))
+
+/*
+ * Sparc SUN4C page table fields. (for now, basically the same as the i386)
+ */
+
+#define _SUN4C_PAGE_VALID     0x80000000   /* valid page */
+#define _SUN4C_PAGE_WRITE     0x40000000   /* can be written to */
+#define _SUN4C_PAGE_USER      0x00000000   /* User page */
+#define _SUN4C_PAGE_NOCACHE   0x10000000   /* non-cacheable page */
+#define _SUN4C_PAGE_PRIV      0x20000000   /* bit to signify privileged page */
+#define _SUN4C_PAGE_REF       0x02000000   /* Page has been accessed/referenced */
+#define _SUN4C_PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
+#define _SUN4C_PAGE_COW       0x00800000   /* COW page */
+
+/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be
+ * read in a load, and executed as code automatically. Although, the memory 
+ * fault hardware does make a distinction between data-read faults and 
+ * insn-read faults which is determined by which trap happened plus magic
+ * sync/async fault register values which must be checked in the actual
+ * fault handler.
+ */
+
+#define _SUN4C_PFN_MASK       0x0000ffff    /* just the page frame number */
+#define _SUN4C_MMU_MASK       0xffff0000    /* just the non-page pte bits */
+
+/* The following are for pgd/pmd's */
+#define _SUN4C_PGD_PFN_MASK   0x00ffffff    /* bits to hold page tables address */
+#define _SUN4C_PGD_MMU_MASK   0xff000000    /* pgd/pfn protection bits          */
+#define _SUN4C_PGD_PAGE_SHIFT 8             /* bits to shift to obtain address  */
+
+/* We want the swapper not to swap out page tables, thus dirty and writable
+ * so that the kernel can change the entries as needed. Also valid for
+ * obvious reasons.
+ */
+#define _SUN4C_PAGE_TABLE     (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_NOCACHE) /* No cache for now */
+#define _SUN4C_PAGE_CHG_MASK  (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PFN_MASK)
+#define _SUN4C_PGD_CHG_MASK   (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PGD_PFN_MASK)
+
+#define SUN4C_PAGE_NONE       __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_SHARED     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_COPY       __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | _SUN4C_PAGE_COW)
+#define SUN4C_PAGE_READONLY   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_KERNEL     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_NOCACHE)
+#define SUN4C_PAGE_INVALID    __pgprot(0)
+
+#define _SUN4C_PAGE_NORMAL(x) __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | (x))
+
+/* The Sun4c mmu physical segment map allocation data structure.
+ * For each physical segmap available on the mmu we have one entry,
+ * 127 on the sun4c (except SparcStation 2's which seem to have 255)
+ * and 512 on the sun4.  Each segmap can be in various stages of
+ * allocation.
+ */
+#define PSEG_ENTRIES  513     /* We allocate 513 entries for simplicity */
+extern unsigned int phys_seg_map[PSEG_ENTRIES];
+extern unsigned int phys_seg_life[PSEG_ENTRIES];
+
+/* for phys_seg_map entries */
+#define PSEG_AVL      0x0     /* Physical segment is available/free */
+#define PSEG_USED     0x1     /* A segmap currently being used */
+#define PSEG_RSV      0x2     /* This segmap is reserved (used for proms addr space) */
+#define PSEG_KERNEL   0x3     /* This is a kernel hard segment, cannot deallocate */
+
+/* for phys_seg_life entries */
+/* The idea is, every call to update_mmu_cache we increment all the life
+ * counters.  When we re-allocate or allocate a physical segment for the
+ * first time we set the phys_seg_life entry to PSEG_BORN.  Also, when we
+ * fill a pte for a segment already loaded we *decrease* the life count
+ * by two for that segment.  We'll see how this works.
+ */
+#define PSEG_BORN     0x00     /* Just allocated */
+
+#endif /* !(_SPARC_PGTSUN4C_H) */
index 7e18bfb2f61bf017493ab71837381e49eb319ce5..7e0af9dbc7a36112218a074f89e75d73e9243977 100644 (file)
@@ -6,10 +6,14 @@
 #ifndef __ASM_SPARC_PROCESSOR_H
 #define __ASM_SPARC_PROCESSOR_H
 
+#include <linux/sched.h>  /* For intr_count */
+
+#include <asm/ptrace.h>   /* For pt_regs declaration */
+
 /*
  * Bus types
  */
-#define EISA_bus 1
+#define EISA_bus 0
 #define EISA_bus__is_a_macro /* for versions in ksyms.c */
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 /*
  * Write Protection works right in supervisor mode on the Sparc
  */
-
+#if 0  /* Let's try this out ;) */
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
+#else
+extern char wp_works_ok;
+#endif
 
 /*
  * User space process size: 3GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  *
- * "this is gonna have to change to 1gig for the sparc" - David S. Miller
+ * With the way identity mapping works on the sun4c, this is the best
+ * value to use.
+ *
+ * This has to be looked into for a unified sun4c/sun4m task size.
  */
-#define TASK_SIZE      (0xC0000000UL)
+#define TASK_SIZE      (0xC000000UL)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
  */
 #define IO_BITMAP_SIZE 32
 
-/* The first five entries here MUST be the first four. This allows me to
+/* The first four entries here MUST be the first four. This allows me to
  * do %lo(offset) loads and stores in entry.S. See TRAP_WIN_CLEAN to see
  * why.
  */
@@ -43,61 +53,32 @@ struct thread_struct {
        unsigned long uwindows;       /* how many user windows are in the set */
        unsigned long wim;            /* user's window invalid mask */
        unsigned long w_saved;        /* how many windows saved in reg_window[] */
-       unsigned long ksp;          /* kernel stack pointer */
-       unsigned long usp;          /* user's sp, throw reg windows here */
-       unsigned long psr;          /* save for condition codes */
-       unsigned long reg_window[16*24];
-       unsigned long cr3;          /* why changed from ptbr? */
-       unsigned int pcc;
-       unsigned int asn;
-       unsigned long unique;
-       unsigned long flags;
-       unsigned long res1, res2;
-       unsigned long pc;           /* program counter */
-       unsigned long npc;          /* next program counter */
+       unsigned long ksp;            /* kernel stack pointer */
+       unsigned long usp;            /* user's sp, throw reg windows here */
+       unsigned long psr;            /* save for condition codes */
+       unsigned long pc;             /* program counter */
+       unsigned long npc;            /* next program counter */
+       unsigned long yreg;
+       unsigned long align;          /* to get 8-byte alignment  XXX  */
+       unsigned long reg_window[16];
+       unsigned long pgd_ptr;
+       int context;                  /* The context allocated to this thread */
 
 /* 8 local registers + 8 in registers * 24 register windows.
- * Most sparcs I know of only have 8 windows implemented,
+ * Most sparcs I know of only have 7 or 8 windows implemented,
  * we determine how many at boot time and store that value
  * in nwindows.
  */
-       unsigned long globl_regs[8];  /* global regs need to be saved too */
-       unsigned long yreg;
        unsigned long float_regs[64]; /* V8 and below have 32, V9 has 64 */
 };
 
-#define INIT_MMAP { &init_task, 0x0, 0x40000000, \
-                     PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_task, (PAGE_OFFSET), (0xff000000UL), \
+                   0x0 , VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  { \
-       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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+       (long) &swapper_pg_dir, -1,  \
         { 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, \
@@ -109,16 +90,14 @@ struct thread_struct {
  * spill if things don't go right (bad user stack pointer). In reality
  * it is not per-process per se, it just sits in the kernel stack while
  * the current process is in a handler then it is basically forgotten
- * about.
+ * about the next time flow control goes back to that process.
  */
 
-struct thread_frame {
-  unsigned int thr_psr;
-  unsigned int thr_pc;
-  unsigned int thr_npc;
-  unsigned int thr_y;
-  unsigned int thr_globals[8];
-  unsigned int thr_outs[8];
+/* Sparc stack save area allocated for each save, not very exciting. */
+struct sparc_save_stack {
+  unsigned int locals[8];
+  unsigned int ins[8];
+  unsigned int padd[8];
 };
 
 /*
@@ -128,28 +107,36 @@ struct thread_frame {
  */
 extern inline void start_bh_atomic(void)
 {
-       unsigned long dummy, psr;
-       __asm__ __volatile__("rd %%psr, %2\n\t"
-                            "wr %2, 0x20, %%psr\n\t"  /* disable traps */
-                            "ld %1,%0\n\t"
-                            "add %0,1,%0\n\t"
-                            "st %0,%1\n\t"
-                            "wr %2, 0x0, %%psr\n\t"   /* enable traps */
-                            : "=r" (dummy), "=m" (intr_count)
-                            : "0" (0), "r" (psr=0));
+       __asm__ __volatile__("rd %%psr, %%g2\n\t"
+                            "wr %%g2, 0x20, %%psr\n\t"  /* disable traps */
+                            "ld %0,%%g3\n\t"
+                            "add %%g3,1,%%g3\n\t"
+                            "st %%g3,%0\n\t"
+                            "wr %%g2, 0x0, %%psr\n\t"   /* enable traps */
+                            : "=m" (intr_count)
+                            : : "g2", "g3", "memory");
 }
 
 extern inline void end_bh_atomic(void)
 {
-       unsigned long dummy, psr;
-       __asm__ __volatile__("rd %%psr, %2\n\t"
-                            "wr %2, 0x20, %%psr\n\t"
-                            "ld %1,%0\n\t"
-                            "sub %0,1,%0\n\t"
-                            "st %0,%1\n\t"
-                            "wr %2, 0x0, %%psr\n\t"
-                            : "=r" (dummy), "=m" (intr_count)
-                            : "0" (0), "r" (psr=0));
+       __asm__ __volatile__("rd %%psr, %%g2\n\t"
+                            "wr %%g2, 0x20, %%psr\n\t"
+                            "ld %0,%%g3\n\t"
+                            "sub %%g3,1,%%g3\n\t"
+                            "st %%g3,%0\n\t"
+                            "wr %%g2, 0x0, %%psr\n\t"
+                            : "=m" (intr_count)
+                            : : "g2", "g3", "memory");
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+static inline void start_thread(struct pt_regs * regs, unsigned long sp,
+                               unsigned long fp)
+{
+  printk("start_thread called, halting..n");
+  halt();
 }
 
 #endif /* __ASM_SPARC_PROCESSOR_H */
index 60b9757ad9d5e3b50fe3ec1da15dbe5923fa5f27..22c711ec715105019be26de1e6640099bb3b489c 100644 (file)
@@ -46,6 +46,42 @@ bits| 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6  | 5  |  4-0  |
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#ifndef __ASSEMBLY__
+/* Get the %psr register. */
+extern inline unsigned int get_psr(void)
+{
+       unsigned int psr;
+       __asm__ __volatile__("rd %%psr, %0\n\t" :
+                            "=r" (psr));
+       return psr;
+}
+
+extern inline void put_psr(unsigned int new_psr)
+{
+  __asm__("wr %0, 0x0, %%psr\n\t" : :
+         "r" (new_psr));
+}
+
+/* Get the %fsr register.  Be careful, make sure the floating point
+ * enable bit is set in the %psr when you execute this or you will
+ * incur a trap.
+ */
+
+extern unsigned int fsr_storage;
+
+extern inline unsigned int get_fsr(void)
+{
+       unsigned int fsr = 0;
+
+       __asm__ __volatile__("st %%fsr, %1\n\t"
+                            "ld %1, %0\n\t" :
+                            "=r" (fsr) :
+                            "m" (fsr_storage));
+       return fsr;
+}
+
+#endif /* !(__ASSEMBLY__) */
+
 #endif /* !(__LINUX_SPARC_V8) */
 
 #ifdef __LINUX_SPARC_V9
@@ -80,6 +116,21 @@ bits |   9   |  8  |  7-6 |  5  |  4  |  3 |   2  |  1 |  0 |
 #define PSTATE_CLE   0x200   /* Current Little Endian         */
 
 
+extern inline unsigned int get_v9_pstate(void)
+{
+       unsigned int pstate;
+       __asm__ __volatile__("rdpr %pstate, %0\n\t" :
+                            "=r" (pstate));
+       return pstate;
+}
+
+extern inline void put_v9_pstate(unsigned int pstate)
+{
+       __asm__ __volatile__("wrpr %0, 0x0, %pstate\n\t" : :
+                            "r" (pstate));
+       return;
+}
+
 /* The Version Register holds vendor information for the chip:
 
     ---------------------------------------------------------------------------
@@ -94,6 +145,38 @@ bits|  63-48       |   47-32        | 31-24|   23-16  | 15-8  | 7-5  |  4-0   |
 #define VERS_MASK    0x0000000ff0000000     /* impl. dep. chip mask revision */
 #define VERS_MANUF   0xffff000000000000     /* Manufacturer ID code          */
 
+extern inline unsigned int get_v9_version(void)
+{
+       unsigned int vers;
+       __asm__ __volatile__("rdpr %ver, %0\n\t" :
+                            "=r" (vers));
+       return vers;
+}
+
+extern inline unsigned int get_v9_tstate(void)
+{
+       unsigned int tstate;
+       __asm__ __volatile__("rdpr %tstate, %0\n\t" :
+                            "=r" (pstate));
+       return tstate;
+}
+
+extern inline unsigned int get_v9_pil(void)
+{
+       unsigned int pil;
+       __asm__ __volatile__("rdpr %pil, %0\n\t" :
+                            "=r" (pstate));
+       return pil;
+}
+
+extern inline void put_v9_pil(unsigned int pil)
+{
+       __asm__ __volatile__("wrpr %0, 0x0, %pil\n\t" : :
+                            "r" (pil));
+       return;
+}
+
+
 #endif /* !(__LINUX_SPARC_V9) */
 
 #endif /* !(__LINUX_SPARC_PSR_H) */
index 70fb8d5df9f38111dcd0359f6e3cf171d711d1b2..0ac7acc7152cb00edfd52cbe8dfa44f6162e7852 100644 (file)
    stack during a system call. */
 
 struct pt_regs {
-       unsigned long ps;    /* previous supervisor, same as alpha I believe */
+       unsigned long psr;   /* for condition codes */
        unsigned long pc;    /* current and next program counter */
        unsigned long npc;
-       unsigned long sp;    /* stack and frame pointer */
-       unsigned long fp;
-       unsigned long psr;   /* for condition codes */
-       unsigned long nuwin; /* number of user windows */
+       unsigned long y;
        /* not sure yet whether all regs are necessary
         * but this is how it is traditionally done on the sparc.
         */
-       unsigned long u_regs[24*16];
-       unsigned long f_regs[64];    /* yuck yuck yuck */
+       unsigned long u_regs[16]; /* globals and ins */
 };
 
 #ifdef __KERNEL__
-#define user_mode(regs) (0x0)  /* if previous supervisor is 0, came from user */
+/* if previous supervisor is 0, came from user */
+#define user_mode(regs) (0x0)
 extern void show_regs(struct pt_regs *);
 #endif
 
diff --git a/include/asm-sparc/ross.h b/include/asm-sparc/ross.h
new file mode 100644 (file)
index 0000000..70df7b9
--- /dev/null
@@ -0,0 +1,151 @@
+/* ross.h: Ross module specific definitions and defines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ROSS_H
+#define _SPARC_ROSS_H
+
+/* Ross made Hypersparcs have a %psr 'impl' field of '0001'.  The 'vers'
+ * field has '1111'.
+ */
+
+/* The MMU control register fields on the HyperSparc.
+ *
+ * -----------------------------------------------------------------
+ * |implvers| RSV |CWR|SE|WBE| MID |BM| C|CS|MR|CM|RSV|CE|RSV|NF|ME|
+ * -----------------------------------------------------------------
+ *  31    24 23-22 21  20  19 18-15 14 13 12 11 10  9   8 7-2  1  0
+ *
+ * Phew, lots of fields there ;-)
+ *
+ * CWR: Cache Wrapping Enabled, if one cache wrapping is on.
+ * SE: Snoop Enable, turns on bus snooping for cache activity if one.
+ * WBE: Write Buffer Enable, one turns it on.
+ * MID: The ModuleID of the chip for MBus transactions.
+ * BM: Boot-Mode. One indicates the MMU is in boot mode.
+ * C: Indicates whether accesses are cachable while the MMU is
+ *    disabled.
+ * CS: Cache Size -- 0 = 128k, 1 = 256k
+ * MR: Memory Reflection, one indicates that the memory bus connected
+ *     to the MBus supports memory reflection.
+ * CM: Cache Mode -- 0 = write-through, 1 = copy-back
+ * CE: Cache Enable -- 0 = no caching, 1 = cache is on
+ * NF: No Fault -- 0 = faults trap the CPU from supervisor mode
+ *                 1 = faults from supervisor mode do not generate traps
+ * ME: MMU Enable -- 0 = MMU is off, 1 = MMU is on
+ */
+
+#define HYPERSPARC_CWENABLE   0x00200000
+#define HYPERSPARC_SBENABLE   0x00100000
+#define HYPERSPARC_WBENABLE   0x00080000
+#define HYPERSPARC_MIDMASK    0x00078000
+#define HYPERSPARC_BMODE      0x00004000
+#define HYPERSPARC_ACENABLE   0x00002000
+#define HYPERSPARC_CSIZE      0x00001000
+#define HYPERSPARC_MRFLCT     0x00000800
+#define HYPERSPARC_CMODE      0x00000400
+#define HYPERSPARC_CENABLE    0x00000100
+#define HYPERSPARC_NFAULT     0x00000002
+#define HYPERSPARC_MENABLE    0x00000001
+
+/* Flushes which clear out only the on-chip Ross HyperSparc ICACHE. */
+extern inline void flush_i_page(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_IFLUSH_PAGE) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_i_seg(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_IFLUSH_SEG) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_i_region(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_IFLUSH_REGION) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_i_ctx(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_IFLUSH_CTX) :
+                            "memory");
+       return;
+}
+
+extern inline void flush_i_user(unsigned int addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_IFLUSH_USER) :
+                            "memory");
+       return;
+}
+
+/* Finally, flush the entire ICACHE. */
+extern inline void flush_whole_icache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_FLUSH_IWHOLE));
+       return;
+}
+
+
+/* The ICCR instruction cache register on the HyperSparc.
+ *
+ * -----------------------------------------------
+ * |                                 | FTD | IDC |
+ * -----------------------------------------------
+ *  31                                  1     0
+ *
+ * This register is accessed using the V8 'wrasr' and 'rdasr'
+ * opcodes, since not all assemblers understand them and those
+ * that do use different semantics I will just hard code the
+ * instruction with a '.word' statement.
+ *
+ * FTD:  If set to one flush instructions executed during an
+ *       instruction cache hit occurs, the corresponding line
+ *       for said cache-hit is invalidated.  If FTD is zero,
+ *       an unimplemented 'flush' trap will occur when any
+ *       flush is executed by the processor.
+ *
+ * ICE:  If set to one, the instruction cache is enabled.  If
+ *       zero, the cache will not be used for instruction fetches.
+ *
+ * All other bits are read as zeros, and writes to them have no
+ * effect.
+ */
+
+extern inline unsigned int get_ross_icr(void)
+{
+       unsigned int icreg;
+
+       __asm__ __volatile__(".word 0xbf402000\n\t" : /* rd %iccr, %g1 */
+                            "=r" (icreg) : :
+                            "g1", "memory");
+
+       return icreg;
+}
+
+extern inline void put_ross_icr(unsigned int icreg)
+{
+       __asm__ __volatile__("or %%g0, %0, %%g1\n\t"
+                            ".word 0xbf802000\n\t" /* wr %g1, 0x0, %iccr */
+                            "nop\n\t"
+                            "nop\n\t"
+                            "nop\n\t" : : 
+                            "r" (icreg) :
+                            "g1", "memory");
+
+       return;
+}
+
+#endif /* !(_SPARC_ROSS_H) */
diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h
new file mode 100644 (file)
index 0000000..9aebfd3
--- /dev/null
@@ -0,0 +1,76 @@
+/* sbus.h:  Defines for the Sun SBus.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SBUS_H
+#define _SPARC_SBUS_H
+
+#include <asm/openprom.h>  /* For linux_prom_registers and linux_prom_irqs */
+
+/* We scan which devices are on the SBus using the PROM node device
+ * tree.  SBus devices are described in two different ways.  You can
+ * either get an absolute address at which to access the device, or
+ * you can get a SBus 'slot' number and an offset within that slot.
+ */
+
+/* The base address at which to calculate device OBIO addresses. */
+#define SUN_SBUS_BVADDR        0xf8000000
+#define SBUS_OFF_MASK          0x01ffffff
+
+/* These routines are used to calculate device address from slot
+ * numbers + offsets, and vice versa.
+ */
+
+extern inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
+{
+  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
+}
+
+extern inline int sbus_dev_slot(unsigned long dev_addr)
+{
+  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
+}
+
+extern inline unsigned long sbus_dev_offset(unsigned long dev_addr)
+{
+  return (unsigned long) (((dev_addr)-SUN_SBUS_BVADDR)&SBUS_OFF_MASK);
+}
+
+/* Handy macro */
+#define STRUCT_ALIGN(addr) ((addr+7)&(~7))
+
+/* Linus SBUS device tables */
+struct linux_sbus_device {
+  struct linux_sbus_device *next;      /* next device on this SBus or null */
+  int prom_node;                       /* PROM device tree node for this device */
+  char *prom_name;                     /* PROM device name */
+  char *linux_name;                    /* Name used internally by Linux */
+
+  /* device register addresses */
+  struct linux_prom_registers reg_addrs[PROMREG_MAX];
+  int num_registers;
+
+  /* List of IRQ's this device uses. */
+  struct linux_prom_irqs irqs[PROMINTR_MAX];
+  int num_irqs;
+
+  unsigned long sbus_addr;             /* Absolute base address for device. */
+  unsigned long sbus_vaddrs[PROMVADDR_MAX];
+  unsigned long num_vaddrs;
+  unsigned long offset;                /* Offset given by PROM */
+  int slot;                            /* Device slot number */
+};
+
+/* This struct describes the SBus-es found on this machine. */
+struct linux_sbus {
+  struct linux_sbus *next;             /* next SBus, if more than one SBus */
+  struct linux_sbus_device *devices;   /* Link to devices on this SBus */
+  int prom_node;                       /* PROM device tree node for this SBus */
+  char *prom_name;                     /* Usually "sbus" */
+  int clock_freq;                 /* Speed of this SBus */
+};
+
+extern struct linux_sbus Linux_SBus;
+
+#endif /* !(_SPARC_SBUS_H) */
index 27489b3e519d9f5ce3020ca70450b7bcf4029c19..06937b6a7c69ced0da6d480f0678bad220b3a9c7 100644 (file)
@@ -82,6 +82,10 @@ static inline unsigned long get_ds(void)
 
 static inline void set_fs(unsigned long val)
 {
+  unsigned long foo;
+  foo = val;
+
+  return;
 }
 
 #endif /* _ASM_SEGMENT_H */
diff --git a/include/asm-sparc/smpprim.h b/include/asm-sparc/smpprim.h
new file mode 100644 (file)
index 0000000..db1cdda
--- /dev/null
@@ -0,0 +1,53 @@
+/*  smpprim.h:  SMP locking primitives on the Sparc
+ *
+ *  God knows we won't be actually using this code for some time
+ *  but I thought I'd write it since I knew how.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SMPPRIM_H
+#define __SPARC_SMPPRIM_H
+
+/* Test and set the unsigned byte at ADDR to 1.  Returns the previous
+ * value.  On the Sparc we use the ldstub instruction since it is
+ * atomic.
+ */
+
+extern inline volatile char test_and_set(void *addr)
+{
+       char state = 0;
+
+       __asm__ __volatile__("ldstub [%0], %1         ! test_and_set\n\t"
+                            "=r" (addr), "=r" (state) :
+                            "0" (addr), "1" (state) : "memory");
+
+       return state;
+}
+
+/* Initialize a spin-lock. */
+extern inline volatile smp_initlock(void *spinlock)
+{
+       /* Unset the lock. */
+       *((unsigned char *) spinlock) = 0;
+
+       return;
+}
+
+/* This routine spins until it acquires the lock at ADDR. */
+extern inline volatile smp_lock(void *addr)
+{
+       while(test_and_set(addr) == 0xff)
+               ;
+
+       /* We now have the lock */
+       return;
+}
+
+/* This routine releases the lock at ADDR. */
+extern inline volatile smp_unlock(void *addr)
+{
+       *((unsigned char *) addr) = 0;
+}
+
+#endif /* !(__SPARC_SMPPRIM_H) */
index 6e0bfc1f7d466515a396b0dca29592eb78120d58..bc02be460449fbcd0c1eef07496b889de1b0f9a3 100644 (file)
 /* string.h: External definitions for optimized assembly string
-             routines for the Linux Kernel.
+ *           routines for the Linux Kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+#ifndef _SPARC_STRING_H
+#define _SPARC_STRING_H
 
-extern inline size_t strlen(const char * str)
+extern __inline__ size_t strlen(const char * str)
 {
-  register size_t retval = 0;
-  register char tmp = 0;
-  register char * lstr;
-
-  lstr = (char *) str;
-
-  __asm__("ldub [%1], %2\n\t"
-         "or %%g0, %%g0, %0\n\t"
-         "orcc %2, %%g0, %%g0\n\t"
-         "be 2f\n\t"
-         "add %1, 0x1, %1\n\t"
-         "1: ldub [%1], %2\n\t"
-         "add %0, 0x1, %0\n\t"
-         "orcc %2, %%g0, %%g0\n\t"
-         "bne 1b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "2:" :
-         "=r" (retval), "=r" (lstr), "=r" (tmp) :
-         "0" (retval), "1" (lstr), "2" (tmp));
-
-  return retval;
+  const char *sc;
+
+  for (sc = str; *sc != '\0'; ++sc)
+    /* nothing */;
+  return sc - str;
 }
 
 extern __inline__ int strcmp(const char* str1, const char* str2)
 {
-  register unsigned int tmp1=0, tmp2=0;
-  register int retval=0;
-
-  __asm__("ldub [%1], %3\n\t"
-         "ldub [%2], %4\n\t"
-         "1: add %2, 0x1, %2\n\t"
-         "cmp %3, %4\n\t"
-         "bne,a 2f\n\t"
-         "sub %2, 0x1, %2\n\t"
-         "ldub [%1], %3\n\t"
-         "add %1, 0x1, %1\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne,a 1b\n\t"
-         "ldub [%2], %4\n\t"
-         "b 3f\n\t"
-         "or %%g0, %%g0, %0\n\t"
-         "2: ldub [%1], %3\n\t"
-         "ldub [%2], %4\n\t"
-          "sub %3, %4, %0\n\t"
-         "3: \n\t" :
-         "=r" (retval), "=r" (str1), "=r" (str2), "=r" (tmp1), "=r" (tmp2) :
-         "0" (retval), "1" (str1), "2" (str2),
-         "3" (tmp1), "4" (tmp2));
-
-  return retval;
+  register signed char __res;
+
+  while (1) {
+    if ((__res = *str1 - *str2++) != 0 || !*str1++)
+      break;
+  }
+
+  return __res;
 }
 
 extern __inline__ int strncmp(const char* str1, const char* str2, size_t strlen)
 {
-  register int retval=0;
-
-  __asm__("cmp %3, 0x0\n\t"
-         "be 2f\n\t"
-         "ldub [%2], %%g3\n\t"
-         "1: ldub [%1], %%g2\n\t"
-         "sub %%g2, %%g3, %0\n\t"
-         "cmp %0, 0x0\n\t"
-         "bne 2f\n\t"
-         "add %2, 0x1, %2\n\t"
-         "cmp %%g2, 0x0\n\t"
-         "be 2f\n\t"
-         "add %1, 0x1, %1\n\t"
-         "addcc %3, -1, %3\n\t"
-         "bne,a 1b\n\t"
-         "ldub [%2], %%g3\n\t"
-         "2: " :
-         "=r" (retval), "=r" (str1), "=r" (str2), "=r" (strlen) :
-         "0" (retval), "1" (str1), "2" (str2), "3" (strlen) :
-         "%g2", "%g3");
-
-  return retval;
+  register signed char __res = 0;
+
+  while (strlen) {
+    if ((__res = *str1 - *str2++) != 0 || !*str1++)
+      break;
+    strlen--;
+  }
+
+  return __res;
 }
 
 
 extern __inline__ char *strcpy(char* dest, const char* source)
 {
-  register char tmp;
-  register char *retval;
-
-  __asm__("or %%g0, %2, %0\n\t"
-         "ldub [%1], %3\n\t"
-         "1: stb %3, [%2]\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne,a 1b\n\t"
-         "ldub [%1], %3\n\t" :
-         "=r" (retval), "=r" (source), "=r" (dest), "=r" (tmp) :
-         "0" (retval), "1" (source), "2" (dest), "3" (tmp));
-
-  return retval;
+  char *tmp = dest;
+
+  while ((*dest++ = *source++) != '\0')
+    /* nothing */;
+  return tmp;
 }
 
 extern __inline__ char *strncpy(char *dest, const char *source, size_t cpylen)
 {
-  register char tmp;
-  register char *retval;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "1: cmp %4, 0x0\n\t"
-         "be 2f\n\t"
-         "ldub [%1], %3\n\t"
-         "add %1, 0x1, %1\n\t"
-         "stb %3, [%2]\n\t"
-         "sub %4, 0x1, %4\n\t"
-         "ba 1\n\t"
-         "add %2, 0x1, %2\n\t" :
-         "=r" (retval), "=r" (dest), "=r" (source), "=r"(tmp), "=r" (cpylen) :
-         "0" (retval), "1" (dest), "2" (source), 
-         "3" (tmp), "4" (cpylen));
-
-  return retval;
+  char *tmp = dest;
+
+  while (cpylen-- && (*dest++ = *source++) != '\0')
+    /* nothing */;
+
+  return tmp;
 }
 
 extern __inline__ char *strcat(char *dest, const char *src)
 {
-  register char *retval;
-  register char temp=0;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "1: ldub [%1], %3\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne,a 1b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "2: ldub [%2], %3\n\t"
-         "stb %3, [%1]\n\t"
-         "add %1, 0x1, %1\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne 2b\n\t"
-         "add %2, 0x1, %2\n\t" :
-         "=r" (retval), "=r" (dest), "=r" (src), "=r" (temp) :
-         "0" (retval), "1" (dest), "2" (src), "3" (temp));
-
-  return retval;
+  char *tmp = dest;
+
+  while (*dest)
+    dest++;
+  while ((*dest++ = *src++) != '\0')
+    ;
+
+  return tmp;
 }
 
 extern __inline__ char *strncat(char *dest, const char *src, size_t len)
 {
-  register char *retval;
-  register char temp=0;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "1: ldub [%1], %3\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne,a 1b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "2: ldub [%2], %3\n\t"
-         "stb %3, [%1]\n\t"
-         "add %1, 0x1, %1\n\t"
-         "add %3, -1, %3\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne 2b\n\t"
-         "add %2, 0x1, %2\n\t" :
-         "=r" (retval), "=r" (dest), "=r" (src), "=r" (len), "=r" (temp) :
-         "0" (retval), "1" (dest), "2" (src), "3" (len), "4" (temp));
-
-  return retval;
+  char *tmp = dest;
+
+  if (len) {
+    while (*dest)
+      dest++;
+    while ((*dest++ = *src++)) {
+      if (--len == 0)
+       break;
+    }
+  }
+
+  return tmp;
 }
 
 extern __inline__ char *strchr(const char *src, int c)
 {
-  register char temp=0;
-  register char *trick=0;
-
-  __asm__("1: ldub [%0], %2\n\t"
-         "cmp %2, %1\n\t"
-         "bne,a 1b\n\t"
-         "add %0, 0x1, %0\n\t"
-         "or %%g0, %0, %3\n\t" :
-         "=r" (src), "=r" (c), "=r" (temp), "=r" (trick), "=r" (src) :
-         "0" (src), "1" (c), "2" (temp), "3" (trick), "4" (src));
-
-  return trick;
+  for(; *src != c; ++src)
+    if (*src == '\0')
+      return NULL;
+  return (char *) src;
 }
 
 extern __inline__ char *strpbrk(const char *cs, const char *ct)
 {
-  register char temp1, temp2;
-  register char *scratch;
-  register char *trick;
-
-  __asm__("or %%g0, %1, %4\n\t"
-         "1: ldub [%0], %2\n\t"
-         "2: ldub [%1], %3\n\t"
-         "cmp %3, %2\n\t"
-         "be 3f\n\t"
-         "nop\n\t"
-         "cmp %3, 0x0\n\t"
-         "bne 2b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "or %%g0, %4, %1\n\t"
-         "b 1b\n\t"
-         "add %0, 0x1, %0\n\t"
-         "or %%g0, %0, %5\n\t" :
-         "=r" (cs) :
-         "r" (ct), "r" (temp1), "r" (temp2), "r" (scratch), "r" (trick=0),
-         "0" (cs), "1" (ct));
-
-  return trick;
+  const char *sc1,*sc2;
 
+  for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+    for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+      if (*sc1 == *sc2)
+       return (char *) sc1;
+    }
+  }
+  return NULL;
 }
 
       
 extern __inline__ size_t strspn(const char *s, const char *accept)
 {
-  register char temp1, temp2;
-  register char* scratch;
-  register size_t trick;
-
-  __asm__("or %%g0, %1, %4\n\t"
-         "1: ldub [%0], %2\n\t"
-         "2: ldub [%1], %3\n\t"
-         "cmp %3, 0x0\n\t"
-         "be 3f\n\t"
-         "cmp %3, %2"
-         "bne 2b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "add %0, 0x1, %0\n\t"
-         "b 1b\n\t"
-         "add %5, 0x1, %5\n\t"
-         "3: or %%g0, %0, %4\n\t" :
-         "=r" (s) :
-         "r" (accept), "r" (temp1), "r" (temp2), 
-         "r" (scratch), "r" (trick=0), "0" (s));
-
-  return trick;
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p) {
+    for (a = accept; *a != '\0'; ++a) {
+      if (*p == *a)
+       break;
+    }
+    if (*a == '\0')
+      return count;
+    ++count;
+  }
 
+  return count;
 }
 
 extern __inline__ char *strtok(char *s, const char *ct)
 {
-  static char* old; /* frob this kludge for now */
-  register char *tok;
-
-  if (s == (char *) 0)
-    {
-      if (old == (char *) 0)
-       {
-         return (char *) 0;
-       }
-      else
-       s = old;
-    }
-
-  s += strspn(s, ct);
-  if(*s == '\0')
-    {
-      old = (char *) 0;
-      return (char *) 0;
-    }
-
-  tok = s;
-  s = strpbrk(tok, ct);
-  if (s == (char *) 0)
-    old = (char *) 0;
-  else
-    {
-      *s = '\0';
-      old = s + 1;
-    }
-  return tok;
+  char *sbegin, *send;
+
+  sbegin  = s ? s : ___strtok;
+  if (!sbegin) {
+    return NULL;
+  }
+  sbegin += strspn(sbegin,ct);
+  if (*sbegin == '\0') {
+    ___strtok = NULL;
+    return( NULL );
+  }
+  send = strpbrk( sbegin, ct);
+  if (send && *send != '\0')
+    *send++ = '\0';
+  ___strtok = send;
+  return (sbegin);
 }
        
 
 extern __inline__ void *memset(void *src, int c, size_t count)
 {
-  register void *retval;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "1: add %1, 0x1, %1\n\t"
-         "2: add %3, -1, %3\n\t"
-         "cmp %3, -1\n\t"
-         "bne,a 1b\n\t"
-         "stb %2, [%1]\n\t" :
-         "=r" (retval), "=r" (src), "=r" (c), "=r" (count) :
-         "0" (retval), "1" (src), "2" (c), "3" (count));
-
-  return retval;
+  char *xs = (char *) src;
+
+  while (count--)
+    *xs++ = c;
+
+  return src;
 }
 
 extern __inline__ void *memcpy(void *dest, const void *src, size_t count)
 {
-  register void *retval;
-  register char tmp;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "add %3, -1, %3\n\t"
-         "cmp %3, -1\n\t"
-         "be 2f\n\t"
-         "1: ldub [%2], %4\n\t"
-         "add %2, 0x1, %2\n\t"
-         "add %3, -1, %3\n\t"
-         "cmp %3, -1\n\t"
-         "stb %4, [%1]\n\t"
-         "bne 1b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "2: " :
-         "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
-         "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
-
-  return retval;
+  char *tmp = (char *) dest, *s = (char *) src;
+
+  while (count--)
+    *tmp++ = *s++;
+
+  return dest;
 }
 
 extern __inline__ void *memmove(void *dest, const void *src, size_t count)
 {
-  register void *retval;
-  register char tmp;
-
-  __asm__("or %%g0, %1, %1\n\t"
-         "add %3, -1, %3\n\t"
-         "cmp %3, -1\n\t"
-         "be 2f\n\t"
-         "1: ldub [%2], %4\n\t"
-         "add %2, 0x1, %2\n\t"
-         "add %3, -1, %3\n\t"
-         "cmp %3, -1\n\t"
-         "stb %4, [%1]\n\t"
-         "bne 1b\n\t"
-         "add %1, 0x1, %1\n\t"
-         "2: " :
-         "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
-         "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
-
-  return retval;
+  char *tmp, *s;
+
+  if (dest <= src) {
+    tmp = (char *) dest;
+    s = (char *) src;
+    while (count--)
+      *tmp++ = *s++;
+  }
+  else {
+    tmp = (char *) dest + count;
+    s = (char *) src + count;
+    while (count--)
+      *--tmp = *--s;
+  }
+
+  return dest;
 }
 
 extern __inline__ int memcmp(const void *cs, const void *ct, size_t count)
 {
-  register int retval;
-  register unsigned long tmp1, tmp2;
-
-  __asm__("or %%g0, %1, %0\n\t"
-         "cmp %3, 0x0\n\t"
-         "ble,a 3f\n\t"
-         "or %%g0, %%g0, %0\n\t"
-         "1: ldub [%1], %4\n\t"
-         "ldub [%2], %5\n\t"
-         "cmp %4, %5\n\t"
-         "be,a 2f\n\t"
-         "add %1, 0x1, %1\n\t"
-         "bgeu 3f\n\t"
-         "or %%g0, 0x1, %0\n\t"
-         "b 3f\n\t"
-         "or %%g0, -1, %0\n\t"
-         "2: add %3, -1, %3\n\t"
-         "cmp %3, 0x0\n\t"
-         "bg 1b\n\t"
-         "add %2, 0x1, %2\n\t"
-         "or %%g0, %%g0, %0\n\t"
-         "3: " :
-         "=r" (retval) :
-         "r" (cs), "r" (ct), "r" (count), "r" (tmp1=0), "r" (tmp2=0));
-
-  return retval;
+  const unsigned char *su1, *su2;
+  signed char res = 0;
+
+  for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+    if ((res = *su1 - *su2) != 0)
+      break;
+  return res;
 }
 
+#endif /* !(_SPARC_STRING_H) */
index f72b40c6750adce2f645bab871323e9cb383ffe8..6e25b91fd7b42e42d0c6005a4d8537e207054875 100644 (file)
@@ -1,14 +1,14 @@
-#ifndef _SPARC_SYSEN_H
-#define _SPARC_SYSEN_H
-
 /* sysen.h:  Bit fields within the "System Enable" register accessed via
-             the ASI_CONTROL address space at address AC_SYSENABLE.
+ *           the ASI_CONTROL address space at address AC_SYSENABLE.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+#ifndef _SPARC_SYSEN_H
+#define _SPARC_SYSEN_H
 
 #define SENABLE_DVMA   0x20   /* enable dvma transfers */
 #define SENABLE_CACHE  0x10   /* enable VAC cache */
-#define SENABLE_RESET  0x04   /* reset the whole machine, danger Will Robinson */
+#define SENABLE_RESET  0x04   /* reset whole machine, danger Will Robinson */
 
 #endif /* _SPARC_SYSEN_H */
index 3c4a62c9adaeab7ab0f38ec5cd494e976fc6f777..67a3f6100f8f3bc6bae67b1dc50915e5434d327d 100644 (file)
@@ -3,51 +3,85 @@
 
 #include <asm/segment.h>
 
-/*
- * System defines.. Note that this is included both from .c and .S
- * files, so it does only defines, not any C code.
- */
-
 /*
  * I wish the boot time image was as beautiful as the Alpha's
  * but no such luck. The icky PROM loads us at 0x0, and jumps
- * to magic address 0x4000 to start thing going. This means that
- * I can stick the pcb and user/kernel stacks in the area from
- * 0x0-0x4000 and be reasonably sure that this is sane.
+ * to magic address 0x4000 to start things going.
  *
  * Sorry, I can't impress people with cool looking 64-bit values
- * yet. ;-)
+ * yet. Wait till V9 ;-)
  */
 
+#include <asm/page.h>
 #include <asm/openprom.h>
 #include <asm/psr.h>
 
-#define INIT_PCB       0x00011fe0
-#define INIT_STACK     0x00013fe0
-#define START_ADDR     0x00004000
-#define START_SIZE     (32*1024)
-#define EMPTY_PGT      0x00001000
-#define EMPTY_PGE      0x00001000
-#define ZERO_PGE       0x00001000
-
-#define IRQ_ENA_ADR     0x2000        /* This is a bitmap of all activated IRQ's
-                                      * which is mapped in head.S during boot.
-                                      */
+#define START_ADDR     (0x00004000)
+#define EMPTY_PGT       (&empty_bad_page)
+#define EMPTY_PGE      (&empty_bad_page_table)
+#define ZERO_PGE       (&empty_zero_page)
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Sparc (general) CPU types
+ */
+enum sparc_cpu {
+  sun4        = 0x00,
+  sun4c       = 0x01,
+  sun4m       = 0x02,
+  sun4d       = 0x03,
+  sun4e       = 0x04,
+  sun4u       = 0x05,
+  sun_unknown = 0x06,
+};
+
+extern enum sparc_cpu sparc_cpu_model;
+
+extern unsigned long empty_bad_page;
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_zero_page;
+
 extern void wrent(void *, unsigned long);
 extern void wrkgp(unsigned long);
 extern struct linux_romvec *romvec;
 
-#define halt() { romvec->pv_halt(); }
+#define halt() do { \
+                        printk("Entering monitor in file %s at line %d\n", __FILE__, __LINE__); \
+romvec->pv_halt(); } while(0)
+
 #define move_to_user_mode() halt()
-#define switch_to(x) halt()
 
 #ifndef stbar  /* store barrier Sparc insn to synchronize stores in PSO */
 #define stbar() __asm__ __volatile__("stbar": : :"memory")
 #endif
 
+/* When a context switch happens we must flush all user windows so that
+ * the windows of the current process are flushed onto it's stack. This
+ * way the windows are all clean for the next process.
+ */
+
+#define flush_user_windows() \
+do { __asm__ __volatile__( \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "save %sp, -64, %sp\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t" \
+                         "restore\n\t"); } while(0)
+
+extern void sparc_switch_to(void *new_task);
+
+#define switch_to(p) sparc_switch_to(p)
+
 /* Changing the PIL on the sparc is a bit hairy. I'll figure out some
  * more optimized way of doing this soon. This is bletcherous code.
  */
@@ -73,36 +107,6 @@ retval; })
 #define iret() __asm__ __volatile__ ("jmp %%l1\n\t" \
                                     "rett %%l2\n\t": : :"memory")
 
-#define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ __volatile__ ("nop\n\t")
-
-#define set_intr_gate(n,addr) \
-       _set_gate(&idt[n],14,0,addr)
-
-#define set_trap_gate(n,addr) \
-       _set_gate(&idt[n],15,0,addr)
-
-#define set_system_gate(n,addr) \
-       _set_gate(&idt[n],15,3,addr)
-
-#define set_call_gate(a,addr) \
-       _set_gate(a,12,3,addr)
-
-
-extern inline unsigned int get_psr(void)
-{
-  unsigned int ret_val;
-  __asm__("rd %%psr, %0\n\t" :
-         "=r" (ret_val));
-  return ret_val;
-}
-
-extern inline void put_psr(unsigned int new_psr)
-{
-  __asm__("wr %0, 0x0, %%psr\n\t" : :
-         "r" (new_psr));
-}
-
 /* Must this be atomic? */
 
 extern inline void *xchg_u32(int * m, unsigned long val)
@@ -110,7 +114,7 @@ extern inline void *xchg_u32(int * m, unsigned long val)
        unsigned long dummy;
 
        __asm__ __volatile__(
-               "ld %1,%2   ! xchg_u32() is here\n\t"
+               "ld %1,%2\n\t"
                "st %0, %1\n\t"
                "or %%g0, %2, %0"
                : "=r" (val), "=m" (*m), "=r" (dummy)
diff --git a/include/asm-sparc/timer.h b/include/asm-sparc/timer.h
new file mode 100644 (file)
index 0000000..68aadee
--- /dev/null
@@ -0,0 +1,83 @@
+/* timer.h:  Definitions for the timer chips on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_TIMER_H
+#define _SPARC_TIMER_H
+
+#include <asm/system.h>  /* For NCPUS */
+
+/* Timer structures. The interrupt timer has two properties which
+ * are the counter (which is handled in do_timer in sched.c) and the limit.
+ * This limit is where the timer's counter 'wraps' around. Oddly enough,
+ * the sun4c timer when it hits the limit wraps back to 1 and not zero
+ * thus when calculating the value at which it will fire a microsecond you
+ * must adjust by one.  Thanks SUN for designing such great hardware ;(
+ */
+
+/* Note that I am only going to use the timer that interrupts at
+ * Sparc IRQ 10.  There is another one available that can fire at
+ * IRQ 14. Currently it is left untouched, we keep the PROM's limit
+ * register value and let the prom take these interrupts.  This allows
+ * L1-A to work.
+ */
+
+struct sun4c_timer_info {
+  volatile unsigned int cur_count10;
+  volatile unsigned int timer_limit10;
+  volatile unsigned int cur_count14;
+  volatile unsigned int timer_limit14;
+};
+
+#define SUN4C_TIMER_PHYSADDR   0xf3000000
+
+/* All accesses to the sun4c timer registers should use this macro. */
+#define  SUN4C_TIMER_STRUCT  ((volatile struct sun4c_timer_info *) TIMER_VADDR)
+
+/* A sun4m has two blocks of registers which are probably of the same
+ * structure. LSI Logic's L64851 is told to _decrement_ from the limit
+ * value. Aurora behaves similarly but its limit value is compacted in
+ * other fashion (it's wider). Documented fields are defined here.
+ */
+
+/* As with the interrupt register, we have two classes of timer registers
+ * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
+ * only level 14 ticks, master timer hits all cpus and is level 10.
+ */
+
+#define SUN4M_PRM_CNT_L       0x80000000
+#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00
+
+struct sun4m_timer_percpu_info {
+  volatile unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
+  volatile unsigned int l14_cur_count;
+
+  /* This register appears to be write only and/or inaccessible
+   * on Uni-Processor sun4m machines.
+   */
+  volatile unsigned int l14_limit_noclear;  /* Data access error is here */
+
+  volatile unsigned int cntrl;            /* =1 after POST on Aurora */
+  volatile unsigned char space[PAGE_SIZE - 16];
+};
+
+struct sun4m_timer_regs {
+       struct sun4m_timer_percpu_info cpu_timers[NCPUS];
+       volatile unsigned int l10_timer_limit;
+       volatile unsigned int l10_cur_count;
+
+       /* Again, this appears to be write only and/or inaccessible
+        * on uni-processor sun4m machines.
+        */
+       volatile unsigned int l10_limit_noclear;
+
+       /* This register too, it must be magic. */
+       volatile unsigned int foobar;
+
+       volatile unsigned int cfg;     /* equals zero at boot time... */
+};
+
+extern struct sun4m_timer_regs *sun4m_timers;
+extern volatile unsigned int *master_l10_limit;
+
+#endif /* !(_SPARC_TIMER_H) */
diff --git a/include/asm-sparc/traps.h b/include/asm-sparc/traps.h
new file mode 100644 (file)
index 0000000..705abc4
--- /dev/null
@@ -0,0 +1,135 @@
+/* traps.h:  Format of entries for the Sparc trap table.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_TRAPS_H
+#define _SPARC_TRAPS_H
+
+#define NUM_SPARC_TRAPS  255
+
+/* This is for V8 and V9 compliant Sparc CPUS */
+struct tt_entry {
+       unsigned long inst_one;
+       unsigned long inst_two;
+       unsigned long inst_three;
+       unsigned long inst_four;
+};
+
+/* We set this to _start in system setup. */
+extern struct tt_entry *sparc_ttable;
+
+/* This for V9 compliant Sparc CPUS */
+struct tt_v9_entry {
+       unsigned long inst_one;
+       unsigned long inst_two;
+       unsigned long inst_three;
+       unsigned long inst_four;
+       unsigned long inst_five;
+       unsigned long inst_six;
+       unsigned long inst_seven;
+       unsigned long inst_eight;
+};
+
+/* V9 has multiple trap tables, which one is used depends
+ * upon how deep within multiple traps you are.
+ * I believe the UltraSparc supports two levels now.
+ */
+extern struct tt_v9_entry *sparc_v9_ttablel0;
+extern struct tt_v9_entry *sparc_v9_ttablel1;
+
+/* For patching the trap table at boot time, we need to know how to
+ * form various common Sparc instructions.  Thus these macros...
+ */
+
+#define SPARC_MOV_CONST_L3(const) (0xa6102000 | (const&0xfff))
+
+/* The following assumes that the branch lies before the place we
+ * are branching to.  This is the case for a trap vector...
+ * You have been warned.
+ */
+#define SPARC_BRANCH(dest_addr, inst_addr) \
+          (0x10800000 | (((dest_addr-inst_addr)>>2)&0x3fffff))
+
+#define SPARC_RD_PSR_L0  (0xa1480000)
+#define SPARC_NOP (0x01000000)
+
+/* Various interesting trap levels. */
+/* First, hardware traps. */
+#define SP_TRAP_TFLT    0x1          /* Text fault */
+#define SP_TRAP_II      0x2          /* Illegal Instruction */
+#define SP_TRAP_PI      0x3          /* Priviledged Instruction */
+#define SP_TRAP_FPD     0x4          /* Floating Point Disabled */
+#define SP_TRAP_WOVF    0x5          /* Window Overflow */
+#define SP_TRAP_WUNF    0x6          /* Window Underflow */
+#define SP_TRAP_MNA     0x7          /* Memory Address Unaligned */
+#define SP_TRAP_FPE     0x8          /* Floating Point Exception */
+#define SP_TRAP_DFLT    0x9          /* Data Fault */
+#define SP_TRAP_TOF     0xa          /* Tag Overflow */
+#define SP_TRAP_WDOG    0xb          /* Watchpoint Detected */
+#define SP_TRAP_IRQ1    0x11         /* IRQ level 1 */
+#define SP_TRAP_IRQ2    0x12         /* IRQ level 2 */
+#define SP_TRAP_IRQ3    0x13         /* IRQ level 3 */
+#define SP_TRAP_IRQ4    0x14         /* IRQ level 4 */
+#define SP_TRAP_IRQ5    0x15         /* IRQ level 5 */
+#define SP_TRAP_IRQ6    0x16         /* IRQ level 6 */
+#define SP_TRAP_IRQ7    0x17         /* IRQ level 7 */
+#define SP_TRAP_IRQ8    0x18         /* IRQ level 8 */
+#define SP_TRAP_IRQ9    0x19         /* IRQ level 9 */
+#define SP_TRAP_IRQ10   0x1a         /* IRQ level 10 */
+#define SP_TRAP_IRQ11   0x1b         /* IRQ level 11 */
+#define SP_TRAP_IRQ12   0x1c         /* IRQ level 12 */
+#define SP_TRAP_IRQ13   0x1d         /* IRQ level 13 */
+#define SP_TRAP_IRQ14   0x1e         /* IRQ level 14 */
+#define SP_TRAP_IRQ15   0x1f         /* IRQ level 15 Non-maskable */
+#define SP_TRAP_RACC    0x20         /* Register Access Error ??? */
+#define SP_TRAP_IACC    0x21         /* Instruction Access Error */
+#define SP_TRAP_CPDIS   0x24         /* Co-Processor Disabled */
+#define SP_TRAP_BADFL   0x25         /* Unimplemented Flush Instruction */
+#define SP_TRAP_CPEXP   0x28         /* Co-Processor Exception */
+#define SP_TRAP_DACC    0x29         /* Data Access Error */
+#define SP_TRAP_DIVZ    0x2a         /* Divide By Zero */
+#define SP_TRAP_DSTORE  0x2b         /* Data Store Error ??? */
+#define SP_TRAP_DMM     0x2c         /* Data Access MMU Miss ??? */
+#define SP_TRAP_IMM     0x3c         /* Instruction Access MMU Miss ??? */
+
+/* Now the Software Traps... */
+#define SP_TRAP_SUNOS   0x80         /* SunOS System Call */
+#define SP_TRAP_SBPT    0x81         /* Software Breakpoint */
+#define SP_TRAP_SDIVZ   0x82         /* Software Divide-by-Zero trap */
+#define SP_TRAP_FWIN    0x83         /* Flush Windows */
+#define SP_TRAP_CWIN    0x84         /* Clean Windows */
+#define SP_TRAP_RCHK    0x85         /* Range Check */
+#define SP_TRAP_FUNA    0x86         /* Fix Unaligned Access */
+#define SP_TRAP_IOWFL   0x87         /* Integer Overflow */
+#define SP_TRAP_SOLARIS 0x88         /* Solaris System Call */
+#define SP_TRAP_NETBSD  0x89         /* NetBSD System Call */
+#define SP_TRAP_LINUX   0x90         /* Linux System Call */
+
+/* Special traps... */
+#define SP_TRAP_KBPT1   0xfe         /* KADB/PROM Breakpoint one */
+#define SP_TRAP_KBPT2   0xff         /* KADB/PROM Breakpoint two */
+
+/* Handy Macros */
+/* Is this a trap we never expect to get? */
+#define BAD_TRAP_P(level) \
+        ((level > SP_TRAP_WDOG && level < SP_TRAP_IRQ1) || \
+        (level > SP_TRAP_IACC && level < SP_TRAP_CPDIS) || \
+        (level > SP_TRAP_BADFL && level < SP_TRAP_CPEXP) || \
+        (level > SP_TRAP_DMM && level < SP_TRAP_IMM) || \
+        (level > SP_TRAP_IMM && level < SP_TRAP_SUNOS) || \
+        (level > SP_TRAP_LINUX && level < SP_TRAP_KBPT1))
+
+/* Is this a Hardware trap? */
+#define HW_TRAP_P(level) ((level > 0) && (level < SP_TRAP_SUNOS))
+
+/* Is this a Software trap? */
+#define SW_TRAP_P(level) ((level >= SP_TRAP_SUNOS) && (level <= SP_TRAP_KBPT2))
+
+/* Is this a system call for some OS we know about? */
+#define SCALL_TRAP_P(level) ((level == SP_TRAP_SUNOS) || \
+                            (level == SP_TRAP_SOLARIS) || \
+                            (level == SP_TRAP_NETBSD) || \
+                            (level == SP_TRAP_LINUX))
+
+#endif /* !(_SPARC_TRAPS_H) */
diff --git a/include/asm-sparc/tsunami.h b/include/asm-sparc/tsunami.h
new file mode 100644 (file)
index 0000000..8bb6357
--- /dev/null
@@ -0,0 +1,45 @@
+/* tsunami.h:  Module specific definitions for Tsunami V8 Sparcs
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_TSUNAMI_H
+#define _SPARC_TSUNAMI_H
+
+/* The MMU control register on the Tsunami:
+ *
+ * -----------------------------------------------------------------------
+ * | implvers |SW|AV|DV|MV| RSV |PC|ITD|ALC| RSV |PE| RC |IE|DE|RSV|NF|ME|
+ * -----------------------------------------------------------------------
+ *  31      24 23 22 21 20 19-18 17  16 14  13-12 11 10-9  8  7 6-2  1  0
+ *
+ * SW: Enable Software Table Walks  0=off 1=on
+ * AV: Address View bit
+ * DV: Data View bit
+ * MV: Memory View bit
+ * PC: Parity Control
+ * ITD: ITBR disable
+ * ALC: Alternate Cacheable
+ * PE: Parity Enable   0=off 1=on
+ * RC: Refresh Control
+ * IE: Instruction cache Enable  0=off 1=on
+ * DE: Data cache Enable  0=off 1=on
+ * NF: No Fault, same as all other SRMMUs
+ * ME: MMU Enable, same as all other SRMMUs
+ */
+
+#define TSUNAMI_SW        0x00800000
+#define TSUNAMI_AV        0x00400000
+#define TSUNAMI_DV        0x00200000
+#define TSUNAMI_MV        0x00100000
+#define TSUNAMI_PC        0x00020000
+#define TSUNAMI_ITD       0x00010000
+#define TSUNAMI_ALC       0x00008000
+#define TSUNAMI_PE        0x00001000
+#define TSUNAMI_RCMASK    0x00000C00
+#define TSUNAMI_IENAB     0x00000200
+#define TSUNAMI_DENAB     0x00000100
+#define TSUNAMI_NF        0x00000002
+#define TSUNAMI_ME        0x00000001
+
+#endif /* !(_SPARC_TSUNAMI_H) */
diff --git a/include/asm-sparc/ultra.h b/include/asm-sparc/ultra.h
new file mode 100644 (file)
index 0000000..2eec66b
--- /dev/null
@@ -0,0 +1,51 @@
+/* ultra.h: Definitions and defines for the TI V9 UltraSparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ULTRA_H
+#define _SPARC_ULTRA_H
+
+/* Spitfire MMU control register:
+ *
+ * ----------------------------------------------------------
+ * |        | IMPL  | VERS  |     |  MID  |                 |
+ * ----------------------------------------------------------
+ *  64        31-28   27-24  23-22  21-17   16             0
+ *
+ * IMPL: Implementation of this Spitfire.
+ * VERS: Version of this Spitfire.
+ * MID: Module ID of this processor.
+ */
+
+#define SPITFIRE_MIDMASK     0x00000000003e0000
+
+/* Spitfire Load Store Unit control register:
+ *
+ * ---------------------------------------------------------------------
+ * | RSV | PWR | PWW | VWR | VWW | RSV | PMASK | DME | IME | DCE | ICE |
+ * ---------------------------------------------------------------------
+ *  63-25  24    23     22    21    20   19-4      3     2     1     0
+ *
+ * PWR: Physical Watchpoint Read enable: 0=off 1=on
+ * PWW: Physical Watchpoint Write enable: 0=off 1=on
+ * VWR: Virtual Watchpoint Read enable: 0=off 1=on
+ * VWW: Virtual Watchpoint Write enable: 0=off 1=on
+ * PMASK: Parity MASK  ???
+ * DME: Data MMU Enable: 0=off 1=on
+ * IME: Instruction MMU Enable: 0=off 1=on
+ * DCE: Data Cache Enable: 0=off 1=on
+ * ICE: Instruction Cache Enable: 0=off 1=on
+ */
+
+#define SPITFIRE_LSU_PWR      0x01000000
+#define SPITFIRE_LSU_PWW      0x00800000
+#define SPITFIRE_LSU_VWR      0x00400000
+#define SPITFIRE_LSU_VWW      0x00200000
+#define SPITFIRE_LSU_PMASK    0x000ffff0
+#define SPITFIRE_LSU_DME      0x00000008
+#define SPITFIRE_LSU_IME      0x00000004
+#define SPITFIRE_LSU_DCE      0x00000002
+#define SPITFIRE_LSU_ICE      0x00000001
+
+#endif /* !(_SPARC_ULTRA_H) */
index 3b0551461ca0467ebd57b4a04235d45850b81e2c..d05b7bb8cd466e3cd830c0bfdda51c7d7fefa3c4 100644 (file)
@@ -8,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
@@ -17,7 +17,9 @@ type name(void) \
 { \
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res) \
                  : "0" (__NR_##name) \
                  : "o0"); \
@@ -33,7 +35,9 @@ type name(type1 arg1) \
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
                  "or %%g0, %1, %%o1\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)) \
                  : "o0", "o1"); \
@@ -50,7 +54,9 @@ long __res; \
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
                  "or %%g0, %1, %%o1\n\t" \
                  "or %%g0, %2, %%o2\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(args)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
                  : "o0", "o1", "o2"); \
@@ -68,7 +74,9 @@ __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
                  "or %%g0, %1, %%o1\n\t" \
                  "or %%g0, %2, %%o2\n\t" \
                  "or %%g0, %3, %%o3\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                    "=r" ((long)(arg3)) \
                  : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
@@ -89,7 +97,9 @@ __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
                  "or %%g0, %2, %%o2\n\t" \
                  "or %%g0, %3, %%o3\n\t" \
                  "or %%g0, %4, %%o4\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                    "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -112,7 +122,9 @@ __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
                  "or %%g0, %3, %%o3\n\t" \
                  "or %%g0, %4, %%o4\n\t" \
                  "or %%g0, %5, %%o5\n\t" \
-                 "t 0xa\n\t" \
+                 "t 0x10\n\t" \
+                 "nop\n\t" \
+                 "or %%g0, %%o0, %0\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                    "=r" ((long)(arg3)), "=r" ((long)(arg4)), "=r" ((long)(arg5)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -139,10 +151,10 @@ return -1; \
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
+/* static inline _syscall0(int,idle) */
 static inline _syscall0(int,fork)
 static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
+/* static inline _syscall0(int,setup) */
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
@@ -153,9 +165,33 @@ static inline _syscall1(int,close,int,fd)
 static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+extern void sys_idle(void);
+static inline void idle(void)
+{
+       printk("[%d]idle()\n",current->pid);
+       sys_idle();
+       for(;;);
+}
+
+extern int sys_setup(void);
+static inline int setup(void)
+{
+       int retval;
+
+       printk("[%d]setup()\n",current->pid);
+       retval = sys_setup();
+       printk("[%d]setup() returned %d\n",current->pid, retval);
+}
+
+extern int sys_waitpid(int, int *, int);
 static inline pid_t wait(int * wait_stat)
 {
-       return waitpid(-1,wait_stat,0);
+       long retval, i;
+       printk("[%d]wait(%p)\n", current->pid, wait_stat);
+       retval = waitpid(-1,wait_stat,0);
+       printk("[%d]wait(%p) returned %ld\n", current->pid, wait_stat, retval);
+       for (i = 0; i < 1000000000; i++);
+       return retval;
 }
 
 #endif
index 18755e048318d819dc9704c811e8862f00690285..4793013946e22da2bbbb45a29b73165be5779d75 100644 (file)
@@ -8,7 +8,7 @@
 */
 
 extern unsigned long *trapbase;
-extern char end, etext, msgbuf;
+extern char end, etext, edata;
 
 extern void flush_vac_context(void);
 extern void flush_vac_segment(unsigned int foo_segment);
index 7df4431030e1226b601f0566e044753826de418f..166fecf409db973ccbc75c315d44b964fc9716ce 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
+#include <asm/head.h>
+
 /* asm-sparc/vaddrs.h:  Here will be define the virtual addresses at
  *                      which important I/O addresses will be mapped.
  *                      For instance the timer register virtual address
@@ -9,8 +11,34 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#define  TIMER_VADDR    0x3000   /* Next page after where the interrupt enable
-                                 * register gets mapped at boot.
-                                 */
+/* I can see only one reason why we should have statically defined
+ * mappings for devices and is the speedup improvements of not loading
+ * a pointer and then the value in the assembly code
+ */
+
+#define  AUXIO_VADDR  (KERNBASE+0x6000)    /* Auxiliary IO register */
+#define  TIMER_VADDR  (AUXIO_VADDR+0x1000) /* One page after AUXIO, length is
+                                           * 5 pages which is needed on sun4m.
+                                           */
+#define  INTREG_VADDR (TIMER_VADDR+0x5000)
+
+#define  IOBASE_VADDR   0xfe000000  /* Base for mapping pages */
+#define  IOBASE_LEN     0x00400000  /* Length of the IO area */
+#define  IOBASE_SUN4C_SEGMAP 100
+#define  DVMA_VADDR     0xfff00000  /* Base area of the DVMA on the 4c */
+#define  DVMA_LEN       0x000c0000  /* Size of the DVMA address space */
+
+/* On sun4m machines we need per-cpu virtual areas */
+#define  PERCPU_VADDR   0xff000000  /* Base for per-cpu virtual mappings */
+#define  PERCPU_ENTSIZE 0x00100000
+#define  PERCPU_LEN     ((PERCPU_ENTSIZE*NCPUS))
+
+/* per-cpu offsets */
+#define  PERCPU_TBR_OFFSET      0x00000      /* %tbr, mainly used for identification. */
+#define  PERCPU_KSTACK_OFFSET   0x01000      /* Beginning of kernel stack for this cpu */
+#define  PERCPU_MBOX_OFFSET     0x02000      /* Prom SMP Mailbox */
+#define  PERCPU_CPUID_OFFSET    0x03000      /* Per-cpu ID number. */
+#define  PERCPU_ISALIVE_OFFSET  0x03004      /* Has CPU been initted yet? */
+#define  PERCPU_ISIDLING_OFFSET 0x03008      /* Is CPU in idle loop spinning? */
 
 #endif /* !(_SPARC_VADDRS_H) */
diff --git a/include/asm-sparc/viking.h b/include/asm-sparc/viking.h
new file mode 100644 (file)
index 0000000..7f2811d
--- /dev/null
@@ -0,0 +1,51 @@
+/* viking.h:  Defines specific to the TI Viking MBUS module.
+ *            This is SRMMU stuff.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_VIKING_H
+#define _SPARC_VIKING_H
+
+/* Bits in the SRMMU control register for TI Viking modules.
+ *
+ * -------------------------------------------------------------
+ * |implvers| RSV |DP|RSV|TC|AC|SP|BM|PC|MBM|SB|IC|DC|RSV|NF|ME|
+ * -------------------------------------------------------------
+ *  31    24 23-20 19  18 17 16 15 14 13  12 11 10  9 8-2  1  0
+ *
+ * DP: Data Prefetcher Enable -- 0 = DP is off, 1 = DP is on
+ * TC: Tablewalk Cacheable -- 0 = Twalks are not cacheable
+ *                            1 = Twalks are cacheable
+ * AC: Alternate Cacheable -- 0 = Direct physical accesses not cacheable
+ *                            1 = Direct physical accesses are cacheable
+ * SP: SnooP Enable -- 0 = bus snooping off, 1 = bus snooping on
+ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode
+ * MBM: MBus Mode -- 0 = not in MBus mode, 1 = in MBus mode
+ * SB: StoreBuffer enable -- 0 = store buffer off, 1 = store buffer on
+ * IC: Instruction Cache -- 0 = off, 1 = on
+ * DC: Data Cache -- 0 = off, 1 = 0n
+ * NF: No Fault -- 0 = faults generate traps, 1 = faults don't trap
+ * ME: MMU enable -- 0 = mmu not translating, 1 = mmu translating
+ *
+ */
+
+#define VIKING_DCENABLE     0x00000100   /* Enable data cache */
+#define VIKING_ICENABLE     0x00000200   /* Enable instruction cache */
+#define VIKING_SBENABLE     0x00000400   /* Enable store buffer */
+#define VIKING_MMODE        0x00000800   /* MBUS mode */
+#define VIKING_PCENABLE     0x00001000   /* Enable parity checking */
+
+/* Boot mode, 0 at boot-time, 1 after prom initializes the MMU. */
+#define VIKING_BMODE        0x00002000   
+#define VIKING_SPENABLE     0x00004000   /* Enable bus cache snooping */
+
+/* The deal with this AC bit is that if you are going to modify the
+ * contents of physical ram using the MMU bypass, you had better set
+ * this bit or things will get unsynchronized.  This is only applicable
+ * if an E-cache (ie. a PAC) is around and the Viking is not in MBUS mode.
+ */
+#define VIKING_ACENABLE     0x00008000   /* Enable alternate caching */
+#define VIKING_TCENABLE     0x00010000   /* Enable table-walks to be cached */
+#define VIKING_DPENABLE     0x00040000   /* Enable the data prefetcher */
+
+#endif
index da1811d82d5ea1f64f55cca3165fb8a85c7d2f5a..bd24ce4492252c35abef63561076f272cc7c5c6b 100644 (file)
@@ -54,6 +54,9 @@
                             512 : 128 << FD_SIZECODE(floppy) )
 #define FD_PERP 0x40
 
+#define FD_STRETCH 1
+#define FD_SWAPSIDES 2
+
 #ifndef __ASSEMBLY__
 /* the following structure is used by FDSETPRM, FDDEFPRM and FDGETPRM */
 struct floppy_struct {
@@ -184,7 +187,8 @@ struct floppy_drive_struct {
   int fd_device;
   int last_checked; /* when was the drive last checked for a disk change? */
 
-
+  char *dmabuf;
+  int bufblocks;
 };
 
 struct floppy_write_errors {
index 157cfe5007f418fa9d6e4fd44b25e4ff345d24b5..587bc5acaffbd78d31c1b8b9153409298921367b 100644 (file)
@@ -331,7 +331,7 @@ struct super_block {
  * This allows the kernel to read directories into kernel space or
  * to have different dirent layouts depending on the binary type.
  */
-typedef int (*filldir_t)(void *, char *, int, off_t, ino_t);
+typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
        
 struct file_operations {
        int (*lseek) (struct inode *, struct file *, off_t, int);
@@ -429,7 +429,7 @@ extern struct file *first_file;
 extern int nr_files;
 extern struct super_block super_blocks[NR_SUPER];
 
-extern int shrink_buffers(unsigned int priority);
+extern int shrink_buffers(unsigned int priority, unsigned long limit);
 extern void refile_buffer(struct buffer_head * buf);
 extern void set_writetime(struct buffer_head * buf, int flag);
 extern void refill_freelist(int size);
index 49338ae2bbed1541c04999ed6d9ce76200299caa..fd17ef1704ea545eb3ff75365dfa89e7d8ad62de 100644 (file)
@@ -149,9 +149,10 @@ extern unsigned char * free_area_map[NR_MEM_LISTS];
  * goes to clearing the page. If you want a page without the clearing
  * overhead, just use __get_free_page() directly..
  */
-#define __get_free_page(priority) __get_free_pages((priority),0)
-extern unsigned long __get_free_pages(int priority, unsigned long gfporder);
-extern unsigned long __get_dma_pages(int priority, unsigned long gfporder);
+#define __get_free_page(priority) __get_free_pages((priority),0,~0UL)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),MAX_DMA_ADDRESS)
+extern unsigned long __get_free_pages(int priority, unsigned long gfporder, unsigned long max_addr);
+
 extern inline unsigned long get_free_page(int priority)
 {
        unsigned long page;
index 699c13ccf2b8b05857fd923f2f099e2ac80e6cf9..1b5b1f39096e0f85a4d83f87c06823c6251fad48 100644 (file)
@@ -85,7 +85,7 @@ extern int register_symtab(struct symbol_table *);
 /*
  * The first word of the module contains the use count.
  */
-#define GET_USE_COUNT(module)  (* (int *) (module)->addr)
+#define GET_USE_COUNT(module)  (* (long *) (module)->addr)
 /*
  * define the count variable, and usage macros.
  */
index f995bd2f9d9ac5e0a6ca62ada58d0c33f471f206..175a83e0db9781677d5d777c822064f669921e7e 100644 (file)
@@ -97,23 +97,11 @@ struct      mtget {
 #define MT_ISSCSI1             0x71    /* Generic ANSI SCSI-1 tape unit */
 #define MT_ISSCSI2             0x72    /* Generic ANSI SCSI-2 tape unit */
 
-/* QIC-40/QIC-80 ftape supported drives.
- * 20bit vendor ID + 0x800000
+/* QIC-40/80/3010/3020 ftape supported drives.
+ * 20bit vendor ID + 0x800000 (see vendors.h in ftape distribution)
  */
-#define MT_ISFTAPE_UNKNOWN     0x800000
-#define MT_ISCMSDJ10_DJ20      0x800047
-#define MT_ISCMSDJ10_DJ20_NEW  0x8011c4
-#define MT_ISARCHIVE_5580I     0x800005
-#define MT_ISARCHIVE_XL9250I   0x80014a
-#define MT_ISARCHIVE_31250Q    0x800146
-#define MT_ISINSIGHT_80                0x810005
-#define MT_ISCONNER_C250MQT    0x80014c
-#define MT_ISWANGTEK_2040F     0x8001c1
-#define MT_ISWANGTEK_2080F     0x8001c8
-#define MT_ISIOMEGA_250                0x808880
-#define MT_ISSUMMIT_SE150      0x800180
-#define MT_ISSUMMIT_SE250      0x800181
-#define MT_ISESCOM_IDTBU120E   0x800140
+#define MT_ISFTAPE_UNKNOWN     0x800000 /* obsolete */
+#define MT_ISFTAPE_FLAG        0x800000
 
 struct mt_tape_info {
        long t_type;            /* device type id (mt_type) */
@@ -137,20 +125,6 @@ struct mt_tape_info {
        {MT_ISEVEREX_FT40A,     "Everex FT40A, QIC-40"}, \
        {MT_ISSCSI1,            "Generic SCSI-1 tape"}, \
        {MT_ISSCSI2,            "Generic SCSI-2 tape"}, \
-       {MT_ISFTAPE_UNKNOWN,    "Unknown floppy interface tape drive"},\
-       {MT_ISCMSDJ10_DJ20,     "Colorado DJ-10/DJ-20"},\
-       {MT_ISCMSDJ10_DJ20_NEW, "Colorado DJ-10/DJ-20 (new)"},\
-       {MT_ISARCHIVE_5580I,    "Archive 5580i"},\
-       {MT_ISARCHIVE_XL9250I,  "Archive XL9250i [Conner/Escom]"},\
-       {MT_ISARCHIVE_31250Q,   "Escom/Archive 31250Q"},\
-       {MT_ISINSIGHT_80,       "Insight 80 Mb"},\
-       {MT_ISCONNER_C250MQT,   "Conner C250MQT"},\
-       {MT_ISWANGTEK_2040F,    "Wangtek 3040F"},\
-       {MT_ISWANGTEK_2080F,    "Wangtek 3080F"},\
-       {MT_ISIOMEGA_250,       "Iomega 250"},\
-       {MT_ISSUMMIT_SE150,     "Summit SE 150"},\
-       {MT_ISSUMMIT_SE250,     "Summit SE 250/Mountain FS8000"},\
-       {MT_ISESCOM_IDTBU120E,  "Identity IDTBU120E, Escom?"},\
        {0, NULL} \
 }
 
index ee7ec8d4c4c287f4b251b7182fa72758df2ec4a3..84fc19a8ba4add31666eb8a83708629c4cda7fe7 100644 (file)
 #define _LINUX_SBPCD_H
 /*==========================================================================*/
 /*==========================================================================*/
-#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
+#define LONG_TIMING 1 /* test against timeouts with "gold" CDs on CR-521 */
 #undef  FUTURE
 
 #define TEST_UPC 0
index a89ae6e22866f52c318e5d1d4b1a222a6683ce07..6b4d365f4d89d3717ab1bfb63feb6a791eb481f4 100644 (file)
@@ -1,6 +1,6 @@
-/* check.c 30/01/95 22.05.32 */
+/* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
-/* dir.c 18/03/95 00.30.50 */
+/* dir.c 22/06/95 00.22.12 */
 int UMSDOS_dir_read (struct inode *inode,
         struct file *filp,
         char *buf,
@@ -19,11 +19,7 @@ int UMSDOS_lookup (struct inode *dir,
         int len,
         struct inode **result);
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
-/* emd.c 30/01/95 22.05.32 */
-int umsdos_readdir_kmem (struct inode *inode,
-        struct file *filp,
-        struct dirent *dirent,
-        int count);
+/* emd.c 22/06/95 00.22.04 */
 int umsdos_file_read_kmem (struct inode *inode,
         struct file *filp,
         char *buf,
@@ -57,11 +53,13 @@ int umsdos_isempty (struct inode *dir);
 int umsdos_findentry (struct inode *dir,
         struct umsdos_info *info,
         int expect);
-/* file.c 30/01/95 22.05.56 */
-/* inode.c 25/02/95 09.21.46 */
+/* file.c 25/01/95 02.25.38 */
+/* inode.c 12/06/95 09.49.40 */
 void UMSDOS_put_inode (struct inode *inode);
 void UMSDOS_put_super (struct super_block *sb);
-void UMSDOS_statfs (struct super_block *sb, struct statfs *buf, int);
+void UMSDOS_statfs (struct super_block *sb,
+        struct statfs *buf,
+        int bufsiz);
 int umsdos_real_lookup (struct inode *dir,
         const char *name,
         int len,
@@ -81,16 +79,16 @@ int UMSDOS_notify_change (struct inode *inode, struct iattr *attr);
 struct super_block *UMSDOS_read_super (struct super_block *s,
         void *data,
         int silent);
-/* ioctl.c 21/02/95 20.58.22 */
+/* ioctl.c 22/06/95 00.22.08 */
 int UMSDOS_ioctl_dir (struct inode *dir,
         struct file *filp,
         unsigned int cmd,
         unsigned long data);
-/* mangle.c 30/01/95 22.05.56 */
+/* mangle.c 25/01/95 02.25.38 */
 void umsdos_manglename (struct umsdos_info *info);
 int umsdos_evalrecsize (int len);
 int umsdos_parse (const char *fname, int len, struct umsdos_info *info);
-/* namei.c 30/01/95 22.05.56 */
+/* namei.c 25/01/95 02.25.38 */
 void umsdos_lockcreate (struct inode *dir);
 void umsdos_startlookup (struct inode *dir);
 void umsdos_unlockcreate (struct inode *dir);
@@ -125,7 +123,7 @@ int UMSDOS_rename (struct inode *old_dir,
         struct inode *new_dir,
         const char *new_name,
         int new_len);
-/* rdir.c 18/03/95 00.30.18 */
+/* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
         const char *name,
         int len,
@@ -135,4 +133,4 @@ int UMSDOS_rlookup (struct inode *dir,
         const char *name,
         int len,
         struct inode **result);
-/* symlink.c 30/01/95 22.05.32 */
+/* symlink.c 23/01/95 03.38.30 */
index be7c845918ce2bd03c1f19a9c0fd69c37277d4e5..28b7a2beb4c4995ff93bb8af68472a25d8015963 100644 (file)
@@ -65,15 +65,15 @@ struct sock {
   struct options               *opt;
   volatile unsigned long       wmem_alloc;
   volatile unsigned long       rmem_alloc;
-  unsigned long                        write_seq;
-  unsigned long                        sent_seq;
-  unsigned long                        acked_seq;
-  unsigned long                        copied_seq;
-  unsigned long                        rcv_ack_seq;
-  unsigned long                        window_seq;
-  unsigned long                        fin_seq;
-  unsigned long                        urg_seq;
-  unsigned long                        urg_data;
+  __u32                                write_seq;
+  __u32                                sent_seq;
+  __u32                                acked_seq;
+  __u32                                copied_seq;
+  __u32                                rcv_ack_seq;
+  __u32                                window_seq;
+  __u32                                fin_seq;
+  __u32                                urg_seq;
+  __u32                                urg_data;
 
   /*
    * Not all are volatile, but some are, so we
index efeaac0da6610e6fcf80b514623bce0ba323ae75..30b09679f7bb5b6408c49d8103f8ac202acd1675 100644 (file)
  * and worry about wraparound (automatic with unsigned arithmetic).
  */
 
-extern __inline int before(unsigned long seq1, unsigned long seq2)
+extern __inline int before(__u32 seq1, __u32 seq2)
 {
-        return (long)(seq1-seq2) < 0;
+        return (__s32)(seq1-seq2) < 0;
 }
 
-extern __inline int after(unsigned long seq1, unsigned long seq2)
+extern __inline int after(__u32 seq1, __u32 seq2)
 {
-       return (long)(seq1-seq2) > 0;
+       return (__s32)(seq1-seq2) > 0;
 }
 
 
 /* is s2<=s1<=s3 ? */
-extern __inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
+extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
 {
        return (after(seq1+1, seq2) && before(seq1, seq3+1));
 }
index a598e692fb3fa0aa8de3ec2c7ed66161ee1f7600..16a91d39135090e20315da3f7641b2374b227d22 100644 (file)
@@ -64,7 +64,7 @@ extern void pas16_setup(char *str, int *ints);
 extern void generic_NCR5380_setup(char *str, int *intr);
 extern void aha152x_setup(char *str, int *ints);
 extern void aha1542_setup(char *str, int *ints);
-extern void aha274x_setup(char *str, int *ints);
+extern void aic7xxx_setup(char *str, int *ints);
 extern void buslogic_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
@@ -175,8 +175,8 @@ struct {
 #ifdef CONFIG_SCSI_AHA1542
        { "aha1542=", aha1542_setup},
 #endif
-#ifdef CONFIG_SCSI_AHA274X
-       { "aha274x=", aha274x_setup},
+#ifdef CONFIG_SCSI_AIC7XXX
+       { "aic7xxx=", aic7xxx_setup},
 #endif
 #ifdef CONFIG_SCSI_BUSLOGIC
        { "buslogic=", buslogic_setup},
index d3c6b955e4f07a3a11bc5660cf77a4af3c6b2994..943920c997034345b410e1c46dd52bdfa3ffa43a 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -51,7 +51,7 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
        err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
        if (err) 
                return err;
-       if ((mtype = get_fs_long (&msgp->mtype)) < 1)
+       if ((mtype = get_user (&msgp->mtype)) < 1)
                return -EINVAL;
        id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
@@ -192,7 +192,7 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long ms
                        msq->msg_cbytes -= nmsg->msg_ts;
                        if (msq->wwait)
                                wake_up (&msq->wwait);
-                       put_fs_long (nmsg->msg_type, &msgp->mtype);
+                       put_user (nmsg->msg_type, &msgp->mtype);
                        memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
                        kfree(nmsg);
                        return msgsz;
index bb747255f2aaa88bbb82b30bb85cb19ea7ee9ce6..4a4fd0ad905038203a644effc97cd54408a7211a 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -674,7 +674,7 @@ done:       /* pte_val(pte) == shp->shm_pages[idx] */
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
 
-int shm_swap (int prio)
+int shm_swap (int prio, unsigned long limit)
 {
        pte_t page;
        struct shmid_ds *shp;
@@ -711,6 +711,8 @@ int shm_swap (int prio)
        pte_val(page) = shp->shm_pages[idx];
        if (!pte_present(page))
                goto check_table;
+       if (pte_page(page) >= limit)
+               goto check_table;
        swap_attempts++;
 
        if (--counter < 0) { /* failed */
@@ -728,7 +730,7 @@ int shm_swap (int prio)
                pte_t *page_table, pte;
                unsigned long tmp;
 
-               if (SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK != id) {
+               if ((SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK) != id) {
                        printk ("shm_swap: id=%ld does not match shmd->vm_pte.id=%ld\n",
                                id, SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK);
                        continue;
index 91aa48d50fd33b58fbc04adde2e47c6a03cca990..5f5f98a8473a85aa905ebde7de4194963fab026b 100644 (file)
@@ -57,7 +57,7 @@ void sem_exit (void)
     return;
 }
 
-int shm_swap (int prio)
+int shm_swap (int prio, unsigned long limit)
 {
     return 0;
 }
index 59c0b075b1eb3f7dc795fab1108eb1c8e36f0fe3..76b47813659776c9f2b6061044ecd29dbe6055a2 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#define DEBUG_PROC_TREE
+#undef DEBUG_PROC_TREE
 
 #include <linux/wait.h>
 #include <linux/errno.h>
@@ -515,7 +515,7 @@ repeat:
                                if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
                                        continue;
                                if (stat_addr)
-                                       put_fs_long((p->exit_code << 8) | 0x7f,
+                                       put_user((p->exit_code << 8) | 0x7f,
                                                stat_addr);
                                p->exit_code = 0;
                                if (ru != NULL)
@@ -531,7 +531,7 @@ repeat:
                                        getrusage(p, RUSAGE_BOTH, ru);
                                flag = p->pid;
                                if (stat_addr)
-                                       put_fs_long(p->exit_code, stat_addr);
+                                       put_user(p->exit_code, stat_addr);
                                if (p->p_opptr != p->p_pptr) {
                                        REMOVE_LINKS(p);
                                        p->p_pptr = p->p_opptr;
index 9341e50597c0daebf91750a93650df008d7945b6..9e4870bf54945d902bb0cba5cb74a465169facba 100644 (file)
@@ -57,7 +57,7 @@
 #endif
 
 #include <asm/irq.h>
-extern char floppy_track_buffer[];
+extern char *get_options(char *str, int *ints);
 extern void set_device_ro(int dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
   
@@ -88,6 +88,7 @@ struct symbol_table symbol_table = {
        /* stackable module support */
        X(rename_module_symbol),
        X(register_symtab),
+       X(get_options),
 
        /* system info variables */
        /* These check that they aren't defines (0/1) */
@@ -298,7 +299,6 @@ struct symbol_table symbol_table = {
        /* The next labels are needed for ftape driver.  */
        X(ftape_big_buffer),
 #endif
-       X(floppy_track_buffer),
 #ifdef CONFIG_INET
        /* support for loadable net drivers */
        X(register_netdev),
index e29a48ba5be33c8ad3b09ebc8d9d4a3a28522af9..f25870724fef19d907d33d8ba47134b6e1ce591d 100644 (file)
@@ -154,8 +154,8 @@ sys_create_module(char *module_name, unsigned long size)
        }
        strcpy((char *)(mp + 1), name); /* why not? */
 
-       npages = (size + sizeof (int) + 4095) / 4096;
-       if ((addr = vmalloc(npages * 4096)) == 0) {
+       npages = (size + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE;
+       if ((addr = vmalloc(npages * PAGE_SIZE)) == 0) {
                kfree_s(mp, sspace);
                return -ENOMEM;
        }
@@ -169,7 +169,7 @@ sys_create_module(char *module_name, unsigned long size)
        mp->state = MOD_UNINITIALIZED;
        mp->cleanup = NULL;
 
-       * (int *) addr = 0;     /* set use count to zero */
+       * (long *) addr = 0;    /* set use count to zero */
        module_list = mp;       /* link it in */
 
        PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
@@ -194,11 +194,14 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
        if (!suser())
                return -EPERM;
 
+#ifdef __i386__
        /* A little bit of protection... we "know" where the user stack is... */
+
        if (symtab && ((unsigned long)symtab > 0xb0000000)) {
                printk("warning: you are using an old insmod, no symbols will be inserted!\n");
                symtab = NULL;
        }
+#endif
 
        /*
         * First reclaim any memory from dead modules that where not
@@ -214,11 +217,11 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
        memcpy_fromfs(&rt, routines, sizeof rt);
        if ((mp = find_module(name)) == NULL)
                return -ENOENT;
-       if ((codesize + sizeof (int) + 4095) / 4096 > mp->size)
+       if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size)
                return -EINVAL;
-       memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize);
-       memset((char *)mp->addr + sizeof (int) + codesize, 0,
-               mp->size * 4096 - (codesize + sizeof (int)));
+       memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize);
+       memset((char *)mp->addr + sizeof (long) + codesize, 0,
+               mp->size * PAGE_SIZE - (codesize + sizeof (long)));
        PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
                (unsigned long) rt.init, (unsigned long) rt.cleanup));
        mp->cleanup = rt.cleanup;
@@ -231,9 +234,9 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
                int i;
                int legal_start;
 
-               if ((error = verify_area(VERIFY_READ, symtab, sizeof(int))))
+               if ((error = verify_area(VERIFY_READ, &symtab->size, sizeof(symtab->size))))
                        return error;
-               memcpy_fromfs((char *)(&(size)), symtab, sizeof(int));
+               size = get_user(&symtab->size);
 
                if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) {
                        return -ENOMEM;
@@ -417,7 +420,7 @@ get_mod_name(char *user_name, char *buf)
        int i;
 
        i = 0;
-       for (i = 0 ; (buf[i] = get_fs_byte(user_name + i)) != '\0' ; ) {
+       for (i = 0 ; (buf[i] = get_user(user_name + i)) != '\0' ; ) {
                if (++i >= MOD_MAX_NAME)
                        return -E2BIG;
        }
@@ -613,7 +616,7 @@ int get_ksyms_list(char *buf)
  * - For a loadable module, the function should only be called in the
  *   context of init_module
  *
- * Those are the only restrictions! (apart from not being reenterable...)
+ * Those are the only restrictions! (apart from not being reentrant...)
  *
  * If you want to remove a symbol table for a loadable module,
  * the call looks like: "register_symtab(0)".
index 8b518f6cbf8804e5427cf82d08fd2802ef012e20..f0d6589bcb407d190cab45631067ce4d7cb69526 100644 (file)
@@ -89,7 +89,7 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
                                log_size--;
                                log_start &= LOG_BUF_LEN-1;
                                sti();
-                               put_fs_byte(c,buf);
+                               put_user(c,buf);
                                buf++;
                                i++;
                                cli();
@@ -115,7 +115,7 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
                        j = log_start + log_size - count;
                        for (i = 0; i < count; i++) {
                                c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
-                               put_fs_byte(c, buf++);
+                               put_user(c, buf++);
                        }
                        if (do_clear)
                                logged_chars = 0;
index 1ba07bd894ffb8676e880296cf354c81c7ec93b9..88bf0d85468c84d548a498cc79028bb260033f35 100644 (file)
@@ -28,7 +28,7 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
                error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
                if (error)
                        return error;
-               new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
+               new_set = get_user(set) & _BLOCKABLE;
                switch (how) {
                case SIG_BLOCK:
                        current->blocked |= new_set;
@@ -47,7 +47,7 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
                error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
                if (error)
                        return error;
-               put_fs_long(old_set, (unsigned long *) oset);
+               put_user(old_set, oset);
        }
        return 0;
 }
@@ -71,7 +71,7 @@ asmlinkage int sys_sigpending(sigset_t *set)
        /* fill in "set" with signals pending but blocked. */
        error = verify_area(VERIFY_WRITE, set, 4);
        if (!error)
-               put_fs_long(current->blocked & current->signal, (unsigned long *)set);
+               put_user(current->blocked & current->signal, set);
        return error;
 }
 
index e7aca9c657161ace78aaa97e6244dbc212693a92..698799f54ce8f15d945c5463a425ed59337f06f8 100644 (file)
@@ -368,10 +368,10 @@ asmlinkage int sys_times(struct tms * tbuf)
                int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
                if (error)
                        return error;
-               put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
-               put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
-               put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
-               put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
+               put_user(current->utime,&tbuf->tms_utime);
+               put_user(current->stime,&tbuf->tms_stime);
+               put_user(current->cutime,&tbuf->tms_cutime);
+               put_user(current->cstime,&tbuf->tms_cstime);
        }
        return jiffies;
 }
@@ -554,7 +554,7 @@ asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
        if (gidsetsize > NGROUPS)
                return -EINVAL;
        for (i = 0; i < gidsetsize; i++, grouplist++) {
-               current->groups[i] = get_fs_word((unsigned short *) grouplist);
+               current->groups[i] = get_user(grouplist);
        }
        if (i < NGROUPS)
                current->groups[i] = NOGROUP;
@@ -619,15 +619,15 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        if (error)
                return error;
        memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-       put_fs_byte(0,name->sysname+__OLD_UTS_LEN);
+       put_user(0,name->sysname+__OLD_UTS_LEN);
        memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-       put_fs_byte(0,name->nodename+__OLD_UTS_LEN);
+       put_user(0,name->nodename+__OLD_UTS_LEN);
        memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-       put_fs_byte(0,name->release+__OLD_UTS_LEN);
+       put_user(0,name->release+__OLD_UTS_LEN);
        memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-       put_fs_byte(0,name->version+__OLD_UTS_LEN);
+       put_user(0,name->version+__OLD_UTS_LEN);
        memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-       put_fs_byte(0,name->machine+__OLD_UTS_LEN);
+       put_user(0,name->machine+__OLD_UTS_LEN);
        return 0;
 }
 
@@ -676,7 +676,7 @@ asmlinkage int sys_setdomainname(char *name, int len)
        if (len > __NEW_UTS_LEN)
                return -EINVAL;
        for (i=0; i < len; i++) {
-               if ((system_utsname.domainname[i] = get_fs_byte(name+i)) == 0)
+               if ((system_utsname.domainname[i] = get_user(name+i)) == 0)
                        return 0;
        }
        system_utsname.domainname[i] = 0;
index 51adb8f5f8050db621762c7c83a2631270d74043..8bea4ed2e5c0fd68774cb3aad272f441127a2229 100644 (file)
@@ -122,31 +122,30 @@ void time_init(void)
  */
 struct timezone sys_tz = { 0, 0};
 
-asmlinkage int sys_time(long * tloc)
+asmlinkage int sys_time(int * tloc)
 {
        int i, error;
 
        i = CURRENT_TIME;
        if (tloc) {
-               error = verify_area(VERIFY_WRITE, tloc, 4);
+               error = verify_area(VERIFY_WRITE, tloc, sizeof(*tloc));
                if (error)
                        return error;
-               put_fs_long(i,(unsigned long *)tloc);
+               put_user(i,tloc);
        }
        return i;
 }
 
-asmlinkage int sys_stime(unsigned long * tptr)
+asmlinkage int sys_stime(int * tptr)
 {
-       int error;
-       unsigned long value;
+       int error, value;
 
        if (!suser())
                return -EPERM;
        error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
        if (error)
                return error;
-       value = get_fs_long(tptr);
+       value = get_user(tptr);
        cli();
        xtime.tv_sec = value;
        xtime.tv_usec = 0;
index e288ecf2f3154ecc178cc63d159e577a6b670448..244f1ebf808d7ba19ab74a16319a98e34586be77 100644 (file)
@@ -13,8 +13,9 @@
  */
 
 #include <linux/mm.h>
-#include <asm/system.h>
 #include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/dma.h>
 
 #define GFP_LEVEL_MASK 0xf
 
@@ -251,10 +252,13 @@ while (tries --)
     sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */
 
     /* This can be done with ints on: This is private to this invocation */
-    if (dma_flag)
-      page = (struct page_descriptor *) __get_dma_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
-    else
-      page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
+    {
+       unsigned long max_addr = ~0UL;
+       if (dma_flag)
+               max_addr = MAX_DMA_ADDRESS;
+       page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK,
+               sizes[order].gfporder, max_addr);
+    }
 
     if (!page) {
         static unsigned long last = 0;
index 3253a06c0df3ae14b4753e348c3878bbd61718eb..80b7f2ce79a3b76c83f2aa04f89a262e85e51f75 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -189,26 +189,6 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
        }
 }
 
-asmlinkage int sys_mmap(unsigned long *buffer)
-{
-       int error;
-       unsigned long flags;
-       struct file * file = NULL;
-
-       error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
-       if (error)
-               return error;
-       flags = get_fs_long(buffer+3);
-       if (!(flags & MAP_ANONYMOUS)) {
-               unsigned long fd = get_fs_long(buffer+4);
-               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-                       return -EBADF;
-       }
-       return do_mmap(file, get_fs_long(buffer), get_fs_long(buffer+1),
-               get_fs_long(buffer+2), flags, get_fs_long(buffer+5));
-}
-
-
 /*
  * Searching a VMA in the linear list task->mm->mmap is horribly slow.
  * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
index 542be511a9e8daed1e8826be7218ea12c8abb772..68a516760b26428f9b57474693cdf48e1976f42e 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -53,7 +53,7 @@ static struct swap_info_struct {
        int next;                       /* next entry on swap list */
 } swap_info[MAX_SWAPFILES];
 
-extern int shm_swap (int);
+extern int shm_swap (int, unsigned long);
 
 unsigned long *swap_cache;
 
@@ -345,7 +345,7 @@ void swap_in(struct vm_area_struct * vma, pte_t * page_table,
  * using a process that no longer actually exists (it might
  * have died while we slept).
  */
-static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table)
+static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, unsigned long limit)
 {
        pte_t pte;
        unsigned long entry;
@@ -357,6 +357,8 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long addr
        page = pte_page(pte);
        if (page >= high_memory)
                return 0;
+       if (page >= limit)
+               return 0;
        if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
                return 0;
        if ((pte_dirty(pte) && delete_from_swap_cache(page)) || pte_young(pte))  {
@@ -428,7 +430,7 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long addr
 #define SWAP_RATIO     128
 
 static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir,
-       unsigned long address, unsigned long end)
+       unsigned long address, unsigned long end, unsigned long limit)
 {
        pte_t * pte;
        unsigned long pmd_end;
@@ -450,7 +452,7 @@ static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir,
        do {
                int result;
                vma->vm_task->mm->swap_address = address + PAGE_SIZE;
-               result = try_to_swap_out(vma, address, pte);
+               result = try_to_swap_out(vma, address, pte, limit);
                if (result)
                        return result;
                address += PAGE_SIZE;
@@ -460,7 +462,7 @@ static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir,
 }
 
 static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir,
-       unsigned long address, unsigned long end)
+       unsigned long address, unsigned long end, unsigned long limit)
 {
        pmd_t * pmd;
        unsigned long pgd_end;
@@ -480,7 +482,7 @@ static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir,
                end = pgd_end;
        
        do {
-               int result = swap_out_pmd(vma, pmd, address, end);
+               int result = swap_out_pmd(vma, pmd, address, end, limit);
                if (result)
                        return result;
                address = (address + PMD_SIZE) & PMD_MASK;
@@ -490,7 +492,7 @@ static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir,
 }
 
 static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir,
-       unsigned long start)
+       unsigned long start, unsigned long limit)
 {
        unsigned long end;
 
@@ -501,7 +503,7 @@ static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir,
 
        end = vma->vm_end;
        while (start < end) {
-               int result = swap_out_pgd(vma, pgdir, start, end);
+               int result = swap_out_pgd(vma, pgdir, start, end, limit);
                if (result)
                        return result;
                start = (start + PGDIR_SIZE) & PGDIR_MASK;
@@ -510,7 +512,7 @@ static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir,
        return 0;
 }
 
-static int swap_out_process(struct task_struct * p)
+static int swap_out_process(struct task_struct * p, unsigned long limit)
 {
        unsigned long address;
        struct vm_area_struct* vma;
@@ -531,7 +533,7 @@ static int swap_out_process(struct task_struct * p)
                address = vma->vm_start;
 
        for (;;) {
-               int result = swap_out_vma(vma, pgd_offset(p, address), address);
+               int result = swap_out_vma(vma, pgd_offset(p, address), address, limit);
                if (result)
                        return result;
                vma = vma->vm_next;
@@ -543,7 +545,7 @@ static int swap_out_process(struct task_struct * p)
        return 0;
 }
 
-static int swap_out(unsigned int priority)
+static int swap_out(unsigned int priority, unsigned long limit)
 {
        static int swap_task;
        int loop, counter;
@@ -589,7 +591,7 @@ static int swap_out(unsigned int priority)
                }
                if (!--p->mm->swap_cnt)
                        swap_task++;
-               switch (swap_out_process(p)) {
+               switch (swap_out_process(p, limit)) {
                        case 0:
                                if (p->mm->swap_cnt)
                                        swap_task++;
@@ -612,7 +614,7 @@ static int swap_out(unsigned int priority)
  * free'd, so hopefully we'll get reasonable behaviour even under very
  * different circumstances.
  */
-static int try_to_free_page(int priority)
+static int try_to_free_page(int priority, unsigned long limit)
 {
        static int state = 0;
        int i=6;
@@ -620,15 +622,15 @@ static int try_to_free_page(int priority)
        switch (state) {
                do {
                case 0:
-                       if (priority != GFP_NOBUFFER && shrink_buffers(i))
+                       if (priority != GFP_NOBUFFER && shrink_buffers(i, limit))
                                return 1;
                        state = 1;
                case 1:
-                       if (shm_swap(i))
+                       if (shm_swap(i, limit))
                                return 1;
                        state = 2;
                default:
-                       if (swap_out(i))
+                       if (swap_out(i, limit))
                                return 1;
                        state = 0;
                } while(i--);
@@ -730,18 +732,22 @@ void free_pages(unsigned long addr, unsigned long order)
 /*
  * Some ugly macros to speed up __get_free_pages()..
  */
-#define RMQUEUE(order) \
+#define RMQUEUE(order, limit) \
 do { struct mem_list * queue = free_area_list+order; \
      unsigned long new_order = order; \
-       do { struct mem_list *next = queue->next; \
-               if (queue != next) { \
-                       (queue->next = next->next)->prev = queue; \
-                       mark_used((unsigned long) next, new_order); \
-                       nr_free_pages -= 1 << order; \
-                       restore_flags(flags); \
-                       EXPAND(next, order, new_order); \
-                       return (unsigned long) next; \
-               } new_order++; queue++; \
+       do { struct mem_list *prev = queue, *ret; \
+               while (queue != (ret = prev->next)) { \
+                       if ((unsigned long) ret < (limit)) { \
+                               (prev->next = ret->next)->prev = prev; \
+                               mark_used((unsigned long) ret, new_order); \
+                               nr_free_pages -= 1 << order; \
+                               restore_flags(flags); \
+                               EXPAND(ret, order, new_order); \
+                               return (unsigned long) ret; \
+                       } \
+                       prev = ret; \
+               } \
+               new_order++; queue++; \
        } while (new_order < NR_MEM_LISTS); \
 } while (0)
 
@@ -761,7 +767,7 @@ do { unsigned long size = PAGE_SIZE << high; \
        } mem_map[MAP_NR((unsigned long) addr)] = 1; \
 } while (0)
 
-unsigned long __get_free_pages(int priority, unsigned long order)
+unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
 {
        unsigned long flags;
        int reserved_pages;
@@ -781,43 +787,16 @@ unsigned long __get_free_pages(int priority, unsigned long order)
 repeat:
        cli();
        if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
-               RMQUEUE(order);
+               RMQUEUE(order, limit);
                restore_flags(flags);
                return 0;
        }
        restore_flags(flags);
-       if (priority != GFP_BUFFER && try_to_free_page(priority))
+       if (priority != GFP_BUFFER && try_to_free_page(priority, limit))
                goto repeat;
        return 0;
 }
 
-/*
- * Yes, I know this is ugly. Don't tell me.
- */
-unsigned long __get_dma_pages(int priority, unsigned long order)
-{
-       unsigned long list = 0;
-       unsigned long result;
-       unsigned long limit = MAX_DMA_ADDRESS;
-
-       /* if (EISA_bus) limit = ~0UL; */
-       if (priority != GFP_ATOMIC)
-               priority = GFP_BUFFER;
-       for (;;) {
-               result = __get_free_pages(priority, order);
-               if (result < limit) /* covers failure as well */
-                       break;
-               *(unsigned long *) result = list;
-               list = result;
-       }
-       while (list) {
-               unsigned long tmp = list;
-               list = *(unsigned long *) list;
-               free_pages(tmp, order);
-       }
-       return result;
-}
-
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
index 107be5546c6b4b9b2e1cafcc7ecf1a2316875535..8012774cc4c293e2587f1c162c09c89f3a9942a3 100644 (file)
@@ -228,7 +228,7 @@ int vread(char *buf, char *addr, int count)
                while (addr < vaddr) {
                        if (count == 0)
                                goto finished;
-                       put_fs_byte('\0', buf++), addr++, count--;
+                       put_user('\0', buf++), addr++, count--;
                }
                n = tmp->size - PAGE_SIZE;
                if (addr > vaddr)
@@ -236,7 +236,7 @@ int vread(char *buf, char *addr, int count)
                while (--n >= 0) {
                        if (count == 0)
                                goto finished;
-                       put_fs_byte(*addr++, buf++), count--;
+                       put_user(*addr++, buf++), count--;
                }
        }
 finished:
index 67ad1bf223d29f3cf9d45e04afd093fc446f9fc2..dbb78aab85762fa9d21409648eede6d32172c2b2 100644 (file)
@@ -998,9 +998,9 @@ static int atalk_getsockopt(struct socket *sock, int level, int optname,
        err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
        if(err)
                return err;
-       put_fs_long(sizeof(int),(unsigned long *)optlen);
+       put_user(sizeof(int),optlen);
        err=verify_area(VERIFY_WRITE,optval,sizeof(int));
-       put_fs_long(val,(unsigned long *)optval);
+       put_user(val,optval);
        return(0);
 }
 
index 725939698e6174d845ac5ea06b020f61f6d46299..e21760a07991bd7eaf50792b4b9b12b52afaa132 100644 (file)
@@ -708,12 +708,12 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname,
        if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0)
                return err;
 
-       put_fs_long(sizeof(int), (unsigned long *)optlen);
+       put_user(sizeof(int), optlen);
 
        if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
                return err;
 
-       put_fs_long(val, (unsigned long *)optval);
+       put_user(val, optval);
 
        return 0;
 }
index f670fa092db47e3bc19b5c5649d3d6cf2f8546c4..e40766bc46c8db9db847fd5ced961282b036c143 100644 (file)
@@ -75,7 +75,7 @@ void raw_err (int err, unsigned char *header, unsigned long daddr,
                return;
 
        /* This is meaningless in raw sockets. */
-       if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) 
+       if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
        {
                if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
                return;
index 352e1a1017ea9a3f94834744b86cb7496afc0c95..894bfa54cdeb5dffd5f3206169a5cdcb551a59c0 100644 (file)
@@ -1252,7 +1252,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk)
  *     This routine sends an ack and also updates the window. 
  */
  
-static void tcp_send_ack(unsigned long sequence, unsigned long ack,
+static void tcp_send_ack(u32 sequence, u32 ack,
             struct sock *sk,
             struct tcphdr *th, unsigned long daddr)
 {
@@ -1361,7 +1361,7 @@ static void tcp_send_ack(unsigned long sequence, unsigned long ack,
        t1->doff = sizeof(*t1)/4;
        tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
        if (sk->debug)
-                printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
+                printk("\rtcp_ack: seq %x ack %x\n", sequence, ack);
        tcp_statistics.TcpOutSegs++;
        sk->prot->queue_xmit(sk, dev, buff, 1);
 }
@@ -1976,8 +1976,8 @@ static int tcp_read(struct sock *sk, unsigned char *to,
 {
        struct wait_queue wait = { current, NULL };
        int copied = 0;
-       unsigned long peek_seq;
-       volatile unsigned long *seq;    /* So gcc doesn't overoptimise */
+       u32 peek_seq;
+       volatile u32 *seq;      /* So gcc doesn't overoptimise */
        unsigned long used;
 
        /* 
@@ -2614,7 +2614,7 @@ static inline unsigned long default_mask(unsigned long dst)
  *     That's funny, Linux has one built in!  Use it!
  */
 
-extern inline unsigned long tcp_init_seq(void)
+extern inline u32 tcp_init_seq(void)
 {
        struct timeval tv;
        do_gettimeofday(&tv);
@@ -2631,7 +2631,7 @@ extern inline unsigned long tcp_init_seq(void)
  
 static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
                 unsigned long daddr, unsigned long saddr,
-                struct options *opt, struct device *dev, unsigned long seq)
+                struct options *opt, struct device *dev, u32 seq)
 {
        struct sk_buff *buff;
        struct tcphdr *t1;
@@ -3069,7 +3069,7 @@ static void tcp_write_xmit(struct sock *sk)
 
 extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
 {
-       unsigned long ack;
+       u32 ack;
        int flag = 0;
 
        /* 
@@ -3116,7 +3116,7 @@ extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long
        if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) 
        {
                if(sk->debug)
-                       printk("Ack ignored %lu %lu\n",ack,sk->sent_seq);
+                       printk("Ack ignored %u %u\n",ack,sk->sent_seq);
                        
                /*
                 *      Keepalive processing.
@@ -3541,7 +3541,7 @@ extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long
                if (!sk->dead)
                        sk->state_change(sk);
                if(sk->debug)
-                       printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n",
+                       printk("rcv_ack_seq: %X==%X, acked_seq: %X==%X\n",
                                sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq);
                if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/) 
                {
@@ -3763,8 +3763,7 @@ extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk,
        struct sk_buff *skb1, *skb2;
        struct tcphdr *th;
        int dup_dumped=0;
-       unsigned long new_seq;
-       unsigned long shut_seq;
+       u32 new_seq, shut_seq;
 
        th = skb->h.th;
        skb->len = len -(th->doff*4);
@@ -3824,7 +3823,7 @@ extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk,
                        if(after(new_seq,shut_seq))
                        {
                                if(sk->debug)
-                                       printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n",
+                                       printk("Data arrived on %p after close [Data right edge %X, Socket shut on %X] %d\n",
                                                sk, new_seq, shut_seq, sk->blog);
                                if(sk->dead)
                                {
@@ -3868,9 +3867,9 @@ extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk,
                        if(sk->debug)
                        {
                                printk("skb1=%p :", skb1);
-                               printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
-                               printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
-                               printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
+                               printk("skb1->h.th->seq = %d: ", skb1->h.th->seq);
+                               printk("skb->h.th->seq = %d\n",skb->h.th->seq);
+                               printk("copied_seq = %d acked_seq = %d\n", sk->copied_seq,
                                                sk->acked_seq);
                        }
                        
@@ -4382,7 +4381,7 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
             struct options *opt, unsigned long saddr, struct device *dev)
 {
-       unsigned long next_seq;
+       u32 next_seq;
 
        next_seq = len - 4*th->doff;
        if (th->fin)
@@ -4751,7 +4750,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead && 
                        after(th->seq, sk->acked_seq) && !th->rst)
                {
-                       long seq=sk->write_seq;
+                       u32 seq = sk->write_seq;
                        if(sk->debug)
                                printk("Doing a BSD time wait\n");
                        tcp_statistics.TcpEstabResets++;           
index 9976e2be2a27abb393cd9c0b500d2c0e8f0e7202..a376e9b983387a14f95b918886e282ac1b420a83 100644 (file)
@@ -142,7 +142,7 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
        if (sk == NULL) 
                return; /* No socket for error */
        
-       if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) 
+       if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
        {       /* Slow down! */
                if (sk->cong_window > 1) 
                        sk->cong_window = sk->cong_window/2;
index 35b31909b1d70d3bd40d2d581579c3aaa02298b7..dabe248d0c5196a2cb945b97055d7b7991f2841f 100644 (file)
@@ -136,7 +136,7 @@ static int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
                
        if((err=verify_area(VERIFY_WRITE,ulen,sizeof(*ulen)))<0)
                return err;
-       len=get_fs_long(ulen);
+       len=get_user(ulen);
        if(len>klen)
                len=klen;
        if(len<0 || len> MAX_SOCK_ADDR)
@@ -147,7 +147,7 @@ static int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
                        return err;
                memcpy_tofs(uaddr,kaddr,len);
        }
-       put_fs_long(len,ulen);
+       put_user(len,ulen);
        return 0;
 }
 
@@ -625,7 +625,7 @@ asmlinkage int sys_socket(int family, int type, int protocol)
  *     Create a pair of connected sockets.
  */
 
-asmlinkage int sys_socketpair(int family, int type, int protocol, unsigned long usockvec[2])
+asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2])
 {
        int fd1, fd2, i;
        struct socket *sock1, *sock2;
@@ -668,15 +668,15 @@ asmlinkage int sys_socketpair(int family, int type, int protocol, unsigned long
        sock1->state = SS_CONNECTED;
        sock2->state = SS_CONNECTED;
 
-       er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int));
+       er=verify_area(VERIFY_WRITE, usockvec, sizeof(usockvec));
        if(er)
        {
                sys_close(fd1);
                sys_close(fd2);
                return er;
        }
-       put_fs_long(fd1, &usockvec[0]);
-       put_fs_long(fd2, &usockvec[1]);
+       put_user(fd1, &usockvec[0]);
+       put_user(fd2, &usockvec[1]);
 
        return(0);
 }
@@ -1132,72 +1132,72 @@ asmlinkage int sys_socketcall(int call, unsigned long *args)
        if(er)
                return er;
                
-       a0=get_fs_long(args);
-       a1=get_fs_long(args+1);
+       a0=get_user(args);
+       a1=get_user(args+1);
        
                
        switch(call) 
        {
                case SYS_SOCKET:
-                       return(sys_socket(a0,a1,get_fs_long(args+2)));
+                       return(sys_socket(a0,a1,get_user(args+2)));
                case SYS_BIND:
                        return(sys_bind(a0,(struct sockaddr *)a1,
-                               get_fs_long(args+2)));
+                                       get_user(args+2)));
                case SYS_CONNECT:
                        return(sys_connect(a0, (struct sockaddr *)a1,
-                               get_fs_long(args+2)));
+                                          get_user(args+2)));
                case SYS_LISTEN:
                        return(sys_listen(a0,a1));
                case SYS_ACCEPT:
                        return(sys_accept(a0,(struct sockaddr *)a1,
-                               (int *)get_fs_long(args+2)));
+                                         (int *)get_user(args+2)));
                case SYS_GETSOCKNAME:
                        return(sys_getsockname(a0,(struct sockaddr *)a1,
-                               (int *)get_fs_long(args+2)));
+                                              (int *)get_user(args+2)));
                case SYS_GETPEERNAME:
                        return(sys_getpeername(a0, (struct sockaddr *)a1,
-                               (int *)get_fs_long(args+2)));
+                                              (int *)get_user(args+2)));
                case SYS_SOCKETPAIR:
                        return(sys_socketpair(a0,a1,
-                               get_fs_long(args+2),
-                               (unsigned long *)get_fs_long(args+3)));
+                                             get_user(args+2),
+                                             (int *)get_user(args+3)));
                case SYS_SEND:
                        return(sys_send(a0,
                                (void *)a1,
-                               get_fs_long(args+2),
-                               get_fs_long(args+3)));
+                               get_user(args+2),
+                               get_user(args+3)));
                case SYS_SENDTO:
                        return(sys_sendto(a0,(void *)a1,
-                               get_fs_long(args+2),
-                               get_fs_long(args+3),
-                               (struct sockaddr *)get_fs_long(args+4),
-                               get_fs_long(args+5)));
+                               get_user(args+2),
+                               get_user(args+3),
+                               (struct sockaddr *)get_user(args+4),
+                               get_user(args+5)));
                case SYS_RECV:
                        return(sys_recv(a0,
                                (void *)a1,
-                               get_fs_long(args+2),
-                               get_fs_long(args+3)));
+                               get_user(args+2),
+                               get_user(args+3)));
                case SYS_RECVFROM:
                        return(sys_recvfrom(a0,
                                (void *)a1,
-                               get_fs_long(args+2),
-                               get_fs_long(args+3),
-                               (struct sockaddr *)get_fs_long(args+4),
-                               (int *)get_fs_long(args+5)));
+                               get_user(args+2),
+                               get_user(args+3),
+                               (struct sockaddr *)get_user(args+4),
+                               (int *)get_user(args+5)));
                case SYS_SHUTDOWN:
                        return(sys_shutdown(a0,a1));
                case SYS_SETSOCKOPT:
                        return(sys_setsockopt(a0,
                                a1,
-                               get_fs_long(args+2),
-                               (char *)get_fs_long(args+3),
-                               get_fs_long(args+4)));
+                               get_user(args+2),
+                               (char *)get_user(args+3),
+                               get_user(args+4)));
                case SYS_GETSOCKOPT:
                        return(sys_getsockopt(a0,
                                a1,
-                               get_fs_long(args+2),
-                               (char *)get_fs_long(args+3),
-                               (int *)get_fs_long(args+4)));
+                               get_user(args+2),
+                               (char *)get_user(args+3),
+                               (int *)get_user(args+4)));
        }
        return -EINVAL; /* to keep gcc happy */
 }